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