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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 430 - (hide annotations)
Mon Feb 24 18:47:06 2003 UTC (22 years ago) by jonathan
File MIME type: text/x-python
File size: 19705 byte(s)
(SelectPropertiesDialog): Support
        for changing the stroke and fill colors and previewing the
        changes.

1 jonathan 372 # Copyright (c) 2001 by Intevation GmbH
2     # Authors:
3     # Jonathan Coles <[email protected]>
4     #
5     # This program is free software under the GPL (>=v2)
6     # Read the file COPYING coming with Thuban for details.
7    
8     """Dialog for classifying how layers are displayed"""
9    
10     __version__ = "$Revision$"
11    
12 jonathan 376 import copy
13    
14 jonathan 372 from wxPython.wx import *
15     from wxPython.grid import *
16    
17 jan 374 from Thuban import _
18 jonathan 415 from Thuban.common import *
19 jan 374
20 jonathan 415 from Thuban.Model.classification import * #Classification, ClassData
21 jonathan 392
22 jonathan 415 from Thuban.Model.color import Color
23    
24 jonathan 392 from Thuban.Model.layer import SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
25    
26 jonathan 372 ID_PROPERTY_SELECT = 4010
27     ID_CLASS_TABLE = 40011
28    
29     ID_CLASSIFY_OK = 4001
30     ID_CLASSIFY_CANCEL = 4002
31 jonathan 415 ID_CLASSIFY_ADD = 4003
32     ID_CLASSIFY_GENRANGE = 4004
33 jonathan 372
34 jonathan 415 COL_VISUAL = 0
35     COL_VALUE = 1
36     COL_LABEL = 2
37    
38     #
39     # this is a silly work around to ensure that the table that is
40     # passed into SetTable is the same that is returned by GetTable
41     #
42     import weakref
43     class ClassGrid(wxGrid):
44    
45     def __init__(self, parent, layer):
46     wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (300, 150))
47     self.SetTable(
48     ClassTable(layer.GetClassification(), layer.ShapeType(), self),
49     true)
50    
51     def SetCellRenderer(self, row, col):
52     raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))
53    
54     def SetTable(self, object, *attributes):
55     self.tableRef = weakref.ref(object)
56     return wxGrid.SetTable(self, object, *attributes)
57    
58     def GetTable(self):
59     return self.tableRef()
60    
61    
62 jonathan 376 class ClassTable(wxPyGridTableBase):
63    
64 jonathan 415 NUM_COLS = 3
65    
66     __col_labels = [_("Visual"), _("Value"), _("Label")]
67    
68     # this is tied to the values of classification.ClassData
69     __row_labels = [_("Default"), _("Point"), _("Range"), _("Map")]
70    
71     def __init__(self, clazz, shapeType, view = None):
72 jonathan 376 wxPyGridTableBase.__init__(self)
73 jonathan 415 self.SetView(view)
74     self.tdata = []
75 jonathan 376
76 jonathan 415 self.Reset(clazz, shapeType)
77    
78     def Reset(self, clazz, shapeType):
79    
80     self.GetView().BeginBatch()
81    
82     self.shapeType = shapeType
83     self.renderer = ClassRenderer(self.shapeType)
84    
85     old_tdata = self.tdata
86    
87 jonathan 376 self.tdata = []
88    
89 jonathan 415 if clazz is None:
90     clazz = Classification()
91 jonathan 392
92 jonathan 415 p = clazz.GetDefaultData()
93 jonathan 430 np = ClassDataDefault(classData = p)
94 jonathan 415 self.tdata.append([np, 'DEFAULT', np.GetLabel()])
95 jonathan 376
96 jonathan 415 for p in clazz.points.values():
97     np = ClassDataPoint(p.GetValue(), classData = p)
98     self.tdata.append([np, np.GetValue(), np.GetLabel()])
99 jonathan 376
100 jonathan 415 for p in clazz.ranges:
101     np = ClassDataRange(p.GetMin(), p.GetMax(), classData = p)
102     self.tdata.append([np,
103     '%s - %s' % (np.GetMin(), np.GetMax()),
104     np.GetLabel()])
105    
106     self.modified = 0
107    
108     #
109     # silly message processing for updates to the number of
110     # rows and columns
111     #
112     curRows = len(old_tdata)
113     newRows = len(self.tdata)
114     if newRows > curRows:
115     msg = wxGridTableMessage(self,
116     wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
117     newRows - curRows) # how many
118     self.GetView().ProcessTableMessage(msg)
119     elif newRows < curRows:
120     msg = wxGridTableMessage(self,
121     wxGRIDTABLE_NOTIFY_ROWS_DELETED,
122     curRows - newRows, # position
123     curRows - newRows) # how many
124     self.GetView().ProcessTableMessage(msg)
125    
126     self.GetView().EndBatch()
127    
128     def GetColLabelValue(self, col):
129     return self.__col_labels[col]
130    
131     def GetRowLabelValue(self, row):
132     data = self.tdata[row][COL_VISUAL]
133     type = data.GetType()
134     return self.__row_labels[type]
135    
136 jonathan 376 def GetNumberRows(self):
137     return len(self.tdata)
138    
139     def GetNumberCols(self):
140 jonathan 415 return self.NUM_COLS
141 jonathan 376
142     def IsEmptyCell(self, row, col):
143 jonathan 415 return 0
144 jonathan 376
145     def GetValue(self, row, col):
146 jonathan 415 return self.GetValueAsCustom(row, col, "")
147 jonathan 376
148     def SetValue(self, row, col, value):
149 jonathan 415 self.SetValueAsCustom(row, col, "", value)
150     self.__Modified()
151    
152 jonathan 392 def GetValueAsCustom(self, row, col, typeName):
153     return self.tdata[row][col]
154 jonathan 376
155 jonathan 415 def __ParseInput(self, value):
156     """Try to determine what kind of input value is
157     (a single number or a range)
158     """
159 jonathan 392
160 jonathan 415 #
161     # first try to take the input as a single number
162     # if there's an exception try to break it into
163     # a range seperated by a '-'. take care to ignore
164     # a leading '-' as that could be for a negative number.
165     # then try to parse the individual parts. if there
166     # is an exception here, let it pass up to the calling
167     # function.
168     #
169     try:
170     return (ClassData.POINT, Str2Num(value))
171     except:
172     i = value.find('-')
173     if i == 0:
174     i = value.find('-', 1)
175    
176     return (ClassData.RANGE,
177     Str2Num(value[:i]),
178     Str2Num(value[i+1:]))
179    
180    
181     def SetValueAsCustom(self, row, col, typeName, value):
182     data = self.tdata[row][COL_VISUAL]
183    
184     if col == COL_VISUAL:
185     self.tdata[row][COL_VISUAL] = value
186     elif col == COL_VALUE:
187     if row != 0: # DefaultData row
188     type = data.GetType()
189    
190     if type == ClassData.MAP:
191     # something special
192     pass
193     else: # POINT, RANGE
194     try:
195     dataInfo = self.__ParseInput(value)
196     except: pass
197     # bad input, ignore the request
198     else:
199    
200     if dataInfo[0] == ClassData.POINT:
201     if type != ClassData.POINT:
202     data = ClassDataPoint(classData = data)
203     data.SetValue(dataInfo[1])
204     self.tdata[row][COL_VALUE] = data.GetValue()
205     elif dataInfo[0] == ClassData.RANGE:
206     if type != ClassData.RANGE:
207     data = ClassDataRange(classData = data)
208     data.SetRange(dataInfo[1], dataInfo[2])
209     self.tdata[row][COL_VALUE] = \
210     "%s - %s" % (data.GetMin(), data.GetMax())
211    
212     self.tdata[row][COL_VISUAL] = data
213    
214 jonathan 430 self.GetView().Refresh()
215 jonathan 415
216     elif col == COL_LABEL:
217     data.SetLabel(value)
218     self.tdata[row][COL_LABEL] = data.GetLabel()
219     else:
220     raise ValueError(_("Invalid column request"))
221    
222     self.__Modified()
223    
224     def GetAttr(self, row, col, someExtraParameter):
225     attr = wxGridCellAttr()
226     #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)
227    
228     if col == COL_VISUAL:
229     attr.SetRenderer(ClassRenderer(self.shapeType))
230     attr.SetReadOnly()
231    
232     return attr
233    
234     def GetClassData(self, row):
235     return self.tdata[row][COL_VISUAL]
236    
237     def __Modified(self):
238     self.modified = 1
239    
240     def IsModified(self):
241     return self.modified
242    
243     def AddNewDataRow(self):
244     np = ClassDataPoint()
245     self.tdata.append([np, np.GetValue(), np.GetLabel()])
246     msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1)
247     self.GetView().ProcessTableMessage(msg)
248 jonathan 430 self.GetView().Refresh()
249 jonathan 415
250 jonathan 372 class Classifier(wxDialog):
251    
252     def __init__(self, parent, layer):
253 jan 374 wxDialog.__init__(self, parent, -1, _("Classify"),
254 jonathan 372 style = wxRESIZE_BORDER)
255    
256 jonathan 415 self.layer = layer
257    
258 jonathan 372 topBox = wxBoxSizer(wxVERTICAL)
259    
260 jonathan 415 topBox.Add(wxStaticText(self, -1, _("Layer: %s") % layer.Title()),
261     0, wxALIGN_LEFT | wxBOTTOM, 4)
262     topBox.Add(wxStaticText(self, -1, _("Type: %s") % layer.ShapeType()),
263     0, wxALIGN_LEFT | wxBOTTOM, 4)
264    
265 jonathan 372 propertyBox = wxBoxSizer(wxHORIZONTAL)
266 jonathan 415 propertyBox.Add(wxStaticText(self, -1, _("Property: ")),
267 jonathan 372 0, wxALIGN_CENTER | wxALL, 4)
268    
269     self.properties = wxComboBox(self, ID_PROPERTY_SELECT, "",
270     style = wxCB_READONLY)
271    
272     self.num_cols = layer.table.field_count()
273 jonathan 415 self.__cur_prop = -1
274     field = layer.GetClassification().GetField()
275 jonathan 372 for i in range(self.num_cols):
276     type, name, len, decc = layer.table.field_info(i)
277 jonathan 415 if name == field:
278     self.__cur_prop = i
279 jonathan 372 self.properties.Append(name)
280 jonathan 415 self.properties.SetClientData(i, None)
281 jonathan 372
282 jonathan 415 self.properties.SetSelection(self.__cur_prop)
283     propertyBox.Add(self.properties, 1, wxGROW|wxALL, 0)
284 jonathan 372 EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self.OnPropertySelect)
285    
286 jonathan 376 topBox.Add(propertyBox, 0, wxGROW, 4)
287 jonathan 372
288     #
289     # Classification data table
290     #
291    
292 jonathan 415 controlBox = wxBoxSizer(wxHORIZONTAL)
293     self.classGrid = ClassGrid(self, layer)
294 jonathan 376
295 jonathan 415 controlBox.Add(self.classGrid, 1, wxGROW, 0)
296 jonathan 376
297 jonathan 415 controlButtonBox = wxBoxSizer(wxVERTICAL)
298     controlButtonBox.Add(wxButton(self, ID_CLASSIFY_ADD,
299     _("Add")), 0, wxGROW | wxALL, 4)
300     controlButtonBox.Add(wxButton(self, ID_CLASSIFY_GENRANGE,
301     _("Generate Ranges")), 0, wxGROW | wxALL, 4)
302 jonathan 372
303 jonathan 415 controlBox.Add(controlButtonBox, 0, wxGROW, 10)
304     topBox.Add(controlBox, 1, wxGROW, 10)
305    
306     EVT_BUTTON(self, ID_CLASSIFY_ADD, self.OnAdd)
307     EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self.OnGenRange)
308     EVT_GRID_CELL_LEFT_DCLICK(self.classGrid, self.OnCellDClick)
309    
310 jonathan 372 #
311     # Control buttons:
312     #
313     buttonBox = wxBoxSizer(wxHORIZONTAL)
314 jan 374 buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),
315 jonathan 372 0, wxALL, 4)
316 jan 374 buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),
317 jonathan 372 0, wxALL, 4)
318     topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
319    
320     EVT_BUTTON(self, ID_CLASSIFY_OK, self.OnOK)
321     EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self.OnCancel)
322    
323     self.SetAutoLayout(true)
324     self.SetSizer(topBox)
325     topBox.Fit(self)
326     topBox.SetSizeHints(self)
327    
328 jonathan 415 def __BuildClassification(self, prop):
329    
330     clazz = Classification()
331     clazz.SetField(self.properties.GetStringSelection())
332    
333     numRows = self.classGrid.GetNumberRows()
334    
335     if numRows > 0:
336     table = self.classGrid.GetTable()
337     clazz.SetDefaultData(table.GetClassData(0))
338    
339     for i in range(1, numRows):
340     clazz.AddClassData(table.GetClassData(i))
341    
342     return clazz
343    
344     def OnPropertySelect(self, event):
345     self.properties.SetClientData(
346     self.__cur_prop, self.__BuildClassification(self.__cur_prop))
347    
348     self.__cur_prop = self.properties.GetSelection()
349     clazz = self.properties.GetClientData(self.__cur_prop)
350     table = self.classGrid.GetTable()
351    
352     table.Reset(clazz, self.layer.ShapeType())
353    
354     def OnOK(self, event):
355     """Put the data from the table into a new Classification and hand
356     it to the layer.
357     """
358    
359     clazz = self.properties.GetClientData(self.__cur_prop)
360    
361     #
362     # only build the classification if there wasn't one to
363     # to begin with or it has been modified
364     #
365     if clazz is None or self.classGrid.GetTable().IsModified():
366     clazz = self.__BuildClassification(self.__cur_prop)
367    
368     clazz.SetLayer(self.layer)
369    
370     self.layer.SetClassification(clazz)
371    
372     self.EndModal(wxID_OK)
373    
374     def OnCancel(self, event):
375     """Do nothing. The layer's current classification stays the same."""
376     self.EndModal(wxID_CANCEL)
377    
378    
379     def OnAdd(self, event):
380     self.classGrid.GetTable().AddNewDataRow()
381     print "Classifier.OnAdd()"
382    
383     def OnGenRange(self, event):
384     print "Classifier.OnGenRange()"
385    
386     def OnCellDClick(self, event):
387     r = event.GetRow()
388     c = event.GetCol()
389     if c == COL_VISUAL:
390     prop = self.classGrid.GetTable().GetValueAsCustom(r, c, None)
391     propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())
392     if propDlg.ShowModal() == wxID_OK:
393     new_prop = propDlg.GetClassData()
394     prop.SetStroke(new_prop.GetStroke())
395     prop.SetStrokeWidth(new_prop.GetStrokeWidth())
396     prop.SetFill(new_prop.GetFill())
397 jonathan 430 self.classGrid.Refresh()
398 jonathan 415 propDlg.Destroy()
399    
400    
401     ID_SELPROP_OK = 4001
402     ID_SELPROP_CANCEL = 4002
403     ID_SELPROP_SPINCTRL = 4002
404 jonathan 430 ID_SELPROP_PREVIEW = 4003
405     ID_SELPROP_STROKECLR = 4004
406     ID_SELPROP_FILLCLR = 4005
407 jonathan 415
408     class SelectPropertiesDialog(wxDialog):
409    
410     def __init__(self, parent, prop, shapeType):
411     wxDialog.__init__(self, parent, -1, _("Select Properties"),
412     style = wxRESIZE_BORDER)
413    
414     self.prop = ClassData(classData = prop)
415    
416 jonathan 430 topBox = wxBoxSizer(wxVERTICAL)
417 jonathan 415
418 jonathan 430 itemBox = wxBoxSizer(wxHORIZONTAL)
419    
420     # preview box
421     previewBox = wxBoxSizer(wxVERTICAL)
422     previewBox.Add(wxStaticText(self, -1, _("Preview:")),
423     0, wxALIGN_LEFT | wxALL, 4)
424     self.previewer = ClassDataPreviewer(None, self.prop, shapeType,
425     self, ID_SELPROP_PREVIEW, (40, 40))
426     previewBox.Add(self.previewer, 1, wxGROW, 15)
427    
428     itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
429    
430     # control box
431     ctrlBox = wxBoxSizer(wxVERTICAL)
432     ctrlBox.Add(
433     wxButton(self, ID_SELPROP_STROKECLR, "Change Stroke Color"),
434     0, wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
435     EVT_BUTTON(self, ID_SELPROP_STROKECLR, self.OnChangeStrokeColor)
436    
437     if shapeType != SHAPETYPE_ARC:
438     ctrlBox.Add(
439     wxButton(self, ID_SELPROP_FILLCLR, "Change Fill Color"),
440     0, wxALIGN_LEFT | wxALL | wxGROW, 4)
441     EVT_BUTTON(self, ID_SELPROP_FILLCLR, self.OnChangeFillColor)
442    
443 jonathan 415 spinBox = wxBoxSizer(wxHORIZONTAL)
444     spinBox.Add(wxStaticText(self, -1, _("Stroke Width: ")),
445 jonathan 430 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
446 jonathan 415 self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,
447     min=1, max=10,
448     value=str(prop.GetStrokeWidth()),
449     initial=prop.GetStrokeWidth())
450    
451     EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self.OnSpin)
452    
453     spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)
454    
455 jonathan 430 ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)
456     itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
457     topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
458 jonathan 415
459    
460     #
461     # Control buttons:
462     #
463     buttonBox = wxBoxSizer(wxHORIZONTAL)
464     buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),
465     0, wxALL, 4)
466     buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),
467     0, wxALL, 4)
468     topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
469    
470     EVT_BUTTON(self, ID_SELPROP_OK, self.OnOK)
471     EVT_BUTTON(self, ID_SELPROP_CANCEL, self.OnCancel)
472    
473     self.SetAutoLayout(true)
474     self.SetSizer(topBox)
475     topBox.Fit(self)
476     topBox.SetSizeHints(self)
477    
478 jonathan 372 def OnOK(self, event):
479     self.EndModal(wxID_OK)
480    
481     def OnCancel(self, event):
482     self.EndModal(wxID_CANCEL)
483    
484 jonathan 415 def OnSpin(self, event):
485     self.prop.SetStrokeWidth(self.spinCtrl.GetValue())
486 jonathan 430 self.previewer.Refresh()
487 jonathan 392
488 jonathan 430 def __GetColor(self, cur):
489     dialog = wxColourDialog(self)
490     dialog.GetColourData().SetColour(Color2wxColour(cur))
491     ret = None
492     if dialog.ShowModal() == wxID_OK:
493     ret = wxColour2Color(dialog.GetColourData().GetColour())
494    
495     dialog.Destroy()
496    
497     return ret
498    
499     def OnChangeStrokeColor(self, event):
500     clr = self.__GetColor(self.prop.GetStroke())
501     if clr is not None:
502     self.prop.SetStroke(clr)
503     self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
504    
505     def OnChangeFillColor(self, event):
506     clr = self.__GetColor(self.prop.GetFill())
507     if clr is not None:
508     self.prop.SetFill(clr)
509     self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
510    
511 jonathan 415 def GetClassData(self):
512     return self.prop
513 jonathan 392
514    
515 jonathan 430 class ClassDataPreviewer(wxWindow):
516 jonathan 415
517 jonathan 430 def __init__(self, rect, data, shapeType,
518     parent = None, id = -1, size = wxDefaultSize):
519     if parent is not None:
520     wxWindow.__init__(self, parent, id, size=size)
521     EVT_PAINT(self, self.OnPaint)
522 jonathan 415
523 jonathan 430 self.rect = rect
524     self.data = data
525     self.shapeType = shapeType
526    
527     def OnPaint(self, event):
528     dc = wxPaintDC(self)
529    
530     # XXX: this doesn't seem to be having an effect:
531     dc.DestroyClippingRegion()
532    
533     self.Draw(dc, None)
534    
535     def Draw(self, dc, rect, data = None, shapeType = None):
536    
537     if data is None: data = self.data
538     if shapeType is None: shapeType = self.shapeType
539    
540     if rect is None:
541     x = y = 0
542     w, h = self.GetClientSizeTuple()
543     else:
544     x = rect.GetX()
545     y = rect.GetY()
546     w = rect.GetWidth()
547     h = rect.GetHeight()
548    
549 jonathan 415 stroke = data.GetStroke()
550     if stroke is Color.None:
551 jonathan 392 pen = wxTRANSPARENT_PEN
552     else:
553 jonathan 430 pen = wxPen(Color2wxColour(stroke),
554 jonathan 415 data.GetStrokeWidth(),
555 jonathan 392 wxSOLID)
556    
557 jonathan 415 stroke = data.GetFill()
558     if stroke is Color.None:
559 jonathan 392 brush = wxTRANSPARENT_BRUSH
560     else:
561 jonathan 430 brush = wxBrush(Color2wxColour(stroke), wxSOLID)
562 jonathan 392
563     dc.SetPen(pen)
564     dc.SetBrush(brush)
565    
566 jonathan 415 if shapeType == SHAPETYPE_ARC:
567 jonathan 430 dc.DrawSpline([wxPoint(x, y + h),
568     wxPoint(x + w/2, y + h/4),
569     wxPoint(x + w/2, y + h/4*3),
570     wxPoint(x + w, y)])
571 jonathan 392
572 jonathan 415 elif shapeType == SHAPETYPE_POINT or \
573     shapeType == SHAPETYPE_POLYGON:
574    
575 jonathan 430 dc.DrawCircle(x + w/2, y + h/2,
576     (min(w, h) - data.GetStrokeWidth())/2)
577 jonathan 392
578 jonathan 415 class ClassRenderer(wxPyGridCellRenderer):
579    
580     def __init__(self, shapeType):
581     wxPyGridCellRenderer.__init__(self)
582 jonathan 430 self.previewer = ClassDataPreviewer(None, None, shapeType)
583 jonathan 415
584     def Draw(self, grid, attr, dc, rect, row, col, isSelected):
585     data = grid.GetTable().GetValueAsCustom(row, col, "")
586    
587    
588     dc.SetClippingRegion(rect.GetX(), rect.GetY(),
589     rect.GetWidth(), rect.GetHeight())
590     dc.SetPen(wxPen(wxLIGHT_GREY))
591     dc.SetBrush(wxBrush(wxLIGHT_GREY, wxSOLID))
592     dc.DrawRectangle(rect.GetX(), rect.GetY(),
593     rect.GetWidth(), rect.GetHeight())
594    
595 jonathan 430 self.previewer.Draw(dc, rect, data)
596 jonathan 415
597     if isSelected:
598     dc.SetPen(wxPen(wxColour(0 * 255, 0 * 255, 0 * 255),
599     4, wxSOLID))
600     dc.SetBrush(wxTRANSPARENT_BRUSH)
601     dc.DrawRectangle(rect.GetX(), rect.GetY(),
602     rect.GetWidth(), rect.GetHeight())
603    
604 jonathan 392 dc.DestroyClippingRegion()
605    

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26