Commit 83242a06378ed7faead941c0c4be8731ebf54ef7

Authored by tfmoraes
1 parent eb522836

ENH: the gradient widget has been rewritten

invesalius/data/slice_.py
@@ -188,15 +188,11 @@ class Slice(object): @@ -188,15 +188,11 @@ class Slice(object):
188 self.SetMaskEditionThreshold(index, threshold_range) 188 self.SetMaskEditionThreshold(index, threshold_range)
189 189
190 def __set_current_mask_threshold(self, evt_pubsub): 190 def __set_current_mask_threshold(self, evt_pubsub):
191 - session = ses.Session()  
192 - #FIXME: find a better way to implement this  
193 - if (self.num_gradient >= 2) or \  
194 - (session.project_status != const.PROJ_OPEN):  
195 - threshold_range = evt_pubsub.data  
196 - index = self.current_mask.index  
197 - self.SetMaskThreshold(index, threshold_range)  
198 - #Clear edited points  
199 - self.current_mask.edited_points = {} 191 + threshold_range = evt_pubsub.data
  192 + index = self.current_mask.index
  193 + self.SetMaskThreshold(index, threshold_range)
  194 + #Clear edited points
  195 + self.current_mask.edited_points = {}
200 self.num_gradient += 1 196 self.num_gradient += 1
201 197
202 def __set_current_mask_colour(self, pubsub_evt): 198 def __set_current_mask_colour(self, pubsub_evt):
invesalius/gui/task_slice.py
@@ -318,7 +318,7 @@ class MaskProperties(wx.Panel): @@ -318,7 +318,7 @@ class MaskProperties(wx.Panel):
318 self.combo_thresh = combo_thresh 318 self.combo_thresh = combo_thresh
319 319
320 ## LINE 4 320 ## LINE 4
321 - gradient = grad.GradientSlider(self, -1, -5000, 5000, 0, 5000, 321 + gradient = grad.GradientCtrl(self, -1, -5000, 5000, 0, 5000,
322 (0, 255, 0, 100)) 322 (0, 255, 0, 100))
323 self.gradient = gradient 323 self.gradient = gradient
324 324
@@ -476,17 +476,17 @@ class MaskProperties(wx.Panel): @@ -476,17 +476,17 @@ class MaskProperties(wx.Panel):
476 476
477 def OnComboThresh(self, evt): 477 def OnComboThresh(self, evt):
478 (thresh_min, thresh_max) = Project().threshold_modes[evt.GetString()] 478 (thresh_min, thresh_max) = Project().threshold_modes[evt.GetString()]
479 - self.gradient.SetMinValue(thresh_min, True)  
480 - self.gradient.SetMaxValue(thresh_max, True) 479 + self.gradient.SetMinValue(thresh_min)
  480 + self.gradient.SetMaxValue(thresh_max)
  481 + self.OnSlideChanged(None)
481 482
482 def OnSlideChanged(self, evt): 483 def OnSlideChanged(self, evt):
483 thresh_min = self.gradient.GetMinValue() 484 thresh_min = self.gradient.GetMinValue()
484 thresh_max = self.gradient.GetMaxValue() 485 thresh_max = self.gradient.GetMaxValue()
485 - if self.bind_evt_gradient:  
486 - ps.Publisher().sendMessage('Set threshold values',  
487 - (thresh_min, thresh_max))  
488 - session = ses.Session()  
489 - session.ChangeProject() 486 + ps.Publisher().sendMessage('Set threshold values',
  487 + (thresh_min, thresh_max))
  488 + session = ses.Session()
  489 + session.ChangeProject()
490 490
491 def OnSelectColour(self, evt): 491 def OnSelectColour(self, evt):
492 colour = evt.GetValue() 492 colour = evt.GetValue()
@@ -549,7 +549,7 @@ class EditionTools(wx.Panel): @@ -549,7 +549,7 @@ class EditionTools(wx.Panel):
549 text_thresh = wx.StaticText(self, -1, _("Brush threshold range:")) 549 text_thresh = wx.StaticText(self, -1, _("Brush threshold range:"))
550 550
551 ## LINE 4 551 ## LINE 4
552 - gradient_thresh = grad.GradientSlider(self, -1, 0, 5000, 0, 5000, 552 + gradient_thresh = grad.GradientCtrl(self, -1, 0, 5000, 0, 5000,
553 (0, 0, 255, 100)) 553 (0, 0, 255, 100))
554 self.gradient_thresh = gradient_thresh 554 self.gradient_thresh = gradient_thresh
555 self.bind_evt_gradient = True 555 self.bind_evt_gradient = True
invesalius/gui/widgets/gradient.py
@@ -19,547 +19,315 @@ @@ -19,547 +19,315 @@
19 # PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais 19 # PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais
20 # detalhes. 20 # detalhes.
21 #-------------------------------------------------------------------------- 21 #--------------------------------------------------------------------------
22 -  
23 import sys 22 import sys
24 23
25 import numpy 24 import numpy
26 import wx 25 import wx
27 -import wx.lib.intctrl  
28 -import wx.lib.pubsub as ps  
29 -  
30 -MINBORDER=1  
31 -MAXBORDER=2  
32 26
33 -class SliderData(object):  
34 - def __init__(self, minRange, maxRange, minValue, maxValue, colour):  
35 - """  
36 - minRange: The minimum value accepted.  
37 - maxRange: The maximum value accepted.  
38 - minValue: initial minimum value.  
39 - maxValue: initial maximum value.  
40 - colour: the colour associated, must be in RGBA form.  
41 - """  
42 - self.minRange = minRange  
43 - self.maxRange = maxRange  
44 - self.minValue = minValue  
45 - self.maxValue = maxValue  
46 - self.colour = colour  
47 - self.wasChanged = True 27 +from wx.lib import intctrl
48 28
49 - def GetMinValue(self):  
50 - return self.minValue 29 +PUSH_WIDTH = 7
51 30
52 - def GetMaxValue(self):  
53 - return self.maxValue  
54 -  
55 - def SetMinValue(self, value):  
56 - if value < self.minRange:  
57 - value = self.minRange  
58 - self.minValue = value  
59 - self.wasChanged = True  
60 -  
61 - def SetMaxValue(self, value):  
62 - if value > self.maxRange:  
63 - value = self.maxRange  
64 - self.maxValue = value  
65 - self.wasChanged = True  
66 -  
67 - def GetMinRange(self):  
68 - return self.minRange  
69 -  
70 - def GetMaxRange(self):  
71 - return self.maxRange  
72 -  
73 - def SetMinRange(self, value):  
74 - if value < self.minValue:  
75 - self.SetMinValue(value)  
76 - self.minRange = value  
77 - self.wasChanged = True 31 +myEVT_SLIDER_CHANGE = wx.NewEventType()
  32 +EVT_SLIDER_CHANGE = wx.PyEventBinder(myEVT_SLIDER_CHANGE, 1)
78 33
79 - def SetMaxRange(self, value):  
80 - if value > self.maxValue:  
81 - self.SetMaxValue(value)  
82 - self.maxRange = value  
83 - self.wasChanged = True 34 +myEVT_THRESHOLD_CHANGE = wx.NewEventType()
  35 +EVT_THRESHOLD_CHANGE = wx.PyEventBinder(myEVT_THRESHOLD_CHANGE, 1)
84 36
85 - def GetColour(self):  
86 - return self.colour 37 +class SliderEvent(wx.PyCommandEvent):
  38 + def __init__(self , evtType, id, minRange, maxRange, minValue, maxValue):
  39 + wx.PyCommandEvent.__init__(self, evtType, id,)
  40 + self.min_range = minRange
  41 + self.max_range = maxRange
  42 + self.minimun = minValue
  43 + self.maximun = maxValue
87 44
88 - def SetColour(self, colour): 45 +class GradientSlider(wx.Panel):
  46 + def __init__(self, parent, id, minRange, maxRange, minValue, maxValue, colour):
  47 + super(GradientSlider, self).__init__(parent, id, size = (100, 25))
  48 + self._bind_events_wx()
  49 +
  50 + self.min_range = minRange
  51 + self.max_range = maxRange
  52 + self.minimun = minValue
  53 + self.maximun = maxValue
89 self.colour = colour 54 self.colour = colour
90 - self.wasChanged = True  
91 -  
92 - def GetRange(self):  
93 - return self.maxRange - self.minRange  
94 -  
95 -  
96 -class SliderControler(object):  
97 - def __init__(self, slider):  
98 - self.slider = slider  
99 - ps.Publisher().subscribe(self.SetMinValue, "ChangeMinValue")  
100 - ps.Publisher().subscribe(self.SetMaxValue, "ChangeMaxValue")  
101 -  
102 - def SetMinValue(self, data):  
103 - self.slider.SetMinValue(data.data) 55 + self.selected = 0
104 56
105 - def SetMaxValue(self, data):  
106 - self.slider.SetMaxValue(data.data) 57 + self.CalculateControlPositions()
107 58
108 - def GetMinValue(self):  
109 - return self.slider.GetMinValue() 59 + def _bind_events_wx(self):
  60 + self.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
  61 + self.Bind(wx.EVT_LEFT_UP, self.OnRelease)
  62 + self.Bind(wx.EVT_PAINT, self.OnPaint)
  63 + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackGround)
  64 + self.Bind(wx.EVT_MOTION, self.OnMotion)
  65 + self.Bind(wx.EVT_SIZE, self.OnSize)
110 66
111 - def GetMaxValue(self):  
112 - return self.slider.GetMaxValue() 67 + def OnPaint(self, evt):
  68 + dc = wx.BufferedPaintDC(self)
  69 + dc.Clear()
  70 +
  71 + w, h = self.GetSize()
  72 + width_gradient = w - 2*PUSH_WIDTH
  73 + height_gradient = h
  74 + x_init_gradient = PUSH_WIDTH
  75 + y_init_gradient = 0
  76 +
  77 + x_init_push1 = self.min_position - PUSH_WIDTH
  78 + x_init_push2 = self.max_position
  79 +
  80 + width_transparency = self.max_position - self.min_position
  81 +
  82 + pen = wx.Pen((0, 0, 0))
  83 + brush = wx.Brush((0, 0, 0))
  84 + dc.SetPen(pen)
  85 + dc.SetBrush(brush)
  86 + dc.DrawRectangle(0, 0, PUSH_WIDTH, h)
  87 +
  88 + pen = wx.Pen((255, 255, 255))
  89 + brush = wx.Brush((255, 255, 255))
  90 + dc.SetPen(pen)
  91 + dc.SetBrush(brush)
  92 + dc.DrawRectangle(x_init_gradient + width_gradient, 0, PUSH_WIDTH, h)
  93 +
  94 + dc.GradientFillLinear((x_init_gradient, y_init_gradient,
  95 + width_gradient, height_gradient),
  96 + (0, 0, 0), (255,255, 255))
  97 +
  98 + n = wx.RendererNative_Get()
  99 + n.DrawPushButton(self, dc, (x_init_push1, 0, PUSH_WIDTH, h))
  100 + n.DrawPushButton(self, dc, (x_init_push2, 0, PUSH_WIDTH, h))
113 101
  102 + bytes = numpy.array(self.colour * width_transparency * h, 'B')
  103 + try:
  104 + slider = wx.BitmapFromBufferRGBA(width_transparency, h, bytes)
  105 + except:
  106 + pass
  107 + else:
  108 + dc.DrawBitmap(slider, self.min_position, 0, True)
114 109
115 -class SliderBorder(object):  
116 - def __init__(self, pos, width, WindowWidth, type):  
117 - """  
118 - pos: initial border's position  
119 - width: border's width  
120 - """  
121 - self.pos = pos  
122 - self.width = width  
123 - self.WindowWidth = WindowWidth  
124 - self.type = type 110 + def OnEraseBackGround(self, evt):
  111 + pass
125 112
126 - def IsOver(self, x):  
127 - """  
128 - Is the mouse over border?  
129 - """  
130 - return self.pos <= x <= self.pos + self.width 113 + def OnMotion(self, evt):
  114 + x = evt.GetX()
  115 + w, h = self.GetSize()
  116 + if self.selected == 1:
  117 + x -= self._delta
  118 + if x - PUSH_WIDTH < 0:
  119 + x = PUSH_WIDTH
  120 + elif x >= self.max_position:
  121 + x = self.max_position
  122 +
  123 + value = self._min_position_to_minimun(x)
  124 + self.minimun = value
  125 + self.min_position = x
  126 + self.Refresh()
  127 + self._generate_event()
  128 +
  129 + elif self.selected == 2:
  130 + x -= self._delta
  131 + if x + PUSH_WIDTH > w:
  132 + x = w - PUSH_WIDTH
  133 + elif x < self.min_position:
  134 + x = self.min_position
  135 +
  136 + value = self._max_position_to_maximun(x)
  137 + self.maximun = value
  138 + self.max_position = x
  139 + self.Refresh()
  140 + self._generate_event()
  141 +
  142 + elif self.selected == 3:
  143 + x -= self._delta
  144 + slider_size = self.max_position - self.min_position
  145 + diff_values = self.maximun - self.minimun
  146 +
  147 + if x - PUSH_WIDTH < 0:
  148 + min_x = PUSH_WIDTH
  149 + self.minimun = self._min_position_to_minimun(min_x)
  150 + self.maximun = self.minimun + diff_values
  151 + self.CalculateControlPositions()
  152 +
  153 + elif x + slider_size + PUSH_WIDTH > w:
  154 + max_x = w - PUSH_WIDTH
  155 + self.maximun = self._max_position_to_maximun(max_x)
  156 + self.minimun = self.maximun - diff_values
  157 + self.CalculateControlPositions()
131 158
132 - def DoSlide(self, slide):  
133 - """  
134 - Move the border  
135 - """  
136 - self.pos += slide  
137 - if self.type == MINBORDER and self.pos < 0:  
138 - self.pos = 0  
139 - elif self.type == MAXBORDER and self.pos+self.width >= self.WindowWidth:  
140 - self.pos = self.WindowWidth - self.width 159 + else:
  160 + min_x = x
  161 + self.minimun = self._min_position_to_minimun(min_x)
  162 + self.maximun = self.minimun + diff_values
  163 + self.CalculateControlPositions()
141 164
142 - def SetPosition(self, pos):  
143 - """  
144 - Move the border  
145 - """  
146 - self.pos = pos  
147 - if self.type == MINBORDER and self.pos < 0:  
148 - self.pos = 0  
149 - elif self.type == MAXBORDER and self.pos+self.width >= self.WindowWidth:  
150 - self.pos = self.WindowWidth - self.width 165 + self.Refresh()
  166 + self._generate_event()
  167 + evt.Skip()
  168 +
  169 +
  170 + def OnClick(self, evt):
  171 + x = evt.GetX()
  172 + if self.min_position - PUSH_WIDTH <= x <= self.min_position:
  173 + self.selected = 1
  174 + self._delta = x - self.min_position
  175 + elif self.max_position <= x <= self.max_position + PUSH_WIDTH:
  176 + self.selected = 2
  177 + self._delta = x - self.max_position
  178 + elif self.min_position <= x <= self.max_position:
  179 + self.selected = 3
  180 + self._delta = x - self.min_position
  181 + evt.Skip()
  182 +
  183 + def OnRelease(self, evt):
  184 + self.selected = 0
  185 + evt.Skip()
  186 +
  187 + def OnSize(self, evt):
  188 + self.CalculateControlPositions()
  189 + self.Refresh()
  190 + evt.Skip()
151 191
152 - def GetCursor(self): 192 + def CalculateControlPositions(self):
153 """ 193 """
154 - This function returns the cursor related to the SliderBorder 194 + Calculates the Min and Max control position based on the size of this
  195 + widget.
155 """ 196 """
156 - return wx.StockCursor(wx.CURSOR_SIZEWE)  
157 -  
158 - def SetWindowWidth(self, width):  
159 - self.WindowWith = width  
160 -  
161 - def GetPosition(self):  
162 - return self.pos 197 + w, h = self.GetSize()
  198 + window_width = w - 2*PUSH_WIDTH
  199 + proportion = window_width / float(self.max_range - self.min_range)
163 200
  201 + self.min_position = int(round((self.minimun - self.min_range) * \
  202 + proportion)) + PUSH_WIDTH
  203 + self.max_position = int(round((self.maximun - self.min_range) * \
  204 + proportion)) + PUSH_WIDTH
  205 + print self.min_position, self.max_position
164 206
165 -class SliderControl(object):  
166 - def __init__(self, sliderData, width, height):  
167 - """  
168 - sliderData: associated sliderData, where the info is.  
169 - width: SliderControl's width  
170 - height: SliderControl's height  
171 - """  
172 - self.width = width  
173 - self.height = height  
174 - self.imgSlider = None  
175 - self.SliderData = sliderData  
176 - self.ToResize = False  
177 - ps.Publisher().subscribe(self.SetMinValue, "SetMinValue")  
178 -  
179 - def Resize(self, WindowWidth, WindowHeight):  
180 - """  
181 - Occurs when parent panel resizes, then the slider resize too keeping the  
182 - proportion  
183 - """  
184 - self.WindowWidth = WindowWidth  
185 - self.MinBorder.SetWindowWidth(WindowWidth)  
186 - self.MaxBorder.SetWindowWidth(WindowWidth)  
187 - proportion = WindowWidth/float(self.SliderData.GetRange())  
188 - self.MinPoint = int(round((self.SliderData.GetMinValue() -\  
189 - self.SliderData.minRange) * proportion))  
190 - self.MaxPoint = int(round((self.SliderData.GetMaxValue() -\  
191 - self.SliderData.minRange)* proportion))  
192 - self.width = self.MaxPoint - self.MinPoint  
193 - self.height = WindowHeight  
194 - self.ToResize = True  
195 -  
196 - def GetSliderControl(self):  
197 - """  
198 - Returns the slider control  
199 - """  
200 - if not self.imgSlider or self.ToResize or self.SliderData.wasChanged:  
201 - bytes = numpy.array(self.SliderData.GetColour() * self.width * self.height, 'B')  
202 - self.imgSlider = wx.BitmapFromBufferRGBA(self.width, self.height, bytes)  
203 - self.ToResize = False  
204 - self.SliderData.wasChanged = False  
205 - return self.imgSlider  
206 -  
207 - def GetCursor(self):  
208 - """  
209 - Returns the slider associated to the SliderControl 207 + def _max_position_to_maximun(self, max_position):
  208 + """
  209 + Calculates the min and max value based on the control positions.
210 """ 210 """
211 - return wx.StockCursor(wx.CURSOR_ARROW) 211 + w, h = self.GetSize()
  212 + window_width = w - 2*PUSH_WIDTH
  213 + proportion = window_width / float(self.max_range - self.min_range)
212 214
213 - def DoSlide(self, slide):  
214 - """  
215 - Moves the SliderControl with associated borders  
216 - """  
217 - if slide + self.MinPoint >= 0 \  
218 - and slide + self.MaxPoint <= self.WindowWidth:  
219 - self.MinPoint += slide  
220 - self.MaxPoint = self.MinPoint + self.width  
221 - self.SetMinValueByMinPoint()  
222 - self.SetMaxValueByMaxPoint()  
223 - self.MinBorder.DoSlide(slide)  
224 - self.MaxBorder.DoSlide(slide)  
225 -  
226 - def IsOver(self, x):  
227 - """  
228 - The mouse cursor is over me?  
229 - """  
230 - return self.MinPoint <= x <= self.MaxPoint  
231 -  
232 - def SetMinValueByMinPoint(self):  
233 - """  
234 - Sets the minimum slider value based on the min point position  
235 - """  
236 - proportion = self.WindowWidth/float(self.SliderData.GetRange())  
237 - self.SliderData.SetMinValue(int(round(self.MinPoint/proportion +\  
238 - self.SliderData.minRange))) 215 + maximun = int(round((max_position - PUSH_WIDTH)/proportion + \
  216 + self.min_range))
239 217
240 - def SetMaxValueByMaxPoint(self):  
241 - """  
242 - Sets the maximum slider values based on the max point position  
243 - """  
244 - proportion = self.WindowWidth/float(self.SliderData.GetRange())  
245 - self.SliderData.SetMaxValue(int(round(self.MaxPoint/proportion +\  
246 - self.SliderData.minRange)))  
247 -  
248 - def SetMaxPointByMaxValue(self):  
249 - # proportion = self.WindowWidth/float(self.SliderData.GetRange())  
250 - #self.SetMaxPoint(int((self.SliderData.GetMaxValue() \  
251 - # -self.SliderData.minRange)*proportion))  
252 - self.MaxBorder.pos = self.MaxPoint  
253 -  
254 - def SetMinPointByMinValue(self):  
255 - # proportion = self.WindowWidth/float(self.SliderData.GetRange())  
256 - #self.SetMinPoint(int((self.SliderData.GetMinValue() \  
257 - # -self.SliderData.minRange)*proportion))  
258 - self.MinBorder.pos = self.MinPoint  
259 -  
260 - def SetMinPoint(self, x):  
261 - """  
262 - Sets the min point position in pixels  
263 - """  
264 - self.MinPoint = x  
265 - self.width = self.MaxPoint - self.MinPoint  
266 - self.SetMinValueByMinPoint()  
267 - self.ToResize = True 218 + return maximun
268 219
269 - def SetMaxPoint(self, x):  
270 - """  
271 - Sets the max point position in pixels  
272 - """  
273 - self.MaxPoint = x  
274 - self.width = self.MaxPoint - self.MinPoint  
275 - self.SetMaxValueByMaxPoint()  
276 - self.ToResize = True  
277 -  
278 - def SetMinValue(self, min):  
279 - self.SliderData.SetMinValue(min)  
280 - proportion = self.WindowWidth/float(self.SliderData.GetRange())  
281 - self.MinPoint = int(round((min - self.SliderData.minRange) * proportion))  
282 - self.width = self.MaxPoint - self.MinPoint  
283 - self.ToResize = True  
284 - self.MinBorder.pos = self.MinPoint  
285 -  
286 - def SetMaxValue(self, max):  
287 - self.SliderData.SetMaxValue(max)  
288 - proportion = self.WindowWidth/float(self.SliderData.GetRange())  
289 - self.MaxPoint = int(round((max - self.SliderData.minRange) * proportion))  
290 - self.width = self.MaxPoint - self.MinPoint  
291 - self.ToResize = True  
292 - self.MaxBorder.pos = self.MaxPoint - self.MaxBorder.width  
293 -  
294 - def SetMinBorder(self, border):  
295 - """  
296 - Hello, I'm the min border. I do the hard work to squeeze and stretch  
297 - the slider body together with my brother max border.  
298 - """  
299 - self.MinBorder = border 220 + def _min_position_to_minimun(self, min_position):
  221 + w, h = self.GetSize()
  222 + window_width = w - 2*PUSH_WIDTH
  223 + proportion = window_width / float(self.max_range - self.min_range)
300 224
301 - def SetMaxBorder(self, border):  
302 - """  
303 - And I'm the max border. I do the same work of my brother, I'm in the  
304 - right side, while he is in left side.  
305 - """  
306 - self.MaxBorder = border 225 + minimun = int(round((min_position - PUSH_WIDTH)/proportion + \
  226 + self.min_range))
307 227
308 - def Calculate(self, object):  
309 - """  
310 - Calculate the new min or max point based on the border brothers position.  
311 - """  
312 - if object is self.MinBorder:  
313 - self.SetMinPoint(object.pos)  
314 - elif object is self.MaxBorder:  
315 - self.SetMaxPoint(object.pos)  
316 -  
317 -  
318 -class GradientPanel(wx.Panel):  
319 - def __init__(self, parent, id, sliderData):  
320 - super(GradientPanel, self).__init__(parent, id, size=wx.Size(200,50))  
321 - self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)  
322 - self.SetMinSize((100, 20))  
323 - self.imgGradient = None  
324 - self.SliderData = sliderData  
325 - self.Slider = SliderControl(self.SliderData, 1, 1)  
326 - self.BorderMin = SliderBorder(self.SliderData.GetMinValue(), 7,  
327 - self.GetSize().GetWidth(),  
328 - MINBORDER)  
329 - self.BorderMax = SliderBorder(self.SliderData.GetMaxValue()-10, 7,  
330 - self.GetSize().GetWidth(),  
331 - MAXBORDER)  
332 - self.Slider.SetMinBorder(self.BorderMin)  
333 - self.Slider.SetMaxBorder(self.BorderMax)  
334 - self._DoBinds()  
335 - self.Show() 228 + return minimun
336 229
337 - def _DoBinds(self):  
338 - self.Bind(wx.EVT_LEFT_DOWN, self.OnClick)  
339 - self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)  
340 - self.Bind(wx.EVT_PAINT, self.OnPaint)  
341 - self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackGround)  
342 - self.Bind(wx.EVT_MOTION, self.OnMotion)  
343 - self.Bind(wx.EVT_SIZE, self.OnSize)  
344 - self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)  
345 -  
346 - def GetMin(self):  
347 - return self.SliderData.GetMinValue()  
348 -  
349 - def GetMax(self):  
350 - return self.SliderData.GetMaxValue() 230 + def SetColour(self, colour):
  231 + self.colour = colour
351 232
352 - def SetMinValue(self, min):  
353 - self.Slider.SetMinValue(min) 233 + def SetMinRange(self, min_range):
  234 + self.min_range = min_range
  235 + self.CalculateControlPositions()
354 self.Refresh() 236 self.Refresh()
355 237
356 - def SetMaxValue(self, max):  
357 - self.Slider.SetMaxValue(max) 238 + def SetMaxRange(self, max_range):
  239 + self.max_range = max_range
  240 + self.CalculateControlPositions()
358 self.Refresh() 241 self.Refresh()
359 242
360 - def GetObjectAt(self, x):  
361 - """  
362 - Is there a object(border or slider) at this x position? Then return it  
363 - to me.  
364 - """  
365 - if self.BorderMin.IsOver(x):  
366 - return self.BorderMin  
367 - elif self.BorderMax.IsOver(x):  
368 - return self.BorderMax  
369 - elif self.Slider.IsOver(x):  
370 - return self.Slider  
371 - else:  
372 - return None  
373 -  
374 - def DrawSliderControl(self, dc):  
375 - try:  
376 - dc.DrawBitmap(self.Slider.GetSliderControl(),  
377 - self.Slider.MinPoint, 0, True)  
378 - except (ValueError, RuntimeError):  
379 - print "ERROR"  
380 -  
381 - def DrawSliderBorders(self, dc):  
382 - n = wx.RendererNative_Get()  
383 - n.DrawPushButton(self, dc, (self.BorderMin.pos, 0,  
384 - self.BorderMin.width,  
385 - self.Slider.height))  
386 - n.DrawPushButton(self, dc, (self.BorderMax.pos, 0,  
387 - self.BorderMax.width,  
388 - self.Slider.height))  
389 -  
390 - def OnPaint(self, e):  
391 - """  
392 - Occurs when panel must be refreshed, it redraw the sliderControl and  
393 - borders.  
394 - """  
395 - dc = wx.BufferedPaintDC(self)  
396 - dc.Clear()  
397 - w,h = self.GetSize()  
398 - dc.GradientFillLinear((0, 0, w, h), (0, 0, 0), (255, 255, 255))  
399 - self.DrawSliderControl(dc)  
400 - self.DrawSliderBorders(dc)  
401 -  
402 - def OnEraseBackGround(self, e):  
403 - pass  
404 -  
405 - def OnSize(self, e):  
406 - """  
407 - OMG! Incredible how I fatten and become thin easily, then I must adjust my  
408 - clothes(SliderControl and the borders).  
409 - """  
410 - w,h = self.GetSize()  
411 - if w > 0:  
412 - self.Slider.Resize(w, h)  
413 - self.BorderMin.pos = self.Slider.MinPoint  
414 - self.BorderMax.pos = self.Slider.MaxPoint - self.BorderMax.width  
415 - self.Refresh()  
416 - e.Skip()  
417 -  
418 - def OnClick(self, e):  
419 - """  
420 - Occurs when the user click in the panel. It verifies if the click was  
421 - over an object and memorise the mouse position to do the slide.  
422 - """  
423 - self.SelectedObject = self.GetObjectAt(e.GetX())  
424 - self.MousePositionX = e.GetX() 243 + def SetMinimun(self, minimun):
  244 + self.minimun = minimun
  245 + self.CalculateControlPositions()
  246 + self.Refresh()
425 247
426 - def OnLeftUp(self, e):  
427 - """  
428 - Occurs when left mouse button is freed then the selected object must be  
429 - freed too.  
430 - """  
431 - self.SelectedObject = None 248 + def SetMaximun(self, maximun):
  249 + self.maximun = maximun
  250 + self.CalculateControlPositions()
  251 + self.Refresh()
432 252
433 - def OnMotion(self, e):  
434 - """  
435 - This is where the slide occurs ...  
436 - """  
437 - x = e.GetX()  
438 - # but the user must be dragging a selected object  
439 - if e.Dragging() and self.SelectedObject:  
440 - slide = x - self.MousePositionX  
441 - self.MousePositionX += slide  
442 - self.SetCursor(self.SelectedObject.GetCursor())  
443 - if isinstance(self.SelectedObject, SliderControl):  
444 - self.SelectedObject.DoSlide(slide)  
445 - else:  
446 - self.SelectedObject.SetPosition(x)  
447 - self.Slider.Calculate(self.SelectedObject)  
448 - if self.GetMin() >= self.GetMax():  
449 - self.SetMinValue(self.GetMax()-1)  
450 - self.Slider.SetMinPointByMinValue()  
451 - # dc = wx.ClientDC(self)  
452 - evt = SliderEvent(myEVT_SLIDER_CHANGE, self.GetId())  
453 - self.GetEventHandler().ProcessEvent(evt)  
454 - self.Refresh()  
455 - # else only the mouse cursor must be changed based on the object the  
456 - # mouse is over  
457 - else:  
458 - try:  
459 - self.SetCursor(self.GetObjectAt(x).GetCursor())  
460 - except AttributeError:  
461 - self.SetCursor(wx.NullCursor)  
462 -  
463 - def OnMouseWheel(self, e):  
464 - v = e.GetWheelRotation()/e.GetWheelDelta()  
465 - self.SliderData.SetMinValue(self.SliderData.GetMinValue()+v)  
466 - self.SliderData.SetMaxValue(self.SliderData.GetMaxValue()+v)  
467 - evt = SliderEvent(myEVT_SLIDER_CHANGE, self.GetId()) 253 + def _generate_event(self):
  254 + evt = SliderEvent(myEVT_SLIDER_CHANGE, self.GetId(), self.min_range,
  255 + self.max_range, self.minimun, self.maximun)
468 self.GetEventHandler().ProcessEvent(evt) 256 self.GetEventHandler().ProcessEvent(evt)
469 - self.Refresh()  
470 257
471 258
472 -class GradientSlider(wx.Panel):  
473 - def __init__(self, parent, id, minRange, maxRange, min, max, colour):  
474 - super(GradientSlider, self).__init__(parent, id)  
475 - self.slided = 0 259 +class GradientCtrl(wx.Panel):
  260 + def __init__(self, parent, id, minRange, maxRange, minValue, maxValue, colour):
  261 + super(GradientCtrl, self).__init__(parent, id)
476 self.sizer = wx.BoxSizer(wx.HORIZONTAL) 262 self.sizer = wx.BoxSizer(wx.HORIZONTAL)
477 self.SetSizer(self.sizer) 263 self.SetSizer(self.sizer)
478 self.sizer.Fit(self) 264 self.sizer.Fit(self)
479 self.SetAutoLayout(1) 265 self.SetAutoLayout(1)
480 - self.SliderData = SliderData(minRange, maxRange, min, max, colour)  
481 - self.transparency = colour[3]  
482 - self.DrawControls()  
483 - #ps.Publisher().subscribe(self.SetMinValue, ('SetMinValue')) 266 + self.min_range = minRange
  267 + self.max_range = maxRange
  268 + self.minimun = minValue
  269 + self.maximun = maxValue
  270 + self.colour = colour
  271 + self._draw_controls()
  272 + self._bind_events_wx()
  273 + self.SetBackgroundColour((0, 255, 0))
484 self.Show() 274 self.Show()
485 - self.__bind_events()  
486 -  
487 - def __bind_events(self):  
488 - ps.Publisher().subscribe(self.SetColour, 'Change Gradient Colour')  
489 - ps.Publisher().subscribe(self.SetMinValue, 'Change Gradient MinValue')  
490 - ps.Publisher().subscribe(self.SetMaxValue, 'Change Gradient MaxValue')  
491 -  
492 - def DrawControls(self):  
493 - """self.SpinMin = wx.SpinCtrl(parent=self,  
494 - id=-1,  
495 - initial=self.SliderData.minValue,  
496 - min=self.SliderData.minRange,  
497 - max=self.SliderData.maxRange,  
498 - size=wx.Size(55,15))  
499 - self.SpinMin.SetValue(self.SliderData.minValue) # needed in MacOS 10.5.5  
500 -  
501 - for child in self.SpinMin.GetChildren():  
502 - if isinstance(child, wx.TextCtrl):  
503 - child.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)  
504 -  
505 - self.SpinMax = wx.SpinCtrl(parent=self,  
506 - id=-1,  
507 - initial=self.SliderData.maxValue,  
508 - min=self.SliderData.minRange,  
509 - max=self.SliderData.maxRange,  
510 - size=wx.Size(55,15))  
511 - self.SpinMax.SetValue(self.SliderData.maxValue) # needed in MacOS 10.5.5  
512 -  
513 - for child in self.SpinMax.GetChildren():  
514 - if isinstance(child, wx.TextCtrl):  
515 - child.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)"""  
516 -  
517 -  
518 - self.SpinMin = wx.lib.intctrl.IntCtrl(self, size=(40,20), style=wx.TE_PROCESS_ENTER)  
519 - #self.SpinMin.SetLimited(True)  
520 - self.SpinMin.SetBounds(self.SliderData.minRange, self.SliderData.maxRange) 275 +
  276 + def _draw_controls(self):
  277 + self.gradient_slider = GradientSlider(self, -1, self.min_range,
  278 + self.max_range, self.minimun,
  279 + self.maximun, self.colour)
  280 +
  281 + self.spin_min = intctrl.IntCtrl(self, size=(40,20),
  282 + style=wx.TE_PROCESS_ENTER)
  283 + self.spin_min.SetValue(self.minimun)
521 if sys.platform != 'win32': 284 if sys.platform != 'win32':
522 - self.SpinMin.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)  
523 - self.SpinMin.SetValue(self.SliderData.minValue) 285 + self.spin_min.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
524 286
525 - self.SpinMax = wx.lib.intctrl.IntCtrl(self, size=(40,20), style=wx.TE_PROCESS_ENTER)  
526 - #self.SpinMax.SetLimited(True)  
527 - self.SpinMax.SetBounds(self.SliderData.minRange, self.SliderData.maxRange) 287 + self.spin_max = intctrl.IntCtrl(self, size=(40,20),
  288 + style=wx.TE_PROCESS_ENTER)
  289 + self.spin_max.SetValue(self.maximun)
528 if sys.platform != 'win32': 290 if sys.platform != 'win32':
529 - self.SpinMax.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)  
530 - self.SpinMax.SetValue(self.SliderData.maxValue)  
531 -  
532 - self.GradientPanel = GradientPanel(self, -1, self.SliderData)  
533 - self.sizer.Add(self.SpinMin, 0, wx.CENTRE)#, wx.EXPAND)  
534 - self.sizer.AddSpacer(5)  
535 - self.sizer.Add(self.GradientPanel, 2, wx.CENTRE)#, wx.EXPAND)  
536 - self.sizer.AddSpacer(5)  
537 - self.sizer.Add(self.SpinMax, 0, wx.CENTRE)#, wx.EXPAND)  
538 - self._DoBinds()  
539 -  
540 - def _DoBinds(self):  
541 - self.SpinMin.Bind(wx.lib.intctrl.EVT_INT, self.ChangeMinValue)  
542 - self.SpinMin.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMinChange)  
543 - self.SpinMin.Bind(wx.EVT_TEXT_ENTER, self._FireSpinMinChange)  
544 - self.SpinMin.Bind(wx.EVT_MOUSEWHEEL, self.OnMinMouseWheel)  
545 -  
546 - self.SpinMax.Bind(wx.lib.intctrl.EVT_INT, self.ChangeMaxValue)  
547 - self.SpinMax.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMaxChange)  
548 - self.SpinMax.Bind(wx.EVT_TEXT_ENTER, self._FireSpinMaxChange)  
549 - self.SpinMax.Bind(wx.EVT_MOUSEWHEEL, self.OnMaxMouseWheel)  
550 -  
551 - self.Bind(EVT_SLIDER_CHANGE, self.OnSlider, self.GradientPanel) 291 + self.spin_max.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
  292 +
  293 + sizer = wx.BoxSizer(wx.HORIZONTAL)
  294 + sizer.Add(self.spin_min, 0, wx.EXPAND)
  295 + sizer.Add(self.gradient_slider, 1, wx.EXPAND)
  296 + sizer.Add(self.spin_max, 0, wx.EXPAND)
  297 + self.sizer.Add(sizer, 1, wx.EXPAND)
  298 +
  299 + def _bind_events_wx(self):
  300 + self.gradient_slider.Bind(EVT_SLIDER_CHANGE, self.OnSlider)
  301 +
  302 + # self.spin_min.Bind(wx.lib.intctrl.EVT_INT, self.ChangeMinValue)
  303 + self.spin_min.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMinChange)
  304 + self.spin_min.Bind(wx.EVT_TEXT_ENTER, self._FireSpinMinChange)
  305 + self.spin_min.Bind(wx.EVT_MOUSEWHEEL, self.OnMinMouseWheel)
  306 +
  307 + # self.spin_max.Bind(wx.lib.intctrl.EVT_INT, self.ChangeMaxValue)
  308 + self.spin_max.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMaxChange)
  309 + self.spin_max.Bind(wx.EVT_TEXT_ENTER, self._FireSpinMaxChange)
  310 + self.spin_max.Bind(wx.EVT_MOUSEWHEEL, self.OnMaxMouseWheel)
  311 +
  312 + def OnSlider(self, evt):
  313 + self.spin_min.SetValue(evt.minimun)
  314 + self.spin_max.SetValue(evt.maximun)
  315 + self.minimun = evt.minimun
  316 + self.maximun = evt.maximun
  317 + self._GenerateEvent()
552 318
553 def _FireSpinMinChange(self, evt): 319 def _FireSpinMinChange(self, evt):
554 - value = int(self.SpinMin.GetValue()) 320 + value = int(self.spin_min.GetValue())
555 if value != self.GetMinValue(): 321 if value != self.GetMinValue():
556 - self.GradientPanel.SetMinValue(value) 322 + self.gradient_slider.SetMinimun(value)
  323 + self.minimun = value
557 self._GenerateEvent() 324 self._GenerateEvent()
558 325
559 def _FireSpinMaxChange(self, evt): 326 def _FireSpinMaxChange(self, evt):
560 - value = int(self.SpinMax.GetValue()) 327 + value = int(self.spin_max.GetValue())
561 if value != self.GetMaxValue(): 328 if value != self.GetMaxValue():
562 - self.GradientPanel.SetMaxValue(value) 329 + self.gradient_slider.SetMaximun(value)
  330 + self.maximun = value
563 self._GenerateEvent() 331 self._GenerateEvent()
564 332
565 def OnMinMouseWheel(self, e): 333 def OnMinMouseWheel(self, e):
@@ -570,97 +338,56 @@ class GradientSlider(wx.Panel): @@ -570,97 +338,56 @@ class GradientSlider(wx.Panel):
570 v = self.GetMaxValue() + e.GetWheelRotation()/e.GetWheelDelta() 338 v = self.GetMaxValue() + e.GetWheelRotation()/e.GetWheelDelta()
571 self.SetMaxValue(v) 339 self.SetMaxValue(v)
572 340
  341 + def SetColour(self, colour):
  342 + colour = colour + [90,]
  343 + self.colour = colour
  344 + self.gradient_slider.SetColour(colour)
  345 + self.gradient_slider.Refresh()
  346 +
  347 + def SetMaxRange(self, value):
  348 + self.spin_min.SetMax(value)
  349 + self.spin_max.SetMax(value)
  350 + self.gradient_slider.SetMaxRange(value)
  351 +
  352 + def SetMinRange(self, value):
  353 + self.spin_min.SetMin(value)
  354 + self.spin_max.SetMin(value)
  355 + self.gradient_slider.SetMinRange(value)
  356 +
  357 + def SetMaxValue(self, value):
  358 + value = int(value)
  359 + self.spin_max.SetValue(value)
  360 + self.gradient_slider.SetMaximun(value)
  361 + self.maximun = value
  362 +
  363 + def SetMinValue(self, value):
  364 + value = int(value)
  365 + self.spin_min.SetValue(value)
  366 + self.gradient_slider.SetMinimun(value)
  367 + self.minimun = value
  368 +
573 def ChangeMinValue(self, e): 369 def ChangeMinValue(self, e):
574 # Why do I need to change slide min value if it has been changed for 370 # Why do I need to change slide min value if it has been changed for
575 # the user? 371 # the user?
576 print "ChangeMinValue", self.slided 372 print "ChangeMinValue", self.slided
577 if not self.slided: 373 if not self.slided:
578 - self.GradientPanel.SetMinValue(int(self.SpinMin.GetValue())) 374 + self.gradient_slider.SetMinValue(int(self.spin_min.GetValue()))
579 self._GenerateEvent() 375 self._GenerateEvent()
580 376
581 def ChangeMaxValue(self, e): 377 def ChangeMaxValue(self, e):
582 # Why do I need to change slide min value if it has been changed for 378 # Why do I need to change slide min value if it has been changed for
583 # the user? 379 # the user?
584 if not self.slided: 380 if not self.slided:
585 - self.GradientPanel.SetMaxValue(int(self.SpinMax.GetValue())) 381 + self.gradient_slider.SetMaxValue(int(self.spin_max.GetValue()))
586 self._GenerateEvent() 382 self._GenerateEvent()
587 383
588 - def OnSlider(self, e):  
589 - self.slided = 1  
590 - self.SpinMin.SetValue(int(self.SliderData.GetMinValue()))  
591 - self.SpinMax.SetValue(int(self.SliderData.GetMaxValue()))  
592 - self.slided = 0  
593 - self._GenerateEvent()  
594 -  
595 - def SetMinValue(self, value, do_event=False):  
596 - try:  
597 - value = value.data  
598 - except AttributeError:  
599 - pass  
600 - self.slided = 0 if do_event else 1  
601 - self.GradientPanel.SetMinValue(value)  
602 - self.SpinMin.SetValue(int(value))  
603 - self.GradientPanel.Refresh()  
604 -  
605 - def SetMaxValue(self, value, do_event=False):  
606 - try:  
607 - value = value.data  
608 - except AttributeError:  
609 - pass  
610 - self.slided = 0 if do_event else 1  
611 - self.GradientPanel.SetMaxValue(value)  
612 - self.SpinMax.SetValue(int(value))  
613 - self.GradientPanel.Refresh()  
614 -  
615 - def SetMaxRange(self, value):  
616 - self.SliderData.SetMaxRange(value)  
617 - self.SpinMin.SetMax(value)  
618 - self.SpinMax.SetMax(value)  
619 - self.GradientPanel.Refresh()  
620 -  
621 - def SetMinRange(self, value):  
622 - self.SliderData.SetMinRange(value)  
623 - self.SpinMin.SetMin(value)  
624 - self.SpinMax.SetMin(value)  
625 - self.GradientPanel.Refresh()  
626 -  
627 def GetMaxValue(self): 384 def GetMaxValue(self):
628 - return self.SliderData.GetMaxValue() 385 + return self.maximun
629 386
630 def GetMinValue(self): 387 def GetMinValue(self):
631 - return self.SliderData.GetMinValue()  
632 -  
633 - def GetSliderData(self):  
634 - """  
635 - Returns the associated SliderData.  
636 - """  
637 - return self.SliderData  
638 -  
639 - def SetColour(self, colour, transparency=None):  
640 - """  
641 - Set colour of the slider, the colour must be in RGB format.  
642 - And values varying 0-255.  
643 - """  
644 - if transparency is not None:  
645 - A = transparency  
646 - else:  
647 - A = self.transparency  
648 - (R,G,B) = colour  
649 - self.SliderData.SetColour((R,G,B,A))  
650 - self.GradientPanel.Refresh() 388 + return self.minimun
651 389
652 def _GenerateEvent(self): 390 def _GenerateEvent(self):
653 - evt = SliderEvent(myEVT_THRESHOLD_CHANGE, self.GetId()) 391 + evt = SliderEvent(myEVT_THRESHOLD_CHANGE, self.GetId(), self.min_range,
  392 + self.max_range, self.minimun, self.maximun)
654 self.GetEventHandler().ProcessEvent(evt) 393 self.GetEventHandler().ProcessEvent(evt)
655 -  
656 -class SliderEvent(wx.PyCommandEvent):  
657 - def __init__(self , evtType, id):  
658 - wx.PyCommandEvent.__init__(self, evtType, id)  
659 -  
660 -myEVT_SLIDER_CHANGE = wx.NewEventType()  
661 -# This event occurs when the user do slide, used only internaly  
662 -EVT_SLIDER_CHANGE = wx.PyEventBinder(myEVT_SLIDER_CHANGE, 1)  
663 -  
664 -myEVT_THRESHOLD_CHANGE = wx.NewEventType()  
665 -# This event occurs when the user change the threshold.  
666 -EVT_THRESHOLD_CHANGE = wx.PyEventBinder(myEVT_THRESHOLD_CHANGE, 1)