From rjshaw at netspace.net.au Wed Sep 1 13:04:24 2004 From: rjshaw at netspace.net.au (Russell Shaw) Date: Wed Sep 1 13:05:37 2004 Subject: [PythonCAD] Execution path Message-ID: <4135ACB8.7090907@netspace.net.au> Hi, I downloaded the code to see how it works. I'm interested in drawing/cad programs. I looked in PythonCAD-DS1-R16/gtkpycad.py. Where are the callbacks for mouseclicks set up? From ahaas at airmail.net Wed Sep 1 15:40:30 2004 From: ahaas at airmail.net (Art Haas) Date: Wed Sep 1 17:02:16 2004 Subject: [PythonCAD] Execution path In-Reply-To: <4135ACB8.7090907@netspace.net.au> References: <4135ACB8.7090907@netspace.net.au> Message-ID: <20040901134030.GN19567@artsapartment.org> On Wed, Sep 01, 2004 at 09:04:24PM +1000, Russell Shaw wrote: > Hi, > I downloaded the code to see how it works. I'm interested in > drawing/cad programs. > > I looked in PythonCAD-DS1-R16/gtkpycad.py. Where are the > callbacks for mouseclicks set up? Hi. The mouse click callbacks are in Interface/Gtk/gtkimage.py for handling the clicking in the drawing area. The clicks for creating the various entities are handled in by the Tool class. They get set/unset in the files in Interface/Gtk like gtkentities.py, gtkmodify.py, gtkdimension.py, etc. Look for lines that say something like: tool.setHandler("button_press", ...) Art -- 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 From rjshaw at netspace.net.au Wed Sep 1 18:23:42 2004 From: rjshaw at netspace.net.au (Russell Shaw) Date: Wed Sep 1 18:24:47 2004 Subject: [PythonCAD] Execution path In-Reply-To: <20040901134030.GN19567@artsapartment.org> References: <4135ACB8.7090907@netspace.net.au> <20040901134030.GN19567@artsapartment.org> Message-ID: <4135F78E.1050001@netspace.net.au> Art Haas wrote: > On Wed, Sep 01, 2004 at 09:04:24PM +1000, Russell Shaw wrote: > >>Hi, >>I downloaded the code to see how it works. I'm interested in >>drawing/cad programs. >> >>I looked in PythonCAD-DS1-R16/gtkpycad.py. Where are the >>callbacks for mouseclicks set up? > > > Hi. > > The mouse click callbacks are in Interface/Gtk/gtkimage.py for handling > the clicking in the drawing area. The clicks for creating the various > entities are handled in by the Tool class. They get set/unset in the > files in Interface/Gtk like gtkentities.py, gtkmodify.py, > gtkdimension.py, etc. Look for lines that say something like: > > tool.setHandler("button_press", ...) > > Art Hi, I had a look thru more of the code, but can't see the forest thru the trees. I've made programs in python and gtk, and pygtk before. Is there a debugger that lets you single-step thru the python code? I'm trying to get an overall idea of how the app works in a high-level kind of way, such as how the app guides the user thru a series of steps when drawing a shape: First i select: Draw|Basic|Rectangles Statusbar: Click in the drawing area or enter a point Does this menu cause a new callback for mouse-clicks to be connected somewhere? Which one? I move the mouse to a second point. Which callback is doing the redrawing of the rectangle in response to mouse movement? Is this callback always connected, or is it specific to each object being drawn? I click a point: Statusbar: Enter the second point or click in the drawing area Which function holds this series of steps (or context) that guides the user thru each action of drawing a rectangle? I click the second point and the rectangle is drawn. I have lots of ideas for lots of cad programs, but am wondering about what 'architecture' to use. From ahaas at airmail.net Wed Sep 1 18:38:40 2004 From: ahaas at airmail.net (Art Haas) Date: Wed Sep 1 18:38:46 2004 Subject: [PythonCAD] Execution path In-Reply-To: <4135F78E.1050001@netspace.net.au> References: <4135ACB8.7090907@netspace.net.au> <20040901134030.GN19567@artsapartment.org> <4135F78E.1050001@netspace.net.au> Message-ID: <20040901163840.GR19567@artsapartment.org> On Thu, Sep 02, 2004 at 02:23:42AM +1000, Russell Shaw wrote: > > Hi, > I had a look thru more of the code, but can't see the forest thru > the trees. I've made programs in python and gtk, and pygtk before. > Is there a debugger that lets you single-step thru the python code? > There is the python debugger module "pdb" that is part of the standard Python distribution. It should do what you want. Check the Python web site for info about using it. > I'm trying to get an overall idea of how the app works in a high-level > kind of way, such as how the app guides the user thru a series of steps > when drawing a shape: > > First i select: > > Draw|Basic|Rectangles > > Statusbar: Click in the drawing area or enter a point > > Does this menu cause a new callback for mouse-clicks to be connected > somewhere? Which one? The menu choice is handled in 'Interface/Gtk/gtkmenus.py', in this case the function draw_rectangle_cb(). This function creates an instance of the RectangleTool in 'Generic/tools.py', and sets things up so that this tool will be the one used for adding the new entities in the drawing. The tool is then modified to handle various events by the call to gtkentities.rectangle_mode_init() in 'Interface/Gtk/gtkentities.py'. It is in this function that the handlers for mouse and keyboard events are set. > I move the mouse to a second point. Which callback is doing the redrawing > of the rectangle in response to mouse movement? Is this callback always > connected, or is it specific to each object being drawn? The callback for redrawing the rectangle is rectangle_motion_notify_cb(), again in the 'gtkentities.py' file. The callback handling the "motion_notify" signals is different for each entity. > I click a point: > > Statusbar: Enter the second point or click in the drawing area > > Which function holds this series of steps (or context) that guides > the user thru each action of drawing a rectangle? Clicking the second point invokes the rectangle_second_button_press_cb() function, yet again in 'gtkentities.py'. > I click the second point and the rectangle is drawn. Success! Adding the rectangle to the drawing is really just adding four segments. Look at the create() method in the RectangleTool class in the file 'Generic/Tools.py'. > I have lots of ideas for lots of cad programs, but am wondering > about what 'architecture' to use. Hope this info helps. When I started on the program, I looked at a number of drawing programs to try and figure out how they handled interaction with the user. The Gimp was helpful, though it is quite a task to find where in the code various events get set and unset, and how the handler gets invoked. Art Haas -- 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 From rjshaw at netspace.net.au Wed Sep 1 19:00:11 2004 From: rjshaw at netspace.net.au (Russell Shaw) Date: Wed Sep 1 19:01:08 2004 Subject: [PythonCAD] Execution path In-Reply-To: <20040901163840.GR19567@artsapartment.org> References: <4135ACB8.7090907@netspace.net.au> <20040901134030.GN19567@artsapartment.org> <4135F78E.1050001@netspace.net.au> <20040901163840.GR19567@artsapartment.org> Message-ID: <4136001B.6010604@netspace.net.au> Art Haas wrote: > On Thu, Sep 02, 2004 at 02:23:42AM +1000, Russell Shaw wrote: > >>Hi, >>I had a look thru more of the code, but can't see the forest thru >>the trees.... ... >>I click the second point and the rectangle is drawn. > > > Success! Adding the rectangle to the drawing is really just adding four > segments. Look at the create() method in the RectangleTool class in the > file 'Generic/Tools.py'. > > >>I have lots of ideas for lots of cad programs, but am wondering >>about what 'architecture' to use. > > > Hope this info helps. When I started on the program, I looked at a > number of drawing programs to try and figure out how they handled > interaction with the user. The Gimp was helpful, though it is quite a > task to find where in the code various events get set and unset, and how > the handler gets invoked. > > Art Haas Thanks, you make it look easy:) Atleast now i have seen one alternative way of handling drawing context. I have a different way in my current program, but it's currently very broken because i didn't know enough about gtk/gobject/gtk-threads at the time. From ahaas at airmail.net Sat Sep 4 01:10:25 2004 From: ahaas at airmail.net (Art Haas) Date: Sat Sep 4 01:10:36 2004 Subject: [PythonCAD] More repo updates Message-ID: <20040903231025.GF19567@artsapartment.org> Hi. Just a brief word to point out that some more stuff is at the repo. TextBlocks will now be printed out, and the printing of the Dimension text(s) is also now in the printing code. I still need to work on the ability to adjust the size of the text, as currently the default is very small. More text work will be on the agenda for the next week. Art -- 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 From ewilhelm at sbcglobal.net Sat Sep 4 03:43:52 2004 From: ewilhelm at sbcglobal.net (Eric Wilhelm) Date: Sat Sep 4 03:39:53 2004 Subject: [PythonCAD] undo with text? Message-ID: <200409032043.52109.ewilhelm@sbcglobal.net> The undo command seems to choke on text. Is it just not logged yet? First Draw->Text, enter a string and pick a point. Then, Edit->Undo and you get this. Traceback (most recent call last): File "/home/ewilhelm/src/pythoncad_svn/trunk/Interface/Gtk/gtkmenus.py", line 313, in edit_undo_cb gtkimage.undo() File "/home/ewilhelm/src/pythoncad_svn/trunk/Generic/image.py", line 916, in undo _layer.undo() File "/home/ewilhelm/src/pythoncad_svn/trunk/Generic/entity.py", line 256, in undo self.__log.undo() File "/home/ewilhelm/src/pythoncad_svn/trunk/Generic/logger.py", line 67, in undo self.execute(True, *_data) File "/home/ewilhelm/src/pythoncad_svn/trunk/Generic/layer.py", line 2340, in execute self._delObject(True, _vals) File "/home/ewilhelm/src/pythoncad_svn/trunk/Generic/layer.py", line 2644, in _delObject _id, _pid = values[1] TypeError: unpack non-sequence I haven't managed to swim my way through this yet, all I know is that it happens. --Eric -- "Left to themselves, things tend to go from bad to worse." --Murphy's Corollary From ahaas at airmail.net Sat Sep 4 13:10:22 2004 From: ahaas at airmail.net (Art Haas) Date: Sat Sep 4 13:12:44 2004 Subject: [PythonCAD] undo with text? In-Reply-To: <200409032043.52109.ewilhelm@sbcglobal.net> References: <200409032043.52109.ewilhelm@sbcglobal.net> Message-ID: <20040904111022.GH19567@artsapartment.org> On Fri, Sep 03, 2004 at 08:43:52PM -0500, Eric Wilhelm wrote: > The undo command seems to choke on text. Is it just not logged yet? > > First Draw->Text, enter a string and pick a point. Then, Edit->Undo > and you get this. > > [ ... snip ... ] The undo/redo ability for text doesn't work because, as you wrote, there is no logging for the TextBlock class yet. I'll see what can be done about avoiding the error, and get to adding the ability to undo and redo TextBlock operations soon. Art -- 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 From ewilhelm at sbcglobal.net Sat Sep 4 15:57:36 2004 From: ewilhelm at sbcglobal.net (Eric Wilhelm) Date: Sat Sep 4 16:26:20 2004 Subject: [PythonCAD] more undo Message-ID: <200409040857.36531.ewilhelm@sbcglobal.net> I'm poking at your undo system to see how it works. If I draw a line, change the color, and then try ctrl+Z, I get this: saveUndoData: ('add', ('point', (4, 1), 159.0, 516.0)) saveUndoData: ('add', ('point', (5, 1), 408.0, 326.0)) saveUndoData: ('add', ('segment', (6, 1), (None, None, None, None), 4, 5)) saveUndoData: ('attr_changed', 'color', (255, 255, 255)) saveUndoData: ('mod', 6) Traceback (most recent call last): File "./trunk/Interface/Gtk/gtkmenus.py", line 313, in edit_undo_cb gtkimage.undo() File "./trunk/Generic/image.py", line 916, in undo _layer.undo() File "./trunk/Generic/entity.py", line 256, in undo self.__log.undo() File "./trunk/Generic/logger.py", line 67, in undo self.execute(True, *_data) File "./trunk/Generic/layer.py", line 2388, in execute _obj.undo() File "./trunk/Generic/entity.py", line 256, in undo self.__log.undo() File "./trunk/Generic/logger.py", line 67, in undo self.execute(True, *_data) File "./trunk/Generic/segment.py", line 991, in execute raise ValueError, "Unexpected operation: %s" % _op ValueError: Unexpected operation: attr_changed I've turned on some of your debugging statements in Generic/logger.py. Digging around a little further, it seems that each class has an execute() function, but this is only involved in undo/redo (and then only with attributes?) I've looked back through the archives, but can't seem to find an "executive summary" of how undo/redo works. Is there some documentation that I'm missing? From my poking around, it looks like the undo/redo is managed on a fairly low level (where each change is logged and there must be a specific action defined for undo/redo of that kind of change.) Is this correct? If so, how well does this scale as new types of entities and actions are added? Is there a more generic system that would work? Consider this. What if you wanted to create an animation of a session's editing changes? What if you wanted to create it backwards? Ignoring the animation issues, how would the code be able to create the data at each change point? What if you want to undo the last thing done before the file was last saved? Global snapshots at each change would be the most generic way, but also the most expensive. Differences of these snapshots might be less expensive, but that could be tricky to do efficiently (unless you work with the persistent directory idea.) With the logging system, you have to have a record of each change and a function that is able to undo each particular change. This gives a foo() and unfoo() pair of functions for each particular action. Efficient, but hard to code and maintain. So, global the snapshot/rollback undo is really simple and hard to get wrong. The local change-specific undo is really CPU efficient and hard to get right. Assuming that you don't want to explore a global diff/patch undo system, what would make the local scheme more robust? Maybe a scripting/unscripting system? This gives you the added benefit of a scripting system while simultaneously abstracting the undo mechanism into a more robust scheme and allowing the undo history to be persistent across a reboot. If you build this into the existing logger, a syntax like the following might work. entity CHANGE property TO value And to make it easily unscriptable, you could pass something like this to the logger. entity CHANGE property FROM value1 TO value2 So, undo becomes a matter of munging the TO and FROM around. What about create/delete? entity ADD type WITH property=value AND property2=value2 entity REMOVE type LOG property=value AND property2=value2 Of course, I'm just messing around with this SQL-like syntax, but you get the idea. It's verbose and very structured. Designed with inversion in mind. The point is, if every action is scriptable and unscriptable, the undo/redo becomes a matter of parsing and running a script. Other than the undo system uses, I'm not sure that this sort of macro scripting is a good idea. After all, you could simply evaluate some Python, or even have an embedded Perl interpreter. The problem with these languages is that parsing for the sake of inversion is HARD. --Eric -- "But as to modern architecture, let us drop it and let us take modernistic out and shoot it at sunrise." --F.L. Wright From ahaas at airmail.net Sat Sep 4 20:40:13 2004 From: ahaas at airmail.net (Art Haas) Date: Sat Sep 4 20:41:25 2004 Subject: [PythonCAD] more undo In-Reply-To: <200409040857.36531.ewilhelm@sbcglobal.net> References: <200409040857.36531.ewilhelm@sbcglobal.net> Message-ID: <20040904184013.GA17776@artsapartment.org> On Sat, Sep 04, 2004 at 08:57:36AM -0500, Eric Wilhelm wrote: > I'm poking at your undo system to see how it works. If I draw a line, > change the color, and then try ctrl+Z, I get this: > > > > saveUndoData: ('add', ('point', (4, 1), 159.0, 516.0)) > saveUndoData: ('add', ('point', (5, 1), 408.0, 326.0)) > saveUndoData: ('add', ('segment', (6, 1), (None, None, None, None), 4, > 5)) > saveUndoData: ('attr_changed', 'color', (255, 255, 255)) > saveUndoData: ('mod', 6) > Traceback (most recent call last): > File "./trunk/Interface/Gtk/gtkmenus.py", line 313, in edit_undo_cb > gtkimage.undo() > File "./trunk/Generic/image.py", line 916, in undo > _layer.undo() > File "./trunk/Generic/entity.py", line 256, in undo > self.__log.undo() > File "./trunk/Generic/logger.py", line 67, in undo > self.execute(True, *_data) > File "./trunk/Generic/layer.py", line 2388, in execute > _obj.undo() > File "./trunk/Generic/entity.py", line 256, in undo > self.__log.undo() > File "./trunk/Generic/logger.py", line 67, in undo > self.execute(True, *_data) > File "./trunk/Generic/segment.py", line 991, in execute > raise ValueError, "Unexpected operation: %s" % _op > ValueError: Unexpected operation: attr_changed > > [ ... Goes and looks at code ... ] A-ha. The SegmentLog doesn't know what to do, but instead of calling its base GraphicObjectLog.execute() method, which deals with the 'attr_changed' operation, the SegmentLog raises an exception. This bug will also be in Circles, Arcs, Leaders, and Polylines as well. > I've turned on some of your debugging statements in Generic/logger.py. > Digging around a little further, it seems that each class has an > execute() function, but this is only involved in undo/redo (and then > only with attributes?) The execute() method is the call that does the work of the particular undo/redo operation. As for what operations the execute method performs, that depends on what the particular Logger instance stores. If you look at the PointLog in 'Generic/point.py', the PointLog will store the coordinates it receives when the movePoint() method is called, and it stores them in a tuple where the first entry is the key 'moved'. When the PointLog execute() method is called, the tuple that contains the arguments is split up and the first thing in the tuple is examined to determine what to do. With the PointLog class, all it knows how to do is handle 'moved' operations. > I've looked back through the archives, but can't seem to find an > "executive summary" of how undo/redo works. Is there some > documentation that I'm missing? Unfortunately not. The only documentation is the code, and you have to step through it. :-( The lack of documentation for the undo/redo stuff is a problem, and I'll try to add some to the website as soon as possible. > From my poking around, it looks like the undo/redo is managed on a > fairly low level (where each change is logged and there must be a > specific action defined for undo/redo of that kind of change.) Is > this correct? Yes. > If so, how well does this scale as new types of > entities and actions are added? The current setup works well enough for the initial undo/redo implementation. As for new entities, as they get added a class for logging the various values that may change in the new entity will need to be written as well. > Is there a more generic system that would work? I can't answer "Yes", as I don't know of a more generic system that would work, but I can't answer question "No" as my lack of knowledge doesn't mean that a better undo/redo approach exists. Prior to writing the undo/redo code, I went looking for examples of how other programs handle this feature. Everyone seems to do it differently, not surprisingly. Some programs built in environments like KDE can utilize some lower-level libraries or functionality provided in KDE. The GNOME programs I looked at didn't seem to have the ability to utilize a common GNOME undo/redo mechanism, but such an infrastructure may exist and I just missed it. I spent a good bit of time looking at how Gnumeric (a wonderful spreadsheet) handles undo and redo, and from that code came my use of execute() as the Gnumeric code had comments suggesting a common undo/redo operation handler was better than what they had at the time. > Consider this. What if you wanted to create an animation of a > session's editing changes? What if you wanted to create it > backwards? Ignoring the animation issues, how would the code be able > to create the data at each change point? What if you want to undo > the last thing done before the file was last saved? > > Global snapshots at each change would be the most generic way, but > also the most expensive. Differences of these snapshots might be > less expensive, but that could be tricky to do efficiently (unless > you work with the persistent directory idea.) > > With the logging system, you have to have a record of each change and > a function that is able to undo each particular change. This gives a > foo() and unfoo() pair of functions for each particular action. > Efficient, but hard to code and maintain. > > So, global the snapshot/rollback undo is really simple and hard to get > wrong. The local change-specific undo is really CPU efficient and > hard to get right. > > Assuming that you don't want to explore a global diff/patch undo > system, what would make the local scheme more robust? I believe the global approach is becomes unworkable as the size of the drawing - number of entities - increases. Each entity would have to have its various values queried and then stored in some fashion. So for drawings with hundreds or thousands of entities, each action in the drawing would means retrieving lots of info that hasn't changed, and the storage requirements for the drawing would explode. Yes, it is harder to store only the bits that changed, but the memory requirements are signifcantly smaller and the CPU usage is low. In a way, the undo/redo stuff is storing just the difference between the drawing at one point in time and another. As for making the existing scheme more robust, I would suggest adding unit test into the repository that would exercise the entity and its logging abilities. When the project started I'd written some unit tests for some of the basic entities, but there haven't been any additions is a long while, and the advancements in the program haven't had unit tests created for verifying the functionality works and that newer functionality doesn't break existing code (without a good reason). > Maybe a scripting/unscripting system? This gives you the added > benefit of a scripting system while simultaneously abstracting the > undo mechanism into a more robust scheme and allowing the undo > history to be persistent across a reboot. I don't see undo/redo stuff needing to store information after a file is closed. Some programs may do this, allowing you to work on a drawing one day, close it for a while, then open it up and undo the very last thing done previously. That ability would require the storage of the undo/redo information in the file, and that sounds like a recipe for the file size to explode. > If you build this into the existing logger, a syntax like the > following might work. > > entity CHANGE property TO value > > And to make it easily unscriptable, you could pass something like this > to the logger. > > entity CHANGE property FROM value1 TO value2 > > So, undo becomes a matter of munging the TO and FROM around. > > What about create/delete? > > entity ADD type WITH property=value AND property2=value2 > entity REMOVE type LOG property=value AND property2=value2 > > Of course, I'm just messing around with this SQL-like syntax, but you > get the idea. It's verbose and very structured. Designed with > inversion in mind. The point is, if every action is scriptable and > unscriptable, the undo/redo becomes a matter of parsing and running a > script. The current undo/redo stuff is somewhat similar to this, except the information is stored in a tuple instead of a script. Here's a quick rundown of how undo/redo works. We'll pretend that there is a drawing with a Point instance at (0,0), and you are going to move it to (1,0). When the Point was added to the drawing, a PointLog was created and connected to listen to any 'moved' messages the Point may send. Also, the Layer containing the newly added Point tests if it has a LayerLog instance, and if so connects the LayerLog to listen for any 'modified' message sent by the Point. 1) Point is moved by Point.setCoords() method. The move() or setX() methods also could be used, but we'll use setCoords() for this example. 2) The displacement is large enough that the point sends out the 'moved' message, and the old coordinates are passed as arguments as part of the sendMessage() call. 3) The PointLog receives the 'moved' message and invokes its movePoint() method. 4) The PointLog stores the information as ('moved', x, y) where 'x' and 'y' were the old coordinates. The info is stored as ('moved', 0, 0). 5) The Point issues a 'modified' message. 6) The LayerLog receives the 'modified' message and invokes its modObj() method. 7) The modObj() method stores in the Layer log the information that the Point has been modified. This info is stored as ('mod', id), where 'id' is the value returned by the entity.getID() method, not the python builtin id(). We'll pretend that our Point has an id of 5, so the LayerLog stores ('mod', 5). 8) The Layer sends a 'modified' message out. The Image containing the Layer listens for 'modified' messages, and it saves in a list the Layer that sent the signal. Now, time to undo. 1) The image checks for the last item in the list it keeps of undoable actions (see Generic/image.py::undo()). 2) The Layer sending the image is identified, and the Layer's undo() method is called (see Generic/entity.py::undo()) 3) If the layer has a LayerLog, the LayerLog undo() method is called (see Generic/logger.py::undo()) 4) The LayerLog takes the last item on its list - ('mod', 5) - and invokes the execute() method with the tuple as arguments. 5) The execute() method sees the first part of the tuple is 'mod', so the object id is extracted from the tuple (5), and the object having that id is found (our Point). (see Generic/layer.py::execute()). 6) The Point.undo() method is then invoked (see Generic/entity.py::execute()). 7) The Point checks to see if it has a PointLog, and as it does executes the PointLog's undo() method (see Generic/logger.py::undo()). 7) The PointLog pops the last thing off its list - ('moved', 0, 0) - and invokes the execute() method the the tuple as arguments. 8) The execuate method sees the first part of is 'moved', so the PointLog ends up invoking Point.setCoords() with the old coordinates as arguments. If you step through the example and look at the code, you'll see how the information for redo operations is stored when doing the undo. You'll also see how places where various messages get ignored. When executing an undo operation, the entity logs would become invalid if they tried to store the effects of the operation as if it was a non-undo type change. To accomplish this, startUndo()/endUndo() calls are placed around the object method that will be invoked to actually do the undo operation. > Other than the undo system uses, I'm not sure that this sort of macro > scripting is a good idea. After all, you could simply evaluate some > Python, or even have an embedded Perl interpreter. The problem with > these languages is that parsing for the sake of inversion is HARD. I'd say it is close to impossible. While not perfect by any stretch, the undo/redo approach used in PythonCAD is performing its job well. Yes, it can be improved, as the bug you found points out. I hope the description of the undo operation I gave above helps to explain how things currently work. Art -- 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 From ahaas at airmail.net Sun Sep 5 21:06:07 2004 From: ahaas at airmail.net (Art Haas) Date: Sun Sep 5 21:06:17 2004 Subject: [PythonCAD] more undo In-Reply-To: <200409040857.36531.ewilhelm@sbcglobal.net> References: <200409040857.36531.ewilhelm@sbcglobal.net> Message-ID: <20040905190607.GA4987@artsapartment.org> On Sat, Sep 04, 2004 at 08:57:36AM -0500, Eric Wilhelm wrote: > I'm poking at your undo system to see how it works. If I draw a line, > change the color, and then try ctrl+Z, I get this: > > > > saveUndoData: ('add', ('point', (4, 1), 159.0, 516.0)) > saveUndoData: ('add', ('point', (5, 1), 408.0, 326.0)) > saveUndoData: ('add', ('segment', (6, 1), (None, None, None, None), 4, > 5)) > saveUndoData: ('attr_changed', 'color', (255, 255, 255)) > saveUndoData: ('mod', 6) > Traceback (most recent call last): > File "./trunk/Interface/Gtk/gtkmenus.py", line 313, in edit_undo_cb > gtkimage.undo() > File "./trunk/Generic/image.py", line 916, in undo > _layer.undo() > File "./trunk/Generic/entity.py", line 256, in undo > self.__log.undo() > File "./trunk/Generic/logger.py", line 67, in undo > self.execute(True, *_data) > File "./trunk/Generic/layer.py", line 2388, in execute > _obj.undo() > File "./trunk/Generic/entity.py", line 256, in undo > self.__log.undo() > File "./trunk/Generic/logger.py", line 67, in undo > self.execute(True, *_data) > File "./trunk/Generic/segment.py", line 991, in execute > raise ValueError, "Unexpected operation: %s" % _op > ValueError: Unexpected operation: attr_changed > I've fixed this error now, and sent the corrected code to the public repo. Changing the linetype, thickness, and color of an object should now work. Styles still don't, unfortunately. The bug, as discussed in an earlier reply, was that the execute() method for the GraphicObjectLog was not being invoked. I tested these changes on segments and circles, but the bug would have also affected arcs, leaders, polylines, chamfers, and fillets as well. Art -- 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 From ahaas at airmail.net Wed Sep 8 22:02:20 2004 From: ahaas at airmail.net (Art Haas) Date: Wed Sep 8 22:02:28 2004 Subject: [PythonCAD] Repo updates with TextBlock undo/redo code Message-ID: <20040908200220.GQ4987@artsapartment.org> Hi. The public repo has some more stuff in it now. There is a new TextBlockLog class which handles the undo/redo code for TextBlock instances, and the Layer code has be modified to behave better when undoing a TextBlock addition. There was a bug report about this last week, and the root of the problem was that the info the Layer stores when adding a new entity was lacking for TextBlocks. Now, a TextBlock can be added, then the addition can be undone without generating an error. You can even redo the addition, then undo it again, then redo it, then undo it ad infinitum. I'm still aiming to make the seventeenth release this month. The sixteenth release came out in the middle of June, so another release is due. The next release will have printing capabilities, as well as improved text behavior, so this upcoming release will be a major advancement in the program. The lack of printing has been a big problem, and I am eager to release the program with this shortcoming now fixed. Art -- 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 From ahaas at airmail.net Thu Sep 9 20:16:09 2004 From: ahaas at airmail.net (Art Haas) Date: Thu Sep 9 20:16:17 2004 Subject: [PythonCAD] TextBlock text size changing now in repo Message-ID: <20040909181609.GX4987@artsapartment.org> Hi. Today's repo update has the first appearance of code allowing you to change the size of the text in a TextBlock. TextBlocks can be selected via the 'Edit' -> 'Select All' menus or by 'Edit' -> 'Select', then clicking on the TextBlock. Then, go to the 'Modify' -> 'Change' -> 'Text' menu and chose 'Size' (currently the only active choice). Type in the new size, and the selected TextBlock(s) have their size altered. I expect many of the other inactive menu choices for changing the TextBlock properties to get activated shortly. There will also be some upcoming modifications to the Preferences dialog that will allow you to set the text size to something other than the default 1.0. The longstanding problem of now clearly showing the selected entities is not yet solved, unfortunately. Also, the dialog box that pops up allowing you to change the size uses spinbox, and I suspect this will change to an entry box at some point. Art -- 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 From ahaas at airmail.net Fri Sep 10 00:20:49 2004 From: ahaas at airmail.net (Art Haas) Date: Fri Sep 10 00:20:58 2004 Subject: [PythonCAD] TextBlock text size changing now in repo In-Reply-To: <20040909181609.GX4987@artsapartment.org> References: <20040909181609.GX4987@artsapartment.org> Message-ID: <20040909222049.GA4987@artsapartment.org> On Thu, Sep 09, 2004 at 01:16:09PM -0500, Art Haas wrote: > > I expect many of the other inactive menu choices for changing the > TextBlock properties to get activated shortly. There will also be some > upcoming modifications to the Preferences dialog that will allow you to > set the text size to something other than the default 1.0. Code for changing the font style (normal/oblique/italic), font weight (normal/light/bold/heavy), and text alignment (left/center/right) is now in the repo as well. There is an occasional oddity when undoing a style or weight change that I'm chasing down, but other than that things work. Art -- 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 From ahaas at airmail.net Fri Sep 10 02:12:56 2004 From: ahaas at airmail.net (Art Haas) Date: Fri Sep 10 02:13:12 2004 Subject: [PythonCAD] TextBlock text size changing now in repo In-Reply-To: <20040909222049.GA4987@artsapartment.org> References: <20040909181609.GX4987@artsapartment.org> <20040909222049.GA4987@artsapartment.org> Message-ID: <20040910001256.GB4987@artsapartment.org> On Thu, Sep 09, 2004 at 05:20:49PM -0500, Art Haas wrote: > > Code for changing the font style (normal/oblique/italic), font weight > (normal/light/bold/heavy), and text alignment (left/center/right) is now > in the repo as well. There is an occasional oddity when undoing a style > or weight change that I'm chasing down, but other than that things work. Occasional oddity now gone. A missing startAction()/endAction() call pair around the creation and addition of a new TextBlock instance was the culprit. Art -- 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 From ahaas at airmail.net Fri Sep 10 20:06:17 2004 From: ahaas at airmail.net (Art Haas) Date: Fri Sep 10 20:06:31 2004 Subject: [PythonCAD] Text preference changes now in repo Message-ID: <20040910180617.GE4987@artsapartment.org> Hi. Today's update contains a reworked Preference's screen for setting the various TextBlock values. The new screen uses drop-down menus to set things like the font family, weight, and style. The preferences dialog now lets you set the text alignment via a drop-down meny, and the text size via an entry box. The layout of the widgets in this screen can use some improvement, but some of the long missing settings for TextBlocks are now available. There are smaller changes in the repo as well, including a change to the file writing code where fixing the TextBlock writing of weight and style values that differed from the TextStyle used by the TextBlock. The bug was introduced recently during the reworking of the TextBlock code, and due to the missing preference settings was hard to hit. Now that more of the TextBlock values can be adjusted, the bug made its appearance, and was quickly fixed. Art -- 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 From ahaas at airmail.net Mon Sep 13 20:32:53 2004 From: ahaas at airmail.net (Art Haas) Date: Mon Sep 13 20:33:01 2004 Subject: [PythonCAD] More textblock modification code in the repo Message-ID: <20040913183253.GE8363@artsapartment.org> Hi. The latest update has code for changing the TextBlock font family and font color. Things seem to work correctly. There is also a small change in the loading of drawings. Previously, when the drawing was being loaded, the addition of entities into the layer was stored in the undo history. Now, the layer will not do that, so a newly opened drawing will have no undo information stored. As much of last week was spent tweaking the TextBlock code, this week will be spent tweaking the Dimension text display code. The preference dialogs for Dimensions will be changed in a manner similar to that of the Text preference dialog. Also, I'll try to enhance some of the undo/redo code for Dimensions and DimStrings. After this flurry of text work is finished, I'm going to add a dialog box for printing, and remove the hard-coded bits that are currently defining the printing parameters. This work should begin this week. Art Haas -- 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 From ahaas at airmail.net Wed Sep 15 19:15:50 2004 From: ahaas at airmail.net (Art Haas) Date: Wed Sep 15 20:59:46 2004 Subject: [PythonCAD] Today's repo update Message-ID: <20040915171550.GN8363@artsapartment.org> Hi. There is lots of new things at the repo today. A good bit of work for improving the Dimension undo/redo abilities, as well as a new menu under 'Modify' -> 'Change' allowing various Dimension parameters to be altered. Finally the UI provides a way to change things like dimension color, endpoint type, endpoint size, etc. There are still many more dimension parameters that need interface support for adjustment, and hopefully I'll be able to add a few more goodies like this before too long. Art -- 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 From ahaas at airmail.net Wed Sep 15 23:04:44 2004 From: ahaas at airmail.net (Art Haas) Date: Wed Sep 15 23:04:58 2004 Subject: [PythonCAD] Today's repo update In-Reply-To: <20040915171550.GN8363@artsapartment.org> References: <20040915171550.GN8363@artsapartment.org> Message-ID: <20040915210444.GQ8363@artsapartment.org> On Wed, Sep 15, 2004 at 12:15:50PM -0500, Art Haas wrote: > Hi. > > [ ... snip ...] There are still many more dimension parameters > that need interface support for adjustment, and hopefully I'll > be able to add a few more goodies like this before too long. > I've added some more code to the repo that allows you to change some of the attributes of the primary dimension text now. Things like the default prefix, suffix, precision, units, printing leading zeros, and printing trailing decimals are now adjustable, while more text-like attributes (font, size, etc) are next on the agenda. The look of the dialog box that changes these values will be changing a bit as the missing text modification options appear. Also, some more undo/redo fixes are in the repo, especially those pertaining to Dimension and DimString instances. Art -- 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 From ahaas at airmail.net Fri Sep 24 02:35:05 2004 From: ahaas at airmail.net (Art Haas) Date: Fri Sep 24 02:35:16 2004 Subject: [PythonCAD] Latest repo code Message-ID: <20040924003505.GM17585@artsapartment.org> Hi. The repo now contains code allowing you to adjust more of the various values in the primary and secondary DimStrings in Dimension entities. The ability to change the color is missing right now, and I think I'm going to push fixing this until the next release as I need to tackle adding a print dialog box. A bug where trying to draw a rectangle by entering the points on the command line has also been fixed. Art Haas -- 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 From ewilhelm at sbcglobal.net Sat Sep 25 19:36:08 2004 From: ewilhelm at sbcglobal.net (Eric Wilhelm) Date: Sat Sep 25 19:35:47 2004 Subject: [PythonCAD] uber-converter status Message-ID: <200409251236.08678.ewilhelm@sbcglobal.net> Things are coming along here. The dxf2rhizopod.py program is mostly functional, as is the pythoncad2rhizopod.py. Going the other direction with dxf is going to take some work still. Getting rhizopod2pythoncad working is just a matter of writing the stream input code. There is support for 3D dxf as well. Transforming these entities into python/svg/ps is likely going to take a 'flattenner' filter. I was hoping to find some already-written python code in Blender for handling the OCS<->WCS transform, but no luck. So, after adding dot(), proj(), and comp() support to Scientific.Geometry.Vector (and then getting bounced by the author's mailserver), I translated my functions from CAD::Drawing::Calculate into python. If you want to play with this stuff, there are instructions in the subversion repository on how to get it and perform a pseudo-install. See the download section of the main page. http://ericwilhelm.homeip.net/uber-converter/ The monolithic-format connectors are changing into stream filters. The directory stuff is all handled by the rhizopod_stream and rhizopod_unstream programs. The latter is ripe for improvements related to the persistence of a directory, since it currently requires permission to smash the destination. Anybody want to code the dxf-write module? Or, for that matter, any other connector your heart desires. Additionally, dealing with dxf text is going to be tricky if the text is anything but left-justified. The "insert point" is always the bottom-left corner (which is different than the "grip" that you see when running autocad.) If anyone knows how to handle the various font-width issues, let me know. Maybe there's something in qcad that addresses it. Aside about Blender: The dxf import code is some 1500 lines of C with a comment in the middle about how it needs to be rewritten. So, once dxf2rhizopod is solid, it would be great to write a python import script to pull any rhizopod-connected format into Blender. Janek is planning to experiment with read/write connection to the actual directory, but a straight-import is a little simpler. --Eric -- "Matter will be damaged in direct proportion to its value." --Murphy's Constant From ahaas at airmail.net Mon Sep 27 22:39:03 2004 From: ahaas at airmail.net (Art Haas) Date: Mon Sep 27 22:39:19 2004 Subject: [PythonCAD] PythonCAD now can print! Message-ID: <20040927203903.GF4981@artsapartment.org> The latest code in the repo has replaced the temporary hard-coded print values with a simple dialog box that allows you to select various options like paper size, printing in landscape mode, and printing in color. At the bottom of the dialog are two entry boxes that allow you to either print to a filename of your choice (you have to enter the name in the entry box), or send the print to a printer (the entry box has "lp" as the default print command). If you send the file to the printer you may have to add various options in the entry like the printer name or possibly an option that tells the printer to print in landscape mode. The dialog box will be enhanced for the next release. I'd like to add something like a button which will bring up a FileSelection widget so that saving to a filename can have some graphical guidance instead of forcing you to /type/the/filename/in/like/this. I need to get in contact with the Zope developers to work out a namespace conflict that PythonCAD and Zope have, and once that is done I'll make an official release. Getting the first printing abilities into PythonCAD is something that has taken quite some time because printing exposed various weaknesses in some of the program classes. A known printing shortcoming is the lack of printing the dimension endpoint markers like arrowheads or slashes, and that should be fixed in release after the one coming up. Also, if you try to print a drawing with fonts not found in the printer, the print will most likely fail or at the very least look incorrect. Anyone with some PostScript experience out there who can make suggestions for addressing this? Try out the new printing code and let me know what you think! Art -- 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