Author: reinhard Date: 2010-12-12 15:50:36 -0600 (Sun, 12 Dec 2010) New Revision: 10270
Modified: trunk/gnue-forms/ trunk/gnue-forms/src/uidrivers/wx/widgets/entry.py Log: Introduced "picker" controls for numeric and date input. Now the user can input numerical and date fields with the mouse. Helpful for applications used with a touch pen. Property changes on: trunk/gnue-forms ___________________________________________________________________ Name: bzr:revision-info - timestamp: 2010-12-08 01:03:04.076999903 +0100 committer: Reinhard Müller <[email protected]> properties: branch-nick: forms + timestamp: 2010-12-11 17:52:20.673000097 +0100 committer: Reinhard Müller <[email protected]> properties: branch-nick: forms Name: bzr:file-ids - src/GFObjects/GFBlock.py 1...@3a364389-8fce-0310-8f11-cc363fde16c7:trunk%2Fgnue-forms:src%2FGFObjects%2FGFBlock.py + src/uidrivers/wx/widgets/entry.py 10...@3a364389-8fce-0310-8f11-cc363fde16c7:trunk%2Fgnue-forms:src%2Fuidrivers%2Fwx%2Fwidgets%2Fentry.py Name: bzr:revision-id:v4 - 3116 [email protected] 3117 [email protected] 3118 [email protected] 3119 [email protected] 3120 [email protected] 3121 [email protected] 3122 [email protected] 3123 [email protected] 3124 [email protected] 3125 [email protected] 3126 [email protected] 3127 [email protected] 3128 [email protected] 3129 [email protected] 3130 [email protected] 3131 [email protected] 3132 [email protected] 3133 [email protected] 3134 [email protected] 3135 [email protected] 3136 [email protected] 3137 [email protected] 3138 [email protected] 3139 [email protected] 3140 [email protected] 3141 [email protected] 3142 [email protected] 3143 [email protected] 3144 [email protected] 3145 [email protected] 3146 [email protected] 3147 [email protected] 3148 [email protected] 3149 [email protected] 3150 [email protected] 3151 [email protected] 3152 [email protected] 3153 [email protected] 3154 [email protected] 3155 [email protected] 3156 [email protected] 3157 [email protected] 3158 [email protected] 3159 [email protected] 3160 [email protected] 3161 [email protected] 3162 [email protected] 3163 [email protected] 3164 [email protected] 3165 [email protected] 3166 [email protected] 3167 [email protected] 3168 [email protected] 3169 [email protected] 3170 [email protected] 3171 [email protected] 3172 [email protected] 3173 [email protected] 3174 [email protected] 3175 [email protected] + 3116 [email protected] 3117 [email protected] 3118 [email protected] 3119 [email protected] 3120 [email protected] 3121 [email protected] 3122 [email protected] 3123 [email protected] 3124 [email protected] 3125 [email protected] 3126 [email protected] 3127 [email protected] 3128 [email protected] 3129 [email protected] 3130 [email protected] 3131 [email protected] 3132 [email protected] 3133 [email protected] 3134 [email protected] 3135 [email protected] 3136 [email protected] 3137 [email protected] 3138 [email protected] 3139 [email protected] 3140 [email protected] 3141 [email protected] 3142 [email protected] 3143 [email protected] 3144 [email protected] 3145 [email protected] 3146 [email protected] 3147 [email protected] 3148 [email protected] 3149 [email protected] 3150 [email protected] 3151 [email protected] 3152 [email protected] 3153 [email protected] 3154 [email protected] 3155 [email protected] 3156 [email protected] 3157 [email protected] 3158 [email protected] 3159 [email protected] 3160 [email protected] 3161 [email protected] 3162 [email protected] 3163 [email protected] 3164 [email protected] 3165 [email protected] 3166 [email protected] 3167 [email protected] 3168 [email protected] 3169 [email protected] 3170 [email protected] 3171 [email protected] 3172 [email protected] 3173 [email protected] 3174 [email protected] 3175 [email protected] 3176 [email protected] Name: bzr:text-parents - src/GFObjects/GFBlock.py [email protected] + src/uidrivers/wx/widgets/entry.py [email protected] Modified: trunk/gnue-forms/src/uidrivers/wx/widgets/entry.py =================================================================== --- trunk/gnue-forms/src/uidrivers/wx/widgets/entry.py 2010-12-12 21:50:33 UTC (rev 10269) +++ trunk/gnue-forms/src/uidrivers/wx/widgets/entry.py 2010-12-12 21:50:36 UTC (rev 10270) @@ -24,8 +24,10 @@ Implementation of the <entry> tag """ +import locale import os import wx +import wx.combo from gnue.forms.uidrivers.wx.widgets import _base from gnue.forms.input import GFKeyMapper @@ -85,28 +87,34 @@ def __build_default(self, parent, password=False, multiline=False): - xFlags = wx.TE_PROCESS_TAB + if multiline and not self.managed: + self.__border = self._uiDriver.control_border('default') - if password: - xFlags |= wx.TE_PASSWORD - - if multiline: - xFlags |= wx.TE_MULTILINE - else: - xFlags |= wx.TE_PROCESS_ENTER - - # Right-align numeric fields. This does work on wxMSW and wxGTK only. if self._gfObject._field.datatype == 'number': - xFlags |= wx.TE_RIGHT + style = wx.CB_DROPDOWN + ctrl = NumberEntryCtrl(parent, style=style) - if multiline and not self.managed: - self.__border = self._uiDriver.control_border('default') + elif self._gfObject._field.datatype == 'date': + style = wx.DP_DROPDOWN | wx.DP_ALLOWNONE + ctrl = DatePickerCtrl(parent, style=style) - ctrl = wx.TextCtrl(parent, -1, style=xFlags) + else: + style = wx.TE_PROCESS_TAB + if password: + style |= wx.TE_PASSWORD + if multiline: + style |= wx.TE_MULTILINE + else: + style |= wx.TE_PROCESS_ENTER + ctrl = wx.TextCtrl(parent, style=style) self.__set_size(ctrl) - ctrl.Bind(wx.EVT_TEXT, self.__on_text_changed) + if isinstance(ctrl, DatePickerCtrl): + ctrl.Bind(wx.EVT_DATE_CHANGED, self.__on_datepicker_date_changed) + ctrl.Bind(wx.EVT_TEXT, self.__on_datepicker_text) + else: + ctrl.Bind(wx.EVT_TEXT, self.__on_text_changed) ctrl.Bind(wx.EVT_CHAR, self.__on_keypress) ctrl.Bind(wx.EVT_KEY_DOWN, self.__on_key_down) ctrl.Bind(wx.EVT_SET_FOCUS, self.__on_set_focus) @@ -311,6 +319,8 @@ if self.__old_background is not None: widget.SetBackgroundColour(self.__old_background) + event.Skip() + # ------------------------------------------------------------------------- def __on_mac_choice_clicked(self, event): @@ -345,6 +355,23 @@ # ------------------------------------------------------------------------- + def __on_datepicker_date_changed(self, event): + + widget = event.GetEventObject() + + self._request('REPLACEVALUE', text=widget.GetText()) + + # ------------------------------------------------------------------------- + + def __on_datepicker_text(self, event): + + widget = event.GetEventObject() + + self._request('REPLACEVALUE', text=widget.GetValue(), + position=widget.GetInsertionPoint()) + + # ------------------------------------------------------------------------- + def __on_gtk_text_changed(self, event): # FIXME: workaround for issue-144. Setting a selection within an @@ -406,6 +433,12 @@ event.Skip() return + # Let Windows' date picker handle up/down. + if 'wxMSW' in wx.PlatformInfo and isinstance(control, DatePickerCtrl): + if keycode in (wx.WXK_UP, wx.WXK_DOWN): + event.Skip() + return + # Handle cursor up/down and page up/down. if not (event.ShiftDown() or event.CmdDown() or event.AltDown()): if keycode == wx.WXK_UP: @@ -541,6 +574,8 @@ # with the string value (e.g. in Choice-Controls on OS X) if not widget.SetStringSelection(value): widget.SetValue(value) + elif isinstance(widget, DatePickerCtrl): + widget.SetText(value) else: widget.SetValue(value) @@ -602,6 +637,10 @@ # Take care: SetSelection in a ListBox sets the selected item! pass + elif isinstance(widget, DatePickerCtrl) and 'wxMSW' in wx.PlatformInfo: + # Windows' native DatePickerCtrl doesn't have a selection. + pass + elif hasattr(widget, 'SetSelection'): if 'wxGTK' in wx.PlatformInfo: wx.CallAfter(widget.SetSelection, selection1, selection2) @@ -743,7 +782,9 @@ # Add border width. # FIXME: This is only an estimate, but I haven't found out how to # determine the real border width in wx. - if self._gfObject.style.lower() == 'dropdown': + if isinstance (control, wx.ComboBox) \ + or isinstance (control, NumberEntryCtrl) \ + or isinstance (control, DatePickerCtrl): min_w += 4 if max_w: max_w += 4 @@ -826,6 +867,271 @@ # ============================================================================= +# Number Entry Control +# ============================================================================= + +class NumberEntryCtrl(wx.combo.ComboCtrl): + + def __init__(self, *args, **kwargs): + + wx.combo.ComboCtrl.__init__(self, *args, **kwargs) + + popup = NumberEntryPopup() + popup.TextCtrl = self.GetTextCtrl() + self.SetPopupControl(popup) + + # In wxWidgets 2.8, wxComboCtrl receives the EVT_SET_FOCUS events from + # the TextCtrl, but not EVT_KILL_FOCUS events. This seems to be fixed + # in wxWidgets 2.9, so this workaround can be removed when we require + # higher versions of wxWidgets. + self.GetTextCtrl().Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) + + # ------------------------------------------------------------------------- + + def OnKillFocus(self, event): + + e = event.Clone() + e.SetEventObject(self) + self.GetEventHandler().ProcessEvent(e) + + event.Skip() + + # ------------------------------------------------------------------------- + + def GetBackgroundColour(self, *args, **kwargs): + + return self.GetTextCtrl().GetBackgroundColour(*args, **kwargs) + + # ------------------------------------------------------------------------- + + def SetBackgroundColour(self, *args, **kwargs): + + return self.GetTextCtrl().SetBackgroundColour(*args, **kwargs) + + # ------------------------------------------------------------------------- + + def SetSelection(self, *args, **kwargs): + + return self.GetTextCtrl().SetSelection(*args, **kwargs) + + # ------------------------------------------------------------------------- + + def SetInsertionPoint(self, *args, **kwargs): + + return self.GetTextCtrl().SetInsertionPoint(*args, **kwargs) + +# ============================================================================= + +class NumberEntryPopup(wx.combo.ComboPopup): + + def Create(self, parent, *args, **kwargs): + + wx.combo.ComboPopup.Create(self, parent, *args, **kwargs) + + self.panel = wx.Panel(parent, style=wx.BORDER_SIMPLE) + + radixc = u" " + locale.localeconv()['decimal_point'] + u" " + + self.b1 = wx.Button(self.panel, label=u" 1 ", style=wx.BU_EXACTFIT) + self.b2 = wx.Button(self.panel, label=u" 2 ", style=wx.BU_EXACTFIT) + self.b3 = wx.Button(self.panel, label=u" 3 ", style=wx.BU_EXACTFIT) + self.b4 = wx.Button(self.panel, label=u" 4 ", style=wx.BU_EXACTFIT) + self.b5 = wx.Button(self.panel, label=u" 5 ", style=wx.BU_EXACTFIT) + self.b6 = wx.Button(self.panel, label=u" 6 ", style=wx.BU_EXACTFIT) + self.b7 = wx.Button(self.panel, label=u" 7 ", style=wx.BU_EXACTFIT) + self.b8 = wx.Button(self.panel, label=u" 8 ", style=wx.BU_EXACTFIT) + self.b9 = wx.Button(self.panel, label=u" 9 ", style=wx.BU_EXACTFIT) + self.b0 = wx.Button(self.panel, label=u" 0 ", style=wx.BU_EXACTFIT) + self.br = wx.Button(self.panel, label=radixc, style=wx.BU_EXACTFIT) + self.bx = wx.Button(self.panel, label=u" x ", style=wx.BU_EXACTFIT) + self.b1.Bind(wx.EVT_BUTTON, self.OnClick) + self.b2.Bind(wx.EVT_BUTTON, self.OnClick) + self.b3.Bind(wx.EVT_BUTTON, self.OnClick) + self.b4.Bind(wx.EVT_BUTTON, self.OnClick) + self.b5.Bind(wx.EVT_BUTTON, self.OnClick) + self.b6.Bind(wx.EVT_BUTTON, self.OnClick) + self.b7.Bind(wx.EVT_BUTTON, self.OnClick) + self.b8.Bind(wx.EVT_BUTTON, self.OnClick) + self.b9.Bind(wx.EVT_BUTTON, self.OnClick) + self.b0.Bind(wx.EVT_BUTTON, self.OnClick) + self.br.Bind(wx.EVT_BUTTON, self.OnClick) + self.bx.Bind(wx.EVT_BUTTON, self.OnClick) + + box = wx.GridSizer(rows=4, cols=3) + box.Add(self.b1, flag=wx.EXPAND) + box.Add(self.b2, flag=wx.EXPAND) + box.Add(self.b3, flag=wx.EXPAND) + box.Add(self.b4, flag=wx.EXPAND) + box.Add(self.b5, flag=wx.EXPAND) + box.Add(self.b6, flag=wx.EXPAND) + box.Add(self.b7, flag=wx.EXPAND) + box.Add(self.b8, flag=wx.EXPAND) + box.Add(self.b9, flag=wx.EXPAND) + box.Add(self.b0, flag=wx.EXPAND) + box.Add(self.br, flag=wx.EXPAND) + box.Add(self.bx, flag=wx.EXPAND) + self.panel.SetSizerAndFit(box) + + # ------------------------------------------------------------------------- + + def OnClick(self, event): + + char = event.GetEventObject().GetLabel()[1:2] + if char == "x": + self.TextCtrl.ChangeValue(self.TextCtrl.GetValue()[:-1]) + self.TextCtrl.SetInsertionPointEnd() + else: + self.TextCtrl.WriteText(char) + + # ------------------------------------------------------------------------- + + def GetControl(self, *args, **kwds): + + return self.panel + + # ------------------------------------------------------------------------- + + def GetAdjustedSize(self, *args, **kwds): + + return self.panel.GetMinSize() + + +# ============================================================================= +# Date Picker Control +# ============================================================================= + +class DatePickerCtrl(wx.DatePickerCtrl): + + def __init__(self, *args, **kwargs): + + wx.DatePickerCtrl.__init__(self, *args, **kwargs) + + # The native control available in Windows doesn't have all the breakage + # we try to fix here, so we just do nothing. + if 'wxMSW' in wx.PlatformInfo: + return + + self.combo = None + + for child in self.GetChildren(): + if isinstance (child, wx.combo.ComboCtrl): + self.combo = child + + # Make sure we receive the interesting events from the TextCtrl. + self.combo.GetTextCtrl().Bind(wx.EVT_KEY_DOWN, self.OnEvent) + self.combo.GetTextCtrl().Bind(wx.EVT_CHAR, self.OnEvent) + self.combo.GetTextCtrl().Bind(wx.EVT_SET_FOCUS, self.OnEvent) + self.combo.GetTextCtrl().Bind(wx.EVT_KILL_FOCUS, self.OnEvent) + + self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) + self.Bind(wx.EVT_TEXT, self.OnText) + + self.propagating_event = False + + # ------------------------------------------------------------------------- + + def OnEvent(self, event): + + self.propagating_event = True + try: + e = event.Clone() + e.SetEventObject(self) + self.GetEventHandler().ProcessEvent(e) + finally: + self.propagating_event = False + + event.Skip() + + # ------------------------------------------------------------------------- + + def OnSetFocus(self, event): + + # wxDatePickerCtrl's EVT_SET_FOCUS handler unconditionally sets the + # focus on the ComboCtrl element, and the combo element sets the focus + # on its TextCtrl element. Since we propagate the TextCtrl's + # EVT_SET_FOCUS up to the DatePickerCtrl, this would create an endless + # recursion. We avoid this here. + + if not self.propagating_event: + event.Skip() + + # ------------------------------------------------------------------------- + + def OnText(self, event): + + # wxDatePickerCtrl's EVT_TEXT handler sends bogus EVT_DATE_CHANGED + # events around. We avoid this here. + + pass + + # ------------------------------------------------------------------------- + + def GetText(self): + + if 'wxMSW' in wx.PlatformInfo: + date = self.GetValue() + if date.IsOk(): + return date.FormatDate() + else: + return u"" + else: + return self.combo.GetValue() + + # ------------------------------------------------------------------------- + + def SetText(self, text): + + # Don't call SetValue() if the value hasn't really changed, since this + # function messes with the cursor position and the selection, and under + # Windows, we have no way to restore the cursor. + if text != self.GetText(): + if 'wxMSW' in wx.PlatformInfo: + date = wx.DateTime() + date.ParseFormat(text, '%x') + self.SetValue(date) + else: + self.combo.SetValue(text) + + # ------------------------------------------------------------------------- + + def GetBackgroundColour(self, *args, **kwargs): + + if 'wxMSW' in wx.PlatformInfo: + return wx.DatePickerCtrl.GetBackgroundColour(self, *args, **kwargs) + else: + return self.combo.GetTextCtrl().GetBackgroundColour(*args, **kwargs) + + # ------------------------------------------------------------------------- + + def SetBackgroundColour(self, *args, **kwargs): + + + if 'wxMSW' in wx.PlatformInfo: + return wx.DatePickerCtrl.SetBackgroundColour(self, *args, **kwargs) + else: + return self.combo.GetTextCtrl().SetBackgroundColour(*args, **kwargs) + + # ------------------------------------------------------------------------- + + def SetSelection(self, *args, **kwargs): + + if not 'wxMSW' in wx.PlatformInfo: + return self.combo.GetTextCtrl().SetSelection(*args, **kwargs) + + # ------------------------------------------------------------------------- + + def GetInsertionPoint(self, *args, **kwargs): + + return self.combo.GetTextCtrl().GetInsertionPoint(*args, **kwargs) + + # ------------------------------------------------------------------------- + + def SetInsertionPoint(self, *args, **kwargs): + + if not 'wxMSW' in wx.PlatformInfo: + return self.combo.GetTextCtrl().SetInsertionPoint(*args, **kwargs) + +# ============================================================================= # Configuration # ============================================================================= Property changes on: trunk/gnue-forms/src/uidrivers/wx/widgets/entry.py ___________________________________________________________________ Name: svn:executable + * _______________________________________________ commit-gnue mailing list [email protected] http://lists.gnu.org/mailman/listinfo/commit-gnue
