# custom_widget.py: custom wxWindow objects # $Id: custom_widget.py,v 1.21 2007/08/07 12:13:43 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from tree import Tree from widget_properties import * from edit_windows import ManagedBase class ArgumentsProperty(GridProperty): def write(self, outfile, tabs): from xml.sax.saxutils import escape if self.getter: values = self.getter() else: values = self.owner[self.name][0]() if values: write = outfile.write write(' ' * tabs + '\n') stab = ' ' * (tabs+1) for value in values: write('%s%s\n' % (stab, escape(value[0]))) write(' ' * tabs + '\n') # end of class ArgumentsProperty class ArgumentsHandler: def __init__(self, parent): self.parent = parent self.arguments = [] self.curr_arg = [] def start_elem(self, name, attrs): pass def end_elem(self, name): if name == 'arguments': self.parent.arguments = self.arguments self.parent.properties['arguments'].set_value(self.arguments) return True elif name == 'argument': self.arguments.append(["".join(self.curr_arg)]) self.curr_arg = [] return False def char_data(self, data): self.curr_arg.append(data) # end of class ArgumentsHandler class CustomWidget(ManagedBase): def __init__(self, name, klass, parent, id, sizer, pos, property_window, show=True): ManagedBase.__init__(self, name, klass, parent, id, sizer, pos, property_window, show) self.arguments = [['$parent'], ['$id']] #,['$width'],['$height']] self.access_functions['arguments'] = (self.get_arguments, self.set_arguments) cols = [('Arguments', GridProperty.STRING)] self.properties['arguments'] = ArgumentsProperty(self, 'arguments', None, cols, 2) def set_klass(self, value): ManagedBase.set_klass(self, value) if self.widget: self.widget.Refresh() def create_widget(self): self.widget = wx.Window(self.parent.widget, self.id, style=wx.SUNKEN_BORDER|wx.FULL_REPAINT_ON_RESIZE) wx.EVT_PAINT(self.widget, self.on_paint) def finish_widget_creation(self): ManagedBase.finish_widget_creation(self, sel_marker_parent=self.widget) def on_paint(self, event): dc = wx.PaintDC(self.widget) dc.BeginDrawing() dc.SetBrush(wx.WHITE_BRUSH) dc.SetPen(wx.BLACK_PEN) dc.SetBackground(wx.WHITE_BRUSH) dc.Clear() w, h = self.widget.GetClientSize() dc.DrawLine(0, 0, w, h) dc.DrawLine(w, 0, 0, h) text = 'Custom Widget: %s' % self.klass tw, th = dc.GetTextExtent(text) x = (w - tw)/2 y = (h - th)/2 dc.SetPen(wx.ThePenList.FindOrCreatePen(wx.BLACK, 0, wx.TRANSPARENT)) dc.DrawRectangle(x-1, y-1, tw+2, th+2) dc.DrawText(text, x, y) dc.EndDrawing() def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1) szr = wx.BoxSizer(wx.VERTICAL) args = self.properties['arguments'] args.display(panel) szr.Add(args.panel, 1, wx.ALL|wx.EXPAND, 5) help_btn = wx.Button(panel, -1, 'Help on "Arguments" property') text = """\ The 'Arguments' property behaves differently when generating XRC code wrt C++ or python: you can use it to add custom attributes to the resource object. To do so, arguments must have the following format: ATTRIBUTE_NAME: ATTRIBUTE_VALUE For instance: default_value: 10 is translated to: 10 Invalid entries are silently ignored""" def show_help(event): wx.MessageBox(text, 'Help on "Arguments" property', wx.OK|wx.CENTRE|wx.ICON_INFORMATION) wx.EVT_BUTTON(help_btn, -1, show_help) szr.Add(help_btn, 0, wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.EXPAND, 5) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') args.set_col_sizes([-1]) def get_arguments(self): return self.arguments def set_arguments(self, value): self.arguments = [[misc.wxstr(v) for v in val] for val in value] def get_property_handler(self, name): if name == 'arguments': return ArgumentsHandler(self) return ManagedBase.get_property_handler(self, name) # end of class CustomWidget def builder(parent, sizer, pos, number=[1]): """\ factory function for CustomWidget objects. """ class Dialog(wx.Dialog): def __init__(self, number=[0]): title = 'Select widget class' wx.Dialog.__init__(self, None, -1, title) self.klass = 'CustomWidget' if number[0]: self.klass = 'CustomWidget%s' % (number[0]-1) number[0] += 1 klass_prop = TextProperty(self, 'class', self) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(klass_prop.panel, 0, wx.ALL|wx.EXPAND, 5) szr.Add(wx.Button(self, wx.ID_OK, 'OK'), 0, wx.ALL|wx.ALIGN_CENTER, 5) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) w = self.GetTextExtent(title)[0] + 50 if self.GetSize()[0] < w: self.SetSize((w, -1)) self.CenterOnScreen() def __getitem__(self, value): def set_klass(c): self.klass = c return (lambda : self.klass, set_klass) # end of inner class dialog = Dialog() dialog.ShowModal() name = 'window_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'window_%d' % number[0] win = CustomWidget(name, dialog.klass, parent, wx.NewId(), sizer, pos, common.property_panel) node = Tree.Node(win) win.node = node win.set_option(1) win.set_flag("wxEXPAND") win.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) sizer.set_item(win.pos, 1, wx.EXPAND) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build CustomWidget objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, "'name' attribute missing" if not sizer or not sizeritem: raise XmlParsingError, "sizer or sizeritem object cannot be None" win = CustomWidget(name, 'CustomWidget', parent, wx.NewId(), sizer, pos, common.property_panel, True) sizer.set_item(win.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(win) win.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return win def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets['CustomWidget'] = builder common.widgets_from_xml['CustomWidget'] = xml_builder return common.make_object_button('CustomWidget', 'icons/custom.xpm', tip='Add a custom widget')