# frame.py: wxFrame and wxStatusBar objects # $Id: frame.py,v 1.46 2007/08/07 12:18:34 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, math, misc from tree import Tree #from MenuTree import * from widget_properties import * from edit_windows import EditBase, TopLevelBase class EditStatusBar(EditBase): _hidden_frame = None def __init__(self, parent, property_window): EditBase.__init__(self, parent.name + '_statusbar', 'wxStatusBar', parent, id, property_window, custom_class=False, show=False) # style property self.style_pos = (wx.ST_SIZEGRIP,) style_labels = ('#section#Style', 'wxST_SIZEGRIP') self.access_functions['style'] = (self.get_style, self.set_style) self.properties['style'] = CheckListProperty(self, 'style', None, style_labels) self.node = Tree.Node(self) common.app_tree.add(self.node, parent.node) self.fields = [ [self.name, "-1"] ] # list of 2-lists label, size # for the statusbar fields self.access_functions['fields'] = (self.get_fields, self.set_fields) prop = self.properties['fields'] = GridProperty( self, 'fields', None, [("Text", GridProperty.STRING), ("Size", GridProperty.INT)]) # replace the default 'write' method of 'prop' with a custom one def write_prop(outfile, tabs): from xml.sax.saxutils import escape, quoteattr fwrite = outfile.write fwrite(' ' * tabs + '\n') tabs += 1 import widget_properties for label, width in self.fields: fwrite(' ' * tabs + '%s\n' % (quoteattr(width), escape(widget_properties._encode(label)))) tabs -= 1 fwrite(' ' * tabs + '\n') prop.write = write_prop def create_widget(self): self.widget = wx.StatusBar(self.parent.widget, wx.NewId()) wx.EVT_LEFT_DOWN(self.widget, self.on_set_focus) self.set_fields(self.fields) if self.parent.widget: self.parent.widget.SetStatusBar(self.widget) def create_properties(self): EditBase.create_properties(self) page = self._common_panel self.properties['style'].display(page) prop = self.properties['fields'] prop.display(page) sizer = page.GetSizer() if not sizer: sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.name_prop.panel, 0, wx.EXPAND) sizer.Add(self.klass_prop.panel, 0, wx.EXPAND) page.SetAutoLayout(1) page.SetSizer(sizer) sizer.Add(self.properties['style'].panel, 0, wx.EXPAND) sizer.Add(prop.panel, 1, wx.ALL|wx.EXPAND, 3) sizer.Fit(page) page.SetSize(self.notebook.GetClientSize()) sizer.Layout() self.notebook.AddPage(page, "Common") self.property_window.Layout() prop.set_col_sizes([190, 0]) def set_fields(self, values): # values is a list of lists self.fields = [] if self.widget: self.widget.SetFieldsCount(len(values)) for i in range(len(values)): try: v = int(values[i][1]) except: v = 0 s = misc.wxstr(values[i][0]) self.fields.append([s, str(v)]) if self.widget: self.widget.SetStatusText(s, i) if self.widget: self.widget.SetStatusWidths([int(i[1]) for i in self.fields]) def get_fields(self): return self.fields def __getitem__(self, key): return self.access_functions[key] def remove(self, *args, **kwds): if not kwds.get('do_nothing', False): if self.parent.widget: self.parent.widget.SetStatusBar(None) try: self.parent.properties['statusbar'].set_value(0) except KeyError: pass if self.widget: self.widget.Hide() EditBase.remove(self) else: if misc.check_wx_version(2, 6): if EditStatusBar._hidden_frame is None: EditStatusBar._hidden_frame = wx.Frame(None, -1, "") if self.widget is not None: self.widget.Reparent(EditStatusBar._hidden_frame) self.widget = None def popup_menu(self, *args): pass # to avoid strange segfault :) def get_property_handler(self, name): class FieldsHandler: """\ custom Property handler for statusbar fields. """ def __init__(self, owner): self.owner = owner self.width = -1 self.value = [] def start_elem(self, name, attrs): if name == 'fields': self.fields = [] else: # name == 'field' self.value = [] self.width = attrs.get('width', '-1') def end_elem(self, name): if name == 'field': self.fields.append(["".join(self.value), self.width]) else: # name == 'fields' self.owner.fields = self.fields self.owner.set_fields(self.owner.fields) self.owner.properties['fields'].set_value( self.owner.fields) return True def char_data(self, data): self.value.append(data) return False # tell there's no need to go further # (i.e. to call add_property) if name == 'fields': return FieldsHandler(self) return None def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] # end of class EditStatusBar class EditFrame(TopLevelBase): def __init__(self, name, parent, id, title, property_window, style=wx.DEFAULT_FRAME_STYLE, show=True, klass='wxFrame'): TopLevelBase.__init__(self, name, klass, parent, id, property_window, show=show, title=title) self.base = 'wxFrame' self.style = style self.statusbar = None self.icon = '' self.access_functions['statusbar'] = (self.get_statusbar, self.set_statusbar) self.menubar = None self.access_functions['menubar'] = (self.get_menubar, self.set_menubar) self.toolbar = None self.access_functions['toolbar'] = (self.get_toolbar, self.set_toolbar) self.access_functions['style'] = (self.get_style, self.set_style) self.access_functions['icon'] = (self.get_icon, self.set_icon) prop = self.properties style_labels = ['#section#Style', 'wxDEFAULT_FRAME_STYLE', 'wxICONIZE', 'wxCAPTION', 'wxMINIMIZE', 'wxMINIMIZE_BOX', 'wxMAXIMIZE', 'wxMAXIMIZE_BOX', 'wxSTAY_ON_TOP', 'wxSYSTEM_MENU', 'wxSIMPLE_BORDER', 'wxRESIZE_BORDER', 'wxFRAME_TOOL_WINDOW', 'wxFRAME_NO_TASKBAR', 'wxFRAME_FLOAT_ON_PARENT', 'wxNO_BORDER', 'wxNO_FULL_REPAINT_ON_RESIZE', 'wxFULL_REPAINT_ON_RESIZE', 'wxTAB_TRAVERSAL', 'wxCLIP_CHILDREN'] self.style_pos = [wx.DEFAULT_FRAME_STYLE, wx.ICONIZE, wx.CAPTION, wx.MINIMIZE, wx.MINIMIZE_BOX, wx.MAXIMIZE, wx.MAXIMIZE_BOX, wx.STAY_ON_TOP, wx.SYSTEM_MENU, wx.SIMPLE_BORDER, wx.RESIZE_BORDER, wx.FRAME_TOOL_WINDOW, wx.FRAME_NO_TASKBAR, wx.FRAME_FLOAT_ON_PARENT, wx.NO_BORDER, wx.NO_FULL_REPAINT_ON_RESIZE, wx.FULL_REPAINT_ON_RESIZE, wx.TAB_TRAVERSAL, wx.CLIP_CHILDREN] if misc.check_wx_version(2, 5): style_labels.insert(5, 'wxCLOSE_BOX') self.style_pos.insert(4, wx.CLOSE_BOX) prop['style'] = CheckListProperty(self, 'style', None, style_labels) # menubar property prop['menubar'] = CheckBoxProperty(self, 'menubar', None, 'Has MenuBar') # statusbar property prop['statusbar'] = CheckBoxProperty(self, 'statusbar', None, 'Has StatusBar') # toolbar property prop['toolbar'] = CheckBoxProperty(self, 'toolbar', None, 'Has ToolBar') # icon property prop['icon'] = FileDialogProperty(self, 'icon', None, style=wx.OPEN|wx.FILE_MUST_EXIST, can_disable=True) # centered property self.centered = False self.access_functions['centered'] = (self.get_centered, self.set_centered) prop['centered'] = CheckBoxProperty(self, 'centered', None) def create_widget(self): if self.parent: w = self.parent.widget else: w = common.palette self.widget = wx.Frame(w, self.id, self.get_title()) self.set_icon(self.icon) def finish_widget_creation(self): TopLevelBase.finish_widget_creation(self) if not self.properties['size'].is_active(): #if self.sizer: self.sizer.fit_parent() #else: self.widget.SetSize((400, 300)) if wx.Platform == '__WXMSW__': self.widget.CenterOnScreen() if self.menubar and self.menubar.widget: self.widget.SetMenuBar(self.menubar.widget) if self.statusbar and self.statusbar.widget: self.widget.SetStatusBar(self.statusbar.widget) if self.toolbar and self.toolbar.widget: self.widget.SetToolBar(self.toolbar.widget) def create_properties(self): TopLevelBase.create_properties(self) prop = self.properties panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) prop['title'].display(panel) prop['icon'].display(panel) prop['centered'].display(panel) prop['menubar'].display(panel) prop['toolbar'].display(panel) try: sbprop = prop['statusbar'] sbprop.display(panel) except KeyError: sbprop = None prop['style'].display(panel) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(prop['title'].panel, 0, wx.EXPAND) szr.Add(prop['icon'].panel, 0, wx.EXPAND) szr.Add(prop['centered'].panel, 0, wx.EXPAND) szr.Add(prop['menubar'].panel, 0, wx.EXPAND) szr.Add(prop['toolbar'].panel, 0, wx.EXPAND) if sbprop: szr.Add(sbprop.panel, 0, wx.EXPAND) szr.Add(prop['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') w, h = panel.GetClientSizeTuple() panel.SetScrollbars(5, 5, int(math.ceil(w/5.0)), int(math.ceil(h/5.0))) def get_menubar(self): return self.menubar is not None def set_menubar(self, value): if value: from menubar import EditMenuBar self.menubar = EditMenuBar(self.name + '_menubar', 'wxMenuBar', self, common.property_panel) self.menubar.node = Tree.Node(self.menubar) common.app_tree.add(self.menubar.node, self.node) if self.widget: self.menubar.show_widget(True) self.menubar.show_properties() else: self.menubar = self.menubar.remove() self.show_properties(None) def get_statusbar(self): return self.statusbar is not None def set_statusbar(self, value): if value: self.statusbar = EditStatusBar(self, common.property_panel) if self.widget: self.statusbar.show_widget(True) self.statusbar.show_properties() else: self.statusbar = self.statusbar.remove() self.show_properties(None) if self.widget: # this is needed at least on win32 wx.PostEvent(self.widget, wx.SizeEvent(self.widget.GetSize(), self.widget.GetId())) def get_toolbar(self): return self.toolbar is not None def set_toolbar(self, value): if value: from toolbar import EditToolBar self.toolbar = EditToolBar(self.name + '_toolbar', 'wxToolBar', self, common.property_panel) self.toolbar.node = Tree.Node(self.toolbar) common.app_tree.add(self.toolbar.node, self.node) if self.widget: self.toolbar.show_widget(True) self.toolbar.show_properties() else: self.toolbar = self.toolbar.remove() self.show_properties(None) def get_style(self): retval = [0] * len(self.style_pos) try: if self.style == wx.DEFAULT_FRAME_STYLE: retval[0] = 1 else: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 retval[0] = 0 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) style = 0 for v in range(len(value)): if value[v]: style |= self.style_pos[v] self.style = style if self.widget: self.widget.SetWindowStyleFlag(style) def remove(self, *args): if self.menubar: self.menubar = self.menubar.remove(gtk_do_nothing=True) if self.statusbar: self.statusbar = self.statusbar.remove(do_nothing=True) if self.toolbar: self.toolbar = self.toolbar.remove(do_nothing=True) TopLevelBase.remove(self, *args) def get_icon(self): # is a string that holds the filename (for example: icon.png) return self.icon def set_icon(self, value): self.icon = value.strip() if self.widget: if self.icon and not (self.icon.startswith('var:') or self.icon.startswith('code:')): # setting icon icon = misc.get_relative_path(self.icon) bmp = wx.Bitmap(icon, wx.BITMAP_TYPE_ANY) if not bmp.Ok(): self.set_icon("") else: icon = wx.EmptyIcon() icon.CopyFromBitmap(bmp) self.widget.SetIcon(icon) else: # removing icon icon = wx.EmptyIcon() import os xpm = os.path.join(common.wxglade_path, 'icons', 'frame.xpm') icon.CopyFromBitmap(misc.get_xpm_bitmap(xpm)) self.widget.SetIcon(icon) def get_centered(self): return self.centered def set_centered(self, value): try: self.centered = bool(int(value)) except ValueError: pass # end of class EditFrame class EditMDIChildFrame(EditFrame): _is_toplevel = False # used to avoid to appear in the "Top Window" property # of the app def __init__(self, *args, **kwds): EditFrame.__init__(self, *args, **kwds) del self.properties['statusbar'] self.base = 'wxFrame' # end of class EditMDIChildFrame def builder(parent, sizer, pos, number=[0]): """\ factory function for EditFrame objects. """ class Dialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, None, -1, 'Select frame class') if common.app_tree.app.get_language().lower() == 'xrc': self.klass = 'wxFrame' else: if not number[0]: self.klass = 'MyFrame' else: self.klass = 'MyFrame%s' % number[0] number[0] += 1 self.base = 0 base_prop = RadioProperty(self, 'base class', self, ['wxFrame', 'wxMDIChildFrame']) klass_prop = TextProperty(self, 'class', self) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(base_prop.panel, 0, wx.ALL|wx.EXPAND, 5) szr.Add(klass_prop.panel, 0, wx.EXPAND) btnbox = wx.BoxSizer(wx.HORIZONTAL) btnOK = wx.Button(self, wx.ID_OK, 'OK') btnCANCEL = wx.Button(self, wx.ID_CANCEL, 'Cancel') btnbox.Add(btnOK, 0, wx.ALL, 3) btnbox.Add(btnCANCEL, 0, wx.ALL, 3) btnOK.SetFocus() szr.Add(btnbox, 0, wx.ALL|wx.ALIGN_CENTER, 3) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) self.CenterOnScreen() def undo(self): if number[0] > 0: number[0] -= 1 def __getitem__(self, value): if value == 'class': def set_klass(c): self.klass = c return (lambda : self.klass, set_klass) else: def set_base(b): self.base = b return (lambda : self.base, set_base) # end of inner class dialog = Dialog() # Check if the user hit Cancel, if so then bail out if dialog.ShowModal() == wx.ID_CANCEL: # restore state dialog.undo() # clean up resources dialog.Destroy() return label = 'frame_%d' % (number[0] or 1) while common.app_tree.has_name(label): number[0] += 1 label = 'frame_%d' % number[0] if dialog.base == 0: base_class = EditFrame else: base_class = EditMDIChildFrame frame = base_class(label, parent, wx.NewId(), label, common.property_panel, klass=dialog.klass) node = Tree.Node(frame) frame.node = node common.app_tree.add(node) frame.show_widget(True) # add a default vertical sizer to the frame import edit_sizers edit_sizers._builder(frame, None, 0) # now select the frame's node in the tree common.app_tree.select_item(node) dialog.Destroy() if wx.Platform == '__WXMSW__': #frame.widget.CenterOnScreen() frame.widget.Raise() def _make_builder(base_class): def xml_builder(attrs, parent, sizer, sizeritem, pos=None): from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, "'name' attribute missing" frame = base_class(label, parent, wx.NewId(), "", common.property_panel, show=False) node = Tree.Node(frame) frame.node = node common.app_tree.add(node) return frame return xml_builder ## def xml_builder(attrs, parent, sizer, sizeritem, pos=None): ## """\ ## factory to build EditFrame objects from an xml file ## """ ## from xml_parse import XmlParsingError ## try: label = attrs['name'] ## except KeyError: raise XmlParsingError, "'name' attribute missing" ## frame = EditFrame(label, parent, wx.NewId(), label, common.property_panel, ## show=False) ## node = Tree.Node(frame) ## frame.node = node ## common.app_tree.add(node) ## return frame def statusbar_xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditStatusBar objects from an xml file """ parent.statusbar.set_fields([]) name = attrs.get('name') if name: parent.statusbar.set_name(name) parent.statusbar.name_prop.set_value(name) return parent.statusbar def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ cwx = common.widgets_from_xml cwx['EditStatusBar'] = statusbar_xml_builder cwx['EditFrame'] = _make_builder(EditFrame) cwx['EditMDIChildFrame'] = _make_builder(EditMDIChildFrame) common.widgets['EditFrame'] = builder # add statusbar icon to WidgetTree from tree import WidgetTree import os.path WidgetTree.images['EditStatusBar'] = os.path.join(common.wxglade_path, 'icons/statusbar.xpm') WidgetTree.images['EditMDIChildFrame'] = os.path.join(common.wxglade_path, 'icons/frame.xpm') return common.make_object_button('EditFrame', 'icons/frame.xpm', 1)