2 # Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Art Haas
4 # This file is part of PythonCAD.
6 # PythonCAD is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # PythonCAD is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with PythonCAD; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 # the GTK code for displaying a drawing
24 from __future__
import division
35 from PythonCAD
.Interface
.Gtk
import gtkdimension
36 from PythonCAD
.Interface
.Gtk
import gtktext
37 from PythonCAD
.Interface
.Gtk
import gtkactions
39 from PythonCAD
.Generic
.image
import Image
40 from PythonCAD
.Generic
.point
import Point
41 from PythonCAD
.Generic
.conobject
import ConstructionObject
42 from PythonCAD
.Generic
.color
import Color
43 from PythonCAD
.Generic
.layer
import Layer
44 from PythonCAD
.Generic
import tools
45 from PythonCAD
.Generic
import globals
46 from PythonCAD
.Generic
import keywords
47 from PythonCAD
.Generic
import prompt
49 from PythonCAD
.Interface
.Gtk
import gtkshell
55 _debug
= False ## SDB debug stuff
56 globals.gtkcolors
= {}
57 globals.gtklinetypes
= {}
59 class GTKImage(object):
60 """The GTK wrapping around an Image
62 The GTKImage class is derived from the Image class, so it shares all
63 the attributes and methods of that class. The GTKImage class has the
64 following addtional methods:
66 close(): Close a GTKImage.
67 getWindow(): Get the GTK Window used in the GTKImage.
68 getEntry(): Get the GTK Entry used in the GTKImage.
69 getDA(): Get the GTK Drawing Area used in the GTKImage.
70 {get/set}Pixmap(): Get/Set the GTK Pixmap used in the GTKImage.
71 {get/set}Prompt(): Get/Set the prompt.
72 {get/set}Tool(): Get/Set the tool used for working in the GTKImage.
73 {get/set}UnitsPerPixel(): Get/Set this display parameter.
74 {get/set}View(): Get/Set the current view seen in the GTKImage.
75 getTolerance(): Get the current drawing tolerance.
76 {get/set}GC(): Get/Set the graphic context used in the GTKImage.
77 {get/set}Point(): Get/Set the current coordinates of the tool.
78 {get/set}Size(): Get/Set the size of the drawing area.
79 pixToCoordTransform(): Convert pixels to x/y coordinates.
80 coordToPixTransform(): Convert x/y coordinates to pixels.
81 refresh(): Redraw the screen using the current pixmap.
82 redraw(): Recalculate the visible entities and redraw the screen.
83 addGroup(): Add a new ActionGroup to the GTKImage.
84 getGroup(): Retrieve an ActionGroup from the GTKImage.
85 deleteGroup(): Remove an ActionGroup from the GTKImage.
92 from PythonCAD
.Interface
.Gtk
import gtkentities
93 from PythonCAD
.Interface
.Gtk
import gtkconobjs
94 from PythonCAD
.Interface
.Gtk
import gtkmodify
95 from PythonCAD
.Interface
.Gtk
import gtkmirror
96 from PythonCAD
.Interface
.Gtk
import gtkprinting
97 from PythonCAD
.Interface
.Gtk
import gtkedit
99 tools
.PasteTool
: gtkedit
.paste_mode_init
,
100 tools
.SelectTool
: gtkedit
.select_mode_init
,
101 tools
.DeselectTool
: gtkedit
.deselect_mode_init
,
102 tools
.PointTool
: gtkentities
.point_mode_init
,
103 tools
.SegmentTool
: gtkentities
.segment_mode_init
,
104 tools
.RectangleTool
: gtkentities
.rectangle_mode_init
,
105 tools
.CircleTool
: gtkentities
.circle_center_mode_init
,
106 tools
.TwoPointCircleTool
: gtkentities
.circle_tp_mode_init
,
107 tools
.ArcTool
: gtkentities
.arc_center_mode_init
,
108 tools
.ChamferTool
: gtkentities
.chamfer_mode_init
,
109 tools
.FilletTool
: gtkentities
.fillet_mode_init
,
110 tools
.LeaderTool
: gtkentities
.leader_mode_init
,
111 tools
.PolylineTool
: gtkentities
.polyline_mode_init
,
112 tools
.PolygonTool
: gtkentities
.polygon_mode_init
,
113 tools
.HCLineTool
: gtkconobjs
.hcline_mode_init
,
114 tools
.VCLineTool
: gtkconobjs
.vcline_mode_init
,
115 tools
.ACLineTool
: gtkconobjs
.acline_mode_init
,
116 tools
.CLineTool
: gtkconobjs
.cline_mode_init
,
117 tools
.PerpendicularCLineTool
: gtkconobjs
.perpendicular_cline_mode_init
,
118 tools
.TangentCLineTool
: gtkconobjs
.tangent_cline_mode_init
,
119 tools
.CCircleTangentLineTool
: gtkconobjs
.two_circle_tangent_line_mode_init
,
120 tools
.ParallelOffsetTool
: gtkconobjs
.parallel_offset_mode_init
,
121 tools
.CCircleTool
: gtkconobjs
.ccircle_cpmode_init
,
122 tools
.TwoPointCCircleTool
: gtkconobjs
.ccircle_tpmode_init
,
123 tools
.TangentCCircleTool
: gtkconobjs
.tangent_ccircle_mode_init
,
124 tools
.TwoPointTangentCCircleTool
: gtkconobjs
.two_cline_tancc_mode_init
,
125 tools
.TextTool
: gtktext
.text_add_init
,
126 tools
.HorizontalMoveTool
: gtkmodify
.move_horizontal_init
,
127 tools
.VerticalMoveTool
: gtkmodify
.move_vertical_init
,
128 tools
.MoveTool
: gtkmodify
.move_twopoint_init
,
129 tools
.HorizontalStretchTool
: gtkmodify
.stretch_horizontal_init
,
130 tools
.VerticalStretchTool
: gtkmodify
.stretch_vertical_init
,
131 tools
.StretchTool
: gtkmodify
.stretch_xy_init
,
132 tools
.TransferTool
: gtkmodify
.transfer_object_init
,
133 tools
.RotateTool
: gtkmodify
.rotate_init
,
134 tools
.SplitTool
: gtkmodify
.split_object_init
,
135 tools
.DeleteTool
: gtkmodify
.delete_mode_init
,
136 tools
.MirrorTool
: gtkmirror
.mirror_mode_init
,
137 tools
.ZoomTool
: gtkmodify
.zoom_init
,
138 tools
.LinearDimensionTool
: gtkdimension
.linear_mode_init
,
139 tools
.HorizontalDimensionTool
: gtkdimension
.horizontal_mode_init
,
140 tools
.VerticalDimensionTool
: gtkdimension
.vertical_mode_init
,
141 tools
.RadialDimensionTool
: gtkdimension
.radial_mode_init
,
142 tools
.AngularDimensionTool
: gtkdimension
.angular_mode_init
,
143 tools
.PlotTool
: gtkprinting
.plot_mode_init
,
146 def __init__(self
, image
):
147 debug_print("Initialized another GTKImage class instance...")
148 if not isinstance(image
, Image
):
149 raise TypeError, "Invalid Image type: " + `
type(image
)`
151 self
.__window
= gtk
.Window()
152 self
.__window
.set_title("Untitled")
153 self
.__window
.connect("destroy", self
.__destroyEvent
)
154 self
.__window
.connect("event", self
.__windowEvent
)
155 self
.__window
.connect("key_press_event", self
.__keyPressEvent
)
156 _width
= min(1024, int(0.8 * float(gtk
.gdk
.screen_width())))
157 _height
= min(768, int(0.8 * float(gtk
.gdk
.screen_height())))
158 self
.__window
.set_default_size(_width
, _height
)
160 main_vbox
= gtk
.VBox(False, 2)
161 main_vbox
.set_border_width(2)
162 self
.__window
.add(main_vbox
)
168 self
.__accel
= gtk
.AccelGroup()
169 self
.__window
.add_accel_group(self
.__accel
)
175 self
.__mb
= gtk
.MenuBar()
176 main_vbox
.pack_start(self
.__mb
, False, False)
179 # action group dictionary
185 # fixme - try to rework code to avoid this import ...
187 from PythonCAD
.Interface
.Gtk
.gtkmenus
import fill_menubar
188 fill_menubar(self
.__mb
, self
)
191 # drawing window has Horizontal Pane:
192 # left side: stuff for layer display
193 # right side: drawing area
197 main_vbox
.pack_start(pane
)
200 pane
.pack1(frame1
, True, False)
201 pane
.set_position(100)
204 # layer display stuff
207 _ld
= gtkshell
.LayerDisplay(self
.__image
, self
.__window
)
208 frame1
.add(_ld
.getWindow())
209 self
.__layerdisplay
= _ld
215 self
.__disp
_width
= None
216 self
.__disp
_height
= None
217 self
.__units
_per
_pixel
= 1.0
218 self
.__da
= gtk
.DrawingArea()
220 black
= gtk
.gdk
.color_parse('black')
221 self
.__da
.modify_fg(gtk
.STATE_NORMAL
, black
)
222 self
.__da
.modify_bg(gtk
.STATE_NORMAL
, black
)
223 pane
.pack2(self
.__da
, True, False)
224 self
.__da
.set_flags(gtk
.CAN_FOCUS
)
226 self
.__da
.connect("event", self
.__daEvent
)
227 self
.__da
.connect("expose_event", self
.__exposeEvent
)
228 self
.__da
.connect("realize", self
.__realizeEvent
)
229 self
.__da
.connect("configure_event", self
.__configureEvent
)
230 # self.__da.connect("focus_in_event", self.__focusInEvent)
231 # self.__da.connect("focus_out_event", self.__focusOutEvent)
233 self
.__da
.set_events(gtk
.gdk
.EXPOSURE_MASK |
234 gtk
.gdk
.LEAVE_NOTIFY_MASK |
235 gtk
.gdk
.BUTTON_PRESS_MASK |
236 gtk
.gdk
.BUTTON_RELEASE_MASK |
237 gtk
.gdk
.ENTER_NOTIFY_MASK|
238 gtk
.gdk
.LEAVE_NOTIFY_MASK|
239 gtk
.gdk
.KEY_PRESS_MASK |
240 gtk
.gdk
.KEY_RELEASE_MASK |
241 gtk
.gdk
.FOCUS_CHANGE_MASK |
242 gtk
.gdk
.POINTER_MOTION_MASK
)
244 lower_hbox
= gtk
.HBox(False, 2)
245 main_vbox
.pack_start(lower_hbox
, False, False)
247 self
.__prompt
= gtk
.Label(_('Enter Command:'))
248 lower_hbox
.pack_start(self
.__prompt
, False, False)
251 # where the action is taking place
254 self
.__coords
= gtk
.Label('(0,0)')
255 lower_hbox
.pack_end(self
.__coords
, False, False)
257 self
.__image
.setCurrentPoint(0.0, 0.0)
263 self
.__entry
= gtk
.Entry()
264 main_vbox
.pack_start(self
.__entry
, False, False)
265 self
.__entry
.connect("activate", self
.__entryEvent
)
268 # the Pixmap, GraphicContext, and CairoContext for the drawing
274 self
.__refresh
= True
277 # the viewable region and tolerance in the drawing
284 self
.__tolerance
= 1e-10
287 # establish message connections
290 _image
= self
.__image
291 _image
.connect('selected_object', self
.__selectedObject
)
292 _image
.connect('deselected_object', self
.__deselectedObject
)
293 _image
.connect('option_changed', self
.__optionChanged
)
294 _image
.connect('current_point_changed', self
.__currentPointChanged
)
295 _image
.connect('active_layer_changed', self
.__activeLayerChanged
)
296 _image
.connect('added_child', self
.__imageAddedChild
)
297 _image
.connect('removed_child', self
.__imageRemovedChild
)
298 _image
.connect('group_action_started', self
.__groupActionStarted
)
299 _image
.connect('group_action_ended', self
.__groupActionEnded
)
300 _image
.connect('units_changed', self
.__imageUnitsChanged
)
301 _image
.connect('tool_changed', self
.__imageToolChanged
)
303 _layers
= [_image
.getTopLayer()]
305 _layer
= _layers
.pop()
306 _layer
.connect('added_child', self
.__layerAddedChild
)
307 _layer
.connect('removed_child', self
.__layerRemovedChild
)
308 for _child
in _layer
.getChildren():
309 _child
.connect('refresh', self
.__refreshObject
)
310 _child
.connect('change_pending', self
.__objChangePending
)
311 _child
.connect('change_complete', self
.__objChangeComplete
)
312 _layers
.extend(_layer
.getSublayers())
314 #------------------------------------------------------------------
316 """Release the entites stored in the drawing.
320 self
.__layerdisplay
.close()
321 self
.__layerdisplay
= None
322 _image
= self
.__image
324 _image
.disconnect(self
)
325 _log
= _image
.getLog()
330 self
.__window
.destroy()
339 #------------------------------------------------------------------
340 def __destroyEvent(self
, widget
, data
=None):
342 for _i
in xrange(len(globals.imagelist
)):
343 _gimage
= globals.imagelist
[_i
]
344 if self
.__image
is _gimage
:
345 del globals.imagelist
[_i
]
346 if not len(globals.imagelist
):
351 #------------------------------------------------------------------
352 def __keyPressEvent(self
, widget
, event
, data
=None):
353 # print "__keyPressEvent()"
354 _entry
= self
.__entry
355 if _entry
.is_focus():
357 _tool
= self
.__image
.getTool()
358 if _tool
is not None and _tool
.hasHandler('entry_event'):
360 return _entry
.event(event
)
363 #------------------------------------------------------------------
364 def __windowEvent(self
, widget
, event
, data
=None):
366 debug_print("__windowEvent: Event type: %d" % _type
)
367 if _type
== gtk
.gdk
.BUTTON_PRESS
:
368 _button
= event
.button
369 debug_print("BUTTON_PRESS: %d" % _button
)
370 elif _type
== gtk
.gdk
.BUTTON_RELEASE
:
371 _button
= event
.button
372 debug_print("BUTTON_RELEASE: %d" % _button
)
373 elif _type
== gtk
.gdk
.KEY_PRESS
:
374 debug_print("KEY_PRESS")
375 if event
.keyval
== gtk
.keysyms
.Escape
:
376 debug_print("Got escape key")
379 elif _type
== gtk
.gdk
.KEY_RELEASE
:
380 debug_print("KEY_RELEASE")
385 #------------------------------------------------------------------
386 def __entryEvent(self
, widget
, data
=None):
388 # The error handling in this function needs work, and probably
389 # a rethink as how the commands are implemented is in order. Perhaps
390 # the command set should be stored in the image's global dictionary?
392 debug_print("__entryEvent()")
393 _entry
= self
.__entry
394 _text
= _entry
.get_text().strip()
396 _text
= _text
.lower()
397 if _text
== 'end' or _text
== 'stop':
398 _entry
.delete_text(0,-1)
401 _tool
= self
.__image
.getTool()
402 if _tool
is not None and _tool
.hasHandler("entry_event"):
403 _handler
= _tool
.getHandler("entry_event")
405 _handler(self
, widget
, _tool
)
406 except StandardError, e
:
407 print "exception called: " + str(e
)
409 _cmds
= keywords
.defaultglobals
410 _entry
.delete_text(0,-1)
411 # print "text is '%s'" % _text
413 # print "valid command"
415 # print "opt: '%s'" % _opt
416 _tooltype
= prompt
.lookup(_opt
)
417 # print "cmd: '%s'" % _cmd
418 if _tooltype
is not None:
419 self
.__image
.setTool(_tooltype())
421 # print "Calling exec for '%s'" % _text
422 # print "Command Error; See http://www.pythoncad.org/commands.html for reference page."
424 exec _text
in self
.__image
.getImageVariables()
426 print "error executing '%s' " % _text
428 # set the focus back to the DisplayArea widget
430 self
.__da
.grab_focus()
433 #------------------------------------------------------------------
434 def __exposeEvent(self
, widget
, event
, data
=None):
435 # print "__exposeEvent()"
436 _pixmap
= self
.__pixmap
437 _x
, _y
, _w
, _h
= event
.area
438 _gc
= widget
.get_style().fg_gc
[widget
.state
]
439 widget
.window
.draw_drawable(_gc
, _pixmap
, _x
, _y
, _x
, _y
, _w
, _h
)
442 #------------------------------------------------------------------
443 def __realizeEvent(self
, widget
, data
=None):
445 _width
, _height
= _win
.get_size()
446 self
.setSize(_width
, _height
)
447 widget
.set_size_request(100,100)
449 _gc
.set_exposures(True)
452 #------------------------------------------------------------------
453 def __configureEvent(self
, widget
, event
, data
=None):
455 _width
, _height
= _win
.get_size()
456 _disp_width
, _disp_height
= self
.getSize()
457 if _disp_width
!= _width
or _disp_height
!= _height
:
458 self
.setSize(_width
, _height
)
459 _pixmap
= gtk
.gdk
.Pixmap(_win
, _width
, _height
)
460 _gc
= widget
.get_style().fg_gc
[widget
.state
]
461 _pixmap
.draw_rectangle(_gc
, True, 0, 0, _width
, _height
)
462 self
.setPixmap(_pixmap
)
463 if hasattr(_pixmap
, 'cairo_create'):
464 self
.__ctx
= _pixmap
.cairo_create()
467 if _xmin
is None or _ymin
is None:
470 _upp
= self
.__units
_per
_pixel
471 self
.setView(_xmin
, _ymin
, _upp
)
474 #------------------------------------------------------------------
475 def __daEvent(self
, widget
, event
, data
=None):
478 # debug_print("__daEvent(): Event type: %d" % _type)
479 _tool
= self
.__image
.getTool()
480 if _type
== gtk
.gdk
.BUTTON_PRESS
:
481 self
.setToolpoint(event
)
482 _button
= event
.button
484 if _tool
is not None and _tool
.hasHandler("button_press"):
485 _rv
= _tool
.getHandler("button_press")(self
, widget
,
487 elif _type
== gtk
.gdk
.BUTTON_RELEASE
:
488 self
.setToolpoint(event
)
489 _button
= event
.button
491 if _tool
is not None and _tool
.hasHandler("button_release"):
492 _rv
=_tool
.getHandler("button_release")(self
, widget
,
494 elif _type
== gtk
.gdk
.MOTION_NOTIFY
:
495 self
.setToolpoint(event
)
496 if _tool
is not None and _tool
.hasHandler("motion_notify"):
497 _rv
= _tool
.getHandler('motion_notify')(self
, widget
,
499 elif _type
== gtk
.gdk
.KEY_PRESS
:
500 debug_print("In __daEvent(), got key press!")
502 if (_key
== gtk
.keysyms
.Page_Up
or
503 _key
== gtk
.keysyms
.Page_Down
or
504 _key
== gtk
.keysyms
.Left
or
505 _key
== gtk
.keysyms
.Right
or
506 _key
== gtk
.keysyms
.Up
or
507 _key
== gtk
.keysyms
.Down
):
508 debug_print("Got Arrow/PageUp/PageDown key")
509 pass # handle moving the drawing in some fashion ...
510 elif _key
== gtk
.keysyms
.Escape
:
511 debug_print("Got escape key")
514 elif _tool
is not None and _tool
.hasHandler("key_press"):
515 _rv
= _tool
.getHandler("key_press")(self
, widget
,
518 _entry
= self
.__entry
520 if _key
== gtk
.keysyms
.Tab
:
523 _rv
= _entry
.event(event
)
524 elif _type
== gtk
.gdk
.ENTER_NOTIFY
:
525 self
.setToolpoint(event
)
527 elif _type
== gtk
.gdk
.LEAVE_NOTIFY
:
528 self
.setToolpoint(event
)
531 debug_print("Got type %d" % _type
)
535 #------------------------------------------------------------------
536 def __focusInEvent(self
, widget
, event
, data
=None):
537 debug_print("in GTKImage::__focusInEvent()")
540 #------------------------------------------------------------------
541 def __focusOutEvent(self
, widget
, event
, data
=None):
542 debug_print("in GTKImage::__focusOutEvent()")
545 #------------------------------------------------------------------
546 def __selectedObject(self
, img
, *args
):
549 raise ValueError, "Invalid argument count: %d" % _alen
552 print "Selected object: " + `_obj`
553 _parent
= _obj
.getParent()
554 if _parent
.isVisible() and _obj
.isVisible():
555 _color
= Color('#ff7733') # FIXME color should be adjustable
556 _obj
.draw(self
, _color
)
557 self
.__refresh
= True
559 #------------------------------------------------------------------
560 def __deselectedObject(self
, img
, *args
):
563 raise ValueError, "Invalid argument count: %d" % _alen
566 print "Deselected object: " + `_obj`
567 _parent
= _obj
.getParent()
568 if _parent
.isVisible() and _obj
.isVisible():
570 self
.__refresh
= True
572 #------------------------------------------------------------------
573 def __optionChanged(self
, img
, *args
):
576 raise ValueError, "Invalid argument count: %d" % _alen
579 print "Option changed: '%s'" % _opt
580 if _opt
== 'BACKGROUND_COLOR':
581 _bc
= self
.__image
.getOption('BACKGROUND_COLOR')
582 _col
= gtk
.gdk
.color_parse(str(_bc
))
583 self
.__da
.modify_fg(gtk
.STATE_NORMAL
, _col
)
584 self
.__da
.modify_bg(gtk
.STATE_NORMAL
, _col
)
586 elif (_opt
== 'HIGHLIGHT_POINTS' or
587 _opt
== 'INACTIVE_LAYER_COLOR' or
588 _opt
== 'SINGLE_POINT_COLOR' or
589 _opt
== 'MULTI_POINT_COLOR'):
594 #------------------------------------------------------------------
595 def __currentPointChanged(self
, img
, *args
):
596 _x
, _y
= self
.__image
.getCurrentPoint()
597 self
.__coords
.set_text("%.4f, %.4f" % (_x
, _y
))
600 #------------------------------------------------------------------
601 def __activeLayerChanged(self
, img
, *args
):
604 raise ValueError, "Invalid argument count: %d" % _alen
605 _prev_layer
= args
[0]
606 self
.drawLayer(_prev_layer
)
607 _active_layer
= self
.__image
.getActiveLayer()
608 self
.drawLayer(_active_layer
)
613 """Return the Image being displayed.
619 image
= property(getImage
, None, None, "Displayed Image")
621 #------------------------------------------------------------------
623 """Return the gtk.AccelGroup in the GTKImage.
629 accel
= property(getAccel
, None, None, "Accel group in the GTKImage.")
631 #------------------------------------------------------------------
633 """Return a handle to the gtk.Window in the GTKImage.
639 window
= property(getWindow
, None, None, "Main GTK Window for a GTKImage.")
641 #------------------------------------------------------------------
643 """Return a handle to the gtk.Entry in the GTKImage.
649 entry
= property(getEntry
, None, None, "Entry box for a GTKImage.")
651 #------------------------------------------------------------------
653 """Return the gtk.DrawingArea in the GTKImage.
659 da
= property(getDA
, None, None, "DrawingArea for a GTKImage.")
661 #------------------------------------------------------------------
663 """Return the Pixmap for the GTKImage.
669 #------------------------------------------------------------------
670 def setPixmap(self
, pixmap
):
671 """Set the Pixmap for the GTKImage.
675 self
.__pixmap
= pixmap
677 pixmap
= property(getPixmap
, setPixmap
, None, "Pixmap for a GTKImage.")
679 #------------------------------------------------------------------
681 """Return the current prompt string.
685 return self
.__prompt
.get_label()
687 #------------------------------------------------------------------
688 def setPrompt(self
, p
):
689 """Set the current prompt string.
693 if not isinstance(p
, types
.StringTypes
):
694 raise TypeError, "Invalid prompt type: " + `
type(p
)`
695 self
.__prompt
.set_text(p
)
697 prompt
= property(getPrompt
, setPrompt
, None, "Prompt string.")
699 #------------------------------------------------------------------
700 def setTool(self
, tool
):
701 """Replace the tool in the image with a new Tool.
705 The argument 'tool' should be an instance of a Tool object.
707 warnings
.warn("Method setTool() is deprecated - use getImage().setTool()", stacklevel
=2)
708 self
.__image
.setTool(tool
)
710 #------------------------------------------------------------------
712 """Return the current Tool used in the drawing.
716 warnings
.warn("Method getTool() is deprecated - use getImage().getTool()", stacklevel
=2)
717 return self
.__image
.getTool()
719 tool
= property(getTool
, None, None, "Tool for adding/modifying entities.")
721 #------------------------------------------------------------------
722 def getUnitsPerPixel(self
):
723 """Return the current value of units/pixel.
727 return self
.__units
_per
_pixel
729 #------------------------------------------------------------------
730 def setUnitsPerPixel(self
, upp
):
731 """Set the current value of units/pixel.
733 setUnitsPerPixel(upp)
735 The argument 'upp' should be a positive float value.
738 if not isinstance(_upp
, float):
741 raise ValueError, "Invalid scale value: %g" % _upp
742 self
.__units
_per
_pixel
= _upp
743 self
.__tolerance
= _upp
* 5.0
745 #------------------------------------------------------------------
746 def setView(self
, xmin
, ymin
, scale
=None):
747 """Set the current visible area in a drawing.
749 setView(xmin, ymin[, scale])
751 xmin: Minimum visible x-coordinate
752 ymin: Minimum visible y-coordinate
754 The optional argument 'scale' defaults to the current
755 value of units/pixel (set with getUnitsPerPixel() method.)
756 This value must be a positive float.
759 if not isinstance(_xmin
, float):
762 if not isinstance(_ymin
, float):
766 _scale
= self
.__units
_per
_pixel
767 if not isinstance(_scale
, float):
768 _scale
= float(scale
)
770 raise ValueError, "Invalid scale value: %g" % _scale
771 _xmax
= _xmin
+ (_scale
* self
.__disp
_width
)
772 _ymax
= _ymin
+ (_scale
* self
.__disp
_height
)
774 if abs(_scale
- self
.__units
_per
_pixel
) > 1e-10:
775 self
.__units
_per
_pixel
= _scale
777 self
.__tolerance
= self
.__units
_per
_pixel
* 5.0
783 self
.calcTextWidths()
786 #------------------------------------------------------------------
787 def calcTextWidths(self
):
788 """Calculate the width of the text strings in the Image.
792 _layers
= [self
.__image
.getTopLayer()]
794 _layer
= _layers
.pop()
795 for _tblock
in _layer
.getLayerEntities('text'):
796 gtktext
.set_textblock_bounds(self
, _tblock
)
797 for _dim
in _layer
.getLayerEntities('linear_dimension'):
798 _ds1
, _ds2
= _dim
.getDimstrings()
799 gtktext
.set_textblock_bounds(self
, _ds1
)
800 if _dim
.getDualDimMode():
801 gtktext
.set_textblock_bounds(self
, _ds2
)
802 for _dim
in _layer
.getLayerEntities('horizontal_dimension'):
803 _ds1
, _ds2
= _dim
.getDimstrings()
804 gtktext
.set_textblock_bounds(self
, _ds1
)
805 if _dim
.getDualDimMode():
806 gtktext
.set_textblock_bounds(self
, _ds2
)
807 for _dim
in _layer
.getLayerEntities('vertical_dimension'):
808 _ds1
, _ds2
= _dim
.getDimstrings()
809 gtktext
.set_textblock_bounds(self
, _ds1
)
810 if _dim
.getDualDimMode():
811 gtktext
.set_textblock_bounds(self
, _ds2
)
812 for _dim
in _layer
.getLayerEntities('radial_dimension'):
813 _ds1
, _ds2
= _dim
.getDimstrings()
814 gtktext
.set_textblock_bounds(self
, _ds1
)
815 if _dim
.getDualDimMode():
816 gtktext
.set_textblock_bounds(self
, _ds2
)
817 for _dim
in _layer
.getLayerEntities('angular_dimension'):
818 _ds1
, _ds2
= _dim
.getDimstrings()
819 gtktext
.set_textblock_bounds(self
, _ds1
)
820 if _dim
.getDualDimMode():
821 gtktext
.set_textblock_bounds(self
, _ds2
)
822 _layers
.extend(_layer
.getSublayers())
824 #------------------------------------------------------------------
826 """Return the current visible area in a drawing.
830 This method returns a tuple with four float values:
832 (xmin, ymin, xmax, ymax)
834 If the view has never been set, each of these values
837 return (self
.__xmin
, self
.__ymin
, self
.__xmax
, self
.__ymax
)
839 view
= property(getView
, setView
, None, "The visible area in a drawing.")
841 #------------------------------------------------------------------
842 def getTolerance(self
):
843 """Return the current drawing tolerance.
847 return self
.__tolerance
849 tolerance
= property(getTolerance
, None, None, "Drawing tolerance.")
852 """Return the GraphicContext allocated for the GTKImage.
858 #------------------------------------------------------------------
860 """Set the GraphicContext for the GTKImage.
864 if not isinstance(gc
, gtk
.gdk
.GC
):
865 raise TypeError, "Invalid GC object: " + `gc`
866 if self
.__gc
is None:
869 gc
= property(getGC
, None, None, "GraphicContext for the GTKImage.")
871 #------------------------------------------------------------------
872 def getCairoContext(self
):
873 """Return the CairoContext allocated for the GTKImage.
879 ctx
= property(getCairoContext
, None, None, "CairoContext for the GTKImage.")
881 #------------------------------------------------------------------
883 """Return the size of the DrawingArea window.
887 return (self
.__disp
_width
, self
.__disp
_height
)
889 #------------------------------------------------------------------
890 def setSize(self
, width
, height
):
891 """Set the size of the DrawingArea window.
893 setSize(width, height)
896 if not isinstance(_width
, int):
899 raise ValueError, "Invalid drawing area width: %d" % _width
901 if not isinstance(_height
, int):
902 _height
= int(height
)
904 raise ValueError, "Invalid drawing area height: %d" % _height
905 self
.__disp
_width
= _width
906 self
.__disp
_height
= _height
908 #------------------------------------------------------------------
909 def setToolpoint(self
, event
):
912 _tx
, _ty
= self
.pixToCoordTransform(_x
, _y
)
913 self
.__image
.setCurrentPoint(_tx
, _ty
)
915 #------------------------------------------------------------------
916 def addGroup(self
, group
):
917 """Add an ActionGroup to the GTKImage.
921 Argument 'group' must be either an instance of either
922 gtk.Action gtk.stdAction.
924 if not isinstance(group
, gtk
.ActionGroup
):
925 if not isinstance(gtkactions
.stdActionGroup
):
926 raise TypeError, "Invalid group type: " + `
type(group
)`
927 self
.__groups
[group
.get_name()] = group
929 #------------------------------------------------------------------
930 def getGroup(self
, name
):
931 """Return an ActionGroup stored in the GTKImage.
935 Argument 'name' should be the name of the ActionGroup. This method
936 will return None if no group by that name is stored.
938 return self
.__groups
.get(name
)
940 #------------------------------------------------------------------
941 def deleteGroup(self
, name
):
942 """Remove an ActionGroup stored in the GTKImage.
946 Argument 'name' should be the name of the ActionGroup to be removed.
948 if name
in self
.__groups
:
949 del self
.__groups
[name
]
951 #------------------------------------------------------------------
952 def pixToCoordTransform(self
, xp
, yp
):
953 """Convert from pixel coordinates to x-y coordinates.
955 pixToCoordTransform(xp, yp)
957 The function arguments are:
962 The function returns a tuple holding two float values
964 _upp
= self
.__units
_per
_pixel
965 _xc
= self
.__xmin
+ (xp
* _upp
)
966 _yc
= self
.__ymax
- (yp
* _upp
)
969 #------------------------------------------------------------------
970 def coordToPixTransform(self
, xc
, yc
):
971 """Convert from x-y coordinates to pixel coordinates
973 coordToPixTransform(xc, yc)
975 The function arguments are:
980 The function returns a tuple holding two integer values
982 _upp
= self
.__units
_per
_pixel
983 _xp
= int((xc
- self
.__xmin
)/_upp
)
984 _yp
= int((self
.__ymax
- yc
)/_upp
)
987 #------------------------------------------------------------------
988 def getColor(self
, c
):
989 """Return an allocated color for a given Color object.
993 Argument 'c' must be a Color object. This method will return an
996 if not isinstance(c
, Color
):
997 raise TypeError, "Invalid Color object: " + `
type(c
)`
998 _color
= globals.gtkcolors
.get(c
)
1000 # _r = int(round(65535.0 * (c.r/255.0)))
1001 # _g = int(round(65535.0 * (c.g/255.0)))
1002 # _b = int(round(65535.0 * (c.b/255.0)))
1003 # _color = self.__da.get_colormap().alloc_color(_r, _g, _b)
1004 _color
= self
.__da
.get_colormap().alloc_color(str(c
))
1005 globals.gtkcolors
[c
] = _color
1008 #------------------------------------------------------------------
1010 """Redraw the image so all entities are visible in the window.
1014 _fw
= float(self
.__disp
_width
)
1015 _fh
= float(self
.__disp
_height
)
1016 _xmin
, _ymin
, _xmax
, _ymax
= self
.__image
.getExtents()
1017 _xdiff
= abs(_xmax
- _xmin
)
1018 _ydiff
= abs(_ymax
- _ymin
)
1019 _xmid
= (_xmin
+ _xmax
)/2.0
1020 _ymid
= (_ymin
+ _ymax
)/2.0
1024 _scale
= _xs
* 1.05 # make it a little larger
1026 _scale
= _ys
* 1.05 # make it a little larger
1027 _xm
= _xmid
- (_fw
/2.0) * _scale
1028 _ym
= _ymid
- (_fh
/2.0) * _scale
1029 self
.setView(_xm
, _ym
, _scale
)
1031 #------------------------------------------------------------------
1033 """This method does a screen refresh.
1037 If entities in the drawing have been added, removed, or
1038 modified, use the redraw() method.
1041 if (_da
.flags() & gtk
.MAPPED
):
1042 # print "refreshing ..."
1043 _gc
= _da
.get_style().fg_gc
[gtk
.STATE_NORMAL
]
1044 _gc
.set_function(gtk
.gdk
.COPY
)
1047 #------------------------------------------------------------------
1049 """This method draws all the objects visible in the window.
1054 if (_da
.flags() & gtk
.MAPPED
):
1056 print "Redrawing image"
1061 _gc
= _da
.get_style().fg_gc
[gtk
.STATE_NORMAL
]
1062 self
.__pixmap
.draw_rectangle(_gc
, True, 0, 0,
1063 self
.__disp
_width
, self
.__disp
_height
)
1064 _active_layer
= self
.__image
.getActiveLayer()
1065 _layers
= [self
.__image
.getTopLayer()]
1066 while (len(_layers
)):
1067 _layer
= _layers
.pop()
1068 if _layer
is not _active_layer
:
1069 self
.drawLayer(_layer
)
1070 _layers
.extend(_layer
.getSublayers())
1071 self
.drawLayer(_active_layer
)
1073 # redraw selected entities
1075 _color
= Color('#ff7733')
1076 for _obj
in self
.__image
.getSelectedObjects(False):
1077 _obj
.draw(self
, _color
)
1080 #------------------------------------------------------------------
1081 def drawLayer(self
, l
):
1082 if not isinstance(l
, Layer
):
1083 raise TypeError, "Invalid layer type: " + `
type(l
)`
1084 if l
.getParent() is not self
.__image
:
1085 raise ValueError, "Layer not found in Image"
1087 _col
= self
.__image
.getOption('INACTIVE_LAYER_COLOR')
1088 if l
is self
.__image
.getActiveLayer():
1093 for _obj
in l
.objsInRegion(self
.__xmin
, self
.__ymin
, self
.__xmax
, self
.__ymax
):
1094 if _obj
.isVisible():
1095 if isinstance(_obj
, Point
):
1097 elif isinstance(_obj
, ConstructionObject
):
1102 _obj
.draw(self
, _col
)
1104 _obj
.draw(self
, _col
)
1106 _obj
.draw(self
, _col
)
1108 #------------------------------------------------------------------
1110 """Set the image to an initial drawing state.
1114 _tool
= self
.__image
.getTool()
1117 # If _tool is None, deselect any selected objects in view.
1118 # This way, if you are currently using a tool, then the
1119 # first time you hit escape, you just clear the tool.
1120 # The second time clears all selections.
1121 debug_print("Entered reset")
1123 debug_print(".....This is second time to be in reset")
1124 self
.__image
.clearSelectedObjects()
1125 self
.__image
.setTool()
1127 self
.setPrompt(_('Enter command'))
1130 # Entity drawing operations
1133 def __drawObject(self
, obj
, col
=None):
1134 # print "__drawObject()"
1136 if self
.__xmin
is None:
1138 _xmin
, _ymin
, _xmax
, _ymax
= self
.getView()
1139 if obj
.inRegion(_xmin
, _ymin
, _xmax
, _ymax
):
1140 _image
= self
.__image
1142 if obj
.getParent() is not _image
.getActiveLayer():
1143 _col
= _image
.getOption('INACTIVE_LAYER_COLOR')
1144 obj
.draw(self
, _col
)
1145 self
.__refresh
= True
1147 def __eraseObject(self
, obj
):
1148 # print "__eraseObject()"
1149 _xmin
, _ymin
, _xmax
, _ymax
= self
.getView()
1150 if self
.__xmin
is None:
1152 if obj
.inRegion(_xmin
, _ymin
, _xmax
, _ymax
):
1154 self
.__refresh
= True
1156 def __imageAddedChild(self
, obj
, *args
):
1157 # print "__imageAddedChild()"
1160 raise ValueError, "Invalid argument count: %d" % _alen
1162 if not isinstance(_layer
, Layer
):
1163 raise TypeError, "Unexpected child type: " + `
type(_layer
)`
1164 _layer
.connect('added_child', self
.__layerAddedChild
)
1165 _layer
.connect('removed_child', self
.__layerRemovedChild
)
1167 def __layerAddedChild(self
, obj
, *args
):
1168 # print "__layerAddedChild()"
1171 raise ValueError, "Invalid argument count: %d" % _alen
1172 _child
= args
[0] # need some verification test here ...
1173 _child
.connect('refresh', self
.__refreshObject
)
1174 _child
.connect('change_pending', self
.__objChangePending
)
1175 _child
.connect('change_complete', self
.__objChangeComplete
)
1176 if _child
.isVisible() and obj
.isVisible():
1177 self
.__drawObject
(_child
)
1179 def __imageRemovedChild(self
, obj
, *args
):
1180 # print "__imageRemovedChild()"
1183 raise ValueError, "Invalid argument count: %d" % _alen
1185 if not isinstance(_layer
, Layer
):
1186 raise TypeError, "Unexpected child type: " + `
type(_layer
)`
1187 _layer
.disconnect(self
)
1189 def __layerRemovedChild(self
, obj
, *args
):
1190 # print "__layerRemovedChild()"
1193 raise ValueError, "Invalid argument count: %d" % _alen
1194 _child
= args
[0] # need some verification test here ...
1195 if _child
.isVisible() and obj
.isVisible():
1196 self
.__eraseObject
(_child
)
1197 _child
.disconnect(self
)
1199 def __groupActionStarted(self
, obj
, *args
):
1200 # print "__groupActionStarted()"
1201 self
.__refresh
= False
1203 def __groupActionEnded(self
, obj
, *args
):
1204 # print "__groupActionEnded()"
1208 self
.__refresh
= True
1210 def __imageUnitsChanged(self
, obj
, *args
):
1211 # print "__imageUnitsChanged()"
1214 def __imageToolChanged(self
, obj
, *args
):
1215 _tool
= self
.__image
.getTool()
1216 if _tool
is not None:
1217 _init
= GTKImage
.__inittool
.get(type(_tool
))
1218 if _init
is not None:
1221 def __objChangePending(self
, obj
, *args
):
1222 # print "__objChangePending()" + `obj`
1225 raise ValueError, "Invalid argument count: %d" % _alen
1227 if (obj
.isVisible() and
1228 obj
.getParent().isVisible() and
1229 _change
!= 'added_user' and
1230 _change
!= 'removed_user'):
1231 self
.__eraseObject
(obj
)
1233 def __objChangeComplete(self
, obj
, *args
):
1234 # print "__objChangeComplete()" + `obj`
1235 if obj
.isVisible() and obj
.getParent().isVisible():
1236 self
.__drawObject
(obj
)
1238 def __refreshObject(self
, obj
, *args
):
1239 # print "__refreshObject()"
1241 if not obj
.isVisible() or not obj
.getParent().isVisible():
1242 _col
= self
.__image
.getOption('BACKGROUND_COLOR')
1243 self
.__drawObject
(obj
, _col
)
1245 #------------------------------------------------------------------
1246 def debug_print(string
):
1248 print "SDB Debug: " + string