Updating download.html page with Git information
[pythoncad.git] / PythonCAD / Interface / Gtk / gtkprinting.py
blob320a403f6cb6d5249a3787e11f3ea611e451710c
2 # Copyright (c) 2004, 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 # code for setting printing parameters
24 import pygtk
25 pygtk.require('2.0')
26 import gtk
28 import os
29 import tempfile
31 from PythonCAD.Generic.plotfile import Plot
32 from PythonCAD.Generic.printing import PSPlot
34 def _toggle_widgets_on(widget):
35 widget.set_sensitive(True)
37 def _toggle_widgets_off(widget):
38 widget.set_sensitive(False)
40 def _print_rb_cb(button, hbox):
41 if button.get_active():
42 hbox.foreach(_toggle_widgets_on)
43 else:
44 hbox.foreach(_toggle_widgets_off)
45 return True
47 def _error_dialog(gtkimage, errmsg):
48 _window = gtkimage.getWindow()
49 _dialog = gtk.MessageDialog(_window,
50 gtk.DIALOG_DESTROY_WITH_PARENT,
51 gtk.MESSAGE_ERROR,
52 gtk.BUTTONS_CLOSE,
53 errmsg)
54 _dialog.run()
55 _dialog.destroy()
57 def print_dialog(gtkimage, plot):
58 _window = gtkimage.getWindow()
59 _dialog = gtk.Dialog(_('Printing Preferences'), _window,
60 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
61 (gtk.STOCK_OK, gtk.RESPONSE_OK,
62 gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
63 _vbox = _dialog.vbox
65 _psplot = PSPlot(plot)
67 # options for all plots
69 _frame = gtk.Frame(_('Plot Options'))
70 _fvbox = gtk.VBox(False, 5)
71 _fvbox.set_border_width(5)
72 _frame.add(_fvbox)
73 _ccb = gtk.CheckButton(_('Print in Color'))
74 _fvbox.pack_start(_ccb, False, False, 5)
75 _icb = gtk.CheckButton(_('Print White as Black'))
76 _fvbox.pack_start(_icb, False, False, 5)
77 _lcb = gtk.CheckButton(_('Print in Landscape Mode'))
78 _fvbox.pack_start(_lcb, False, False, 5)
79 _hbox = gtk.HBox(False, 5)
80 _fvbox.pack_start(_hbox, True, True, 5)
81 _label = gtk.Label(_('Paper Size:'))
82 _hbox.pack_start(_label, False, False, 5)
83 _papersizes = _psplot.getPaperSizes()
84 _papersizes.sort()
85 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4
86 _size_widget = gtk.combo_box_new_text()
87 for _size in _papersizes:
88 _size_widget.append_text(_size)
89 _size_widget.set_active(0) # perhaps a global preferences value?
90 else:
91 _menu = gtk.Menu()
92 for _size in _papersizes:
93 _item = gtk.MenuItem(_size)
94 _menu.append(_item)
95 _size_widget = gtk.OptionMenu()
96 _size_widget.set_menu(_menu)
97 _size_widget.set_history(0) # perhaps a global preference value?
98 _hbox.pack_start(_size_widget, False, False, 5)
99 _vbox.pack_start(_frame, False, False, 5)
102 _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
103 _frame = gtk.Frame(_('Print Destination'))
104 _fvbox = gtk.VBox(False, 5)
105 _fvbox.set_border_width(5)
106 _frame.add(_fvbox)
108 _phbox = gtk.HBox(False, 5)
109 _label = gtk.Label(_('Printer:'))
110 _label_size_group.add_widget(_label)
111 _phbox.pack_start(_label, False, False, 5)
112 _print_entry = gtk.Entry()
113 _print_entry.set_text("lp")
114 _phbox.pack_start(_print_entry, False, False, 5)
115 _fvbox.pack_start(_phbox, False, False, 5)
117 _fhbox = gtk.HBox(False, 5)
118 _label = gtk.Label(_('File:'))
119 _label_size_group.add_widget(_label)
120 _label.set_sensitive(False)
121 _fhbox.pack_start(_label, False, False, 5)
122 _file_entry = gtk.Entry()
123 _file_entry.set_sensitive(False)
124 _fhbox.pack_start(_file_entry, False, False, 5)
125 _fvbox.pack_start(_fhbox, False, False, 5)
127 _hbox = gtk.HBox(False, 5)
128 _label = gtk.Label(_('Send print to ...'))
129 _label_size_group.add_widget(_label)
130 _hbox.pack_start(_label, False, False, 5)
131 _prb = gtk.RadioButton()
132 _prb.set_label(_('Printer'))
133 _prb.set_mode(True)
134 _prb.connect("toggled", _print_rb_cb, _phbox)
135 _hbox.pack_start(_prb, False, False, 5)
136 _frb = gtk.RadioButton(_prb)
137 _frb.set_label(_('File'))
138 _frb.set_mode(True)
139 _frb.connect("toggled", _print_rb_cb, _fhbox)
140 _hbox.pack_start(_frb, False, False, 5)
141 _fvbox.pack_start(_hbox, False, False, 5)
143 _vbox.pack_start(_frame, False, False, 5)
144 _dialog.show_all()
145 while True:
146 _response = _dialog.run()
147 if _response == gtk.RESPONSE_OK:
148 plot.setColorMode(_ccb.get_active())
149 plot.invertWhite(_icb.get_active())
150 plot.setLandscapeMode(_lcb.get_active())
151 plot.getPlotData()
152 if hasattr(gtk, 'ComboBox') and isinstance(_size_widget, gtk.ComboBox):
153 _idx = _size_widget.get_active()
154 elif isinstance(_size_widget, gtk.OptionMenu):
155 _idx = _sizewidget.get_history()
156 else:
157 raise TypeError, "Unexpected size_widget: " + `type(_size_widget)`
158 _psplot.setSize(_papersizes[_idx])
159 if _prb.get_active(): # send job out
160 try:
161 _f = tempfile.NamedTemporaryFile()
162 _fname = _f.name
163 try:
164 try:
165 _psplot.write(_f)
166 _cmd = "%s %s" %(_print_entry.get_text(), _fname)
167 try:
168 _res = os.system(_cmd)
169 if _res == 0:
170 break
171 else:
172 _msg = "Non-zero exit status from '%s': %d" % (_cmd, _res)
173 _error_dialog(gtkimage, _msg)
174 except StandardError, _err:
175 _msg = "Error executing command '%s': %s" % (_cmd, _err)
176 _error_dialog(gtkimage, _msg)
177 except StandardError, _err:
178 _msg = "Error writing '%s': %s" % (_fname, _err)
179 _error_dialog(gtkimage, _msg)
180 finally:
181 _f.close()
182 except StandardError, _err:
183 _msg = "Error creating temporary file %s" % _err
184 _error_dialog(gtkimage, _msg)
185 else:
186 _fname = _file_entry.get_text()
187 try:
188 _f = file(_fname, "w")
189 try:
190 _psplot.write(_f)
191 finally:
192 _f.close()
193 break
194 except StandardError, _err:
195 _msg = "Error writing to %s: %s" % (_fname, _err)
196 _error_dialog(gtkimage, _msg)
197 else:
198 break
199 _psplot.finish()
200 _dialog.destroy()
202 def _show_print_dialog(gtkimage, tool=None):
203 _plot = Plot(gtkimage.image)
204 _tool = gtkimage.getImage().getTool()
205 _x1, _y1 = _tool.getFirstCorner()
206 _x2, _y2 = _tool.getSecondCorner()
207 _xmin = min(_x1, _x2)
208 _ymin = min(_y1, _y2)
209 _xmax = max(_x1, _x2)
210 _ymax = max(_y1, _y2)
211 _plot.setBounds(_xmin, _ymin, _xmax, _ymax)
212 _tool.reset()
213 plot_mode_init(gtkimage)
214 gtkimage.refresh()
215 print_dialog(gtkimage, _plot)
217 def plot_motion_notify(gtkimage, widget, event, tool):
218 _tx, _ty = tool.getFirstCorner()
219 _px, _py = gtkimage.coordToPixTransform(_tx, _ty)
220 _gc = gtkimage.getGC()
221 _x = int(event.x)
222 _y = int(event.y)
223 _cp = tool.getCurrentPoint()
224 if _cp is not None:
225 _xc, _yc = _cp
226 _xmin = min(_xc, _px)
227 _ymin = min(_yc, _py)
228 _rw = abs(_xc - _px)
229 _rh = abs(_yc - _py)
230 widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh)
231 tool.setCurrentPoint(_x, _y)
232 _xmin = min(_x, _px)
233 _ymin = min(_y, _py)
234 _rw = abs(_x - _px)
235 _rh = abs(_y - _py)
236 widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh)
237 return True
239 def _make_tuple(text, gdict):
240 _tpl = eval(text, gdict)
241 if not isinstance(_tpl, tuple):
242 raise TypeError, "Invalid tuple: " + `type(_tpl)`
243 if len(_tpl) != 2:
244 raise ValueError, "Invalid tuple: " + str(_tpl)
245 return _tpl
247 def plot_second_button_press_cb(gtkimage, widget, event, tool):
248 _tol = gtkimage.getTolerance()
249 _image = gtkimage.getImage()
250 _x, _y = _image.getCurrentPoint()
251 _pt, _pc = _image.getClosestPoint(_x, _y, tolerance=_tol)
252 if _pt is not None:
253 _x, _y = _pt.getCoords()
254 else:
255 _x, _y = _pc
256 tool.setSecondCorner(_x, _y)
257 _show_print_dialog(gtkimage, tool)
258 return True
260 def plot_second_entry_event_cb(gtkimage, widget, tool):
261 _entry = gtkimage.getEntry()
262 _text = _entry.get_text()
263 _entry.delete_text(0,-1)
264 if len(_text):
265 _x, _y = _make_tuple(_text, gtkimage.image.getImageVariables())
266 tool.setSecondCorner(_x, _y)
267 _show_print_dialog(gtkimage, tool)
269 def plot_first_button_press_cb(gtkimage, widget, event, tool):
270 _tol = gtkimage.getTolerance()
271 _image = gtkimage.getImage()
272 _x, _y = _image.getCurrentPoint()
273 _pt, _pc = _image.getClosestPoint(_x, _y, tolerance=_tol)
274 if _pt is not None:
275 _x, _y = _pt.getCoords()
276 else:
277 _x, _y = _pc
278 tool.setFirstCorner(_x, _y)
279 gtkimage.setPrompt(_('Click in the drawing area or enter another point'))
280 tool.setHandler("button_press", plot_second_button_press_cb)
281 tool.setHandler("entry_event", plot_second_entry_event_cb)
282 tool.setHandler("motion_notify", plot_motion_notify)
283 gtkimage.getGC().set_function(gtk.gdk.INVERT)
284 return True
286 def plot_first_entry_event_cb(gtkimage, widget, tool):
287 _entry = gtkimage.getEntry()
288 _text = _entry.get_text()
289 _entry.delete_text(0,-1)
290 if len(_text):
291 _x, _y = _make_tuple(_text, gtkimage.image.getImageVariables())
292 tool.setFirstCorner(_x, _y)
293 gtkimage.setPrompt(_('Click in the drawing area or enter another point'))
294 tool.setHandler("button_press", plot_second_button_press_cb)
295 tool.setHandler("entry_event", plot_second_entry_event_cb)
296 tool.setHandler("motion_notify", plot_motion_notify)
297 gtkimage.getGC().set_function(gtk.gdk.INVERT)
299 def plot_mode_init(gtkimage, tool=None):
300 gtkimage.setPrompt(_('Click in the drawing area or enter a point'))
301 _tool = gtkimage.getImage().getTool()
302 _tool.setHandler("initialize", plot_mode_init)
303 _tool.setHandler("button_press", plot_first_button_press_cb)
304 _tool.setHandler("entry_event", plot_first_entry_event_cb)