1 /**
2 * \brief This class implements the functionality of the window layout, menus,
3 * and signals.
4 *
5 * This is a reimplementation into C++/Gtkmm of Sodipodi's SPDesktopWidget class.
6 * Both SPDesktopWidget and EditWidget adhere to the EditWidgetInterface, so
7 * they both can serve as widget for the same SPDesktop/Edit class.
8 *
9 * Ideally, this class should only contain the handling of the Window (i.e.,
10 * content construction and window signals) and implement its
11 * EditWidgetInterface.
12 *
13 * Authors:
14 * Ralf Stephan <ralf@ark.in-berlin.de>
15 * Bryce W. Harrington <bryce@bryceharrington.org>
16 * Derek P. Moore <derekm@hackunix.org>
17 * Lauris Kaplinski <lauris@kaplinski.com>
18 * Frank Felfe <innerspace@iname.com>
19 *
20 * Copyright (C) 1999-2005 Authors
21 * Copyright (C) 2000-2001 Ximian, Inc.
22 *
23 * Released under GNU GPL. Read the file 'COPYING' for more information.
24 */
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
30 #include <gtk/gtkwindow.h>
31 #include <gtk/gtkversion.h>
32 #include <gtk/gtklabel.h>
33 #include <gtkmm/radioaction.h>
34 #include <gtkmm/menubar.h>
35 #include <gtkmm/messagedialog.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/accelmap.h>
38 #include <gtkmm/separator.h>
39 #include <gtkmm/base.h>
41 #include "macros.h"
42 #include "path-prefix.h"
43 #include "prefs-utils.h"
44 #include "file.h"
45 #include "application/editor.h"
46 #include "edit-widget.h"
47 #include "ui/stock.h"
48 #include "ui/stock-items.h"
49 #include "ui/icons.h"
51 #include "display/sodipodi-ctrlrect.h"
52 #include "helper/units.h"
53 #include "shortcuts.h"
54 #include "widgets/spw-utilities.h"
55 #include "event-context.h"
56 #include "document.h"
57 #include "sp-namedview.h"
58 #include "sp-item.h"
59 #include "interface.h"
60 #include "extension/db.h"
62 using namespace Inkscape::UI;
63 using namespace Inkscape::UI::Widget;
65 namespace Inkscape {
66 namespace UI {
67 namespace View {
69 EditWidget::EditWidget (SPDocument *doc)
70 : _main_window_table(4),
71 _viewport_table(3,3),
72 _act_grp(Gtk::ActionGroup::create()),
73 _ui_mgr(Gtk::UIManager::create()),
74 _update_s_f(false),
75 _update_a_f(false)
76 {
77 g_warning("Creating new EditWidget");
79 _desktop = 0;
80 Icons::init();
81 Stock::init();
82 initActions();
83 initAccelMap();
84 initUIManager();
85 initLayout();
86 initEdit (doc);
87 g_warning("Done creating new EditWidget");
88 }
90 EditWidget::~EditWidget()
91 {
92 destroyEdit();
93 }
95 void
96 EditWidget::initActions()
97 {
98 initMenuActions();
99 initToolbarActions();
100 }
102 void
103 EditWidget::initUIManager()
104 {
105 _ui_mgr->insert_action_group(_act_grp);
106 add_accel_group(_ui_mgr->get_accel_group());
108 gchar *filename_utf8 = g_build_filename(INKSCAPE_UIDIR, "menus-bars.xml", NULL);
109 if (_ui_mgr->add_ui_from_file(filename_utf8) == 0) {
110 g_warning("Error merging ui from file '%s'", filename_utf8);
111 // fixme-charset: What charset should we pass to g_warning?
112 }
113 g_free(filename_utf8);
114 }
116 void
117 EditWidget::initLayout()
118 {
119 set_title("New document 1 - Inkscape");
120 set_resizable();
121 set_default_size(640, 480);
123 // top level window into which all other portions of the UI get inserted
124 add(_main_window_table);
125 // attach box for horizontal toolbars
126 _main_window_table.attach(_toolbars_vbox, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
127 // attach sub-window for viewport and vertical toolbars
128 _main_window_table.attach(_sub_window_hbox, 0, 1, 2, 3);
129 // viewport table with 3 rows by 3 columns
130 _sub_window_hbox.pack_end(_viewport_table);
132 // Menus and Bars
133 initMenuBar();
134 initCommandsBar();
135 initToolControlsBar();
136 initUriBar();
137 initToolsBar();
139 // Canvas Viewport
140 initLeftRuler();
141 initTopRuler();
142 initStickyZoom();
143 initBottomScrollbar();
144 initRightScrollbar();
145 _viewport_table.attach(_svg_canvas.widget(), 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
146 _svg_canvas.widget().show_all();
149 // The statusbar comes last and appears at the bottom of _main_window_table
150 initStatusbar();
152 signal_size_allocate().connect (sigc::mem_fun (*this, &EditWidget::onWindowSizeAllocate), false);
153 signal_realize().connect (sigc::mem_fun (*this, &EditWidget::onWindowRealize));
154 show_all_children();
155 }
157 void
158 EditWidget::onMenuItem()
159 {
160 g_warning("onMenuItem called");
161 }
163 void
164 EditWidget::onActionFileNew()
165 {
166 // g_warning("onActionFileNew called");
167 sp_file_new_default();
168 }
170 void
171 EditWidget::onActionFileOpen()
172 {
173 // g_warning("onActionFileOpen called");
174 sp_file_open_dialog (NULL, NULL);
175 }
177 void
178 EditWidget::onActionFileQuit()
179 {
180 g_warning("onActionFileQuit");
181 sp_ui_close_all();
182 }
184 void
185 EditWidget::onActionFilePrint()
186 {
187 g_warning("onActionFilePrint");
188 }
190 void
191 EditWidget::onToolbarItem()
192 {
193 g_warning("onToolbarItem called");
194 }
196 void
197 EditWidget::onSelectTool()
198 {
199 _tool_ctrl->remove();
200 _tool_ctrl->add(*_select_ctrl);
201 }
203 void
204 EditWidget::onNodeTool()
205 {
206 _tool_ctrl->remove();
207 _tool_ctrl->add(*_node_ctrl);
208 }
210 void
211 EditWidget::onDialogInkscapePreferences()
212 {
213 _dlg_mgr.showDialog("InkscapePreferences");
214 }
216 void
217 EditWidget::onDialogAbout()
218 {
219 }
221 void
222 EditWidget::onDialogAlignAndDistribute()
223 {
224 _dlg_mgr.showDialog("AlignAndDistribute");
225 }
227 void
228 EditWidget::onDialogDocumentProperties()
229 {
230 // manage (Inkscape::UI::Dialog::DocumentPreferences::create());
231 _dlg_mgr.showDialog("DocumentPreferences");
232 }
234 void
235 EditWidget::onDialogExport()
236 {
237 _dlg_mgr.showDialog("Export");
238 }
240 void
241 EditWidget::onDialogExtensionEditor()
242 {
243 _dlg_mgr.showDialog("ExtensionEditor");
244 }
246 void
247 EditWidget::onDialogFillAndStroke()
248 {
249 _dlg_mgr.showDialog("FillAndStroke");
250 }
252 void
253 EditWidget::onDialogFind()
254 {
255 _dlg_mgr.showDialog("Find");
256 }
258 void
259 EditWidget::onDialogLayerEditor()
260 {
261 _dlg_mgr.showDialog("LayerEditor");
262 }
264 void
265 EditWidget::onDialogMessages()
266 {
267 _dlg_mgr.showDialog("Messages");
268 }
270 void
271 EditWidget::onDialogObjectProperties()
272 {
273 _dlg_mgr.showDialog("ObjectProperties");
274 }
276 void
277 EditWidget::onDialogTextProperties()
278 {
279 _dlg_mgr.showDialog("TextProperties");
280 }
282 void
283 EditWidget::onDialogTrace()
284 {
285 }
287 void
288 EditWidget::onDialogTransformation()
289 {
290 _dlg_mgr.showDialog("Transformation");
291 }
293 void
294 EditWidget::onDialogXmlEditor()
295 {
296 _dlg_mgr.showDialog("XmlEditor");
297 }
299 void
300 EditWidget::onUriChanged()
301 {
302 g_message("onUriChanged called");
304 }
306 // FIXME: strings are replaced by placeholders, NOT to be translated until the code is enabled
307 // See http://sourceforge.net/mailarchive/message.php?msg_id=11746016 for details
309 void
310 EditWidget::initMenuActions()
311 {
312 // _act_grp->add(Gtk::Action::create("MenuFile", _("PLACEHOLDER, do not translate")));
313 // _act_grp->add(Gtk::Action::create("MenuEdit", _("PLACEHOLDER, do not translate")));
314 // _act_grp->add(Gtk::Action::create("MenuView", _("PLACEHOLDER, do not translate")));
315 // _act_grp->add(Gtk::Action::create("MenuLayer", _("PLACEHOLDER, do not translate")));
316 // _act_grp->add(Gtk::Action::create("MenuObject", _("PLACEHOLDER, do not translate")));
317 // _act_grp->add(Gtk::Action::create("MenuPath", _("PLACEHOLDER, do not translate")));
318 // _act_grp->add(Gtk::Action::create("MenuText", _("PLACEHOLDER, do not translate")));
319 // _act_grp->add(Gtk::Action::create("MenuHelp", _("PLACEHOLDER, do not translate")));
320 // temporarily replaced with non-gettext version to have a well-sized menu
321 // for testing:
323 _act_grp->add(Gtk::Action::create("MenuFile", "File"));
324 _act_grp->add(Gtk::Action::create("MenuEdit", "Edit"));
325 _act_grp->add(Gtk::Action::create("MenuView", "View"));
326 _act_grp->add(Gtk::Action::create("MenuLayer", "Layer"));
327 _act_grp->add(Gtk::Action::create("MenuObject", "Object"));
328 _act_grp->add(Gtk::Action::create("MenuPath", "Path"));
329 _act_grp->add(Gtk::Action::create("MenuText", "Text"));
330 _act_grp->add(Gtk::Action::create("MenuHelp", "Help"));
332 // File menu
333 _act_grp->add(Gtk::Action::create("New",
334 Gtk::Stock::NEW, Glib::ustring(),
335 _("PLACEHOLDER, do not translate")),
336 sigc::mem_fun(*this, &EditWidget::onActionFileNew));
338 _act_grp->add(Gtk::Action::create("Open",
339 Gtk::Stock::OPEN, Glib::ustring(),
340 _("PLACEHOLDER, do not translate")),
341 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
343 _act_grp->add(Gtk::Action::create("OpenRecent",
344 Stock::OPEN_RECENT));
346 _act_grp->add(Gtk::Action::create("Revert",
347 Gtk::Stock::REVERT_TO_SAVED, Glib::ustring(),
348 _("PLACEHOLDER, do not translate")),
349 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
351 _act_grp->add(Gtk::Action::create("Save",
352 Gtk::Stock::SAVE, Glib::ustring(),
353 _("PLACEHOLDER, do not translate")),
354 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
356 _act_grp->add(Gtk::Action::create("SaveAs",
357 Gtk::Stock::SAVE_AS, Glib::ustring(),
358 _("PLACEHOLDER, do not translate")),
359 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
361 _act_grp->add(Gtk::Action::create("Import",
362 Stock::IMPORT, Glib::ustring(),
363 _("PLACEHOLDER, do not translate")),
364 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
366 _act_grp->add(Gtk::Action::create("Export",
367 Stock::EXPORT, Glib::ustring(),
368 _("PLACEHOLDER, do not translate")),
369 sigc::mem_fun(*this, &EditWidget::onDialogExport));
371 _act_grp->add(Gtk::Action::create("Print",
372 Gtk::Stock::PRINT, Glib::ustring(),
373 _("PLACEHOLDER, do not translate")),
374 sigc::mem_fun(*this, &EditWidget::onActionFilePrint));
376 _act_grp->add(Gtk::Action::create("PrintPreview",
377 Gtk::Stock::PRINT_PREVIEW),
378 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
380 _act_grp->add(Gtk::Action::create("VacuumDefs",
381 Stock::VACUUM_DEFS),
382 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
384 _act_grp->add(Gtk::Action::create("DocumentProperties",
385 Gtk::Stock::PROPERTIES, Glib::ustring(),
386 _("PLACEHOLDER, do not translate")),
387 sigc::mem_fun(*this, &EditWidget::onDialogDocumentProperties));
389 _act_grp->add(Gtk::Action::create("InkscapePreferences",
390 Gtk::Stock::PREFERENCES, Glib::ustring(),
391 _("PLACEHOLDER, do not translate")),
392 sigc::mem_fun(*this, &EditWidget::onDialogInkscapePreferences));
394 _act_grp->add(Gtk::Action::create("Close",
395 Gtk::Stock::CLOSE),
396 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
398 _act_grp->add(Gtk::Action::create("Quit",
399 Gtk::Stock::QUIT),
400 sigc::mem_fun(*this, &EditWidget::onActionFileQuit));
402 // EditWidget menu
403 _act_grp->add(Gtk::Action::create("Undo",
404 Gtk::Stock::UNDO, Glib::ustring(),
405 _("PLACEHOLDER, do not translate")));
407 _act_grp->add(Gtk::Action::create("Redo",
408 Gtk::Stock::REDO, Glib::ustring(),
409 _("PLACEHOLDER, do not translate")));
411 _act_grp->add(Gtk::Action::create("UndoHistory",
412 Stock::UNDO_HISTORY, Glib::ustring(),
413 _("PLACEHOLDER, do not translate")));
415 _act_grp->add(Gtk::Action::create("Cut",
416 Gtk::Stock::CUT, Glib::ustring(),
417 _("PLACEHOLDER, do not translate")));
419 _act_grp->add(Gtk::Action::create("Copy",
420 Gtk::Stock::COPY, Glib::ustring(),
421 _("PLACEHOLDER, do not translate")));
423 _act_grp->add(Gtk::Action::create("Paste",
424 Gtk::Stock::PASTE, Glib::ustring(),
425 _("PLACEHOLDER, do not translate")));
427 _act_grp->add(Gtk::Action::create("PasteInPlace",
428 Stock::PASTE_IN_PLACE));
430 _act_grp->add(Gtk::Action::create("PasteStyle",
431 Stock::PASTE_STYLE));
433 _act_grp->add(Gtk::Action::create("Find",
434 Gtk::Stock::FIND),
435 sigc::mem_fun(*this, &EditWidget::onDialogFind));
437 _act_grp->add(Gtk::Action::create("Duplicate",
438 Stock::DUPLICATE, Glib::ustring(),
439 _("PLACEHOLDER, do not translate")));
441 _act_grp->add(Gtk::Action::create("Clone",
442 Stock::CLONE, Glib::ustring(),
443 _("PLACEHOLDER, do not translate")));
445 _act_grp->add(Gtk::Action::create("CloneUnlink",
446 Stock::CLONE_UNLINK, Glib::ustring(),
447 _("PLACEHOLDER, do not translate")));
449 _act_grp->add(Gtk::Action::create("CloneSelectOrig",
450 Stock::CLONE_SELECT_ORIG));
452 _act_grp->add(Gtk::Action::create("MakeBitmap",
453 Stock::MAKE_BITMAP));
455 _act_grp->add(Gtk::Action::create("Tile",
456 Stock::TILE));
458 _act_grp->add(Gtk::Action::create("Untile",
459 Stock::UNTILE));
461 _act_grp->add(Gtk::Action::create("Delete",
462 Gtk::Stock::DELETE));
464 _act_grp->add(Gtk::Action::create("SelectAll",
465 Stock::SELECT_ALL));
467 _act_grp->add(Gtk::Action::create("SelectAllInAllLayers",
468 Stock::SELECT_ALL_IN_ALL_LAYERS));
470 _act_grp->add(Gtk::Action::create("SelectInvert",
471 Stock::SELECT_INVERT));
473 _act_grp->add(Gtk::Action::create("SelectNone",
474 Stock::SELECT_NONE));
476 _act_grp->add(Gtk::Action::create("XmlEditor",
477 Stock::XML_EDITOR, Glib::ustring(),
478 _("PLACEHOLDER, do not translate")),
479 sigc::mem_fun(*this, &EditWidget::onDialogXmlEditor));
481 // View menu
482 _act_grp->add(Gtk::Action::create("Zoom",
483 Stock::ZOOM));
485 _act_grp->add(Gtk::Action::create("ZoomIn",
486 Stock::ZOOM_IN, Glib::ustring(),
487 _("PLACEHOLDER, do not translate")));
489 _act_grp->add(Gtk::Action::create("ZoomOut",
490 Stock::ZOOM_OUT, Glib::ustring(),
491 _("PLACEHOLDER, do not translate")));
493 _act_grp->add(Gtk::Action::create("Zoom100",
494 Stock::ZOOM_100, Glib::ustring(),
495 _("PLACEHOLDER, do not translate")));
497 _act_grp->add(Gtk::Action::create("Zoom50",
498 Stock::ZOOM_50, Glib::ustring(),
499 _("PLACEHOLDER, do not translate")));
501 _act_grp->add(Gtk::Action::create("Zoom200",
502 Stock::ZOOM_200, Glib::ustring(),
503 _("PLACEHOLDER, do not translate")));
505 _act_grp->add(Gtk::Action::create("ZoomSelection",
506 Stock::ZOOM_SELECTION, Glib::ustring(),
507 _("PLACEHOLDER, do not translate")));
509 _act_grp->add(Gtk::Action::create("ZoomDrawing",
510 Stock::ZOOM_DRAWING, Glib::ustring(),
511 _("PLACEHOLDER, do not translate")));
513 _act_grp->add(Gtk::Action::create("ZoomPage",
514 Stock::ZOOM_PAGE, Glib::ustring(),
515 _("PLACEHOLDER, do not translate")));
517 _act_grp->add(Gtk::Action::create("ZoomWidth",
518 Stock::ZOOM_WIDTH, Glib::ustring(),
519 _("PLACEHOLDER, do not translate")));
521 _act_grp->add(Gtk::Action::create("ZoomPrev",
522 Stock::ZOOM_PREV, Glib::ustring(),
523 _("PLACEHOLDER, do not translate")));
525 _act_grp->add(Gtk::Action::create("ZoomNext",
526 Stock::ZOOM_NEXT, Glib::ustring(),
527 _("PLACEHOLDER, do not translate")));
529 _act_grp->add(Gtk::Action::create("ShowHide",
530 Stock::SHOW_HIDE));
532 _act_grp->add(Gtk::ToggleAction::create("ShowHideCommandsBar",
533 Stock::SHOW_HIDE_COMMANDS_BAR));
535 _act_grp->add(Gtk::ToggleAction::create("ShowHideToolControlsBar",
536 Stock::SHOW_HIDE_TOOL_CONTROLS_BAR));
538 _act_grp->add(Gtk::ToggleAction::create("ShowHideToolsBar",
539 Stock::SHOW_HIDE_TOOLS_BAR));
541 _act_grp->add(Gtk::ToggleAction::create("ShowHideRulers",
542 Stock::SHOW_HIDE_RULERS));
544 _act_grp->add(Gtk::ToggleAction::create("ShowHideScrollbars",
545 Stock::SHOW_HIDE_SCROLLBARS));
547 _act_grp->add(Gtk::ToggleAction::create("ShowHideStatusbar",
548 Stock::SHOW_HIDE_STATUSBAR));
550 _act_grp->add(Gtk::Action::create("ShowHideDialogs",
551 Stock::SHOW_HIDE_DIALOGS));
553 _act_grp->add(Gtk::Action::create("Grid",
554 Stock::GRID));
556 _act_grp->add(Gtk::Action::create("Guides",
557 Stock::GUIDES));
559 _act_grp->add(Gtk::Action::create("Fullscreen",
560 Stock::FULLSCREEN));
562 _act_grp->add(Gtk::Action::create("Messages",
563 Stock::MESSAGES),
564 sigc::mem_fun(*this, &EditWidget::onDialogMessages));
566 _act_grp->add(Gtk::Action::create("Scripts",
567 Stock::SCRIPTS));
569 _act_grp->add(Gtk::Action::create("WindowPrev",
570 Stock::WINDOW_PREV));
572 _act_grp->add(Gtk::Action::create("WindowNext",
573 Stock::WINDOW_NEXT));
575 _act_grp->add(Gtk::Action::create("WindowDuplicate",
576 Stock::WINDOW_DUPLICATE));
578 // Layer menu
579 _act_grp->add(Gtk::Action::create("LayerNew",
580 Stock::LAYER_NEW));
582 _act_grp->add(Gtk::Action::create("LayerRename",
583 Stock::LAYER_RENAME));
585 _act_grp->add(Gtk::Action::create("LayerDuplicate",
586 Stock::LAYER_DUPLICATE));
588 _act_grp->add(Gtk::Action::create("LayerAnchor",
589 Stock::LAYER_ANCHOR));
591 _act_grp->add(Gtk::Action::create("LayerMergeDown",
592 Stock::LAYER_MERGE_DOWN));
594 _act_grp->add(Gtk::Action::create("LayerDelete",
595 Stock::LAYER_DELETE));
597 _act_grp->add(Gtk::Action::create("LayerSelectNext",
598 Stock::LAYER_SELECT_NEXT));
600 _act_grp->add(Gtk::Action::create("LayerSelectPrev",
601 Stock::LAYER_SELECT_PREV));
603 _act_grp->add(Gtk::Action::create("LayerSelectTop",
604 Stock::LAYER_SELECT_TOP));
606 _act_grp->add(Gtk::Action::create("LayerSelectBottom",
607 Stock::LAYER_SELECT_BOTTOM));
609 _act_grp->add(Gtk::Action::create("LayerRaise",
610 Stock::LAYER_RAISE));
612 _act_grp->add(Gtk::Action::create("LayerLower",
613 Stock::LAYER_LOWER));
615 _act_grp->add(Gtk::Action::create("LayerToTop",
616 Stock::LAYER_TO_TOP));
618 _act_grp->add(Gtk::Action::create("LayerToBottom",
619 Stock::LAYER_TO_BOTTOM));
621 // Object menu
622 _act_grp->add(Gtk::Action::create("FillAndStroke",
623 Stock::FILL_STROKE, Glib::ustring(),
624 _("PLACEHOLDER, do not translate")),
625 sigc::mem_fun(*this, &EditWidget::onDialogFillAndStroke));
627 _act_grp->add(Gtk::Action::create("ObjectProperties",
628 Stock::OBJECT_PROPERTIES),
629 sigc::mem_fun(*this, &EditWidget::onDialogObjectProperties));
631 _act_grp->add(Gtk::Action::create("Group",
632 Stock::GROUP, Glib::ustring(),
633 _("PLACEHOLDER, do not translate")));
635 _act_grp->add(Gtk::Action::create("Ungroup",
636 Stock::UNGROUP, Glib::ustring(),
637 _("PLACEHOLDER, do not translate")));
639 _act_grp->add(Gtk::Action::create("Raise",
640 Stock::RAISE, Glib::ustring(),
641 _("PLACEHOLDER, do not translate")));
643 _act_grp->add(Gtk::Action::create("Lower",
644 Stock::LOWER, Glib::ustring(),
645 _("PLACEHOLDER, do not translate")));
647 _act_grp->add(Gtk::Action::create("RaiseToTop",
648 Stock::RAISE_TO_TOP, Glib::ustring(),
649 _("PLACEHOLDER, do not translate")));
651 _act_grp->add(Gtk::Action::create("LowerToBottom",
652 Stock::LOWER_TO_BOTTOM, Glib::ustring(),
653 _("PLACEHOLDER, do not translate")));
655 _act_grp->add(Gtk::Action::create("MoveToNewLayer",
656 Stock::MOVE_TO_NEW_LAYER, Glib::ustring(),
657 _("PLACEHOLDER, do not translate")));
659 _act_grp->add(Gtk::Action::create("MoveToNextLayer",
660 Stock::MOVE_TO_NEXT_LAYER, Glib::ustring(),
661 _("PLACEHOLDER, do not translate")));
663 _act_grp->add(Gtk::Action::create("MoveToPrevLayer",
664 Stock::MOVE_TO_PREV_LAYER, Glib::ustring(),
665 _("PLACEHOLDER, do not translate")));
667 _act_grp->add(Gtk::Action::create("MoveToTopLayer",
668 Stock::MOVE_TO_TOP_LAYER, Glib::ustring(),
669 _("PLACEHOLDER, do not translate")));
671 _act_grp->add(Gtk::Action::create("MoveToBottomLayer",
672 Stock::MOVE_TO_BOTTOM_LAYER, Glib::ustring(),
673 _("PLACEHOLDER, do not translate")));
675 _act_grp->add(Gtk::Action::create("Rotate90CW",
676 Stock::ROTATE_90_CW, Glib::ustring(),
677 _("PLACEHOLDER, do not translate")));
679 _act_grp->add(Gtk::Action::create("Rotate90CCW",
680 Stock::ROTATE_90_CCW, Glib::ustring(),
681 _("PLACEHOLDER, do not translate")));
683 _act_grp->add(Gtk::Action::create("FlipHoriz",
684 Stock::FLIP_HORIZ, Glib::ustring(),
685 _("PLACEHOLDER, do not translate")));
687 _act_grp->add(Gtk::Action::create("FlipVert",
688 Stock::FLIP_VERT, Glib::ustring(),
689 _("PLACEHOLDER, do not translate")));
691 _act_grp->add(Gtk::Action::create("Transformation",
692 Stock::TRANSFORMATION, Glib::ustring(),
693 _("PLACEHOLDER, do not translate")),
694 sigc::mem_fun(*this, &EditWidget::onDialogTransformation));
696 _act_grp->add(Gtk::Action::create("AlignAndDistribute",
697 Stock::ALIGN_DISTRIBUTE, Glib::ustring(),
698 _("PLACEHOLDER, do not translate")),
699 sigc::mem_fun(*this, &EditWidget::onDialogAlignAndDistribute));
701 // Path menu
702 _act_grp->add(Gtk::Action::create("ObjectToPath",
703 Stock::OBJECT_TO_PATH, Glib::ustring(),
704 _("PLACEHOLDER, do not translate")));
706 _act_grp->add(Gtk::Action::create("StrokeToPath",
707 Stock::STROKE_TO_PATH, Glib::ustring(),
708 _("PLACEHOLDER, do not translate")));
710 _act_grp->add(Gtk::Action::create("Trace",
711 Stock::TRACE),
712 sigc::mem_fun(*this, &EditWidget::onDialogTrace));
714 _act_grp->add(Gtk::Action::create("Union",
715 Stock::UNION));
717 _act_grp->add(Gtk::Action::create("Difference",
718 Stock::DIFFERENCE));
720 _act_grp->add(Gtk::Action::create("Intersection",
721 Stock::INTERSECTION));
723 _act_grp->add(Gtk::Action::create("Exclusion",
724 Stock::EXCLUSION));
726 _act_grp->add(Gtk::Action::create("Division",
727 Stock::DIVISION));
729 _act_grp->add(Gtk::Action::create("CutPath",
730 Stock::CUT_PATH));
732 _act_grp->add(Gtk::Action::create("Combine",
733 Stock::COMBINE));
735 _act_grp->add(Gtk::Action::create("BreakApart",
736 Stock::BREAK_APART));
738 _act_grp->add(Gtk::Action::create("Inset",
739 Stock::INSET));
741 _act_grp->add(Gtk::Action::create("Outset",
742 Stock::OUTSET));
744 _act_grp->add(Gtk::Action::create("OffsetDynamic",
745 Stock::OFFSET_DYNAMIC));
747 _act_grp->add(Gtk::Action::create("OffsetLinked",
748 Stock::OFFSET_LINKED));
750 _act_grp->add(Gtk::Action::create("Simplify",
751 Stock::SIMPLIFY));
753 _act_grp->add(Gtk::Action::create("Reverse",
754 Stock::REVERSE));
756 _act_grp->add(Gtk::Action::create("Cleanup",
757 Gtk::Stock::CLEAR,
758 _("PLACEHOLDER, do not translate")));
760 // Text menu
761 _act_grp->add(Gtk::Action::create("TextProperties",
762 Gtk::Stock::SELECT_FONT, Glib::ustring(),
763 _("PLACEHOLDER, do not translate")),
764 sigc::mem_fun(*this, &EditWidget::onDialogTextProperties));
766 _act_grp->add(Gtk::Action::create("PutOnPath",
767 Stock::PUT_ON_PATH));
769 _act_grp->add(Gtk::Action::create("RemoveFromPath",
770 Stock::REMOVE_FROM_PATH));
772 _act_grp->add(Gtk::Action::create("RemoveManualKerns",
773 Stock::REMOVE_MANUAL_KERNS));
775 // Whiteboard menu
776 #ifdef WITH_INKBOARD
777 #endif
779 // About menu
780 _act_grp->add(Gtk::Action::create("KeysAndMouse",
781 Stock::KEYS_MOUSE));
783 _act_grp->add(Gtk::Action::create("Tutorials",
784 Stock::TUTORIALS));
786 _act_grp->add(Gtk::Action::create("About",
787 Stock::ABOUT),
788 sigc::mem_fun(*this, &EditWidget::onDialogAbout));
789 }
791 void
792 EditWidget::initToolbarActions()
793 {
794 // Tools bar
795 Gtk::RadioAction::Group tools;
797 _act_grp->add(Gtk::RadioAction::create(tools, "ToolSelect",
798 Stock::TOOL_SELECT, Glib::ustring(),
799 _("PLACEHOLDER, do not translate")),
800 sigc::mem_fun(*this, &EditWidget::onSelectTool));
802 _act_grp->add(Gtk::RadioAction::create(tools, "ToolNode",
803 Stock::TOOL_NODE, Glib::ustring(),
804 _("PLACEHOLDER, do not translate")),
805 sigc::mem_fun(*this, &EditWidget::onNodeTool));
807 _act_grp->add(Gtk::RadioAction::create(tools, "ToolZoom",
808 Stock::TOOL_ZOOM, Glib::ustring(),
809 _("PLACEHOLDER, do not translate")));
811 _act_grp->add(Gtk::RadioAction::create(tools, "ToolRect",
812 Stock::TOOL_RECT, Glib::ustring(),
813 _("PLACEHOLDER, do not translate")));
815 _act_grp->add(Gtk::RadioAction::create(tools, "ToolArc",
816 Stock::TOOL_ARC, Glib::ustring(),
817 _("PLACEHOLDER, do not translate")));
819 _act_grp->add(Gtk::RadioAction::create(tools, "ToolStar",
820 Stock::TOOL_STAR, Glib::ustring(),
821 _("PLACEHOLDER, do not translate")));
823 _act_grp->add(Gtk::RadioAction::create(tools, "ToolSpiral",
824 Stock::TOOL_SPIRAL, Glib::ustring(),
825 _("PLACEHOLDER, do not translate")));
827 _act_grp->add(Gtk::RadioAction::create(tools, "ToolFreehand",
828 Stock::TOOL_FREEHAND, Glib::ustring(),
829 _("PLACEHOLDER, do not translate")));
831 _act_grp->add(Gtk::RadioAction::create(tools, "ToolPen",
832 Stock::TOOL_PEN, Glib::ustring(),
833 _("PLACEHOLDER, do not translate")));
835 _act_grp->add(Gtk::RadioAction::create(tools, "ToolDynaDraw",
836 Stock::TOOL_DYNADRAW, Glib::ustring(),
837 _("PLACEHOLDER, do not translate")));
839 _act_grp->add(Gtk::RadioAction::create(tools, "ToolText",
840 Stock::TOOL_TEXT, Glib::ustring(),
841 _("PLACEHOLDER, do not translate")));
843 _act_grp->add(Gtk::RadioAction::create(tools, "ToolDropper",
844 Stock::TOOL_DROPPER, Glib::ustring(),
845 _("PLACEHOLDER, do not translate")));
847 // Select Controls bar
848 _act_grp->add(Gtk::ToggleAction::create("TransformStroke",
849 Stock::TRANSFORM_STROKE, Glib::ustring(),
850 _("PLACEHOLDER, do not translate")));
852 _act_grp->add(Gtk::ToggleAction::create("TransformCorners",
853 Stock::TRANSFORM_CORNERS, Glib::ustring(),
854 _("PLACEHOLDER, do not translate")));
856 _act_grp->add(Gtk::ToggleAction::create("TransformGradient",
857 Stock::TRANSFORM_GRADIENT, Glib::ustring(),
858 _("PLACEHOLDER, do not translate")));
860 _act_grp->add(Gtk::ToggleAction::create("TransformPattern",
861 Stock::TRANSFORM_PATTERN, Glib::ustring(),
862 _("PLACEHOLDER, do not translate")));
864 // Node Controls bar
865 _act_grp->add(Gtk::Action::create("NodeInsert",
866 Gtk::Stock::ADD, Glib::ustring(),
867 _("PLACEHOLDER, do not translate")));
869 _act_grp->add(Gtk::Action::create("NodeDelete",
870 Gtk::Stock::REMOVE, Glib::ustring(),
871 _("PLACEHOLDER, do not translate")));
873 _act_grp->add(Gtk::Action::create("NodeJoin",
874 Stock::NODE_JOIN, Glib::ustring(),
875 _("PLACEHOLDER, do not translate")));
877 _act_grp->add(Gtk::Action::create("NodeJoinSegment",
878 Stock::NODE_JOIN_SEGMENT, Glib::ustring(),
879 _("PLACEHOLDER, do not translate")));
881 _act_grp->add(Gtk::Action::create("NodeDeleteSegment",
882 Stock::NODE_DELETE_SEGMENT, Glib::ustring(),
883 _("PLACEHOLDER, do not translate")));
885 _act_grp->add(Gtk::Action::create("NodeBreak",
886 Stock::NODE_BREAK, Glib::ustring(),
887 _("PLACEHOLDER, do not translate")));
889 _act_grp->add(Gtk::Action::create("NodeCorner",
890 Stock::NODE_CORNER, Glib::ustring(),
891 _("PLACEHOLDER, do not translate")));
893 _act_grp->add(Gtk::Action::create("NodeSmooth",
894 Stock::NODE_SMOOTH, Glib::ustring(),
895 _("PLACEHOLDER, do not translate")));
897 _act_grp->add(Gtk::Action::create("NodeSymmetric",
898 Stock::NODE_SYMMETRIC, Glib::ustring(),
899 _("PLACEHOLDER, do not translate")));
901 _act_grp->add(Gtk::Action::create("NodeLine",
902 Stock::NODE_LINE, Glib::ustring(),
903 _("PLACEHOLDER, do not translate")));
905 _act_grp->add(Gtk::Action::create("NodeCurve",
906 Stock::NODE_CURVE, Glib::ustring(),
907 _("PLACEHOLDER, do not translate")));
908 }
910 void
911 EditWidget::initAccelMap()
912 {
913 gchar *filename = g_build_filename(INKSCAPE_UIDIR, "keybindings.rc", NULL);
914 Gtk::AccelMap::load(filename);
915 g_free(filename);
917 // One problem is that the keys 1-6 are zoom accelerators which get
918 // caught as accelerator _before_ any Entry input handler receives them,
919 // for example the zoom status. At the moment, the best way seems to
920 // disable them as accelerators when the Entry gets focus, and enable
921 // them when focus goes elsewhere. The code for this belongs here,
922 // and not in zoom-status.cpp .
924 _zoom_status.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditWidget::onEntryFocusIn));
925 _zoom_status.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditWidget::onEntryFocusOut));
926 }
928 bool
929 EditWidget::onEntryFocusIn (GdkEventFocus* ev)
930 {
931 Gdk::ModifierType m = static_cast<Gdk::ModifierType>(0);
932 Gtk::AccelMap::change_entry ("<Actions>//Zoom100", 0, m, false);
933 Gtk::AccelMap::change_entry ("<Actions>//Zoom50", 0, m, false);
934 Gtk::AccelMap::change_entry ("<Actions>//ZoomSelection", 0, m, false);
935 Gtk::AccelMap::change_entry ("<Actions>//ZoomDrawing", 0, m, false);
936 Gtk::AccelMap::change_entry ("<Actions>//ZoomPage", 0, m, false);
937 Gtk::AccelMap::change_entry ("<Actions>//ZoomWidth", 0, m, false);
938 return false;
939 }
941 bool
942 EditWidget::onEntryFocusOut (GdkEventFocus* ev)
943 {
944 Gdk::ModifierType m = static_cast<Gdk::ModifierType>(0);
945 Gtk::AccelMap::change_entry ("<Actions>//Zoom100", '1', m, false);
946 Gtk::AccelMap::change_entry ("<Actions>//Zoom50", '2', m, false);
947 Gtk::AccelMap::change_entry ("<Actions>//ZoomSelection", '3', m, false);
948 Gtk::AccelMap::change_entry ("<Actions>//ZoomDrawing", '4', m, false);
949 Gtk::AccelMap::change_entry ("<Actions>//ZoomPage", '5', m, false);
950 Gtk::AccelMap::change_entry ("<Actions>//ZoomWidth", '6', m, false);
951 return false;
952 }
954 void
955 EditWidget::initMenuBar()
956 {
957 g_assert(_ui_mgr);
958 Gtk::MenuBar *menu = static_cast<Gtk::MenuBar*>(_ui_mgr->get_widget("/MenuBar"));
959 g_assert(menu != NULL);
960 _main_window_table.attach(*Gtk::manage(menu), 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
961 }
963 void
964 EditWidget::initCommandsBar()
965 {
966 g_assert(_ui_mgr);
967 Toolbox *bar = new Toolbox(static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/CommandsBar")),
968 Gtk::TOOLBAR_ICONS);
969 g_assert(bar != NULL);
970 _toolbars_vbox.pack_start(*Gtk::manage(bar), Gtk::PACK_SHRINK);
971 }
973 void
974 EditWidget::initToolControlsBar()
975 {
976 // TODO: Do UIManager controlled widgets need to be deleted?
977 _select_ctrl = static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/SelectControlsBar"));
978 _node_ctrl = static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/NodeControlsBar"));
980 _tool_ctrl = new Toolbox(_select_ctrl, Gtk::TOOLBAR_ICONS);
982 _toolbars_vbox.pack_start(*Gtk::manage(_tool_ctrl), Gtk::PACK_SHRINK);
983 }
985 void
986 EditWidget::initUriBar()
987 {
988 /// \todo Create an Inkscape::UI::Widget::UriBar class (?)
990 _uri_ctrl = new Gtk::Toolbar();
992 _uri_label.set_label(_("PLACEHOLDER, DO NOT TRANSLATE"));
993 _uri_ctrl->add(_uri_label);
994 _uri_ctrl->add(_uri_entry);
996 _uri_entry.signal_activate()
997 .connect_notify(sigc::mem_fun(*this, &EditWidget::onUriChanged));
999 _toolbars_vbox.pack_start(*Gtk::manage(_uri_ctrl), Gtk::PACK_SHRINK);
1000 }
1002 void
1003 EditWidget::initToolsBar()
1004 {
1005 Toolbox *bar = new Toolbox(static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/ToolsBar")),
1006 Gtk::TOOLBAR_ICONS,
1007 Gtk::ORIENTATION_VERTICAL);
1008 g_assert(bar != NULL);
1009 _sub_window_hbox.pack_start(*Gtk::manage(bar), Gtk::PACK_SHRINK);
1010 }
1012 void
1013 EditWidget::initTopRuler()
1014 {
1015 _viewport_table.attach(_top_ruler, 1, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
1017 _tooltips.set_tip (_top_ruler, _top_ruler.get_tip());
1018 }
1020 void
1021 EditWidget::initLeftRuler()
1022 {
1023 _viewport_table.attach(_left_ruler, 0, 1, 1, 2, Gtk::SHRINK, Gtk::FILL|Gtk::EXPAND);
1025 _tooltips.set_tip (_left_ruler, _left_ruler.get_tip());
1026 }
1028 void
1029 EditWidget::initBottomScrollbar()
1030 {
1031 _viewport_table.attach(_bottom_scrollbar, 1, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
1032 _bottom_scrollbar.signal_value_changed().connect (sigc::mem_fun (*this, &EditWidget::onAdjValueChanged));
1033 _bottom_scrollbar.property_adjustment() = new Gtk::Adjustment (0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0);
1034 }
1036 void
1037 EditWidget::initRightScrollbar()
1038 {
1039 _viewport_table.attach(_right_scrollbar, 2, 3, 1, 2, Gtk::SHRINK, Gtk::FILL|Gtk::EXPAND);
1041 _right_scrollbar.signal_value_changed().connect (sigc::mem_fun (*this, &EditWidget::onAdjValueChanged));
1042 _right_scrollbar.property_adjustment() = new Gtk::Adjustment (0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0);
1043 }
1045 void
1046 EditWidget::initStickyZoom()
1047 {
1048 _viewport_table.attach(_sticky_zoom, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
1050 _sticky_zoom.set_active (prefs_get_int_attribute ("options.stickyzoom", "value", 0) != 0);
1051 _tooltips.set_tip (_sticky_zoom, _("Zoom drawing if window size changes"));
1053 /// \todo icon not implemented
1054 }
1056 void
1057 EditWidget::initStatusbar()
1058 {
1059 _statusbar.pack_start (_selected_style_status, false, false, 1);
1060 _statusbar.pack_start (*new Gtk::VSeparator(), false, false, 0);
1062 _tooltips.set_tip (_zoom_status, _("Zoom"));
1064 _layer_selector.reference();
1065 _statusbar.pack_start (_layer_selector, false, false, 1);
1067 _coord_status.property_n_rows() = 2;
1068 _coord_status.property_n_columns() = 5;
1069 _coord_status.property_row_spacing() = 0;
1070 _coord_status.property_column_spacing() = 2;
1071 _coord_eventbox.add (_coord_status);
1072 _tooltips.set_tip (_coord_eventbox, _("Cursor coordinates"));
1073 _coord_status.attach (*new Gtk::VSeparator(), 0,1, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1074 _coord_status.attach (*new Gtk::Label("X:", 0.0, 0.5), 1,2, 0,1, Gtk::FILL,Gtk::FILL, 0,0);
1075 _coord_status.attach (*new Gtk::Label("Y:", 0.0, 0.5), 1,2, 1,2, Gtk::FILL,Gtk::FILL, 0,0);
1076 _coord_status_x.set_text ("0.0");
1077 _coord_status_x.set_alignment (0.0, 0.5);
1078 _coord_status_y.set_text ("0.0");
1079 _coord_status_y.set_alignment (0.0, 0.5);
1080 _coord_status.attach (_coord_status_x, 2,3, 0,1, Gtk::FILL,Gtk::FILL, 0,0);
1081 _coord_status.attach (_coord_status_y, 2,3, 1,2, Gtk::FILL,Gtk::FILL, 0,0);
1082 _coord_status.attach (*new Gtk::Label("Z:", 0.0, 0.5), 3,4, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1083 _coord_status.attach (_zoom_status, 4,5, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1084 sp_set_font_size_smaller (static_cast<GtkWidget*>((void*)_coord_status.gobj()));
1085 _statusbar.pack_end (_coord_eventbox, false, false, 1);
1087 _select_status.property_xalign() = 0.0;
1088 _select_status.property_yalign() = 0.5;
1089 _select_status.set_markup (_("<b>Welcome to Inkscape!</b> Use shape or freehand tools to create objects; use selector (arrow) to move or transform them."));
1090 // include this again with Gtk+-2.6
1091 #if GTK_VERSION_GE(2,6)
1092 gtk_label_set_ellipsize (GTK_LABEL(_select_status.gobj()), PANGO_ELLIPSIZE_END);
1093 #endif
1094 _select_status.set_size_request (1, -1);
1095 _statusbar.pack_start (_select_status, true, true, 0);
1097 _main_window_table.attach(_statusbar, 0, 1, 3, 4, Gtk::FILL, Gtk::SHRINK);
1098 }
1100 //========================================
1101 //----------implements EditWidgetInterface
1103 void *
1104 EditWidget::getWindow()
1105 {
1106 return this;
1107 }
1109 void
1110 EditWidget::setTitle (gchar const* new_title)
1111 {
1112 set_title (new_title);
1113 }
1115 void
1116 EditWidget::layout()
1117 {
1118 show_all_children();
1119 }
1121 void
1122 EditWidget::present()
1123 {
1124 this->Gtk::Window::present();
1125 }
1127 void
1128 EditWidget::getGeometry (gint &x, gint &y, gint &w, gint &h)
1129 {
1130 get_position (x, y);
1131 get_size (w, h);
1132 }
1134 void
1135 EditWidget::setSize (gint w, gint h)
1136 {
1137 resize (w, h);
1138 }
1140 void
1141 EditWidget::setPosition (NR::Point p)
1142 {
1143 move (int(p[NR::X]), int(p[NR::Y]));
1144 }
1146 /// \param p is already gobj()!
1147 void
1148 EditWidget::setTransient (void* p, int i)
1149 {
1150 #ifndef WIN32
1151 gtk_window_set_transient_for (static_cast<GtkWindow*>(p), this->gobj());
1152 if (i==2)
1153 this->Gtk::Window::present();
1154 #endif
1155 }
1157 NR::Point
1158 EditWidget::getPointer()
1159 {
1160 int x, y;
1161 get_pointer (x, y);
1162 return NR::Point (x, y);
1163 }
1165 void
1166 EditWidget::setFullscreen()
1167 {
1168 fullscreen();
1169 }
1171 /**
1172 * Shuts down the desktop object for the view being closed. It checks
1173 * to see if the document has been edited, and if so prompts the user
1174 * to save, discard, or cancel. Returns TRUE if the shutdown operation
1175 * is cancelled or if the save is cancelled or fails, FALSE otherwise.
1176 */
1177 bool
1178 EditWidget::shutdown()
1179 {
1180 g_assert (_desktop != NULL);
1181 if (Inkscape::NSApplication::Editor::isDuplicatedView (_desktop))
1182 return false;
1184 SPDocument *doc = _desktop->doc();
1185 if (sp_document_repr_root(doc)->attribute("sodipodi:modified") != NULL)
1186 {
1187 gchar *markup;
1188 /// \todo FIXME !!! obviously this will have problems if the document
1189 /// name contains markup characters
1190 markup = g_strdup_printf(
1191 _("<span weight=\"bold\" size=\"larger\">Save changes to document \"%s\" before closing?</span>\n\n"
1192 "If you close without saving, your changes will be discarded."),
1193 SP_DOCUMENT_NAME(doc));
1195 Gtk::MessageDialog dlg (*this,
1196 markup,
1197 true,
1198 Gtk::MESSAGE_WARNING,
1199 Gtk::BUTTONS_NONE,
1200 true);
1201 g_free(markup);
1202 Gtk::Button close_button (_("Close _without saving"), true);
1203 dlg.add_action_widget (close_button, Gtk::RESPONSE_NO);
1204 close_button.show();
1205 dlg.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1206 dlg.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_YES);
1207 dlg.set_default_response (Gtk::RESPONSE_YES);
1209 int response = dlg.run();
1210 switch (response)
1211 {
1212 case Gtk::RESPONSE_YES:
1213 sp_document_ref(doc);
1214 if (sp_file_save_document(doc)) {
1215 sp_document_unref(doc);
1216 } else { // save dialog cancelled or save failed
1217 sp_document_unref(doc);
1218 return TRUE;
1219 }
1220 break;
1221 case Gtk::RESPONSE_NO:
1222 break;
1223 default: // cancel pressed, or dialog was closed
1224 return TRUE;
1225 break;
1226 }
1227 }
1229 /* Code to check data loss */
1230 bool allow_data_loss = FALSE;
1231 while (sp_document_repr_root(doc)->attribute("inkscape:dataloss") != NULL && allow_data_loss == FALSE)
1232 {
1233 gchar *markup;
1234 /// \todo FIXME !!! obviously this will have problems if the document
1235 /// name contains markup characters
1236 markup = g_strdup_printf(
1237 _("<span weight=\"bold\" size=\"larger\">The file \"%s\" was saved with a format (%s) that may cause data loss!</span>\n\n"
1238 "Do you want to save this file in another format?"),
1239 SP_DOCUMENT_NAME(doc),
1240 Inkscape::Extension::db.get(sp_document_repr_root(doc)->attribute("inkscape:output_extension"))->get_name());
1242 Gtk::MessageDialog dlg (*this,
1243 markup,
1244 true,
1245 Gtk::MESSAGE_WARNING,
1246 Gtk::BUTTONS_NONE,
1247 true);
1248 g_free(markup);
1249 Gtk::Button close_button (_("Close _without saving"), true);
1250 dlg.add_action_widget (close_button, Gtk::RESPONSE_NO);
1251 close_button.show();
1252 dlg.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1253 dlg.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_YES);
1254 dlg.set_default_response (Gtk::RESPONSE_YES);
1256 int response = dlg.run();
1258 switch (response)
1259 {
1260 case Gtk::RESPONSE_YES:
1261 sp_document_ref(doc);
1262 if (sp_file_save_document(doc)) {
1263 sp_document_unref(doc);
1264 } else { // save dialog cancelled or save failed
1265 sp_document_unref(doc);
1266 return TRUE;
1267 }
1268 break;
1269 case Gtk::RESPONSE_NO:
1270 allow_data_loss = TRUE;
1271 break;
1272 default: // cancel pressed, or dialog was closed
1273 return TRUE;
1274 break;
1275 }
1276 }
1278 return false;
1279 }
1282 void
1283 EditWidget::destroy()
1284 {
1285 delete this;
1286 }
1288 void
1289 EditWidget::requestCanvasUpdate()
1290 {
1291 _svg_canvas.widget().queue_draw();
1292 }
1294 void
1295 EditWidget::activateDesktop()
1296 {
1297 /// \todo active_desktop_indicator not implemented
1298 }
1300 void
1301 EditWidget::deactivateDesktop()
1302 {
1303 /// \todo active_desktop_indicator not implemented
1304 }
1306 void
1307 EditWidget::viewSetPosition (NR::Point p)
1308 {
1309 p -= _namedview->gridorigin;
1310 double lo, up, pos, max;
1311 _top_ruler.get_range (lo, up, pos, max);
1312 _top_ruler.set_range (lo, up, p[NR::X], max);
1313 _left_ruler.get_range (lo, up, pos, max);
1314 _left_ruler.set_range (lo, up, p[NR::Y], max);
1315 }
1317 void
1318 EditWidget::updateRulers()
1319 {
1320 NR::Point origin = _namedview->gridorigin;
1322 NR::Rect const viewbox = _svg_canvas.spobj()->getViewbox();
1323 double lo, up, pos, max;
1324 double const scale = _desktop->current_zoom();
1325 double s = viewbox.min()[NR::X] / scale - origin[NR::X];
1326 double e = viewbox.max()[NR::X] / scale - origin[NR::X];
1327 _top_ruler.get_range(lo, up, pos, max);
1328 _top_ruler.set_range(s, e, pos, e);
1329 s = viewbox.min()[NR::Y] / -scale - origin[NR::Y];
1330 e = viewbox.max()[NR::Y] / -scale - origin[NR::Y];
1331 _left_ruler.set_range(s, e, origin[NR::Y], e);
1332 /// \todo is that correct?
1333 }
1335 void
1336 EditWidget::updateScrollbars (double scale)
1337 {
1338 // do not call this function before canvas has its size allocated
1339 if (!is_realized() || _update_s_f) {
1340 return;
1341 }
1343 _update_s_f = true;
1345 /* The desktop region we always show unconditionally */
1346 SPDocument *doc = _desktop->doc();
1347 NR::Rect const r = sp_item_bbox_desktop(SP_ITEM(SP_DOCUMENT_ROOT(doc)));
1348 NR::Rect darea(NR::Point(MIN(r.min()[NR::X], -sp_document_width(doc)),
1349 MIN(r.min()[NR::Y], -sp_document_height(doc))),
1350 NR::Point(MAX(r.max()[NR::X], 2 * sp_document_width(doc)),
1351 MAX(r.max()[NR::Y], 2 * sp_document_height(doc))));
1353 /* Canvas region we always show unconditionally */
1354 NR::Rect carea(NR::Point(darea.min()[NR::X] * scale - 64,
1355 darea.max()[NR::Y] * -scale - 64),
1356 NR::Point(darea.max()[NR::X] * scale + 64,
1357 darea.min()[NR::Y] * -scale + 64));
1359 NR::Rect const viewbox = _svg_canvas.spobj()->getViewbox();
1361 /* Viewbox is always included into scrollable region */
1362 carea = NR::Rect::union_bounds(carea, viewbox);
1364 Gtk::Adjustment *adj = _bottom_scrollbar.get_adjustment();
1365 adj->set_value(viewbox.min()[NR::X]);
1366 adj->set_lower(carea.min()[NR::X]);
1367 adj->set_upper(carea.max()[NR::X]);
1368 adj->set_page_increment(viewbox.dimensions()[NR::X]);
1369 adj->set_step_increment(0.1 * (viewbox.dimensions()[NR::X]));
1370 adj->set_page_size(viewbox.dimensions()[NR::X]);
1372 adj = _right_scrollbar.get_adjustment();
1373 adj->set_value(viewbox.min()[NR::Y]);
1374 adj->set_lower(carea.min()[NR::Y]);
1375 adj->set_upper(carea.max()[NR::Y]);
1376 adj->set_page_increment(viewbox.dimensions()[NR::Y]);
1377 adj->set_step_increment(0.1 * viewbox.dimensions()[NR::Y]);
1378 adj->set_page_size(viewbox.dimensions()[NR::Y]);
1380 _update_s_f = false;
1381 }
1383 void
1384 EditWidget::toggleRulers()
1385 {
1386 if (_top_ruler.is_visible())
1387 {
1388 _top_ruler.hide_all();
1389 _left_ruler.hide_all();
1390 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.rulers" : "window.rulers", "state", 0);
1391 } else {
1392 _top_ruler.show_all();
1393 _left_ruler.show_all();
1394 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.rulers" : "window.rulers", "state", 1);
1395 }
1396 }
1398 void
1399 EditWidget::toggleScrollbars()
1400 {
1401 if (_bottom_scrollbar.is_visible())
1402 {
1403 _bottom_scrollbar.hide_all();
1404 _right_scrollbar.hide_all();
1405 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.scrollbars" : "window.scrollbars", "state", 0);
1406 } else {
1407 _bottom_scrollbar.show_all();
1408 _right_scrollbar.show_all();
1409 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.scrollbars" : "window.scrollbars", "state", 1);
1410 }
1411 }
1413 void
1414 EditWidget::updateZoom()
1415 {
1416 _zoom_status.update();
1417 }
1419 void
1420 EditWidget::letZoomGrabFocus()
1421 {
1422 _zoom_status.grab_focus();
1423 }
1425 void
1426 EditWidget::setToolboxFocusTo (const gchar *)
1427 {
1428 /// \todo not implemented
1429 }
1431 void
1432 EditWidget::setToolboxAdjustmentValue (const gchar *, double)
1433 {
1434 /// \todo not implemented
1435 }
1437 bool
1438 EditWidget::isToolboxButtonActive (gchar const*)
1439 {
1440 /// \todo not implemented
1441 return true;
1442 }
1444 void
1445 EditWidget::setCoordinateStatus (NR::Point p)
1446 {
1447 gchar *cstr = g_strdup_printf ("%6.2f", _dt2r * p[NR::X]);
1448 _coord_status_x.property_label() = cstr;
1449 g_free (cstr);
1450 cstr = g_strdup_printf ("%6.2f", _dt2r * p[NR::Y]);
1451 _coord_status_y.property_label() = cstr;
1452 g_free (cstr);
1453 }
1455 void
1456 EditWidget::setMessage (Inkscape::MessageType type, gchar const* msg)
1457 {
1458 _select_status.set_markup (msg? msg : "");
1459 }
1461 bool
1462 EditWidget::warnDialog (gchar* msg)
1463 {
1464 Gtk::MessageDialog dlg (*this,
1465 msg,
1466 true,
1467 Gtk::MESSAGE_WARNING,
1468 Gtk::BUTTONS_YES_NO,
1469 true);
1470 int r = dlg.run();
1471 return r == Gtk::RESPONSE_YES;
1472 }
1475 /// \todo make this a member function when the signal is a sigc++ signal
1476 void _namedview_modified (SPNamedView* nv, guint flags, EditWidget* ew)
1477 {
1478 if (flags & SP_OBJECT_MODIFIED_FLAG)
1479 {
1480 ew->_dt2r = 1.0 / nv->doc_units->unittobase;
1481 ew->_top_ruler.update_metric();
1482 ew->_left_ruler.update_metric();
1483 ew->_tooltips.set_tip (ew->_top_ruler, ew->_top_ruler.get_tip());
1484 ew->_tooltips.set_tip (ew->_left_ruler, ew->_left_ruler.get_tip());
1485 ew->updateRulers();
1486 }
1487 }
1489 void
1490 EditWidget::initEdit (SPDocument *doc)
1491 {
1492 _desktop = new SPDesktop();
1493 _desktop->registerEditWidget (this);
1495 _namedview = sp_document_namedview (doc, 0);
1496 _svg_canvas.init (_desktop);
1497 _desktop->init (_namedview, _svg_canvas.spobj());
1498 sp_namedview_window_from_document (_desktop);
1499 _dt2r = 1.0 / _namedview->doc_units->unittobase;
1501 /// \todo convert to sigc++ when SPObject hierarchy gets converted
1502 /* Listen on namedview modification */
1503 g_signal_connect (G_OBJECT (_desktop->namedview), "modified",
1504 G_CALLBACK (_namedview_modified), this);
1505 _layer_selector.setDesktop (_desktop);
1506 _selected_style_status.setDesktop (_desktop);
1508 Inkscape::NSApplication::Editor::addDesktop (_desktop);
1510 _zoom_status.init (_desktop);
1511 _top_ruler.init (_desktop, _svg_canvas.widget());
1512 _left_ruler.init (_desktop, _svg_canvas.widget());
1513 updateRulers();
1514 }
1516 void
1517 EditWidget::destroyEdit()
1518 {
1519 if (_desktop) {
1520 _layer_selector.unreference();
1521 Inkscape::NSApplication::Editor::removeDesktop (_desktop); // clears selection too
1522 sp_signal_disconnect_by_data (G_OBJECT (_desktop->namedview), this);
1523 _desktop->destroy();
1524 Inkscape::GC::release (_desktop);
1525 _desktop = 0;
1526 }
1527 }
1529 //----------end of EditWidgetInterface implementation
1531 //----------start of other callbacks
1533 bool
1534 EditWidget::on_key_press_event (GdkEventKey* event)
1535 {
1536 // this is the original code from helper/window.cpp
1538 unsigned int shortcut;
1539 shortcut = get_group0_keyval (event) |
1540 ( event->state & GDK_SHIFT_MASK ?
1541 SP_SHORTCUT_SHIFT_MASK : 0 ) |
1542 ( event->state & GDK_CONTROL_MASK ?
1543 SP_SHORTCUT_CONTROL_MASK : 0 ) |
1544 ( event->state & GDK_MOD1_MASK ?
1545 SP_SHORTCUT_ALT_MASK : 0 );
1546 return sp_shortcut_invoke (shortcut,
1547 Inkscape::NSApplication::Editor::getActiveDesktop());
1548 }
1550 bool
1551 EditWidget::on_delete_event (GdkEventAny*)
1552 {
1553 return shutdown();
1554 }
1556 bool
1557 EditWidget::on_focus_in_event (GdkEventFocus*)
1558 {
1559 Inkscape::NSApplication::Editor::activateDesktop (_desktop);
1560 _svg_canvas.widget().grab_focus();
1562 return false;
1563 }
1565 void
1566 EditWidget::onWindowSizeAllocate (Gtk::Allocation &newall)
1567 {
1568 if (!is_realized()) return;
1570 const Gtk::Allocation& all = get_allocation();
1571 if ((newall.get_x() == all.get_x()) &&
1572 (newall.get_y() == all.get_y()) &&
1573 (newall.get_width() == all.get_width()) &&
1574 (newall.get_height() == all.get_height())) {
1575 return;
1576 }
1578 NR::Rect const area = _desktop->get_display_area();
1579 double zoom = _desktop->current_zoom();
1581 if (_sticky_zoom.get_active()) {
1582 /* Calculate zoom per pixel */
1583 double const zpsp = zoom / hypot(area.dimensions()[NR::X], area.dimensions()[NR::Y]);
1584 /* Find new visible area */
1585 NR::Rect const newarea = _desktop->get_display_area();
1586 /* Calculate adjusted zoom */
1587 zoom = zpsp * hypot(newarea.dimensions()[NR::X], newarea.dimensions()[NR::Y]);
1588 }
1590 _desktop->zoom_absolute(area.midpoint()[NR::X], area.midpoint()[NR::Y], zoom);
1591 }
1593 void
1594 EditWidget::onWindowRealize()
1595 {
1596 NR::Rect d(NR::Point(0, 0),
1597 NR::Point(sp_document_width(_desktop->doc()), sp_document_height(_desktop->doc())));
1599 if (fabs(d.dimensions()[NR::X]) < 1.0 || fabs(d.dimensions()[NR::Y]) < 1.0) {
1600 return;
1601 }
1603 _desktop->set_display_area(d.min()[NR::X], d.min()[NR::Y], d.max()[NR::X], d.max()[NR::Y], 10);
1604 _namedview_modified(_desktop->namedview, SP_OBJECT_MODIFIED_FLAG, this);
1605 setTitle (SP_DOCUMENT_NAME(_desktop->doc()));
1606 }
1608 void
1609 EditWidget::onAdjValueChanged()
1610 {
1611 if (_update_a_f) return;
1612 _update_a_f = true;
1614 sp_canvas_scroll_to (_svg_canvas.spobj(),
1615 _bottom_scrollbar.get_value(),
1616 _right_scrollbar.get_value(),
1617 false);
1618 updateRulers();
1620 _update_a_f = false;
1621 }
1624 } // namespace View
1625 } // namespace UI
1626 } // namespace Inkscape
1628 /*
1629 Local Variables:
1630 mode:c++
1631 c-file-style:"stroustrup"
1632 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1633 indent-tabs-mode:nil
1634 fill-column:99
1635 End:
1636 */
1637 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :