/[thuban]/trunk/thuban/Thuban/UI/classifier.py
ViewVC logotype

Diff of /trunk/thuban/Thuban/UI/classifier.py

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

revision 392 by jonathan, Mon Feb 10 15:26:30 2003 UTC revision 455 by bh, Tue Mar 4 11:32:20 2003 UTC
# Line 15  from wxPython.wx import * Line 15  from wxPython.wx import *
15  from wxPython.grid import *  from wxPython.grid import *
16    
17  from Thuban import _  from Thuban import _
18    from Thuban.common import *
19    from Thuban.UI.common import *
20    
21  from Thuban.Model.classification import Classification  from Thuban.Model.classification import *
22    
23    from Thuban.Model.color import Color
24    
25  from Thuban.Model.layer import SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT  from Thuban.Model.layer import SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
26    
# Line 25  ID_CLASS_TABLE = 40011 Line 29  ID_CLASS_TABLE = 40011
29    
30  ID_CLASSIFY_OK = 4001  ID_CLASSIFY_OK = 4001
31  ID_CLASSIFY_CANCEL = 4002  ID_CLASSIFY_CANCEL = 4002
32    ID_CLASSIFY_ADD = 4003
33    ID_CLASSIFY_GENRANGE = 4004
34    ID_CLASSIFY_REMOVE = 4005
35    
36    COL_VISUAL = 0
37    COL_VALUE  = 1
38    COL_LABEL  = 2
39    
40    FIELD_CLASS = 0
41    FIELD_TYPE = 1
42    FIELD_NAME = 2
43    
44    FIELD_TYPE_STRING = "string"
45    FIELD_TYPE_INT = "int"
46    FIELD_TYPE_DOUBLE = "double"
47    
48    #
49    # this is a silly work around to ensure that the table that is
50    # passed into SetTable is the same that is returned by GetTable
51    #
52    import weakref
53    class ClassGrid(wxGrid):
54    
55        def __init__(self, parent, layer, fieldData):
56            wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (340, 160))
57            self.SetTable(ClassTable(fieldData, layer.ShapeType(), self), true)
58            self.SetSelectionMode(wxGrid.wxGridSelectRows)
59            EVT_GRID_CELL_LEFT_DCLICK(self, self.OnCellDClick)
60    
61            EVT_GRID_RANGE_SELECT(self, self._OnSelectedRange)
62            EVT_GRID_SELECT_CELL(self, self._OnSelectedCell)
63    
64            self.layer = layer
65            self.currentSelection = []
66    
67        def GetCurrentSelection(self):
68            sel = copy.copy(self.currentSelection)
69            sel.sort()
70            return sel
71    
72        def SetCellRenderer(self, row, col):
73            raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))
74    
75        def SetTable(self, object, *attributes):
76            self.tableRef = weakref.ref(object)
77            return wxGrid.SetTable(self, object, *attributes)
78    
79        def GetTable(self):
80            return self.tableRef()
81    
82        def DeleteSelectedRows(self):
83            sel = self.GetCurrentSelection()
84    
85            if len(sel) == 0: return
86            if len(sel) == 1:
87                group = self.GetTable().GetValueAsCustom(sel[0], COL_VISUAL, None)
88                if isinstance(group, ClassGroupDefault):
89                    wxMessageDialog(self,
90                                    "The Default group cannot be removed.",
91                                    style = wxOK | wxICON_EXCLAMATION).ShowModal()
92                    return
93            
94            self.ClearSelection()
95    
96            sel.reverse()
97            table = self.GetTable()
98            for row in sel:
99                table.DeleteRows(row)
100    
101            if len(sel) == 1:
102                r = sel[0]
103                if r > self.GetNumberRows() - 1:
104                    r = self.GetNumberRows() - 1
105                self.SelectRow(r)
106            
107    #
108    # XXX: This isn't working, and there is no way to deselect rows wxPython!
109    #
110    #   def DeselectRow(self, row):
111    #       self.ProcessEvent(
112    #           wxGridRangeSelectEvent(-1,
113    #                                  wxEVT_GRID_RANGE_SELECT,
114    #                                  self,
115    #                                  (row, row), (row, row),
116    #                                  sel = False))
117    
118        def OnCellDClick(self, event):
119            r = event.GetRow()
120            c = event.GetCol()
121            if c == COL_VISUAL:
122                # XXX: getting the properties is only possible with non-Maps!!!
123                group = self.GetTable().GetValueAsCustom(r, c, None)
124                prop = group.GetProperties()
125                propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())
126                if propDlg.ShowModal() == wxID_OK:
127                    new_prop = propDlg.GetClassGroupProperties()
128                    prop.SetStroke(new_prop.GetStroke())
129                    prop.SetStrokeWidth(new_prop.GetStrokeWidth())
130                    prop.SetFill(new_prop.GetFill())
131                    self.Refresh()
132                propDlg.Destroy()
133    
134        #
135        # _OnSelectedRange() and _OnSelectedCell() were borrowed
136        # from http://wiki.wxpython.org
137        #
138        def _OnSelectedRange(self, event):
139            """Internal update to the selection tracking list"""
140            if event.Selecting():
141                for index in range( event.GetTopRow(), event.GetBottomRow()+1):
142                    if index not in self.currentSelection:
143                        self.currentSelection.append( index )
144            else:
145                for index in range( event.GetTopRow(), event.GetBottomRow()+1):
146                    while index in self.currentSelection:
147                        self.currentSelection.remove( index )
148            #self.ConfigureForSelection()
149    
150            event.Skip()
151    
152        def _OnSelectedCell( self, event ):
153            """Internal update to the selection tracking list"""
154            self.currentSelection = [ event.GetRow() ]
155            #self.ConfigureForSelection()
156            event.Skip()
157    
158  class ClassTable(wxPyGridTableBase):  class ClassTable(wxPyGridTableBase):
159    
160      def __init__(self, clinfo):      NUM_COLS = 3
         wxPyGridTableBase.__init__(self)  
         self.clinfo = copy.deepcopy(clinfo)  
161    
162        __col_labels = [_("Symbol"), _("Value"), _("Label")]
163    
164        def __init__(self, fieldData, shapeType, view = None):
165            wxPyGridTableBase.__init__(self)
166            self.SetView(view)
167          self.tdata = []          self.tdata = []
168    
169          self.tdata.append([self.clinfo.DefaultData, 'DEFAULT'])          self.Reset(fieldData, shapeType)
170    
171          for value, data in self.clinfo.points.items():      def Reset(self, fieldData, shapeType):
             self.tdata.append([data, value])  
172    
173          for range in self.clinfo.ranges:          self.GetView().BeginBatch()
174              self.tdata.append([range[2], '%s-%s' % range[0], range[1]])  
175            self.fieldData = fieldData
176            self.shapeType = shapeType
177            self.renderer = ClassRenderer(self.shapeType)
178    
179            old_len = len(self.tdata)
180    
181            self.tdata = []
182    
183            clazz = fieldData[FIELD_CLASS]
184            if clazz is None:
185                clazz = Classification()
186    
187    #       p = clazz.GetDefaultGroup()
188    #       np = ClassDataDefault(classData = p)
189    #       self.tdata.append([np, 'DEFAULT', np.GetLabel()])
190    
191    #       for p in clazz.points.values():
192    #           np = ClassDataPoint(p.GetValue(), classData = p)
193    #           self.tdata.append([np, np.GetValue(), np.GetLabel()])
194    
195    #       for p in clazz.ranges:
196    #           np = ClassDataRange(p.GetMin(), p.GetMax(), classData = p)
197    #           self.tdata.append([np,
198    #                              '%s - %s' % (np.GetMin(), np.GetMax()),
199    #                              np.GetLabel()])
200    
201            i = 0
202            for p in clazz:
203                np = copy.copy(p)
204                self.__SetRow(i, np)
205                i += 1
206    
         self.SetColLabelValue(1, _("Data Values"))  
207    
208            self.modified = 0
209    
210            self.__NotifyRowChanges(old_len, len(self.tdata))
211            self.GetView().EndBatch()
212    
213        def __NotifyRowChanges(self, curRows, newRows):
214            #
215            # silly message processing for updates to the number of
216            # rows and columns
217            #
218            if newRows > curRows:
219                msg = wxGridTableMessage(self,
220                            wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
221                            newRows - curRows)    # how many
222                self.GetView().ProcessTableMessage(msg)
223            elif newRows < curRows:
224                msg = wxGridTableMessage(self,
225                            wxGRIDTABLE_NOTIFY_ROWS_DELETED,
226                            curRows - newRows,    # position
227                            curRows - newRows)    # how many
228                self.GetView().ProcessTableMessage(msg)
229    
230    
231        def __SetRow(self, row, group):
232    
233            if isinstance(group, ClassGroupDefault):
234                data = [group, _('DEFAULT'), group.GetLabel()]
235            elif isinstance(group, ClassGroupSingleton):
236                data = [group, group.GetValue(), group.GetLabel()]
237            elif isinstance(group, ClassGroupRange):
238                data = [group,
239                        _('%s - %s') % (group.GetMin(), group.GetMax()),
240                        group.GetLabel()]
241    
242            if row >= len(self.tdata):
243                self.tdata.append(data)
244            else:
245                self.tdata[row] = data
246    
247        def GetColLabelValue(self, col):
248            return self.__col_labels[col]
249    
250        def GetRowLabelValue(self, row):
251            data = self.tdata[row][COL_VISUAL]
252            if isinstance(data, ClassGroupDefault):   return _("Default")
253            if isinstance(data, ClassGroupSingleton): return _("Singleton")
254            if isinstance(data, ClassGroupRange):     return _("Range")
255            if isinstance(data, ClassGroupMap):       return _("Map")
256    
257      def GetNumberRows(self):      def GetNumberRows(self):
258          return len(self.tdata)          return len(self.tdata)
259    
260      def GetNumberCols(self):      def GetNumberCols(self):
261          return 2          return self.NUM_COLS
262    
263      def IsEmptyCell(self, row, col):      def IsEmptyCell(self, row, col):
264          return false          return 0
265    
266      def GetValue(self, row, col):      def GetValue(self, row, col):
267          return self.tdata[row][col]          return self.GetValueAsCustom(row, col, "")
268    
269      def SetValue(self, row, col, value):      def SetValue(self, row, col, value):
270          self.tdata[row][col] = value          self.SetValueAsCustom(row, col, "", value)
271            self.__Modified()
272          
273      def GetValueAsCustom(self, row, col, typeName):      def GetValueAsCustom(self, row, col, typeName):
274          return self.tdata[row][col]          return self.tdata[row][col]
275    
276        def __ParseInput(self, value):
277            """Try to determine what kind of input value is
278               (a single number or a range)
279            """
280    
281            type = self.fieldData[FIELD_TYPE]
282    
283            if type == FIELD_TYPE_STRING:
284                return (value,)
285            elif type == FIELD_TYPE_INT or type == FIELD_TYPE_DOUBLE:
286    
287                #
288                # first try to take the input as a single number
289                # if there's an exception try to break it into
290                # a range seperated by a '-'. take care to ignore
291                # a leading '-' as that could be for a negative number.
292                # then try to parse the individual parts. if there
293                # is an exception here, let it pass up to the calling
294                # function.
295                #
296                try:
297                    return (Str2Num(value),)
298                except:
299                    i = value.find('-')
300                    if i == 0:
301                        i = value.find('-', 1)
302    
303                    return (Str2Num(value[:i]), Str2Num(value[i+1:]))
304                
305    
306        def SetValueAsCustom(self, row, col, typeName, value):
307            group = self.tdata[row][COL_VISUAL]
308    
309            if col == COL_VISUAL:
310                self.tdata[row][COL_VISUAL] = value
311            elif col == COL_VALUE:
312                if isinstance(group, ClassGroupDefault):
313                    # not allowed to modify the default value
314                    pass
315                elif isinstance(group, ClassGroupMap):
316                    # something special
317                    pass
318                else: # SINGLETON, RANGE
319                    try:
320                        dataInfo = self.__ParseInput(value)
321                    except:
322                        # bad input, ignore the request
323                        pass
324                    else:
325    
326                        ngroup = group
327                        props = group.GetProperties()
328                        if len(dataInfo) == 1:
329                            if not isinstance(group, ClassGroupSingleton):
330                                ngroup = ClassGroupSingleton(prop = props)
331                            ngroup.SetValue(dataInfo[0])
332                        elif len(dataInfo) == 2:
333                            if not isinstance(group, ClassGroupRange):
334                                ngroup = ClassGroupRange(prop = props)
335                            ngroup.SetRange(dataInfo[0], dataInfo[1])
336                        else:
337                            assert(False)
338    
339                        ngroup.SetLabel(group.GetLabel())
340                        self.__SetRow(row, ngroup)
341    
342                        self.GetView().Refresh()
343    
344            elif col == COL_LABEL:
345                group.SetLabel(value)
346                self.tdata[row][COL_LABEL] = group.GetLabel()
347            else:
348                raise ValueError(_("Invalid column request"))
349    
350            self.__Modified()
351    
352        def GetAttr(self, row, col, someExtraParameter):
353            attr = wxGridCellAttr()
354            #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)
355    
356            if col == COL_VISUAL:
357                attr.SetRenderer(ClassRenderer(self.shapeType))
358                attr.SetReadOnly()
359    
360            return attr
361    
362        def GetClassGroup(self, row):
363            return self.tdata[row][COL_VISUAL]
364    
365        def __Modified(self):
366            self.modified = 1
367    
368        def IsModified(self):
369            return self.modified
370    
371        def DeleteRows(self, pos, numRows = 1):
372            assert(pos >= 0)
373            old_len = len(self.tdata)
374            for row in range(pos, pos - numRows, -1):
375                group = self.GetValueAsCustom(row, COL_VISUAL, None)
376                if not isinstance(group, ClassGroupDefault):
377                    self.tdata.pop(row)
378                    self.__Modified()
379        
380            if self.IsModified():
381                self.__NotifyRowChanges(old_len, len(self.tdata))
382    
383        def AppendRows(self, numRows = 1):
384            old_len = len(self.tdata)
385            for i in range(numRows):
386                np = ClassGroupSingleton()
387                self.tdata.append([np, np.GetValue(), np.GetLabel()])
388                self.__Modified()
389    
390            if self.IsModified():
391                self.__NotifyRowChanges(old_len, len(self.tdata))
392    
393    
394  class Classifier(wxDialog):  class Classifier(wxDialog):
395            
396      def __init__(self, parent, layer):      def __init__(self, parent, layer):
397          wxDialog.__init__(self, parent, -1, _("Classify"),          wxDialog.__init__(self, parent, -1, _("Classify"),
398                            style = wxRESIZE_BORDER)                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
399    
400    
401            self.layer = layer
402    
403          topBox = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
404    
405            topBox.Add(wxStaticText(self, -1, _("Layer: %s") % layer.Title()),
406                0, wxALIGN_LEFT | wxALL, 4)
407            topBox.Add(wxStaticText(self, -1, _("Type: %s") % layer.ShapeType()),
408                0, wxALIGN_LEFT | wxALL, 4)
409    
410          propertyBox = wxBoxSizer(wxHORIZONTAL)          propertyBox = wxBoxSizer(wxHORIZONTAL)
411          propertyBox.Add(wxStaticText(self, -1, _("Property")),          propertyBox.Add(wxStaticText(self, -1, _("Field: ")),
412              0, wxALIGN_CENTER | wxALL, 4)              0, wxALIGN_CENTER | wxALL, 4)
413    
414          self.properties = wxComboBox(self, ID_PROPERTY_SELECT, "",          self.fields = wxComboBox(self, ID_PROPERTY_SELECT, "",
415                                       style = wxCB_READONLY)                                       style = wxCB_READONLY)
416    
417          self.num_cols = layer.table.field_count()          self.num_cols = layer.table.field_count()
418          cur_hilight = 0          # just assume the first field in case one hasn't been
419            # specified in the file.
420            self.__cur_field = 0
421            clazz = layer.GetClassification()
422            field = clazz.GetField()
423          for i in range(self.num_cols):          for i in range(self.num_cols):
424              type, name, len, decc = layer.table.field_info(i)              type, name, len, decc = layer.table.field_info(i)
425              if name == layer.classification.field:              self.fields.Append(name)
426                  cur_hilight = i  
427              self.properties.Append(name)              if name == field:
428                    self.__cur_field = i
429          self.properties.SetSelection(cur_hilight)                  self.fields.SetClientData(i, [clazz, type, name, len, decc])
430          propertyBox.Add(self.properties, 1, wxGROW, 4)              else:
431          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self.OnPropertySelect)                  self.fields.SetClientData(i, [None, type, name, len, decc])
432    
433            self.fields.SetSelection(self.__cur_field)
434    
435            propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)
436            EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self.OnFieldSelect)
437    
438          topBox.Add(propertyBox, 0, wxGROW, 4)          topBox.Add(propertyBox, 0, wxGROW, 4)
439    
# Line 96  class Classifier(wxDialog): Line 441  class Classifier(wxDialog):
441          # Classification data table          # Classification data table
442          #          #
443    
444          self.classTable = wxGrid(self, ID_CLASS_TABLE, size=(300, 150))          controlBox = wxBoxSizer(wxHORIZONTAL)
445            self.classGrid = ClassGrid(self,
446          table = ClassTable(layer.classification)                                     layer,
447          self.classTable.SetTable(table, true)                                     self.fields.GetClientData(self.__cur_field))
448          self.classTable.EnableEditing(false)  
449          cr = ClassRenderer(layer.ShapeType())          controlBox.Add(self.classGrid, 1, wxGROW, 0)
450          for i in range(self.classTable.GetNumberRows()):  
451              self.classTable.SetCellRenderer(i, 0, cr)          controlButtonBox = wxBoxSizer(wxVERTICAL)
452            controlButtonBox.Add(wxButton(self, ID_CLASSIFY_ADD,
453          topBox.Add(self.classTable, 1, wxGROW, 0)              _("Add")), 0, wxGROW | wxALL, 4)
454            controlButtonBox.Add(wxButton(self, ID_CLASSIFY_GENRANGE,
455                _("Generate Ranges")), 0, wxGROW | wxALL, 4)
456    
457            controlButtonBox.Add(wxButton(self, ID_CLASSIFY_REMOVE,
458                _("Remove")), 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
459    
460            controlBox.Add(controlButtonBox, 0, wxGROW, 10)
461            topBox.Add(controlBox, 1, wxGROW, 10)
462    
463            EVT_BUTTON(self, ID_CLASSIFY_ADD, self.OnAdd)
464            EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self.OnRemove)
465            EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self.OnGenRange)
466    
467          #          #
468          # Control buttons:          # Control buttons:
# Line 120  class Classifier(wxDialog): Line 477  class Classifier(wxDialog):
477          EVT_BUTTON(self, ID_CLASSIFY_OK, self.OnOK)          EVT_BUTTON(self, ID_CLASSIFY_OK, self.OnOK)
478          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self.OnCancel)          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self.OnCancel)
479    
480    
481    
482          self.SetAutoLayout(true)          self.SetAutoLayout(true)
483          self.SetSizer(topBox)          self.SetSizer(topBox)
484          topBox.Fit(self)          topBox.Fit(self)
485          topBox.SetSizeHints(self)          topBox.SetSizeHints(self)
486    
487      def OnPropertySelect(self, event): pass      def __BuildClassification(self, prop):
488    
489            clazz = Classification()
490            clazz.SetField(self.fields.GetString(prop))
491    
492            numRows = self.classGrid.GetNumberRows()
493    
494            if numRows > 0:
495                table = self.classGrid.GetTable()
496                clazz.SetDefaultGroup(table.GetClassGroup(0))
497    
498                for i in range(1, numRows):
499                    clazz.AddGroup(table.GetClassGroup(i))
500    
501            return clazz
502    
503        def OnFieldSelect(self, event):
504            data = self.fields.GetClientData(self.__cur_field)
505            data[FIELD_CLASS] = self.__BuildClassification(self.__cur_field)
506    
507            self.fields.SetClientData(self.__cur_field, data)
508    
509            self.__cur_field = self.fields.GetSelection()
510            fieldData = self.fields.GetClientData(self.__cur_field)
511            self.classGrid.GetTable().Reset(fieldData, self.layer.ShapeType())
512    
513      def OnOK(self, event):      def OnOK(self, event):
514            """Put the data from the table into a new Classification and hand
515               it to the layer.
516            """
517    
518            clazz = self.fields.GetClientData(self.__cur_field)[FIELD_CLASS]
519    
520            #
521            # only build the classification if there wasn't one to
522            # to begin with or it has been modified
523            #
524            if clazz is None or self.classGrid.GetTable().IsModified():
525                clazz = self.__BuildClassification(self.__cur_field)
526    
527            clazz.SetLayer(self.layer)
528    
529            self.layer.SetClassification(clazz)
530    
531          self.EndModal(wxID_OK)          self.EndModal(wxID_OK)
532    
533      def OnCancel(self, event):      def OnCancel(self, event):
534            """Do nothing. The layer's current classification stays the same."""
535          self.EndModal(wxID_CANCEL)          self.EndModal(wxID_CANCEL)
536    
537        def OnAdd(self, event):
538            self.classGrid.AppendRows()
539    
540  class ClassRenderer(wxPyGridCellRenderer):      def OnRemove(self, event):
541            self.classGrid.DeleteSelectedRows()
542    
543      def __init__(self, shapeType):      def OnGenRange(self, event):
544          wxPyGridCellRenderer.__init__(self)          print "Classifier.OnGenRange()"
545    
546    
547    ID_SELPROP_OK = 4001
548    ID_SELPROP_CANCEL = 4002
549    ID_SELPROP_SPINCTRL = 4002
550    ID_SELPROP_PREVIEW = 4003
551    ID_SELPROP_STROKECLR = 4004
552    ID_SELPROP_FILLCLR = 4005
553    
554    class SelectPropertiesDialog(wxDialog):
555    
556        def __init__(self, parent, prop, shapeType):
557            wxDialog.__init__(self, parent, -1, _("Select Properties"),
558                              style = wxRESIZE_BORDER)
559    
560            self.prop = ClassGroupProperties(prop)
561    
562            topBox = wxBoxSizer(wxVERTICAL)
563    
564            itemBox = wxBoxSizer(wxHORIZONTAL)
565    
566            # preview box
567            previewBox = wxBoxSizer(wxVERTICAL)
568            previewBox.Add(wxStaticText(self, -1, _("Preview:")),
569                0, wxALIGN_LEFT | wxALL, 4)
570            self.previewer = ClassDataPreviewer(None, self.prop, shapeType,
571                                                self, ID_SELPROP_PREVIEW, (40, 40))
572            previewBox.Add(self.previewer, 1, wxGROW, 15)
573    
574            itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
575    
576            # control box
577            ctrlBox = wxBoxSizer(wxVERTICAL)
578            ctrlBox.Add(
579                wxButton(self, ID_SELPROP_STROKECLR, "Change Stroke Color"),
580                1, wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
581            EVT_BUTTON(self, ID_SELPROP_STROKECLR, self.OnChangeStrokeColor)
582    
583            if shapeType != SHAPETYPE_ARC:
584                ctrlBox.Add(
585                    wxButton(self, ID_SELPROP_FILLCLR, "Change Fill Color"),
586                    0, wxALIGN_LEFT | wxALL | wxGROW, 4)
587                EVT_BUTTON(self, ID_SELPROP_FILLCLR, self.OnChangeFillColor)
588    
589            spinBox = wxBoxSizer(wxHORIZONTAL)
590            spinBox.Add(wxStaticText(self, -1, _("Stroke Width: ")),
591                    0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
592            self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,
593                                       min=1, max=10,
594                                       value=str(prop.GetStrokeWidth()),
595                                       initial=prop.GetStrokeWidth())
596    
597            EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self.OnSpin)
598    
599            spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)
600    
601            ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)
602            itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
603            topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
604    
605    
606            #
607            # Control buttons:
608            #
609            buttonBox = wxBoxSizer(wxHORIZONTAL)
610            buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),
611                          0, wxALL, 4)
612            buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),
613                          0, wxALL, 4)
614            topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
615                                                                                    
616            EVT_BUTTON(self, ID_SELPROP_OK, self.OnOK)
617            EVT_BUTTON(self, ID_SELPROP_CANCEL, self.OnCancel)
618                                                                                    
619            self.SetAutoLayout(true)
620            self.SetSizer(topBox)
621            topBox.Fit(self)
622            topBox.SetSizeHints(self)
623    
624        def OnOK(self, event):
625            self.EndModal(wxID_OK)
626    
627        def OnCancel(self, event):
628            self.EndModal(wxID_CANCEL)
629    
630        def OnSpin(self, event):
631            self.prop.SetStrokeWidth(self.spinCtrl.GetValue())
632            self.previewer.Refresh()
633    
634        def __GetColor(self, cur):
635            dialog = wxColourDialog(self)
636            dialog.GetColourData().SetColour(Color2wxColour(cur))
637            ret = None
638            if dialog.ShowModal() == wxID_OK:
639                ret = wxColour2Color(dialog.GetColourData().GetColour())
640    
641            dialog.Destroy()
642    
643            return ret
644            
645        def OnChangeStrokeColor(self, event):
646            clr = self.__GetColor(self.prop.GetStroke())
647            if clr is not None:
648                self.prop.SetStroke(clr)
649            self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
650    
651        def OnChangeFillColor(self, event):
652            clr = self.__GetColor(self.prop.GetFill())
653            if clr is not None:
654                self.prop.SetFill(clr)
655            self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
656    
657        def GetClassGroupProperties(self):
658            return self.prop
659    
660    
661    class ClassDataPreviewer(wxWindow):
662    
663        def __init__(self, rect, prop, shapeType,
664                           parent = None, id = -1, size = wxDefaultSize):
665            if parent is not None:
666                wxWindow.__init__(self, parent, id, size=size)
667                EVT_PAINT(self, self.OnPaint)
668    
669            self.rect = rect
670            self.prop = prop
671          self.shapeType = shapeType          self.shapeType = shapeType
672    
673      def Draw(self, grid, attr, dc, rect, row, col, isSelected):      def OnPaint(self, event):
674          value = grid.GetTable().GetValueAsCustom(row, col, "")          dc = wxPaintDC(self)
675          # XXX: check if value is a dictionary  
676          stroke = value.GetStroke()          # XXX: this doesn't seem to be having an effect:
677          if stroke is None:          dc.DestroyClippingRegion()
678    
679            self.Draw(dc, None)
680    
681        def Draw(self, dc, rect, prop = None, shapeType = None):
682    
683            if prop is None: prop = self.prop
684            if shapeType is None: shapeType = self.shapeType
685    
686            if rect is None:
687                x = y = 0
688                w, h = self.GetClientSizeTuple()
689            else:
690                x = rect.GetX()
691                y = rect.GetY()
692                w = rect.GetWidth()
693                h = rect.GetHeight()
694    
695            stroke = prop.GetStroke()
696            if stroke is Color.None:
697              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
698          else:          else:
699              pen = wxPen(wxColour(stroke.red * 255,              pen = wxPen(Color2wxColour(stroke),
700                                   stroke.green * 255,                          prop.GetStrokeWidth(),
                                  stroke.blue * 255),  
                         value.GetStrokeWidth(),  
701                          wxSOLID)                          wxSOLID)
702    
703          stroke = value.GetFill()          stroke = prop.GetFill()
704          if stroke is None:          if stroke is Color.None:
705              brush = wxTRANSPARENT_BRUSH              brush = wxTRANSPARENT_BRUSH
706          else:          else:
707              brush = wxBrush(wxColour(stroke.red * 255,              brush = wxBrush(Color2wxColour(stroke), wxSOLID)
708                                       stroke.green * 255,  
709                                       stroke.blue * 255), wxSOLID)          dc.SetPen(pen)
710            dc.SetBrush(brush)
711    
712            if shapeType == SHAPETYPE_ARC:
713                dc.DrawSpline([wxPoint(x, y + h),
714                               wxPoint(x + w/2, y + h/4),
715                               wxPoint(x + w/2, y + h/4*3),
716                               wxPoint(x + w, y)])
717    
718            elif shapeType == SHAPETYPE_POINT or \
719                 shapeType == SHAPETYPE_POLYGON:
720    
721                dc.DrawCircle(x + w/2, y + h/2,
722                              (min(w, h) - prop.GetStrokeWidth())/2)
723    
724    class ClassRenderer(wxPyGridCellRenderer):
725    
726        def __init__(self, shapeType):
727            wxPyGridCellRenderer.__init__(self)
728            self.previewer = ClassDataPreviewer(None, None, shapeType)
729    
730        def Draw(self, grid, attr, dc, rect, row, col, isSelected):
731            data = grid.GetTable().GetValueAsCustom(row, col, None)
732    
733          dc.SetClippingRegion(rect.GetX(), rect.GetY(),          dc.SetClippingRegion(rect.GetX(), rect.GetY(),
734                               rect.GetWidth(), rect.GetHeight())                               rect.GetWidth(), rect.GetHeight())
# Line 168  class ClassRenderer(wxPyGridCellRenderer Line 737  class ClassRenderer(wxPyGridCellRenderer
737          dc.DrawRectangle(rect.GetX(), rect.GetY(),          dc.DrawRectangle(rect.GetX(), rect.GetY(),
738                           rect.GetWidth(), rect.GetHeight())                           rect.GetWidth(), rect.GetHeight())
739    
740          dc.SetPen(pen)          if not isinstance(data, ClassGroupMap):
741          dc.SetBrush(brush)              self.previewer.Draw(dc, rect, data.GetProperties())
742    
743          if self.shapeType == SHAPETYPE_ARC:          if isSelected:
744              dc.DrawSpline([wxPoint(rect.GetX(), rect.GetY() + rect.GetHeight()),              dc.SetPen(wxPen(wxColour(0 * 255, 0 * 255, 0 * 255),
745                             wxPoint(rect.GetX() + rect.GetWidth()/2,                        4, wxSOLID))
746                                     rect.GetY() + rect.GetHeight()/4),              dc.SetBrush(wxTRANSPARENT_BRUSH)
747                             wxPoint(rect.GetX() + rect.GetWidth()/2,              dc.DrawRectangle(rect.GetX(), rect.GetY(),
748                                     rect.GetY() + rect.GetHeight()/4*3),                               rect.GetWidth(), rect.GetHeight())
                            wxPoint(rect.GetX() + rect.GetWidth(), rect.GetY())])  
   
         elif self.shapeType == SHAPETYPE_POINT or self.shapeType == SHAPETYPE_POLYGON:  
             dc.DrawCircle(rect.GetX() + rect.GetWidth()/2,  
                           rect.GetY() + rect.GetHeight()/2,  
                           (min(rect.GetWidth(), rect.GetHeight())  
                            - value.GetStrokeWidth())/2)  
749    
750          dc.DestroyClippingRegion()          dc.DestroyClippingRegion()
751    
   

Legend:
Removed from v.392  
changed lines
  Added in v.455

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26