
import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, id=wx.ID_ANY):
        wx.Frame.__init__(self, parent, id)

        self.PanelTop = wx.Panel(self, -1)
        self.PanelTop.SetBackgroundColour("GREEN")
        self.PanelInterior1 = wx.Panel(self.PanelTop, -1)
        self.PanelInterior1.SetBackgroundColour("YELLOW")
        
        SizerInterior1 = wx.BoxSizer(wx.VERTICAL)
        
        self.ComboPanel = wx.ComboBox(self.PanelInterior1, -1, choices=["Show One Line Panel", "Show Three Line Panel"])
        self.ComboPanel.SetSelection(0)
        sizer3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer3.Add(self.ComboPanel, 0, wx.EXPAND, 0)
        SizerInterior1.Add(sizer3, 0, wx.EXPAND, 0)

        self.PanelDynamic = wx.Panel(self.PanelInterior1, -1)
        SizerInterior1.Add(self.PanelDynamic, 0, wx.EXPAND, 0)
        
        label = wx.StaticText(self.PanelInterior1, -1, "Bottom Widget - Should move down")
        sizer4 = wx.BoxSizer(wx.HORIZONTAL)
        sizer4.Add(label, 0, wx.EXPAND, 0)
        SizerInterior1.Add(sizer4, 0, wx.EXPAND, 0)

        self.PanelInterior1.SetSizer(SizerInterior1)
        SizerTop = wx.BoxSizer(wx.VERTICAL)
        SizerTop.Add(self.PanelInterior1, 0, wx.EXPAND, 0)

        self.PanelTop.SetSizer(SizerTop)
        
        sizer1 = wx.BoxSizer(wx.VERTICAL)
        sizer1.Add(self.PanelTop, 1, wx.EXPAND, 0)
        self.SetSizer(sizer1)

        self.Bind(wx.EVT_COMBOBOX, self.on_combo, self.ComboPanel)

        # here are the panels I will optionally Hide/Show in PanelDynamic
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.panel1 = PanelOneLine(self.PanelDynamic)
        self.panel1.SetBackgroundColour("KHAKI")
        self.panel2 = PanelThreeLine(self.PanelDynamic)
        self.panel2.SetBackgroundColour("ORANGE")
        
        self.panel1.Show()
        self.panel2.Hide()
        sizer.Add(self.panel1, 0, wx.EXPAND, 0)
        sizer.Add(self.panel2, 0, wx.EXPAND, 0)
        self.PanelDynamic.SetSizer(sizer)
        self.Layout()
                


    def on_combo(self, event): # wxGlade: MyFrame.<event_handler>
        value = event.GetEventObject().GetStringSelection()

        if value == 'Show One Line Panel':
            self.panel1.Show()
            self.panel2.Hide()
            sz = self.panel1.GetBestSize()
        else:
            self.panel1.Hide()
            self.panel2.Show()
            sz = self.panel2.GetBestSize()
            
        # minimal size has priority over the best size so set here our min size
        self.PanelDynamic.SetMinSize(sz)
        self.PanelDynamic.SetSize(sz)
        
        #self.PanelDynamic.Parent.Layout()
        self.Layout()
        self.PanelTop.Layout()          # Comment this line to see XP behave badly
        #self.PanelInterior1.Layout()   # In my big application I have to add Layout()
                                        # at progressively deeper levels to make this 
                                        # behave nicely


class PanelOneLine(wx.Panel):
    def __init__(self, parent):
        # this displays one label line of text
        wx.Panel.__init__(self, parent)
        sizer1 = wx.BoxSizer(wx.VERTICAL)
        label1 = wx.StaticText(self, -1, "  Line 1 of 1 ")
        sizer1.Add(label1, 0, wx.EXPAND, 3)
        self.SetSizer(sizer1)
        sizer1.Fit(self)


class PanelThreeLine(wx.Panel):
    def __init__(self, parent):
        # the difference between this and PanelOne is that this has three 
        # labels and so should take up more space in the middle of the 
        # dynamic panel, thus forcing widgets below downward.
        wx.Panel.__init__(self, parent)
        sizer1 = wx.BoxSizer(wx.VERTICAL)
        label1 = wx.StaticText(self, -1, "  Line 1 of 3 ")
        label2 = wx.StaticText(self, -1, "  Line 2 of 3 ")
        label3 = wx.StaticText(self, -1, "  Line 3 of 3 ")
        sizer1.Add(label1, 0, wx.EXPAND, 3)
        sizer1.Add(label2, 0, wx.EXPAND, 3)
        sizer1.Add(label3, 0, wx.EXPAND, 3)
        self.SetSizer(sizer1)



if __name__ == "__main__":
    app = wx.App(0)
    frame1 = MyFrame(None, -1)
    frame1.Show()
    app.MainLoop()
