Support for custom size/move operations in top level windows.

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Support for custom size/move operations in top level windows.

Brian Vanderburg
I'm working one something right now in wxPython to be ported to C++ some
more work.  I'm wondering if this could somehow be made generic and have
support in wxWidgets.

1. A window has no border, so now resize/moving handles.  This is needed
for custom drawing.  (A desktop sticky notes program that does not want
the window decoration)
2. Custom mouse handlers allow moving and resizing the window.
3. The window can be normal (wxFrame, with task button) or mini
(wxMiniFrame, with no task button)

One though was to add support directly to wxTopLevelWindow that would
allow setting the custom regions for resizing and dragging, and
implementing it internally.  I've attached a wxPython script that does
what I'm mean.  A window with no decoration exists and any custom
drawing can be done, custom colors, etc.  But events and code are added
to allow resizing and moving the window still.  If wx.MiniFrame is
changed to wx.Frame, then it will also appear on the taskbar.

Another thought was maybe the wxPopup classes could have such support,
probably not wxTransientPopup since it goes away when losing focus, but
a persistent popup that stays could have such support added to allow
resizing/moving perhaps.  Just an idea.

Brian Vanderburg II





import wx
import wx.richtext

class StickyNoteFrame(wx.MiniFrame):
    def __init__(self):
        wx.MiniFrame.__init__(self, None, -1, "Title", pos = (100, 100), style = wx.NO_BORDER)

        # Normally, the data and id of the note would be passed and we
        # would fetch the information from the database
        self.framebgcolor = wx.Colour(0, 128, 64)
        self.textbgcolor = wx.Colour(0, 0, 128)
        self.textfgcolor = wx.Colour(255, 255, 0)
        self.textsize = 14
        self.textwrap = True
       
        # Load cursors
        self.cursorNS = wx.StockCursor(wx.CURSOR_SIZENS)
        self.cursorWE = wx.StockCursor(wx.CURSOR_SIZEWE)
        self.cursorNESW = wx.StockCursor(wx.CURSOR_SIZENESW)
        self.cursorNWSE = wx.StockCursor(wx.CURSOR_SIZENWSE)
       
        # Set self
        self.SetBackgroundColour(self.framebgcolor)

        # Create note area
        self.text = wx.richtext.RichTextCtrl(self, style = wx.NO_BORDER | wx.TE_MULTILINE  | wx.TE_NO_VSCROLL| wx.WANTS_CHARS)

        self.text.SetBackgroundColour(self.textbgcolor)
        style = wx.richtext.RichTextAttr()
        style.SetBackgroundColour(self.textbgcolor)
        style.SetTextColour(self.textfgcolor)
       
        self.text.SetBasicStyle(style)
        self.text.SetForegroundColour(self.textbgcolor)
       
        # Sizer sizer
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add((0, 25), 0, wx.EXPAND)
        sizer.Add(self.text, 1, wx.EXPAND | wx.ALL, 5)
       
        self.SetMinSize((50, 20))
        self.SetSizerAndFit(sizer)

        # Events
        self.Bind(wx.EVT_MOTION, self.OnMotion)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
        self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
        self.state = 0

    def OnSetFocus(self, evt):
        pass
       
    def OnKillFocus(self, evt):
        wx.LogMessage("Focus lost")
        pass
       
    def OnLeave(self, evt):
        self.SetCursor(wx.NullCursor)
       
    def OnMouseDown(self, evt):
        (self.oldx, self.oldy) = wx.GetMousePosition()
        self.CaptureMouse()
       
    def OnMouseUp(self, evt):
        if self.HasCapture():
            self.ReleaseMouse()

    def OnMotion(self, evt):
        (mousex, mousey) = wx.GetMousePosition()
   
        if self.HasCapture():
            try:
                mode = self.mode
            except:
                mode = 4

            deltax = (mousex - self.oldx)
            deltay = (mousey - self.oldy)

            if deltax == 0 and deltay == 0:
                return

            (winx, winy) = self.GetPosition()
            (winw, winh) = self.GetSize()
            (minw, minh) = self.GetMinSize()
            (curx, cury, curw, curh) = (winx, winy, winw, winh)
           
            # Adjust x/w
            if mode == 0 or mode == 3 or mode == 6:
                winx += deltax
                winw -= deltax
                if winw < minw:
                    winx = curx
                    winw = curw
                else:
                    self.oldx = mousex
            elif mode == 2 or mode == 5 or mode == 8:
                winw += deltax
                if winw < minw:
                    winw = curw
                else:
                    self.oldx = mousex
                   
            # Adjust y/h
            if mode == 0 or mode == 1 or mode == 2:
                winy += deltay
                winh -= deltay
                if winh < minh:
                    winy = cury
                    winh = curh
                else:
                    self.oldy = mousey
            elif mode == 6 or mode == 7 or mode == 8:
                winh += deltay
                if winh < minh:
                    winh = curh
                else:
                    self.oldy = mousey
                   
            if mode == 4:
                winx += deltax
                winy += deltay
                self.oldx = mousex
                self.oldy = mousey
               
            self.SetDimensions(winx, winy, winw, winh)


        else:
            # Convert point to window units
            (mousex, mousey) = self.ScreenToClient((mousex, mousey))
            (sizex, sizey) = self.GetSize()
           
            # left/mid/right
            if mousex < 5:
                part1 = 0
            elif mousex > sizex - 5:
                part1 = 2
            else:
                part1 = 1
               
            # top/mid/bottom
            if mousey < 5:
                part2 = 0
            elif mousey > sizey - 5:
                part2 = 2
            else:
                part2 = 1
               
            self.mode = part1 + (3 * part2)
           
            # mouse cursor
            if self.mode == 0 or self.mode == 8:
                self.SetCursor(self.cursorNWSE)
            elif self.mode == 1 or self.mode == 7:
                self.SetCursor(self.cursorNS)
            elif self.mode == 2 or self.mode == 6:
                self.SetCursor(self.cursorNESW)
            elif self.mode == 3 or self.mode == 5:
                self.SetCursor(self.cursorWE)
            else:
                self.SetCursor(wx.NullCursor)
               
               


       
class App(wx.App):
    def OnInit(self):
        frame = StickyNoteFrame()
        self.SetTopWindow(frame)
        frame.Show(True)
        return True
       
app = App(redirect = False)
app.MainLoop()

_______________________________________________
wx-dev mailing list
[hidden email]
http://lists.wxwidgets.org/mailman/listinfo/wx-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Borderless frames with custom resize/more operations:

Brian Vanderburg
I don't know if this would be useful as part of the toolkit or not, but
I've got some code working, so far on Windows against wx 2.8.5.  Haven't
had a chance to test any other platforms.

This code creates a new type of frame, wxBorderlessFrame.  It still
honors some of the frame flags, and implements another.

It has built in moving and resizing code, so the entire frame can be
drawn with no problem.  There is no 'non-client' area.  I created this
because when trying to create a borderless or static/simple border frame
with wxRESIZE_BORDER on MSW, it always made it a 3D frame, which was
undesired.

Several things about this code:

Both event handlers and DoSetSize are provided, so the real size will be
updated by events and by programatic size changes when it is not collapsed.

When creating a frame WITHOUT wxBORDERLESS_FRAME_AUTOCOLLAPSE, it is
relatively simple.  The frame is created about like normal and it can be
moved and resized (if wxRESIZE_BORDER) is passed, but still has a flat
look allowing custom drawing of 'borders' background, etc.  It's size is
adjusted by the user or program.  It does not automatically 'collapse'
when losing activation.

If the frame is created with wxBORDERLESS_FRAME_AUTOCOLLAPSE, it is a
little more work.  After creating the frame, the 'real' size should be
set with SetRealSize, and the state should be set with Collapse or
Uncollapse.  The real size will be the initial frame size otherwise.
But, (at least with tests on MSW), if the frame is also created with
wxFRAME_TOOL_WINDOW, it will not receive focus (become activated), but
not be deactivated either, so it will sit there with the size it has.  
IsCollapsed will return false as if it is active, but clicking out of it
will not cause it to collapse since it is not active so won't get a
wxEVT_ACTIVATE event.  This isn't a real problem it still has the
initial size, and the user can click on it and out of it to collapse
it.  Program code can restore the state by directly calling Collapse or
Uncollapse

The source file contains a small test showing it work.


Brian Vanderburg II

// File:    borderlesswnd.cpp
// Author:  Brian Vanderburg II
// Purpose: create borderless windows with moving and resizing operations
//------------------------------------------------------------------------


// Includes
#include <wx/defs.h>
#include <wx/frame.h>
#include <wx/display.h>
#include <wx/cursor.h>
#include <wx/utils.h>

#include "borderlesswnd.h"

// Constructors
wxBorderlessFrame::wxBorderlessFrame()
{
    Init();
}

wxBorderlessFrame::wxBorderlessFrame(wxWindow* parent,
                                     wxWindowID id,
                                     const wxString& title,
                                     const wxPoint& pos,
                                     const wxSize& size,
                                     long style,
                                     const wxString& name)
{
    Init();
    Create(parent, id, title, pos, size, style, name);
}

// Destructor
wxBorderlessFrame::~wxBorderlessFrame()
{
    wxDELETE(m_cursorNS);
    wxDELETE(m_cursorWE);
    wxDELETE(m_cursorNESW);
    wxDELETE(m_cursorNWSE);
}

// Creation
bool wxBorderlessFrame::Create(wxWindow* parent,
                               wxWindowID id,
                               const wxString& title,
                               const wxPoint& pos,
                               const wxSize& size,
                               long style,
                               const wxString& name)
{
    // Style fix
    m_ourStyle = style;

    // Remove borders
    style &= ~wxBORDER_MASK;
    style |= wxBORDER_NONE;


    // Remove caption components
    style &= ~(wxCAPTION | wxSYSTEM_MENU | wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCLOSE_BOX);

    // We do our own resizing
    style &= ~wxRESIZE_BORDER;

    // Create the frame
    if(wxFrame::Create(parent, id, title, pos, size, style, name) == false)
    {
        return false;
    }

    // Create cursors for the items here
    m_cursorNS = new wxCursor(wxCURSOR_SIZENS);
    m_cursorWE = new wxCursor(wxCURSOR_SIZEWE);
    m_cursorNESW = new wxCursor(wxCURSOR_SIZENESW);
    m_cursorNWSE = new wxCursor(wxCURSOR_SIZENWSE);
}

// Set the real position
void wxBorderlessFrame::SetRealPosition(const wxRect& position)
{
    m_realPosition = position;
    if(m_collapsed == false)
    {
        SetSize(m_realPosition.x, m_realPosition.y,
                m_realPosition.width, m_realPosition.height);
    }
}


void wxBorderlessFrame::Collapse()
{
    // Set this FIRST so calls to DoSetSize will not save 'real' position
    m_collapsed = true;

    // Get display and set up new position/size
    wxDisplay display(wxDisplay::GetFromWindow(this));
    const wxRect displayRect = display.GetClientArea();
   
    wxRect newPos;
    wxSize minSize = GetMinSize();
    newPos.width = minSize.x;
    newPos.height = minSize.y;

    // Adjust x
    if(m_realPosition.x + m_realPosition.width / 2 < displayRect.x + displayRect.width / 2)
    {
        newPos.x = m_realPosition.x;
    }
    else
    {
        newPos.x = m_realPosition.x + (m_realPosition.width - newPos.width);
    }

    // Adjust y
    if(m_realPosition.y + m_realPosition.height / 2 < displayRect.y + displayRect.height / 2)
    {
        newPos.y = m_realPosition.y;
    }
    else
    {
        newPos.y = m_realPosition.y + (m_realPosition.height - newPos.height);
    }

    // Ensure on screen
    if(newPos.x > displayRect.x + displayRect.width - newPos.width)
    {
        newPos.x = displayRect.x + displayRect.width - newPos.width;
    }
    /* NOT else */
    if(newPos.x < displayRect.x)
    {
        newPos.x = displayRect.x;
    }

    if(newPos.y > displayRect.y + displayRect.height - newPos.height)
    {
        newPos.y = displayRect.y + displayRect.height - newPos.height;
    }
    /* NOT else */
    if(newPos.y < displayRect.y)
    {
        newPos.y = displayRect.y;
    }

    SetSize(newPos.x, newPos.y,
            newPos.width, newPos.height);
}

void wxBorderlessFrame::Uncollapse()
{
    wxDisplay display(wxDisplay::GetFromWindow(this));
    const wxRect displayRect = display.GetClientArea();

    if(m_realPosition.x > displayRect.x + displayRect.width - m_realPosition.width)
    {
        m_realPosition.x = displayRect.x + displayRect.width - m_realPosition.width;
    }
    /* NOT else */
    if(m_realPosition.x < displayRect.x)
    {
        m_realPosition.x = displayRect.x;
    }

    if(m_realPosition.y > displayRect.y + displayRect.height - m_realPosition.height)
    {
        m_realPosition.y = displayRect.y + displayRect.height - m_realPosition.height;
    }
    /* NOT else */
    if(m_realPosition.y < displayRect.y)
    {
        m_realPosition.y = displayRect.y;
    }

    // Allow DoSetSize to change real position
    m_collapsed = false;
   
    SetSize(m_realPosition.x, m_realPosition.y,
            m_realPosition.width, m_realPosition.height);
}

// event handlers
void wxBorderlessFrame::OnActivate(wxActivateEvent& evt)
{
    if(m_ourStyle & wxBORDERLESS_FRAME_AUTOCOLLAPSE)
    {
        if(evt.GetActive())
        {
            Uncollapse();
        }
        else
        {
            Collapse();
        }
    }
}

void wxBorderlessFrame::OnLeaveWindow(wxMouseEvent& WXUNUSED(evt))
{
    SetCursor(wxNullCursor);
}

void wxBorderlessFrame::OnLeftDown(wxMouseEvent& WXUNUSED(evt))
{
    m_oldMousePos = ::wxGetMousePosition();
    CaptureMouse();
}

void wxBorderlessFrame::OnLeftUp(wxMouseEvent& WXUNUSED(evt))
{
    if(HasCapture())
    {
        ReleaseMouse();
    }
}

void wxBorderlessFrame::OnMotion(wxMouseEvent& WXUNUSED(evt))
{
    wxPoint mousePos = ::wxGetMousePosition();

    if(HasCapture())
    {
        // Operating mode?
        if(m_mode == -1)
            m_mode = 4; // Moving

        int deltax, deltay;

        deltax = (mousePos.x - m_oldMousePos.x);
        deltay = (mousePos.y - m_oldMousePos.y);

        if(deltax == 0 && deltay == 0)
        {
            return;
        }

        // Some variables
        wxRect winPos = GetScreenRect();

        // Resize if needed
        if((m_ourStyle & wxRESIZE_BORDER) && m_collapsed == false)
        {
            const wxRect curPos = winPos;
            const wxSize minSize = GetMinSize();

            // Adjust x/w
            if(m_mode == 0 || m_mode == 3 || m_mode == 6)
            {
                winPos.x += deltax;
                winPos.width -= deltax;
                if(winPos.width < minSize.x)
                {
                    winPos.x = curPos.x;
                    winPos.width = curPos.width;
                }
                else
                {
                    m_oldMousePos.x = mousePos.x;
                }
            }
            else if(m_mode == 2 || m_mode == 5 || m_mode == 8)
            {
                winPos.width += deltax;
                if(winPos.width < minSize.x)
                {
                    winPos.width = curPos.width;
                }
                else
                {
                    m_oldMousePos.x = mousePos.x;
                }
            }

            // Adjust y/h
            if(m_mode == 0 || m_mode == 1 || m_mode == 2)
            {
                winPos.y += deltay;
                winPos.height -= deltay;
                if(winPos.height < minSize.y)
                {
                    winPos.y = curPos.y;
                    winPos.height = curPos.height;
                }
                else
                {
                    m_oldMousePos.y = mousePos.y;
                }
            }
            else if(m_mode == 6 || m_mode == 7 || m_mode == 8)
            {
                winPos.height += deltay;
                if(winPos.height < minSize.y)
                {
                    winPos.height = curPos.height;
                }
                else
                {
                    m_oldMousePos.y = mousePos.y;
                }
            }
        } // wxRESIZE_BORDER

        // Move
        if(m_mode == 4)
        {
            winPos.x += deltax;
            winPos.y += deltay;
            m_oldMousePos = mousePos;
        }

        // Set the size
        // The real position will get correctly set
        SetSize(winPos.x, winPos.y,
                winPos.width, winPos.height);
    }
    else
    {
        mousePos = ScreenToClient(mousePos);
        wxSize size = GetSize();

        // What is the mode
        int part1 = 1;
        int part2 = 1;

        if((m_ourStyle & wxRESIZE_BORDER) && m_collapsed == false)
        {
            if(mousePos.x < 5)
            {
                part1 = 0;
            }
            else if(mousePos.x > size.x - 5)
            {
                part1 = 2;
            }

            if(mousePos.y < 5)
            {
                part2 = 0;
            }
            else if(mousePos.y > size.y - 5)
            {
                part2 = 2;
            }
        }

        m_mode = part1 + (3 * part2);

        // Mouse cursor
        switch(m_mode)
        {
            case 0:
            case 8:
                SetCursor(*m_cursorNWSE);
                break;

            case 1:
            case 7:
                SetCursor(*m_cursorNS);
                break;

            case 2:
            case 6:
                SetCursor(*m_cursorNESW);
                break;

            case 3:
            case 5:
                SetCursor(*m_cursorWE);
                break;

            case 4:
            default:
                SetCursor(wxNullCursor);
                break;
        };
    }
}

void wxBorderlessFrame::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(evt))
{
    m_mode = -1;
}

void wxBorderlessFrame::OnMove(wxMoveEvent& evt)
{
    if(m_collapsed == false)
    {
        wxPoint p = evt.GetPosition();
        m_realPosition.x = p.x;
        m_realPosition.y = p.y;
    }
    evt.Skip();
}

void wxBorderlessFrame::OnSize(wxSizeEvent& evt)
{
    if(m_collapsed == false)
    {
        wxSize s = evt.GetSize();
        m_realPosition.width = s.x;
        m_realPosition.height = s.y;
    }
    evt.Skip();    
}

void wxBorderlessFrame::DoSetSize(int x, int y,
                                  int width, int height,
                                  int sizeFlags)
{
    // Pass it on
    wxFrame::DoSetSize(x, y, width, height, sizeFlags);

    // If not collapsed, then record as the real size
    if(m_collapsed == false)
    {
        m_realPosition = GetScreenRect(); // GetRect ok for TLWs?
    }
}

void wxBorderlessFrame::DoSetClientSize(int width, int height)
{
    // Pass it on
    wxFrame::DoSetClientSize(width, height);

    // If not collapsed, then record as the real size
    if(m_collapsed == false)
    {
        m_realPosition = GetScreenRect(); // GetRect ok for TLWs?
    }
}

void wxBorderlessFrame::Init()
{
    m_cursorNS = NULL;
    m_cursorWE = NULL;
    m_cursorNESW = NULL;
    m_cursorNWSE = NULL;

    // An arbitrary real position until set or discovered
    m_realPosition = wxRect(100, 100, 400, 300);
    m_collapsed = false;

    m_mode = -1;
    m_ourStyle = 0;
}

BEGIN_EVENT_TABLE(wxBorderlessFrame, wxFrame)
    EVT_ACTIVATE(wxBorderlessFrame::OnActivate)
    EVT_LEAVE_WINDOW(wxBorderlessFrame::OnLeaveWindow)
    EVT_LEFT_DOWN(wxBorderlessFrame::OnLeftDown)
    EVT_LEFT_UP(wxBorderlessFrame::OnLeftUp)
    EVT_MOTION(wxBorderlessFrame::OnMotion)
    EVT_MOUSE_CAPTURE_LOST(wxBorderlessFrame::OnCaptureLost)
    EVT_MOVE(wxBorderlessFrame::OnMove)
    EVT_SIZE(wxBorderlessFrame::OnSize)
END_EVENT_TABLE()

// A test application
#include <wx/app.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>
#include <wx/dcclient.h>

class MyFrame : public wxBorderlessFrame
{
public:
    MyFrame() :
        wxBorderlessFrame(NULL, -1, wxT("A Title"), wxDefaultPosition, wxDefaultSize,
                          wxRESIZE_BORDER | wxBORDERLESS_FRAME_AUTOCOLLAPSE |
                          wxFRAME_TOOL_WINDOW | wxFULL_REPAINT_ON_RESIZE)
             
    {
        m_edit = new wxTextCtrl(this, -1, wxT(""), wxDefaultPosition, wxDefaultSize,
            wxTE_MULTILINE | wxWANTS_CHARS | wxTE_NO_VSCROLL | wxBORDER_NONE);
        m_edit->SetBackgroundColour(wxColour(0, 0, 128));
        m_edit->SetForegroundColour(wxColour(255, 255, 0));

        wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
        sizer->Add(200, 24, 0);
        sizer->Add(m_edit, 1, wxEXPAND | wxALL, 5);



        SetSizer(sizer);
        Layout();
    };

    void OnPaint(wxPaintEvent& evt)
    {
        wxPaintDC dc(this);

        dc.SetBrush(wxColour(0, 0, 64));
        dc.SetPen(wxColour(255, 127, 0));

        wxSize s = GetClientSize();
        dc.DrawRectangle(0, 0, s.x, s.y);

        wxRect p = m_edit->GetRect();
        dc.DrawRectangle(p.x - 1, p.y - 1, p.width + 2, p.height + 2);

        dc.SetBrush(wxNullBrush);
        dc.SetPen(wxNullPen);
    }

    void OnErase(wxEraseEvent& evt)
    {
    }
private:
    wxTextCtrl* m_edit;

DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(MyFrame, wxBorderlessFrame)
    EVT_PAINT(MyFrame::OnPaint)
    EVT_ERASE_BACKGROUND(MyFrame::OnErase)
END_EVENT_TABLE()

class MyApp : public wxApp
{
public:
    bool OnInit()
    {
        wxBorderlessFrame* frame;
        frame = new MyFrame();
        frame->SetMinSize(wxSize(200, 45));

        SetTopWindow(frame);
        frame->Show();
        //frame->Raise();
        return true;
    }
};

IMPLEMENT_APP(MyApp)

// File:    borderlesswnd.h
// Author:  Brian Vanderburg II
// Purpose: create borderless windows with moving and resizing operations
//------------------------------------------------------------------------


#ifndef __BORDERLESS_WND_H__
#define __BORDERLESS_WND_H__

// Includes
#include <wx/defs.h>
#include <wx/frame.h>

// Foward declarations
class WXDLLEXPORT wxWindow;
class WXDLLEXPORT wxCursor;



// Since wxCAPTION is ignored by this class, it is reused for the this
#define wxBORDERLESS_FRAME_AUTOCOLLAPSE wxCAPTION

// A borderless frame with moving/resizing function support
// NOTE: Because of the way this code works, a derived frame should
// not handle any mouse events.  If custom mouse events are
// needed then they should be done in a wxPanel child window
class wxBorderlessFrame : public wxFrame
{
public:
    // reckognized style:
    // wxRESIZE_BORDER - Resizing is allowed
    // wxBORDERLESS_FRAME_AUTOCOLLAPSE - Auto-collapse when activation is lost (to minimum size)
    // reset styles (ignored)
    // BORDERS
    // Caption/system menu/minimize/maximize/close box

    // ctors
    wxBorderlessFrame();
    wxBorderlessFrame(wxWindow* parent,
                      wxWindowID id,
                      const wxString& title,
                      const wxPoint& pos = wxDefaultPosition,
                      const wxSize& size = wxDefaultSize,
                      long style = 0,
                      const wxString& name = wxFrameNameStr);

    // dtor
    ~wxBorderlessFrame();

    // 2 step creation
    bool Create(wxWindow* parent,
                wxWindowID id,
                const wxString& title,
                const wxPoint& pos = wxDefaultPosition,
                const wxSize& size = wxDefaultSize,
                long style = 0,
                const wxString& name = wxFrameNameStr);

    // Set the real position and size of the item
    // This will allow setting the 'real' position of the item
    // when it is collapsed, otherwise SetSize will set the real position when it is uncollapsed
    void SetRealPosition(const wxRect& position);
    void SetRealPosition(int x, int y, int w, int h)
    {
        SetRealPosition(wxRect(x, y, w, h));
    }

    const wxRect& GetRealPosition() const { return m_realPosition; }

    void Collapse();
    void Uncollapse(); // Restore is taken by window
    bool IsCollapsed() const { return m_collapsed; }

    // event handlers
    void OnActivate(wxActivateEvent& evt);
    void OnLeaveWindow(wxMouseEvent& evt);
    void OnLeftDown(wxMouseEvent& evt);
    void OnLeftUp(wxMouseEvent& evt);
    void OnMotion(wxMouseEvent& evt);
    void OnCaptureLost(wxMouseCaptureLostEvent& evt);
    void OnMove(wxMoveEvent& evt);
    void OnSize(wxSizeEvent& evt);

protected:
    void DoSetSize(int x, int y,
                   int width, int height,
                   int sizeFlags = wxSIZE_AUTO);
    void DoSetClientSize(int width, int height);

private:
    // init variables
    void Init();

    wxCursor* m_cursorNS;
    wxCursor* m_cursorWE;
    wxCursor* m_cursorNESW;
    wxCursor* m_cursorNWSE;

    wxRect m_realPosition;
    bool m_collapsed;

    int m_mode;
    long m_ourStyle;

    wxPoint m_oldMousePos;

DECLARE_NO_COPY_CLASS(wxBorderlessFrame)
DECLARE_EVENT_TABLE()
};

#endif // Include once header

_______________________________________________
wx-dev mailing list
[hidden email]
http://lists.wxwidgets.org/mailman/listinfo/wx-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Support for custom size/move operations in top level windows.

Careful
In reply to this post by Brian Vanderburg
I successfully compiled borderlesswnd (wxWidgets v2.8.12 on VC++ 2008 Express). I had been looking for an implementation of borderless windows for sometime. How may one enable controls to minimize, restore and close the window? Thanks...

Brian Vanderburg wrote
I'm working one something right now in wxPython to be ported to C++ some
more work.  I'm wondering if this could somehow be made generic and have
support in wxWidgets.

1. A window has no border, so now resize/moving handles.  This is needed
for custom drawing.  (A desktop sticky notes program that does not want
the window decoration)
2. Custom mouse handlers allow moving and resizing the window.
3. The window can be normal (wxFrame, with task button) or mini
(wxMiniFrame, with no task button)

One though was to add support directly to wxTopLevelWindow that would
allow setting the custom regions for resizing and dragging, and
implementing it internally.  I've attached a wxPython script that does
what I'm mean.  A window with no decoration exists and any custom
drawing can be done, custom colors, etc.  But events and code are added
to allow resizing and moving the window still.  If wx.MiniFrame is
changed to wx.Frame, then it will also appear on the taskbar.

Another thought was maybe the wxPopup classes could have such support,
probably not wxTransientPopup since it goes away when losing focus, but
a persistent popup that stays could have such support added to allow
resizing/moving perhaps.  Just an idea.

Brian Vanderburg II





import wx
import wx.richtext

class StickyNoteFrame(wx.MiniFrame):
    def __init__(self):
        wx.MiniFrame.__init__(self, None, -1, "Title", pos = (100, 100), style = wx.NO_BORDER)

        # Normally, the data and id of the note would be passed and we
        # would fetch the information from the database
        self.framebgcolor = wx.Colour(0, 128, 64)
        self.textbgcolor = wx.Colour(0, 0, 128)
        self.textfgcolor = wx.Colour(255, 255, 0)
        self.textsize = 14
        self.textwrap = True
       
        # Load cursors
        self.cursorNS = wx.StockCursor(wx.CURSOR_SIZENS)
        self.cursorWE = wx.StockCursor(wx.CURSOR_SIZEWE)
        self.cursorNESW = wx.StockCursor(wx.CURSOR_SIZENESW)
        self.cursorNWSE = wx.StockCursor(wx.CURSOR_SIZENWSE)
       
        # Set self
        self.SetBackgroundColour(self.framebgcolor)

        # Create note area
        self.text = wx.richtext.RichTextCtrl(self, style = wx.NO_BORDER | wx.TE_MULTILINE  | wx.TE_NO_VSCROLL| wx.WANTS_CHARS)

        self.text.SetBackgroundColour(self.textbgcolor)
        style = wx.richtext.RichTextAttr()
        style.SetBackgroundColour(self.textbgcolor)
        style.SetTextColour(self.textfgcolor)
       
        self.text.SetBasicStyle(style)
        self.text.SetForegroundColour(self.textbgcolor)
       
        # Sizer sizer
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add((0, 25), 0, wx.EXPAND)
        sizer.Add(self.text, 1, wx.EXPAND | wx.ALL, 5)
       
        self.SetMinSize((50, 20))
        self.SetSizerAndFit(sizer)

        # Events
        self.Bind(wx.EVT_MOTION, self.OnMotion)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
        self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
        self.state = 0

    def OnSetFocus(self, evt):
        pass
       
    def OnKillFocus(self, evt):
        wx.LogMessage("Focus lost")
        pass
       
    def OnLeave(self, evt):
        self.SetCursor(wx.NullCursor)
       
    def OnMouseDown(self, evt):
        (self.oldx, self.oldy) = wx.GetMousePosition()
        self.CaptureMouse()
       
    def OnMouseUp(self, evt):
        if self.HasCapture():
            self.ReleaseMouse()

    def OnMotion(self, evt):
        (mousex, mousey) = wx.GetMousePosition()
   
        if self.HasCapture():
            try:
                mode = self.mode
            except:
                mode = 4

            deltax = (mousex - self.oldx)
            deltay = (mousey - self.oldy)

            if deltax == 0 and deltay == 0:
                return

            (winx, winy) = self.GetPosition()
            (winw, winh) = self.GetSize()
            (minw, minh) = self.GetMinSize()
            (curx, cury, curw, curh) = (winx, winy, winw, winh)
           
            # Adjust x/w
            if mode == 0 or mode == 3 or mode == 6:
                winx += deltax
                winw -= deltax
                if winw < minw:
                    winx = curx
                    winw = curw
                else:
                    self.oldx = mousex
            elif mode == 2 or mode == 5 or mode == 8:
                winw += deltax
                if winw < minw:
                    winw = curw
                else:
                    self.oldx = mousex
                   
            # Adjust y/h
            if mode == 0 or mode == 1 or mode == 2:
                winy += deltay
                winh -= deltay
                if winh < minh:
                    winy = cury
                    winh = curh
                else:
                    self.oldy = mousey
            elif mode == 6 or mode == 7 or mode == 8:
                winh += deltay
                if winh < minh:
                    winh = curh
                else:
                    self.oldy = mousey
                   
            if mode == 4:
                winx += deltax
                winy += deltay
                self.oldx = mousex
                self.oldy = mousey
               
            self.SetDimensions(winx, winy, winw, winh)


        else:
            # Convert point to window units
            (mousex, mousey) = self.ScreenToClient((mousex, mousey))
            (sizex, sizey) = self.GetSize()
           
            # left/mid/right
            if mousex < 5:
                part1 = 0
            elif mousex > sizex - 5:
                part1 = 2
            else:
                part1 = 1
               
            # top/mid/bottom
            if mousey < 5:
                part2 = 0
            elif mousey > sizey - 5:
                part2 = 2
            else:
                part2 = 1
               
            self.mode = part1 + (3 * part2)
           
            # mouse cursor
            if self.mode == 0 or self.mode == 8:
                self.SetCursor(self.cursorNWSE)
            elif self.mode == 1 or self.mode == 7:
                self.SetCursor(self.cursorNS)
            elif self.mode == 2 or self.mode == 6:
                self.SetCursor(self.cursorNESW)
            elif self.mode == 3 or self.mode == 5:
                self.SetCursor(self.cursorWE)
            else:
                self.SetCursor(wx.NullCursor)
               
               


       
class App(wx.App):
    def OnInit(self):
        frame = StickyNoteFrame()
        self.SetTopWindow(frame)
        frame.Show(True)
        return True
       
app = App(redirect = False)
app.MainLoop()

_______________________________________________
wx-dev mailing list
wx-dev@lists.wxwidgets.org
http://lists.wxwidgets.org/mailman/listinfo/wx-dev
Loading...