Files
pyfa/gui/toggle_panel.py
2017-06-12 20:42:03 -04:00

188 lines
6.3 KiB
Python

#===============================================================================
# TogglePanel is based on PyCollapsiblePane - includes a few improvements
# such as adding items to header, lack of button implementation ("GTK
# expander" style is implemented with plain text with unicode arrows rather
# than drawn geometry), etc.
#
# When adding TogglePanel to sizer, it is important to ensure the following:
# sizer is vertical
# set proportion = 0
#
# ToDo: Create animations for collapsing / expanding
#
#===============================================================================
import wx
class TogglePanel (wx.Panel):
def __init__(self, parent, force_layout=False, *args, **kargs):
super().__init__(parent, *args, **kargs)
self._toggled = True
self.parent = parent
self.force_layout = force_layout
# Create the main sizer of this panel
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self.main_sizer)
# Create the header panel, set sizer, and add to main sizer
self.header_panel = wx.Panel(self)
header_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.header_panel.SetSizer(header_sizer)
self.main_sizer.Add(self.header_panel, 0, wx.EXPAND | wx.TOP |
wx.BOTTOM | wx.RIGHT, 1)
# Add arrow
self.header_arrow = wx.StaticText(self.header_panel, wx.ID_ANY,
"\u25bc")
header_sizer.Add(self.header_arrow, 0, wx.RIGHT, 5)
# Add header text
self.header_label = wx.StaticText(self.header_panel, wx.ID_ANY, "")
font = parent.GetFont()
font.SetWeight(wx.BOLD)
self.header_label.SetFont(font)
header_sizer.Add(self.header_label, 0, wx.RIGHT, 5)
# Add a sizer for additional header items if we need it
self.hcontent_sizer = wx.BoxSizer(wx.HORIZONTAL)
header_sizer.Add(self.hcontent_sizer, 0, wx.RIGHT, 5)
# Create the content panel, set sizer, and add to main sizer
self.content_panel = wx.Panel(self)
self.content_sizer = wx.BoxSizer(wx.VERTICAL)
self.content_panel.SetSizer(self.content_sizer)
self.main_sizer.Add(self.content_panel, 0, wx.EXPAND | wx.RIGHT |
wx.LEFT, 5)
self.Layout()
# Connect Events
self.header_label.Bind(wx.EVT_LEFT_UP, self.ToggleContent)
self.header_arrow.Bind(wx.EVT_LEFT_UP, self.ToggleContent)
self.header_panel.Bind(wx.EVT_LEFT_UP, self.ToggleContent)
def __del__(self):
pass
def AddToggleItem(self, item):
item.Bind(wx.EVT_LEFT_UP, self.ToggleContent)
def GetHeaderContentSizer(self):
return self.hcontent_sizer
def GetHeaderPanel(self):
return self.header_panel
def InsertItemInHeader(self, item):
self.hcontent_sizer.Add(item, 0, 0, 0)
self.AddToggleItem(item)
self.Layout()
def AddSizer(self, sizer):
self.content_sizer.Add(sizer, 0, wx.EXPAND | wx.ALL, 0)
self.Layout()
def GetContentPanel(self):
return self.content_panel
def SetLabel(self, label):
self.header_label.SetLabel(label)
def IsCollapsed(self):
return not self._toggled
def IsExpanded(self):
return self._toggled
def OnStateChange(self, sz):
self.SetSize(sz)
self.parent.GetSizer().SetSizeHints(self.parent)
if not self._toggled:
if self.parent.GetSizer():
# we have just set the size hints...
sz = self.parent.GetSizer().CalcMin()
# use SetClientSize() and not SetSize() otherwise the size for
# e.g. a wxFrame with a menubar wouldn't be correctly set
self.parent.SetClientSize(sz)
else:
self.parent.Layout()
else:
# force our parent to "fit", i.e. expand so that it can honor
# our minimal size
self.parent.Fit()
def ToggleContent(self, event):
#self.Freeze()
if self._toggled:
# If we are expanded, save previous size and collapse by setting
# content height to 0
self.content_min_size = self.content_panel.GetSize()
self.content_panel.SetMinSize((self.content_min_size[0], 0))
self.header_arrow.SetLabel("\u25b6")
else:
# If we are collapsed, set content size to previously saved value
self.content_panel.SetMinSize(self.content_min_size)
self.header_arrow.SetLabel("\u25bc")
self._toggled = not self._toggled
#self.Thaw()
if self.force_layout:
self.parent.Layout()
else:
self.OnStateChange(self.GetBestSize())
if __name__ == "__main__":
class TestPanel(wx.Panel):
def __init__(self, parent):
super().__init__(parent, size=(-1, -1))
if 'wxMSW' in wx.PlatformInfo:
color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)
self.SetBackgroundColour(color)
main_sizer = wx.BoxSizer(wx.VERTICAL)
# Generate 3 test panels with different font sizes
for x in range(3):
toggle_panel = TogglePanel(self)
toggle_panel.SetLabel("Test Header")
content_panel = toggle_panel.GetContentPanel()
content_panel.SetBackgroundColour(wx.WHITE)
content_sizer = wx.BoxSizer(wx.HORIZONTAL)
header = wx.StaticText(content_panel, -1, "TogglePanel Test")
header.SetFont(wx.Font(10+(x*3), wx.SWISS, wx.NORMAL, wx.BOLD))
content_sizer.Add(header, 0, wx.ALL, 10)
content_panel.SetSizer(content_sizer)
main_sizer.Add(toggle_panel, 0, wx.EXPAND | wx.ALL, 2)
self.SetSizer(main_sizer)
class Frame(wx.Frame):
def __init__(self, title):
super().__init__(None, title=title, size=(500, 500))
main_sizer = wx.BoxSizer(wx.VERTICAL)
self.statsPane = TestPanel(self)
main_sizer.Add(self.statsPane, 0, wx.EXPAND)
self.SetSizerAndFit(main_sizer)
app = wx.App(redirect=False) # Error messages go to popup window
top = Frame("Test Toggle Panel")
top.Show()
app.MainLoop()