/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/classgen.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/UI/classgen.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 607 by jonathan, Fri Apr 4 12:16:57 2003 UTC revision 2709 by dpinte, Tue Oct 3 09:34:51 2006 UTC
# Line 1  Line 1 
1  # Copyright (c) 2003 by Intevation GmbH  # Copyright (c) 2003, 2004 by Intevation GmbH
2  # Authors:  # Authors:
3  # Jonathan Coles <[email protected]>  # Jonathan Coles <[email protected]>
4  #  #
5  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
6  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
7    
8  from Thuban import _  """The Classification Generator Dialog"""
9    
10    __version__ = "$Revision$"
11    # $Source$
12    # $Id$
13    
14    
15  from wxPython.wx import *  import sys
16    
17    import wx
18    
19    from Thuban import _
20    
21  from Thuban.Model.classification import Classification, ClassGroupRange, \  from Thuban.Model.classification import ClassGroupProperties
     ClassGroupSingleton, ClassGroupProperties  
22    
23  from Thuban.Model.table import Table, FIELDTYPE_INT, FIELDTYPE_DOUBLE, \  from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
24       FIELDTYPE_STRING       FIELDTYPE_STRING
25    
26  from Thuban.Model.color import Color  from Thuban.Model.layer import SHAPETYPE_ARC
27    from Thuban.Model.range import Range
28    from Thuban.UI.common import ThubanBeginBusyCursor, ThubanEndBusyCursor
29    
30    import classifier, resource
31    
32    from Thuban.Model.classgen import \
33        generate_uniform_distribution, generate_singletons, generate_quantiles, \
34        CustomRamp, grey_ramp, red_ramp, green_ramp, blue_ramp, green_to_red_ramp, \
35        HotToColdRamp, FixedRamp
36    
37    
38    USEALL_BMP  = "group_use_all"
39    USE_BMP     = "group_use"
40    USENOT_BMP  = "group_use_not"
41    USENONE_BMP = "group_use_none"
42    
43    GENCOMBOSTR_UNIFORM = _("Uniform Distribution")
44    GENCOMBOSTR_UNIQUE = _("Unique Values")
45    GENCOMBOSTR_QUANTILES = _("Quantiles from Table")
46    
47  ID_CLASSGEN_GEN = 4001  PROPCOMBOSTR_CUSTOM     = _("Custom Ramp")
48  ID_CLASSGEN_CANCEL = 4002  PROPCOMBOSTR_GREY       = _("Grey Ramp")
49    PROPCOMBOSTR_RED        = _("Red Ramp")
50    PROPCOMBOSTR_GREEN      = _("Green Ramp")
51    PROPCOMBOSTR_BLUE       = _("Blue Ramp")
52    PROPCOMBOSTR_GREEN2RED  = _("Green-to-Red Ramp")
53    PROPCOMBOSTR_HOT2COLD   = _("Hot-to-Cold Ramp")
54    
55  class ClassGenDialog(wxDialog):  ID_CLASSGEN_GENCOMBO = 4007
56                                                                                    ID_CLASSGEN_PROPCOMBO = 4008
57      def __init__(self, parent, table, fieldName):  
58          wxDialog.__init__(self, parent, -1, _("Generate Classification"),  ID_BORDER_COLOR = 4009
59                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)  ID_BORDER_COLOR_CHANGE = 4010
60                                                                                    
61    class ClassGenDialog(wx.Dialog):
62    
63        def __init__(self, parent, layer, fieldName):
64            """Inialize the class generating dialog.
65    
66            parent -- this must be an instance of the Classifier class
67            """
68    
69            wx.Dialog.__init__(self, parent, -1, _("Generate Classification"),
70                              style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
71    
72            self.parent = parent
73            self.layer = layer
74          self.clazz = None          self.clazz = None
75    
76          type, name, width, prec = table.field_info_by_name(fieldName)          col = layer.ShapeStore().Table().Column(fieldName)
77            self.type = col.type
78    
79          sizer = wxBoxSizer(wxVERTICAL)          self.fieldName = fieldName
80            self.fieldType = self.type
81    
82          buttonSizer = wxBoxSizer(wxHORIZONTAL)          self.curGenPanel = None
83          self.genButton = wxButton(self, ID_CLASSGEN_GEN, _("Generate"))  
84          buttonSizer.Add(self.genButton, 0, wxALL, 4)          self.genpanels = []
85          buttonSizer.Add(60, 20, 0, wxALL, 4)  
86          buttonSizer.Add(wxButton(self, ID_CLASSGEN_CANCEL, _("Cancel")),          #############
87                          0, wxALL, 4)          # we need to create genButton first because when we create the
88            # panels they will call AllowGenerate() which uses genButton.
89          if type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):          #
90              self.panel = GenRangePanel(self, table, fieldName, type)          self.genButton = wx.Button(self, wx.ID_OK, _("Generate"))
91          elif type == FIELDTYPE_STRING:          self.cancelButton = wx.Button(self, wx.ID_CANCEL, _("Close"))
92              print "Select a field that is an int/decimal"          self.genButton.SetDefault()
93              #panel = GenSingletonPanel(self, table, fieldName)  
94            self.genChoice = wx.Choice(self, ID_CLASSGEN_GENCOMBO)
95    
96            self.genpanels.append((GENCOMBOSTR_UNIQUE, GenUniquePanel))
97            if self.type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
98                self.genpanels.append((GENCOMBOSTR_UNIFORM, GenUniformPanel))
99                self.genpanels.append((GENCOMBOSTR_QUANTILES, GenQuantilesPanel))
100    
101            for name, clazz in self.genpanels:
102                self.genChoice.Append(name, [clazz, None])
103    
104            self.genChoice.SetSelection(0)
105    
106            for i in range(self.genChoice.GetCount()):
107                clazz, obj = self.genChoice.GetClientData(i)
108    
109                if obj is None:
110                    obj = clazz(self, self.layer, self.fieldName, self.fieldType)
111                    obj.Hide()
112                    self.genChoice.SetClientData(i, [clazz, obj])
113    
114    
115            #############
116    
117            sizer = wx.BoxSizer(wx.VERTICAL)
118    
119            sizer.Add(wx.StaticText(self, -1, _("Field: %s") % fieldName),
120                      0, wx.ALL, 4)
121            sizer.Add(wx.StaticText(
122                self, -1,
123                _("Data Type: %s") % classifier.Classifier.type2string[self.type]),
124                0, wx.ALL, 4)
125    
126            psizer = wx.BoxSizer(wx.HORIZONTAL)
127            psizer.Add(wx.StaticText(self, -1, _("Generate:")),
128                0, wx.ALIGN_CENTER_VERTICAL, 0)
129            psizer.Add(self.genChoice, 1, wx.ALL | wx.GROW, 4)
130    
131            sizer.Add(psizer, 0, wx.ALL | wx.GROW, 4)
132    
133            self.sizer_genPanel = wx.BoxSizer(wx.VERTICAL)
134            sizer.Add(self.sizer_genPanel, 1, wx.GROW | wx.ALL, 4)
135    
136            psizer = wx.BoxSizer(wx.HORIZONTAL)
137            psizer.Add(wx.StaticText(self, -1, _("Color Scheme:")),
138                0, wx.ALIGN_CENTER_VERTICAL, 0)
139    
140            # Properties (Ramp) ComboBox
141            self.propCombo = wx.Choice(self, ID_CLASSGEN_PROPCOMBO)
142    
143            self.propPanel = None
144            custom_ramp_panel = CustomRampPanel(self, layer.ShapeType())
145    
146            self.propCombo.Append(PROPCOMBOSTR_GREY,  grey_ramp)
147            self.propCombo.Append(PROPCOMBOSTR_RED,   red_ramp)
148            self.propCombo.Append(PROPCOMBOSTR_GREEN, green_ramp)
149            self.propCombo.Append(PROPCOMBOSTR_BLUE,  blue_ramp)
150            self.propCombo.Append(PROPCOMBOSTR_GREEN2RED, green_to_red_ramp)
151            self.propCombo.Append(PROPCOMBOSTR_HOT2COLD,  HotToColdRamp())
152            self.propCombo.Append(PROPCOMBOSTR_CUSTOM, custom_ramp_panel)
153    
154            self.propCombo.SetSelection(0)
155    
156            psizer.Add(self.propCombo, 1, wx.ALL | wx.GROW, 4)
157            sizer.Add(psizer, 0, wx.ALL | wx.GROW, 4)
158    
159            if layer.ShapeType() != SHAPETYPE_ARC:
160                psizer = wx.BoxSizer(wx.HORIZONTAL)
161                self.fix_border_check = wx.CheckBox(self, -1, _("Fix Border Color"))
162                psizer.Add(self.fix_border_check, 0, wx.ALL | wx.GROW, 4)
163                self.border_color = classifier.ClassGroupPropertiesCtrl(
164                    self, ID_BORDER_COLOR,
165                    ClassGroupProperties(), SHAPETYPE_ARC,
166                    style=wx.SIMPLE_BORDER, size=(40, 20))
167                psizer.Add(self.border_color, 0, wx.ALL | wx.GROW, 4)
168                psizer.Add(wx.Button(self, ID_BORDER_COLOR_CHANGE, _("Change")),
169                        0, wx.ALL, 4)
170                sizer.Add(psizer, 0, wx.ALL | wx.GROW, 4)
171                self.Bind(wx.EVT_BUTTON, self.OnBorderColorChange, id=ID_BORDER_COLOR_CHANGE)
172          else:          else:
173              assert False, "Shouldn't be here."              self.border_color = None
             pass  
174    
175          sizer.Add(self.panel, 1, wxGROW | wxALL, 4)          sizer.Add(custom_ramp_panel, 1, wx.GROW | wx.ALL, 4)
176          sizer.Add(buttonSizer, 0,          sizer.Show(custom_ramp_panel, False)
177                    wxALL | wxALIGN_BOTTOM | wxALIGN_CENTER_HORIZONTAL, 4)  
178            # Finally place the main buttons
179            buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
180            buttonSizer.Add(self.genButton, 0, wx.RIGHT|wx.EXPAND, 10)
181            buttonSizer.Add(self.cancelButton, 0, wx.RIGHT|wx.EXPAND, 10)
182            sizer.Add(buttonSizer, 0, wx.ALIGN_RIGHT|wx.BOTTOM|wx.TOP, 10)
183    
184          self.SetSizer(sizer)          self.SetSizer(sizer)
185          self.SetAutoLayout(True)          self.SetAutoLayout(True)
186          sizer.SetSizeHints(self)          sizer.SetSizeHints(self)
187    
188          EVT_BUTTON(self, ID_CLASSGEN_GEN, self._OnGenerate)          self.topBox = sizer
189          EVT_BUTTON(self, ID_CLASSGEN_CANCEL, self._OnCancel)  
190            self.__DoOnGenTypeSelect()
191    
192            self.Bind(wx.EVT_CHOICE, self._OnGenTypeSelect, id=ID_CLASSGEN_GENCOMBO)
193            self.Bind(wx.EVT_CHOICE, self._OnPropTypeSelect, id=ID_CLASSGEN_PROPCOMBO)
194            self.Bind(wx.EVT_BUTTON, self.OnOK, self.genButton)
195            self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelButton)
196    
197            self.__DoOnGenTypeSelect()
198    
199            self.genChoice.SetFocus()
200    
201      def GetClassification(self):      def GetClassification(self):
202          return self.clazz          return self.clazz
203    
204      def AllowGenerate(self, on):      def AllowGenerate(self, on):
205          self.genButton.Enable(on)          pass #self.genButton.Enable(on)
206    
207      def _OnGenerate(self, event):      def OnOK(self, event):
208          min = self.panel.GetMin()          """This is really the generate button, but we want to override
209          max = self.panel.GetMax()          the wxDialog class.
210          numGroups = self.panel.GetNumGroups()          """
         cgp = ClassGroupProperties()  
         cgp2 = ClassGroupProperties()  
                                                                                   
         cgp.SetLineColor(Color(.5, 0, 0))  
         cgp2.SetLineColor(Color(1, 0, 1))  
         cgp2.SetLineWidth(10)  
211    
212          if min is not None \          index = self.genChoice.GetSelection()
             and max is not None \  
             and numGroups is not None:  
             self.clazz = ClassGenerator().GenerateRanges(min, max,  
                                                          numGroups, cgp, cgp2)  
         else:    
             self.clazz = None # for now  
   
         self.EndModal(wxID_OK)  
                                                                                   
     def _OnCancel(self, event):  
         self.EndModal(wxID_CANCEL)  
   
 ID_RANGE_MIN = 4001  
 ID_RANGE_MAX = 4002  
 ID_RANGE_NGROUPS = 4003  
 ID_RANGE_STEP = 4004  
213    
214  class GenRangePanel(wxPanel):          assert index != -1, "button should be disabled!"
215    
216      def __init__(self, parent, table, fieldName, fieldType):          genSel = self.genChoice.GetString(index)
217          wxPanel.__init__(self, parent, -1)          clazz, genPanel = self.genChoice.GetClientData(index)
218    
219          self.parent = parent          propPanel = self.propPanel
220    
221            if genSel in (GENCOMBOSTR_UNIFORM,          \
222                          GENCOMBOSTR_UNIQUE,           \
223                          GENCOMBOSTR_QUANTILES):
224    
225                numGroups = genPanel.GetNumGroups()
226    
227                index = self.propCombo.GetSelection()
228    
229                propSel = self.propCombo.GetString(index)
230                propPanel = self.propCombo.GetClientData(index)
231    
232                ramp = propPanel.GetRamp()
233                if self.border_color and self.fix_border_check.IsChecked():
234                    props = self.border_color.GetProperties()
235                    ramp = FixedRamp(ramp,
236                        (props.GetLineColor(), props.GetLineWidth(), None))
237    
238                if genSel == GENCOMBOSTR_UNIFORM:
239    
240                    min = genPanel.GetMin()
241                    max = genPanel.GetMax()
242    
243                    if min is not None \
244                        and max is not None \
245                        and numGroups is not None:
246    
247                        self.clazz = generate_uniform_distribution(
248                                    min, max, numGroups, ramp,
249                                    self.type == FIELDTYPE_INT)
250    
251                        self.parent._SetClassification(self.clazz)
252    
253                elif genSel == GENCOMBOSTR_UNIQUE:
254    
255                    list = genPanel.GetValueList()
256    
257                    if len(list) > 0:
258                        self.clazz = generate_singletons(list, ramp)
259                        self.parent._SetClassification(self.clazz)
260    
261                elif genSel == GENCOMBOSTR_QUANTILES:
262    
263                    _range = genPanel.GetRange()
264                    _list = genPanel.GetList()
265                    _list.sort()
266    
267                    delta = 1 / float(numGroups)
268                    percents = [delta * i for i in range(1, numGroups + 1)]
269                    adjusted, self.clazz = \
270                        generate_quantiles(_list, percents, ramp, _range)
271    
272                    if adjusted:
273                        dlg = wx.MessageDialog(self,
274                            _("Based on the data from the table and the input\n"
275                         "values, the exact quantiles could not be generated.\n\n"
276                              "Accept a close estimate?"),
277                            _("Problem with Quantiles"),
278    
279                            wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
280                        if dlg.ShowModal() == wx.ID_YES:
281                            self.parent._SetClassification(self.clazz)
282                    else:
283                        self.parent._SetClassification(self.clazz)
284    
285        def OnCancel(self, event):
286            self.Close()
287    
288        def OnBorderColorChange(self, event):
289            self.border_color.DoEdit()
290    
291        def _OnGenTypeSelect(self, event):
292            self.__DoOnGenTypeSelect()
293            return
294    
295            combo = event.GetEventObject()
296    
297            selIndex = combo.GetSelection()
298    
299            if self.genPanel is not None:
300                self.topBox.Show(self.genPanel, False)
301    
302            self.genPanel = combo.GetClientData(selIndex)
303            if self.genPanel is not None:
304                self.topBox.Show(self.genPanel, True)
305    
306            self.topBox.SetSizeHints(self)
307            self.topBox.Layout()
308    
309        def _OnPropTypeSelect(self, event):
310            combo = event.GetEventObject()
311    
312            selIndex = combo.GetSelection()
313            sel = combo.GetString(selIndex)
314    
315            if isinstance(self.propPanel, wx.Panel):
316                self.topBox.Show(self.propPanel, False)
317    
318            self.propPanel = combo.GetClientData(selIndex)
319    
320            if isinstance(self.propPanel, wx.Panel):
321                self.topBox.Show(self.propPanel, True)
322    
323            self.topBox.SetSizeHints(self)
324            self.topBox.Layout()
325    
326        def __DoOnGenTypeSelect(self):
327            choice = self.genChoice
328    
329            sel = choice.GetSelection()
330            if sel == -1: return
331    
332            clazz, obj = choice.GetClientData(sel)
333    
334            if self.curGenPanel is not None:
335                self.curGenPanel.Hide()
336                self.sizer_genPanel.Remove(self.curGenPanel)
337    
338            self.curGenPanel = obj
339            self.curGenPanel.Show()
340    
341            self.sizer_genPanel.Add(self.curGenPanel, 1,
342                wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 3)
343            self.sizer_genPanel.Layout()
344            self.Layout()
345            self.topBox.SetSizeHints(self)
346    
347    ID_UNIFORM_MIN = 4001
348    ID_UNIFORM_MAX = 4002
349    ID_UNIFORM_NGROUPS = 4003
350    ID_UNIFORM_STEP = 4004
351    ID_UNIFORM_RETRIEVE = 4005
352    
353    class GenUniformPanel(wx.Panel):
354    
355        def __init__(self, parent, layer, fieldName, fieldType):
356            wx.Panel.__init__(self, parent, -1)
357    
358            self.parent = parent
359            self.layer = layer
360            self.fieldName = fieldName
361          self.fieldType = fieldType          self.fieldType = fieldType
362    
363          topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, "Ranges"),          topSizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""),
364                                      wxVERTICAL)                                      wx.VERTICAL)
365    
366            #############
367    
368            sizer = wx.BoxSizer(wx.HORIZONTAL)
369    
370          sizer = wxBoxSizer(wxHORIZONTAL)          sizer.Add(wx.StaticText(self, -1, _("Min:")), 0, wx.ALL, 4)
371            self.minCtrl = wx.TextCtrl(self, ID_UNIFORM_MIN, style=wx.TE_RIGHT)
372            sizer.Add(self.minCtrl, 1, wx.ALL, 4)
373            self.Bind(wx.EVT_TEXT, self._OnRangeChanged, id=ID_UNIFORM_MIN)
374    
375          sizer.Add(wxStaticText(self, -1, _("Min:")), 0, wxALL, 4)          sizer.Add(wx.StaticText(self, -1, _("Max:")), 0, wx.ALL, 4)
376          self.minCtrl = wxTextCtrl(self, ID_RANGE_MIN, style=wxTE_RIGHT)          self.maxCtrl = wx.TextCtrl(self, ID_UNIFORM_MAX, style=wx.TE_RIGHT)
377          sizer.Add(self.minCtrl, 0, wxALL, 4)          sizer.Add(self.maxCtrl, 1, wx.ALL, 4)
378          EVT_TEXT(self, ID_RANGE_MIN, self._OnRangeChanged)          self.Bind(wx.EVT_TEXT, self._OnRangeChanged, id=ID_UNIFORM_MAX)
379          self.goodTextColour = self.minCtrl.GetForegroundColour()  
380          self.badTextColour = wxRED          sizer.Add(wx.Button(self, ID_UNIFORM_RETRIEVE, _("Retrieve From Table")),
381                0, wx.ALL, 4)
382          sizer.Add(wxStaticText(self, -1, _("Max:")), 0, wxALL, 4)          self.Bind(wx.EVT_BUTTON, self._OnRetrieve, id=ID_UNIFORM_RETRIEVE)
383          self.maxCtrl = wxTextCtrl(self, ID_RANGE_MAX, style=wxTE_RIGHT)  
384          sizer.Add(self.maxCtrl, 0, wxALL, 4)          topSizer.Add(sizer, 1, wx.GROW, 0)
385          EVT_TEXT(self, ID_RANGE_MAX, self._OnRangeChanged)  
386          topSizer.Add(sizer, 0, wxALL, 4)          #############
387    
388          sizer = wxBoxSizer(wxHORIZONTAL)          sizer = wx.BoxSizer(wx.HORIZONTAL)
389          sizer.Add(wxStaticText(self, -1, _("Number of Groups:")), 0, wxALL, 4)  
390          self.numGroupsCtrl = wxSpinCtrl(self, ID_RANGE_NGROUPS, style=wxTE_RIGHT)          sizer.Add(wx.StaticText(self, -1, _("Number of Groups:")), 0, wx.ALL, 4)
391          EVT_TEXT(self, ID_RANGE_NGROUPS, self._OnNumGroupsChanged)          self.numGroupsCtrl = wx.SpinCtrl(self, ID_UNIFORM_NGROUPS,
392          EVT_SPINCTRL(self, ID_RANGE_NGROUPS, self._OnNumGroupsChanged)                                          style=wx.TE_RIGHT)
393          sizer.Add(self.numGroupsCtrl, 0, wxALL, 4)          self.Bind(wx.EVT_TEXT, self._OnNumGroupsChanged, id=ID_UNIFORM_NGROUPS)
394            self.Bind(wx.EVT_SPINCTRL, self._OnNumGroupsChanged, id=ID_UNIFORM_NGROUPS)
395          sizer.Add(wxStaticText(self, -1, _("Stepping:")), 0, wxALL, 4)          sizer.Add(self.numGroupsCtrl, 1, wx.ALL, 4)
396          self.stepCtrl = wxTextCtrl(self, ID_RANGE_STEP, style=wxTE_RIGHT)  
397          EVT_TEXT(self, ID_RANGE_STEP, self._OnSteppingChanged)          sizer.Add(wx.StaticText(self, -1, _("Stepping:")), 0, wx.ALL, 4)
398          sizer.Add(self.stepCtrl , 0, wxALL, 4)          self.stepCtrl = wx.TextCtrl(self, ID_UNIFORM_STEP, style=wx.TE_RIGHT)
399          topSizer.Add(sizer, 0, wxALL, 4)          self.Bind(wx.EVT_TEXT, self._OnSteppingChanged, id=ID_UNIFORM_STEP)
400            sizer.Add(self.stepCtrl , 1, wx.ALL, 4)
401    
402            topSizer.Add(sizer, 1, wx.GROW, 0)
403    
404            #############
405    
406          self.SetSizer(topSizer)          self.SetSizer(topSizer)
407          self.SetAutoLayout(True)          self.SetAutoLayout(True)
# Line 141  class GenRangePanel(wxPanel): Line 410  class GenRangePanel(wxPanel):
410          self.numGroupsChanging = False          self.numGroupsChanging = False
411          self.steppingChanging = False          self.steppingChanging = False
412    
413          self.numGroupsCtrl.SetRange(1, 100)          self.numGroupsCtrl.SetRange(1, sys.maxint)
414    
415          self.numGroupsCtrl.SetValue(1)          self.numGroupsCtrl.SetValue(1)
416          self.stepCtrl.SetValue("1")          self.stepCtrl.SetValue("1")
# Line 151  class GenRangePanel(wxPanel): Line 420  class GenRangePanel(wxPanel):
420    
421      def GetNumGroups(self):      def GetNumGroups(self):
422          value = self.numGroupsCtrl.GetValue()          value = self.numGroupsCtrl.GetValue()
423          return self.__GetValidatedTypeEntry(self.numGroupsCtrl,          return self.__GetValidatedTypeEntry(self.numGroupsCtrl,
424                                              value,                                              value,
425                                              FIELDTYPE_INT,                                              FIELDTYPE_INT,
426                                              None)                                              None)
427    
         ##if self.__ValidateEntry(self.numGroupsCtrl, value, int):  
             #return value  
   
         #return None  
   
428      def GetStepping(self):      def GetStepping(self):
429          step = self.stepCtrl.GetValue()          step = self.stepCtrl.GetValue()
430          return self.__GetValidatedTypeEntry(self.stepCtrl,          return self.__GetValidatedTypeEntry(self.stepCtrl,
431                                              step,                                              step,
432                                              self.fieldType,                                              self.fieldType,
433                                              0)                                              0)
# Line 171  class GenRangePanel(wxPanel): Line 435  class GenRangePanel(wxPanel):
435      def GetMin(self):      def GetMin(self):
436          min = self.minCtrl.GetValue()          min = self.minCtrl.GetValue()
437          max = self.maxCtrl.GetValue()          max = self.maxCtrl.GetValue()
438          return self.__GetValidatedTypeEntry(self.minCtrl,          return self.__GetValidatedTypeEntry(self.minCtrl,
439                                              min,                                              min,
440                                              self.fieldType,                                              self.fieldType,
441                                              max)                                              max)
# Line 179  class GenRangePanel(wxPanel): Line 443  class GenRangePanel(wxPanel):
443      def GetMax(self):      def GetMax(self):
444          min = self.minCtrl.GetValue()          min = self.minCtrl.GetValue()
445          max = self.maxCtrl.GetValue()          max = self.maxCtrl.GetValue()
446          return self.__GetValidatedTypeEntry(self.maxCtrl,          return self.__GetValidatedTypeEntry(self.maxCtrl,
447                                              max,                                              max,
448                                              self.fieldType,                                              self.fieldType,
449                                              min)                                              min)
450    
451      def _OnRangeChanged(self, event):      def _OnRangeChanged(self, event):
452    
453          hasFocus = wxWindow_FindFocus() == event.GetEventObject()          hasFocus = wx.Window_FindFocus() == event.GetEventObject()
454          min = self.GetMin()          min = self.GetMin()
455          max = self.GetMax()          max = self.GetMax()
456    
# Line 196  class GenRangePanel(wxPanel): Line 460  class GenRangePanel(wxPanel):
460          self.numGroupsCtrl.Enable(on)          self.numGroupsCtrl.Enable(on)
461          self.stepCtrl.Enable(on)          self.stepCtrl.Enable(on)
462    
         if on:  
             self.numGroupsCtrl.SetRange(1, abs(max - min) / 0.001)  
   
463          ngroups = self.GetNumGroups()          ngroups = self.GetNumGroups()
464    
465          if ngroups is not None  \          if ngroups is not None  \
# Line 206  class GenRangePanel(wxPanel): Line 467  class GenRangePanel(wxPanel):
467              and max is not None \              and max is not None \
468              and ngroups != 0:              and ngroups != 0:
469    
470              self.stepCtrl.SetValue(str((max - min) / ngroups))              #self.stepCtrl.SetValue(str((max - min) / ngroups))
471                self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
472                #self.numGroupsCtrl.SetValue(ngroups)
473    
474              self.parent.AllowGenerate(self.GetStepping() is not None)              self.parent.AllowGenerate(self.GetStepping() is not None)
475          else:          else:
# Line 227  class GenRangePanel(wxPanel): Line 490  class GenRangePanel(wxPanel):
490          min = self.GetMin()          min = self.GetMin()
491          max = self.GetMax()          max = self.GetMax()
492    
         if ngroups >= self.numGroupsCtrl.GetMax():  
             self.numGroupsCtrl.SetRange(1, ngroups + 1)  
   
493          if ngroups is not None  \          if ngroups is not None  \
494              and min is not None \              and min is not None \
495              and max is not None \              and max is not None \
# Line 243  class GenRangePanel(wxPanel): Line 503  class GenRangePanel(wxPanel):
503              # called steppingChanging tries to prevent the recursion.              # called steppingChanging tries to prevent the recursion.
504              #              #
505              self.numGroupsChanging = True              self.numGroupsChanging = True
506              self.stepCtrl.SetValue(str((max - min) / ngroups))  
507                self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
508    
509              self.parent.AllowGenerate(self.GetStepping() is not None)              self.parent.AllowGenerate(self.GetStepping() is not None)
510          else:          else:
# Line 268  class GenRangePanel(wxPanel): Line 529  class GenRangePanel(wxPanel):
529              # see note in _OnNumGroupsChanged              # see note in _OnNumGroupsChanged
530              #              #
531              self.steppingChanging = True              self.steppingChanging = True
532              n = int((max - min) / step)              self.numGroupsCtrl.SetValue(self.__CalcNumGroups(min, max, step))
             if n == 0:  
                 n = 1  
   
             self.numGroupsCtrl.SetValue(n)  
533    
534              self.parent.AllowGenerate(self.GetNumGroups() is not None)              self.parent.AllowGenerate(self.GetNumGroups() is not None)
535          else:          else:
536              self.parent.AllowGenerate(False)              self.parent.AllowGenerate(False)
537    
538        def _OnRetrieve(self, event):
539            table = self.layer.ShapeStore().Table()
540            if table is not None:
541                ThubanBeginBusyCursor()
542                try:
543                    min, max = table.ValueRange(self.fieldName)
544                    self.minCtrl.SetValue(str(min))
545                    self.maxCtrl.SetValue(str(max))
546                finally:
547                    ThubanEndBusyCursor()
548    
549      def __GetValidatedTypeEntry(self, win, value, type, badValue = None):      def __GetValidatedTypeEntry(self, win, value, type, badValue = None):
550    
551          if type == FIELDTYPE_INT:          if type == FIELDTYPE_INT:
552              func = int              func = int
553          elif type == FIELDTYPE_DOUBLE:          elif type == FIELDTYPE_DOUBLE:
554              func = float              func = float
# Line 309  class GenRangePanel(wxPanel): Line 577  class GenRangePanel(wxPanel):
577              valid = False              valid = False
578    
579          if valid:          if valid:
580              win.SetForegroundColour(wxBLACK)              win.SetForegroundColour(wx.BLACK)
581          else:          else:
582              win.SetForegroundColour(wxRED)              win.SetForegroundColour(wx.RED)
583    
584            win.Refresh()
585    
586          return valid          return valid
           
587    
588  class GenSingletonPanel(wxPanel):      def __CalcStepping(self, min, max, ngroups):
589            if self.fieldType == FIELDTYPE_INT:
590                step = int((max - min + 1) / float(ngroups))
591            else:
592                step = (max - min) / float(ngroups)
593    
594      def __init__(self, parent, table, fieldName, fieldType):          return step
         wxPanel.__init__(self, parent, -1)  
595    
596        def __CalcNumGroups(self, min, max, step):
597            n = int((max - min) / step)
598            if n == 0:
599                n = 1
600    
601  class ClassGenerator:          if self.fieldType == FIELDTYPE_INT and step == 1:
602                n += 1
603    
604      def GenerateSingletons(self, list, numGroups, prop1, prop2):          return n
         """Generate a new classification consisting solely of singletons.  
605    
         The resulting classification will consist of at most 'numGroups'  
         groups whose group properties ramp between 'prop1' and 'prop2'. There  
         could be fewer groups if 'list' contains fewer that 'numGroups' items.  
606    
607          list -- any object that implements the iterator interface  ID_UNIQUE_RETRIEVE = 4001
608    ID_UNIQUE_USEALL = 4002
609    ID_UNIQUE_USE = 4003
610    ID_UNIQUE_DONTUSE = 4004
611    ID_UNIQUE_USENONE = 4005
612    ID_UNIQUE_SORTAVAIL = 4006
613    ID_UNIQUE_SORTUSE = 4007
614    ID_UNIQUE_REVAVAIL = 4008
615    ID_UNIQUE_REVUSE = 4009
616    
617          numGroups -- how many groups to generate. This can not be  class GenUniquePanel(wx.Panel):
                      determined while the classification is being  
                      generated because the stepping values must  
                      be precalculated to ramp between prop1 and prop2.  
618    
619          prop1 -- initial group property values      def __init__(self, parent, layer, fieldName, fieldType):
620            wx.Panel.__init__(self, parent, -1)
621    
622          prop2 -- final group property values          self.parent = parent
623          """          self.layer = layer
624            self.fieldName = fieldName
625            self.fieldType = fieldType
626    
627            topSizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""),
628                                        wx.VERTICAL)
629    
630    
631            #bsizer = wxBoxSizer(wxVERTICAL)
632            topSizer.Add(wx.Button(self, ID_UNIQUE_RETRIEVE,
633                                _("Retrieve From Table")),
634                       0, wx.ALL | wx.ALIGN_RIGHT, 4)
635    
636            self.Bind(wx.EVT_BUTTON, self._OnRetrieve, id=ID_UNIQUE_RETRIEVE)
637    
638            #topSizer.Add(bsizer, 0, wx.ALL, 4)
639    
640            sizer = wx.BoxSizer(wx.HORIZONTAL)
641    
642            self.dataList = []
643    
644            psizer = wx.BoxSizer(wx.VERTICAL)
645            self.list_avail = wx.ListCtrl(self, -1,
646                            style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
647            self.list_avail.InsertColumn(0, _("Available"))
648            self.list_avail_data = []
649            psizer.Add(self.list_avail, 1, wx.GROW, 0)
650    
651            bsizer = wx.BoxSizer(wx.HORIZONTAL)
652            bsizer.Add(wx.Button(self, ID_UNIQUE_SORTAVAIL, _("Sort")))
653            self.Bind(wx.EVT_BUTTON, self._OnSortList, id=ID_UNIQUE_SORTAVAIL)
654    
655            bsizer.Add(wx.Button(self, ID_UNIQUE_REVAVAIL, _("Reverse")))
656            self.Bind(wx.EVT_BUTTON, self._OnReverseList, id=ID_UNIQUE_REVAVAIL)
657    
658            psizer.Add(bsizer, 0, wx.GROW, 0)
659            sizer.Add(psizer, 1, wx.GROW, 0)
660    
661    
662            bsizer = wx.BoxSizer(wx.VERTICAL)
663    
664            bmp = resource.GetBitmapResource(USEALL_BMP, wx.BITMAP_TYPE_XPM)
665            bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_USEALL, bmp),
666                       0, wx.GROW | wx.ALL, 4)
667            bmp = resource.GetBitmapResource(USE_BMP, wx.BITMAP_TYPE_XPM)
668            bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_USE, bmp),
669                       0, wx.GROW | wx.ALL, 4)
670            bmp = resource.GetBitmapResource(USENOT_BMP, wx.BITMAP_TYPE_XPM)
671            bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_DONTUSE, bmp),
672                       0, wx.GROW | wx.ALL, 4)
673            bmp = resource.GetBitmapResource(USENONE_BMP, wx.BITMAP_TYPE_XPM)
674            bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_USENONE, bmp),
675                       0, wx.GROW | wx.ALL, 4)
676    
677            self.Bind(wx.EVT_BUTTON, self._OnUseAll, id=ID_UNIQUE_USEALL)
678            self.Bind(wx.EVT_BUTTON, self._OnUse, id=ID_UNIQUE_USE)
679            self.Bind(wx.EVT_BUTTON, self._OnDontUse, id=ID_UNIQUE_DONTUSE)
680            self.Bind(wx.EVT_BUTTON, self._OnUseNone, id=ID_UNIQUE_USENONE)
681    
682            sizer.Add(bsizer, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
683    
684            psizer = wx.BoxSizer(wx.VERTICAL)
685            self.list_use = wx.ListCtrl(self, -1,
686                            style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
687            self.list_use.InsertColumn(0, _("Use"))
688            self.list_use_data = []
689            psizer.Add(self.list_use, 1, wx.GROW, 0)
690    
691            bsizer = wx.BoxSizer(wx.HORIZONTAL)
692            bsizer.Add(wx.Button(self, ID_UNIQUE_SORTUSE, _("Sort")))
693            self.Bind(wx.EVT_BUTTON, self._OnSortList, id=ID_UNIQUE_SORTUSE)
694    
695            bsizer.Add(wx.Button(self, ID_UNIQUE_REVUSE, _("Reverse")))
696            self.Bind(wx.EVT_BUTTON, self._OnReverseList, id=ID_UNIQUE_REVUSE)
697    
698            psizer.Add(bsizer, 0, wx.GROW, 0)
699    
700            sizer.Add(psizer, 1, wx.GROW, 0)
701    
702    
703            topSizer.Add(sizer, 1, wx.GROW, 0)
704    
705            self.SetSizer(topSizer)
706            self.SetAutoLayout(True)
707            topSizer.SetSizeHints(self)
708    
709            width, height = self.list_avail.GetSizeTuple()
710            self.list_avail.SetColumnWidth(0,width)
711            width, height = self.list_use.GetSizeTuple()
712            self.list_use.SetColumnWidth(0,width)
713    
714            self.parent.AllowGenerate(False)
715    
716        def GetNumGroups(self):
717            return self.list_use.GetItemCount()
718    
719          clazz = Classification()      def GetValueList(self):
720          if numGroups == 0: return clazz          list = []
721            for i in range(self.list_use.GetItemCount()):
722                list.append(self.dataList[self.list_use.GetItemData(i)])
723            return list
724    
725          for value, prop in zip(list, PropertyRamp(numGroups, prop1, prop2)):      def _OnSortList(self, event):
726              clazz.AddGroup(ClassGroupSingleton(value, prop))          id = event.GetId()
727    
728          return clazz          if id == ID_UNIQUE_SORTUSE:
729                list = self.list_use
730            else:
731                list = self.list_avail
732    
733            list.SortItems(lambda i1, i2: cmp(self.dataList[i1],
734                                              self.dataList[i2]))
735    
736        def _OnReverseList(self, event):
737            id = event.GetId()
738    
739            if id == ID_UNIQUE_REVUSE:
740                list = self.list_use
741            else:
742                list = self.list_avail
743    
744            #
745            # always returning 1 reverses the list
746            #
747            list.SortItems(lambda i1, i2: 1)
748    
749        def _OnRetrieve(self, event):
750            self.list_use.DeleteAllItems()
751            self.list_use_data = []
752            self.list_avail.DeleteAllItems()
753            self.list_avail_data = []
754    
755            ThubanBeginBusyCursor()
756            try:
757                list = self.layer.ShapeStore().Table().UniqueValues(self.fieldName)
758                index = 0
759                for v in list:
760                    self.dataList.append(v)
761                    i = self.list_avail.InsertStringItem(index, str(v))
762                    self.list_avail.SetItemData(index, i)
763    
764                    self.list_avail_data.append(v)
765                    index += 1
766            finally:
767                ThubanEndBusyCursor()
768    
769        def _OnUseAll(self, event):
770            for i in range(self.list_avail.GetItemCount()):
771                self.__MoveListItem(0, self.list_avail, self.list_use)
772    
773        def _OnUse(self, event):
774            self.__MoveSelectedItems(self.list_avail, self.list_use)
775    
776      def GenerateRanges(self, min, max, numGroups, prop1, prop2):      def _OnDontUse(self, event):
777            self.__MoveSelectedItems(self.list_use, self.list_avail)
778    
779          clazz = Classification()      def _OnUseNone(self, event):
         if numGroups == 0: return clazz  
780    
781          step = (max - min) / float(numGroups)          for i in range(self.list_use.GetItemCount()):
782                self.__MoveListItem(0, self.list_use, self.list_avail)
783    
784          cur_min = min      def __MoveSelectedItems(self, list_src, list_dest):
785          cur_max = cur_min + step          while True:
786                index = list_src.GetNextItem(-1,
787                                             wx.LIST_NEXT_ALL,
788                                             wx.LIST_STATE_SELECTED)
789    
790          i = 0              if index == -1:
791          for prop in PropertyRamp(numGroups, prop1, prop2):                  break
792    
793              if i == (numGroups - 1):              self.__MoveListItem(index, list_src, list_dest)
                 cur_max = max  
794    
             # this check guards against rounding issues  
             if cur_min != cur_max:  
                 clazz.AddGroup(ClassGroupRange(cur_min, cur_max, prop))  
795    
796              cur_min = cur_max      def __MoveListItem(self, index, list_src, list_dest):
             cur_max += step  
             i += 1  
797    
798          return clazz          item = list_src.GetItem(index)
799    
800  class PropertyRamp:          x = list_dest.InsertStringItem(
801                    list_dest.GetItemCount(),
802                    str(self.dataList[item.GetData()]))
803    
804            list_dest.SetItemData(x, item.GetData())
805    
806            list_src.DeleteItem(index)
807    
808    #   def _OnListSize(self, event):
809    #       list = event.GetEventObject()
810    
811    #       list.SetColumnWidth(0, event.GetSize().GetWidth())
812    #      
813    
814    ID_QUANTILES_RANGE = 4001
815    ID_QUANTILES_RETRIEVE = 4002
816    
817    class GenQuantilesPanel(wx.Panel):
818    
819        def __init__(self, parent, layer, fieldName, fieldType):
820            wx.Panel.__init__(self, parent, -1)
821    
822            self.parent = parent
823            self.layer = layer
824            self.fieldName = fieldName
825            self.fieldType = fieldType
826    
827      def __init__(self, num, prop1, prop2):          topBox = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""),
828                                        wx.VERTICAL)
829    
830          self.count = int(num)          self.text_range = wx.TextCtrl(self, ID_QUANTILES_RANGE, "")
831          num = float(num)          self.button_retrieve = wx.Button(self, ID_QUANTILES_RETRIEVE,
832                                            _("Retrieve from Table"))
833    
834            self.spin_numClasses = wx.SpinCtrl(self, -1, style=wx.TE_RIGHT)
835            self.spin_numClasses.SetRange(2, sys.maxint)
836            self.spin_numClasses.SetValue(2)
837    
         self.lineColor = prop1.GetLineColor()  
         self.fillColor = prop1.GetFill()  
         self.lineWidth = prop1.GetLineWidth()  
838    
839          lineColor2 = prop2.GetLineColor()          sizer = wx.BoxSizer(wx.HORIZONTAL)
840          fillColor2 = prop2.GetFill()          sizer.Add(wx.StaticText(self, -1, _("Apply to Range")), 0, wx.ALL, 4)
841          lineWidth2 = prop2.GetLineWidth()          sizer.Add(self.text_range, 1, wx.ALL, 4)
842            sizer.Add(self.button_retrieve, 0, wx.ALL, 4)
843    
844          self.line_redStep   = (lineColor2.red   - self.lineColor.red)   / num          topBox.Add(sizer, 0, wx.EXPAND, 0)
         self.line_greenStep = (lineColor2.green - self.lineColor.green) / num  
         self.line_blueStep  = (lineColor2.blue  - self.lineColor.blue)  / num  
845    
846          self.line_widthStep = (lineWidth2 - self.lineWidth) / num          sizer = wx.BoxSizer(wx.HORIZONTAL)
847            sizer.Add(wx.StaticText(self, -1, _("Number of Classes:")), 0, wx.ALL, 4)
848            sizer.Add(self.spin_numClasses, 1, wx.ALL, 4)
849    
850          self.fill_redStep   = (fillColor2.red   - self.fillColor.red)   / num          topBox.Add(sizer, 0, wx.EXPAND, 0)
         self.fill_greenStep = (fillColor2.green - self.fillColor.green) / num  
         self.fill_blueStep  = (fillColor2.blue  - self.fillColor.blue)  / num  
851    
852      def __iter__(self):          self.SetSizer(topBox)
853          return self          self.SetAutoLayout(True)
854            topBox.Fit(self)
855            topBox.SetSizeHints(self)
856    
857            self.Bind(wx.EVT_TEXT, self.OnRangeText, id=ID_QUANTILES_RANGE)
858            self.Bind(wx.EVT_BUTTON, self.OnRetrieve, id=ID_QUANTILES_RETRIEVE)
859    
860            self.__range = None
861    
862        def GetNumGroups(self):
863            return self.spin_numClasses.GetValue()
864    
865        def GetRange(self):
866            assert self.__range is not None
867    
868            return self.__range
869    
870        def GetList(self):
871            _list = []
872            table = self.layer.ShapeStore().Table()
873            if table is not None:
874                ThubanBeginBusyCursor()
875                try:
876                    #
877                    # FIXME: Replace with a call to table when the method
878                    # has been written to get all the values
879                    #
880                    for i in range(table.NumRows()):
881                        _list.append(table.ReadValue(i, self.fieldName,
882                                                     row_is_ordinal = True))
883                finally:
884                    ThubanEndBusyCursor()
885    
886            return _list
887    
888        def OnRangeText(self, event):
889    
890            try:
891                self.__range = Range(self.text_range.GetValue())
892            except ValueError:
893                self.__range = None
894    
895            if self.__range is not None:
896                self.text_range.SetForegroundColour(wx.BLACK)
897            else:
898                self.text_range.SetForegroundColour(wx.RED)
899    
900        def OnRetrieve(self, event):
901            table = self.layer.ShapeStore().Table()
902            if table is not None:
903                ThubanBeginBusyCursor()
904                try:
905                    min, max = table.ValueRange(self.fieldName)
906                    self.text_range.SetValue("[" + str(min) + ";" + str(max) + "]")
907                    # This is a workaround, which will result in OnRangeText
908                    # being called twice on some platforms.
909                    # Testing showed this is needed with current wx 2.4. versions
910                    # on MacOSX to guarantee that it is called at all.
911                    self.OnRangeText(None)
912                finally:
913                    ThubanEndBusyCursor()
914    
915    ID_CUSTOMRAMP_COPYSTART = 4001
916    ID_CUSTOMRAMP_COPYEND = 4002
917    ID_CUSTOMRAMP_EDITSTART = 4003
918    ID_CUSTOMRAMP_EDITEND = 4004
919    ID_CUSTOMRAMP_SPROP = 4005
920    ID_CUSTOMRAMP_EPROP = 4006
921    
922    class CustomRampPanel(wx.Panel):
923    
924        def __init__(self, parent, shapeType):
925            wx.Panel.__init__(self, parent, -1)
926    
927            topSizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""), wx.HORIZONTAL)
928    
929            bsizer = wx.BoxSizer(wx.VERTICAL)
930            bsizer.Add(wx.StaticText(self, -1, _("Start:")), 0, wx.ALL | wx.CENTER, 4)
931            self.startPropCtrl = classifier.ClassGroupPropertiesCtrl(
932                self, ID_CUSTOMRAMP_SPROP,
933                ClassGroupProperties(), shapeType,
934                style=wx.SIMPLE_BORDER, size=(40, 20))
935            bsizer.Add(self.startPropCtrl, 1, wx.GROW | wx.ALL | wx.CENTER, 4)
936            bsizer.Add(wx.Button(self, ID_CUSTOMRAMP_EDITSTART, _("Change")),
937                       0, wx.GROW | wx.ALL | wx.CENTER, 4)
938    
939            topSizer.Add(bsizer,
940                       1, wx.ALL \
941                          | wx.SHAPED \
942                          | wx.ALIGN_CENTER_HORIZONTAL \
943                          | wx.ALIGN_CENTER_VERTICAL, \
944                       4)
945    
946            bmp = resource.GetBitmapResource(USE_BMP, wx.BITMAP_TYPE_XPM)
947            bsizer = wx.BoxSizer(wx.VERTICAL)
948            bsizer.Add(wx.BitmapButton(self, ID_CUSTOMRAMP_COPYSTART, bmp),
949                       0, wx.GROW | wx.ALL, 4)
950            bmp = resource.GetBitmapResource(USENOT_BMP, wx.BITMAP_TYPE_XPM)
951            bsizer.Add(wx.BitmapButton(self, ID_CUSTOMRAMP_COPYEND, bmp),
952                       0, wx.GROW | wx.ALL, 4)
953    
954            topSizer.Add(bsizer,
955                       0, wx.ALL \
956                          | wx.ALIGN_CENTER_HORIZONTAL \
957                          | wx.ALIGN_CENTER_VERTICAL,
958                       4)
959    
960            bsizer = wx.BoxSizer(wx.VERTICAL)
961            bsizer.Add(wx.StaticText(self, -1, _("End:")), 0, wx.ALL | wx.CENTER, 4)
962            self.endPropCtrl = classifier.ClassGroupPropertiesCtrl(
963                self, ID_CUSTOMRAMP_EPROP,
964                ClassGroupProperties(), shapeType,
965                style=wx.SIMPLE_BORDER, size=(40, 20))
966            bsizer.Add(self.endPropCtrl, 1, wx.GROW | wx.ALL | wx.CENTER, 4)
967            bsizer.Add(wx.Button(self, ID_CUSTOMRAMP_EDITEND, _("Change")),
968                       0, wx.GROW | wx.ALL | wx.CENTER, 4)
969    
970            topSizer.Add(bsizer,
971                       1, wx.ALL \
972                          | wx.SHAPED \
973                          | wx.ALIGN_RIGHT \
974                          | wx.ALIGN_CENTER_HORIZONTAL \
975                          | wx.ALIGN_CENTER_VERTICAL,
976                       4)
977    
978            self.Bind(wx.EVT_BUTTON, self._OnCopyStart, id=ID_CUSTOMRAMP_COPYSTART)
979            self.Bind(wx.EVT_BUTTON, self._OnCopyEnd, id=ID_CUSTOMRAMP_COPYEND)
980            self.Bind(wx.EVT_BUTTON, self._OnEditStart, id=ID_CUSTOMRAMP_EDITSTART)
981            self.Bind(wx.EVT_BUTTON, self._OnEditEnd, id=ID_CUSTOMRAMP_EDITEND)
982    
983            self.SetSizer(topSizer)
984            self.SetAutoLayout(True)
985            topSizer.SetSizeHints(self)
986    
987      def next(self):      def GetRamp(self):
988          if self.count == 0:          return CustomRamp(self.startPropCtrl.GetProperties(),
989              raise StopIteration                            self.endPropCtrl.GetProperties())
990    
991          prop = ClassGroupProperties()      def _OnCopyStart(self, event):
992          prop.SetFill(self.fillColor)          self.endPropCtrl.SetProperties(self.startPropCtrl.GetProperties())
         prop.SetLineColor(self.lineColor)  
         prop.SetLineWidth(int(self.lineWidth))  
           
         self.lineColor.red   += self.line_redStep  
         self.lineColor.green += self.line_greenStep  
         self.lineColor.blue  += self.line_blueStep  
993    
994          self.fillColor.red   += self.fill_redStep      def _OnCopyEnd(self, event):
995          self.fillColor.green += self.fill_greenStep          self.startPropCtrl.SetProperties(self.endPropCtrl.GetProperties())
         self.fillColor.blue  += self.fill_blueStep  
996    
997          self.lineWidth       += self.line_widthStep      def _OnEditStart(self, event):
998            self.startPropCtrl.DoEdit()
999    
1000          self.count -= 1      def _OnEditEnd(self, event):
1001            self.endPropCtrl.DoEdit()
1002    
         return prop  
1003    

Legend:
Removed from v.607  
changed lines
  Added in v.2709

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26