DoGetClientAreaOrigin - does that exist?

I'd like to create a custom panel class by...

1) Deriving it from wx.PyPanel

2) Setting the client area of that derived panel class
    to a smaller size than the panel itself.

3) Drawing decorative custom border graphics around the
    shrunk-down client area.

OK; I can base my custom class on wx.PyPanel and override the DoGetClientSize() method, and this does get me a smaller client area. If I then add any child windows and sizers, they will respect the smaller client area that I give them, and only draw themselves within that smaller area.

So no problems here; everything seems to work fine.

However, the origin of this shrunk-down client area is still located at (0,0) - the top-left corner of my panel widget. This means that I can only draw my custom borders to the left and bottom edges of the panel; not around all edges, as I originally hoped.

Overriding GetClientOrigin() does not seem to help here. Neither does overriding GetClientRect().

"DoGetClientAreaOrigin()" could have been a logical choice of name for an overridable virtual function that would let the programmer set the position of the client area origin but a function by that name does not seem to exist.

So... how _does_ one reposition the origin of the client area in a custom panel class? Is that possible at all?

If not, why not? (Is there some specific wxWidgets design principle behind the decision to not allow this?)

* * *

I should perhaps mention that I've already found this old thread where this very same problem was discussed...

<http://thread.gmane.org/gmane.comp.python.wxpython/49418/>

...but that discussion quickly swerved off into the direction of circumventing the problem with alternative solutions, instead of explaining why this approach doesn't work, or delving into the details of whether overriding the origin of the client area is at all technically possible in wxPython/wxWidgets.

···

--
znark

Jukka Aho wrote:

I'd like to create a custom panel class by...

1) Deriving it from wx.PyPanel

2) Setting the client area of that derived panel class
   to a smaller size than the panel itself.

3) Drawing decorative custom border graphics around the
   shrunk-down client area.

OK; I can base my custom class on wx.PyPanel and override the DoGetClientSize() method, and this does get me a smaller client area. If I then add any child windows and sizers, they will respect the smaller client area that I give them, and only draw themselves within that smaller area.

So no problems here; everything seems to work fine.

However, the origin of this shrunk-down client area is still located at (0,0) - the top-left corner of my panel widget. This means that I can only draw my custom borders to the left and bottom edges of the panel; not around all edges, as I originally hoped.

Overriding GetClientAreaOrigin() does not seem to help here. Neither does overriding GetClientRect().

There isn't a DoGetClientAreaOrigin in the C++ code, Apparently that one has survived the slow migration to the Do functions over the years. :wink: I'll make GetClientAreaOrigin be overridable from Python.

Do you have a simple example that I could use to test the change with?

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn wrote:

There isn't a DoGetClientAreaOrigin in the C++ code, Apparently that one has survived the slow migration to the Do functions over the years. :wink: I'll make GetClientAreaOrigin be overridable from Python.

Sounds great... what about GetClientRect(), though? (I'm not sure which methods the sizers will actually call on their containing object to get their idea of the client area... or is it the other way around?)

Do you have a simple example that I could use to test the change with?

Sure, have a look at this:

--- 8< ---

#!/usr/bin/env python

import wx

class BorderPanel(wx.PyPanel):

    def __init__(self, *args, **kwargs):
        wx.PyPanel.__init__(self, *args, **kwargs)
        self.border = 20

    def DoGetClientSize(self):
        print "DoGetClientSize"
        border2 = self.border * 2
        width, height = self.GetSize()
        width = width - border2 if width > border2 else 0
        height = height - border2 if height > border2 else 0
        return width, height

    def GetClientAreaOrigin(self):
        print "GetClientAreaOrigin"
        return self.border, self.border

    def GetClientRect(self):
        print "GetClientRect"
        rect = wx.PyPanel.GetClientRect(self)
        rect.x, rect.y = self.GetClientAreaOrigin()
        return rect

class MyPanel(BorderPanel):

    def __init__(self, *args, **kwargs):
        BorderPanel.__init__(self, *args, **kwargs)
        childpanel = wx.Panel(self)
        childpanel.SetBackgroundColour(wx.Colour(0,0,255))
        sizer = wx.BoxSizer()
        sizer.Add(childpanel, 1, wx.EXPAND)
        self.SetSizer(sizer)

class BorderTestFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, parent=None, title="BorderTest")
        mypanel = MyPanel(self)
        sizer = wx.BoxSizer()
        sizer.Add(mypanel, 1, wx.EXPAND)
        self.SetSizer(sizer)

class BorderTestApp(wx.App):

    def __init__(self):
        wx.App.__init__(self, redirect=False)
        frame = BorderTestFrame()
        frame.Show(True)

if __name__ == '__main__':
    app = BorderTestApp()
    app.MainLoop()

--- 8< ---

I removed the actual border-drawing / decoration functions to keep it simple, but it displays a blue child panel inside a gray BorderPanel.

If relocating the origin of the client area worked as envisioned, there would be 20 pixel gray borders all around the blue panel. As of now, however, there are only double-sized (40 pixel) gray borders on the right and the bottom because the origin stays at (0,0).

···

--
znark

Jukka Aho wrote:

Robin Dunn wrote:

There isn't a DoGetClientAreaOrigin in the C++ code, Apparently that one has survived the slow migration to the Do functions over the years. :wink: I'll make GetClientAreaOrigin be overridable from Python.

Sounds great... what about GetClientRect(), though? (I'm not sure which methods the sizers will actually call on their containing object to get their idea of the client area... or is it the other way around?)

GetClientRect is implemented using the other two, so there's no need to override it:

     wxRect GetClientRect() const
     {
         return wxRect(GetClientAreaOrigin(), GetClientSize());
     }

Do you have a simple example that I could use to test the change with?

Sure, have a look at this:

See the attached for the results.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!