[PythonCAD] Sample patch for selection highlighting

Art Haas ahaas at airmail.net
Fri Nov 11 17:11:30 CET 2005


On Thu, Nov 10, 2005 at 10:57:41AM -0600, Art Haas wrote:
> On Tue, Nov 08, 2005 at 08:21:01PM -0500, Stuart Brorson wrote:
> > 
> > *  Apropos highlighting:  In light of our recent back and forth about
> > signal sending and receiving, I have tried to wrap my head around teh
> > signaling system.  My question is:  when an object is selected and 
> > highlighted, who should send the signal, and who should receive it?
> > Also, what's the correct way to send a signal?  If I do:
> > 
> > foo.send('signal_name', bar)
> > 
> > then the object "foo" is emitting the signal, right?  But who is
> > "bar"?  The intended receiving object?  Or is "bar" the emitter?  Then
> > what is "foo"?
> 
> The code currently is set up that the 'selected_object' message is sent
> by an Image instance. Refer to the selectedObject() method in the
> 'image.py' file, around lines 1540 or so. The actual sendMessage() call
> looks like ...
> 
> 	self.sendMessage('selected_object', obj)
> 
> ... where 'self' is the Image instance and 'obj' is the selected object.
> 
> The patch you'd sent with your selection/deselection work was structured
> so that the selected object itself would send the 'selected_object'
> message, so the sendMessage() call would look like ...
> 
> 	obj.sendMessage('selected_object')
> 
> ... where 'obj' is the selected entity.
> 
> As for which one is right, that cannot be answered as both approaches
> can work. It is just a matter of picking one approach or the other and
> coding things. I'm leaning toward my approach as I think it fits in
> with the message name 'selected_object' better, but if the message name
> was just 'selected' than your approach would look better.
> 
> As for sending messages themselves, your example above of with slight
> modifications looks like this:
> 
> foo.sendMessage('some_message', bar)
> 
> So, entity 'foo' is sending out the message 'some_message', and any
> entity that is listening for 'some_message' will receive argument 'bar'
> as an argument to the connected method. What is 'bar'? It can be any
> object you want it to be. An integer, boolean, float, a class instance,
> etc. There is no restriction on what 'bar' is so long as the code is
> valid Python code, of course. The sendMessage() method only requires
> one argument, the message string, and any other arguments are simply
> passed along to the method specified in the connect() call listening for
> the message.
> 
> As for receiving a message, that depends on what you wish to do. Going
> back to the 'selected_object' message, if we pretend that the code is
> structured as I'd written it, like ...
> 
> 	self.sendMessage('selected_object', obj)
> 
> ... then I'd guess that initially a GTKImage instance would be listening
> for 'selected_object' messages. Here's what the handler of this message
> would start out like:
> 
> 	def selectObjectHandler(self, image, *args):
> 		_alen = len(args)
> 		if _alen < 1:
> 			raise ValueError, "Invalid argument count"
> 		_obj = args[0]
> 		#
> 		# 'self' is a GTKImage, and argument 'image' will
> 		# be the same instance as 'self', and variable '_obj'
> 		# will be the selected object
> 		#
> 		... do clever stuff to highlight the object here ...
> 
> The handler would be specified by a 'connect' call probably in the
> GTKImage::__init__() method looking like
> 
> 	self.connect('selected_object', self.selectObjectHandler)
> 
> Don't forget there would also be a corresponding method and connect()
> call for the 'deselected_object' message as well.

Hi.

I fiddled around a bit yesterday evening and added the first take at
'clever stuff' to do the highlighting. I've attached my patch below.
When an entity is selected, it is redrawn with the color '#ff7733',
which is somewhat orangish. This patch is not commited yet, by the way,
as I probably don't want to rely on a hardcoded value for the selection
color.

I think the patch also serves as a nice example of using the messaging
system, especially with the recent e-mails regarding the sending and
receiving of messages. The 'print' statements in the handlers were just
for debugging, so they'll eventually be commented out or turned into
print_debug() calls. Also, instead of calling redraw() to show the
selection the gtk.DrawingArea method queue_draw() is used, providing a
big speedup in that we skip having to query and redraw all the entities
in the drawing but simply redisplay the current pixmap. Finally, the
tests for visibility ensure that the draw operation is only performed if
both the entity and its parent Layer are visible.

I'll cook up a deselect patch shortly and fill in this missing piece
in dealing with entity selection.

Comments?

Art

Index: PythonCAD/Interface/Gtk/gtkimage.py
===================================================================
--- PythonCAD/Interface/Gtk/gtkimage.py	(revision 2038)
+++ PythonCAD/Interface/Gtk/gtkimage.py	(working copy)
@@ -441,6 +441,11 @@
         self.__tolerance = 1e-10
 
         #
+
+        self.connect('selected_object', self._selectedObject)
+        self.connect('deselected_object', self._deselectedObject)
+        
+        #
         # set the background color
         #
 
@@ -457,6 +462,35 @@
         super(GTKImage, self).close()
         self.__window.destroy()
 
+    def _selectedObject(self, img, *args):
+        _alen = len(args)
+        if _alen < 1:
+            raise ValueError, "Invalid argument count: %d" % _alen
+        _obj = args[0]
+        print "Selected object: " + `_obj`
+        _parent = _obj.getParent()
+        if _parent.isVisible() and _obj.isVisible():
+            print "Redrawing ..."
+            _obj.draw(self, self.getOption('BACKGROUND_COLOR'))
+            self.__da.queue_draw()
+            _color = Color('#ff7733')
+            _obj.draw(self, _color)
+            self.__da.queue_draw()
+
+    def _deselectedObject(self, img, *args):
+        _alen = len(args)
+        if _alen < 1:
+            raise ValueError, "Invalid argument count: %d" % _alen
+        _obj = args[0]
+        print "Deselected object: " + `_obj`
+        _parent = _obj.getParent()
+        if _parent.isVisible() and _obj.isVisible():
+            print "Redrawing ..."
+            _obj.draw(self, self.getOption('BACKGROUND_COLOR'))
+            self.__da.queue_draw()
+            _obj.draw(self)
+            self.__da.queue_draw()
+        
     #------------------------------------------------------------------
     def getAccel(self):
         """Return the gtk.AccelGroup in the GTKImage.

-- 
Man once surrendering his reason, has no remaining guard against absurdities
the most monstrous, and like a ship without rudder, is the sport of every wind.

-Thomas Jefferson to James Smith, 1822


More information about the PythonCAD mailing list