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 * John Bintz <jcoswell@coswellproductions.org>
20 * Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
21 *
22 * Copyright (C) 2007 Johan Engelen
23 * Copyright (C) 2006 John Bintz
24 * Copyright (C) 1999-2005 Authors
25 * Copyright (C) 2000-2001 Ximian, Inc.
26 *
27 * Released under GNU GPL. Read the file 'COPYING' for more information.
28 */
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
34 #include <gtk/gtkwindow.h>
35 #include <gtk/gtkversion.h>
36 #include <gtk/gtklabel.h>
37 #include <gtkmm/radioaction.h>
38 #include <gtkmm/menubar.h>
39 #include <gtkmm/messagedialog.h>
40 #include <gtkmm/stock.h>
41 #include <gtkmm/accelmap.h>
42 #include <gtkmm/separator.h>
43 #include <gtkmm/base.h>
45 #include <sigc++/functors/mem_fun.h>
47 #include "macros.h"
48 #include "path-prefix.h"
49 #include "prefs-utils.h"
50 #include "file.h"
51 #include "application/editor.h"
52 #include "edit-widget.h"
53 #include "ui/stock.h"
54 #include "ui/stock-items.h"
55 #include "ui/icons.h"
57 #include "display/sodipodi-ctrlrect.h"
58 #include "helper/units.h"
59 #include "shortcuts.h"
60 #include "widgets/spw-utilities.h"
61 #include "event-context.h"
62 #include "document.h"
63 #include "sp-namedview.h"
64 #include "sp-item.h"
65 #include "interface.h"
66 #include "extension/db.h"
68 using namespace Inkscape::UI;
69 using namespace Inkscape::UI::Widget;
71 namespace Inkscape {
72 namespace UI {
73 namespace View {
75 EditWidget::EditWidget (SPDocument *doc)
76 : _main_window_table(4),
77 _viewport_table(3,3),
78 _act_grp(Gtk::ActionGroup::create()),
79 _ui_mgr(Gtk::UIManager::create()),
80 _update_s_f(false),
81 _update_a_f(false),
82 _interaction_disabled_counter(0)
83 {
84 g_warning("Creating new EditWidget");
86 _desktop = 0;
87 Icons::init();
88 Stock::init();
89 initActions();
90 initAccelMap();
91 initUIManager();
92 initLayout();
93 initEdit (doc);
94 g_warning("Done creating new EditWidget");
95 }
97 EditWidget::~EditWidget()
98 {
99 destroyEdit();
100 }
102 void
103 EditWidget::initActions()
104 {
105 initMenuActions();
106 initToolbarActions();
107 }
109 void
110 EditWidget::initUIManager()
111 {
112 _ui_mgr->insert_action_group(_act_grp);
113 add_accel_group(_ui_mgr->get_accel_group());
115 gchar *filename_utf8 = g_build_filename(INKSCAPE_UIDIR, "menus-bars.xml", NULL);
116 if (_ui_mgr->add_ui_from_file(filename_utf8) == 0) {
117 g_warning("Error merging ui from file '%s'", filename_utf8);
118 // fixme-charset: What charset should we pass to g_warning?
119 }
120 g_free(filename_utf8);
121 }
123 void
124 EditWidget::initLayout()
125 {
126 set_title("New document 1 - Inkscape");
127 set_resizable();
128 set_default_size(640, 480);
130 // top level window into which all other portions of the UI get inserted
131 add(_main_window_table);
132 // attach box for horizontal toolbars
133 _main_window_table.attach(_toolbars_vbox, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
134 // attach sub-window for viewport and vertical toolbars
135 _main_window_table.attach(_sub_window_hbox, 0, 1, 2, 3);
136 // viewport table with 3 rows by 3 columns
137 _sub_window_hbox.pack_end(_viewport_table);
139 // Menus and Bars
140 initMenuBar();
141 initCommandsBar();
142 initToolControlsBar();
143 initUriBar();
144 initToolsBar();
146 // Canvas Viewport
147 initLeftRuler();
148 initTopRuler();
149 initStickyZoom();
150 initBottomScrollbar();
151 initRightScrollbar();
152 _viewport_table.attach(_svg_canvas.widget(), 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
153 _svg_canvas.widget().show_all();
156 // The statusbar comes last and appears at the bottom of _main_window_table
157 initStatusbar();
159 signal_size_allocate().connect (sigc::mem_fun (*this, &EditWidget::onWindowSizeAllocate), false);
160 signal_realize().connect (sigc::mem_fun (*this, &EditWidget::onWindowRealize));
161 show_all_children();
162 }
164 void
165 EditWidget::onMenuItem()
166 {
167 g_warning("onMenuItem called");
168 }
170 void
171 EditWidget::onActionFileNew()
172 {
173 // g_warning("onActionFileNew called");
174 sp_file_new_default();
175 }
177 void
178 EditWidget::onActionFileOpen()
179 {
180 // g_warning("onActionFileOpen called");
181 sp_file_open_dialog (NULL, NULL);
182 }
184 void
185 EditWidget::onActionFileQuit()
186 {
187 g_warning("onActionFileQuit");
188 sp_ui_close_all();
189 }
191 void
192 EditWidget::onActionFilePrint()
193 {
194 g_warning("onActionFilePrint");
195 }
197 void
198 EditWidget::onToolbarItem()
199 {
200 g_warning("onToolbarItem called");
201 }
203 void
204 EditWidget::onSelectTool()
205 {
206 _tool_ctrl->remove();
207 _tool_ctrl->add(*_select_ctrl);
208 }
210 void
211 EditWidget::onNodeTool()
212 {
213 _tool_ctrl->remove();
214 _tool_ctrl->add(*_node_ctrl);
215 }
217 void
218 EditWidget::onDialogInkscapePreferences()
219 {
220 _dlg_mgr.showDialog("InkscapePreferences");
221 }
223 void
224 EditWidget::onDialogAbout()
225 {
226 }
228 void
229 EditWidget::onDialogAlignAndDistribute()
230 {
231 _dlg_mgr.showDialog("AlignAndDistribute");
232 }
234 void
235 EditWidget::onDialogDocumentProperties()
236 {
237 // manage (Inkscape::UI::Dialog::DocumentPreferences::create());
238 _dlg_mgr.showDialog("DocumentPreferences");
239 }
241 void
242 EditWidget::onDialogExport()
243 {
244 _dlg_mgr.showDialog("Export");
245 }
247 void
248 EditWidget::onDialogExtensionEditor()
249 {
250 _dlg_mgr.showDialog("ExtensionEditor");
251 }
253 void
254 EditWidget::onDialogFillAndStroke()
255 {
256 _dlg_mgr.showDialog("FillAndStroke");
257 }
259 void
260 EditWidget::onDialogFind()
261 {
262 _dlg_mgr.showDialog("Find");
263 }
265 void
266 EditWidget::onDialogLayerEditor()
267 {
268 _dlg_mgr.showDialog("LayerEditor");
269 }
271 void
272 EditWidget::onDialogMessages()
273 {
274 _dlg_mgr.showDialog("Messages");
275 }
277 void
278 EditWidget::onDialogObjectProperties()
279 {
280 _dlg_mgr.showDialog("ObjectProperties");
281 }
283 void
284 EditWidget::onDialogTextProperties()
285 {
286 _dlg_mgr.showDialog("TextProperties");
287 }
289 void
290 EditWidget::onDialogTrace()
291 {
292 }
294 void
295 EditWidget::onDialogTransformation()
296 {
297 _dlg_mgr.showDialog("Transformation");
298 }
300 void
301 EditWidget::onDialogXmlEditor()
302 {
303 _dlg_mgr.showDialog("XmlEditor");
304 }
306 void
307 EditWidget::onUriChanged()
308 {
309 g_message("onUriChanged called");
311 }
313 // FIXME: strings are replaced by placeholders, NOT to be translated until the code is enabled
314 // See http://sourceforge.net/mailarchive/message.php?msg_id=11746016 for details
316 void
317 EditWidget::initMenuActions()
318 {
319 // _act_grp->add(Gtk::Action::create("MenuFile", _("PLACEHOLDER, do not translate")));
320 // _act_grp->add(Gtk::Action::create("MenuEdit", _("PLACEHOLDER, do not translate")));
321 // _act_grp->add(Gtk::Action::create("MenuView", _("PLACEHOLDER, do not translate")));
322 // _act_grp->add(Gtk::Action::create("MenuLayer", _("PLACEHOLDER, do not translate")));
323 // _act_grp->add(Gtk::Action::create("MenuObject", _("PLACEHOLDER, do not translate")));
324 // _act_grp->add(Gtk::Action::create("MenuPath", _("PLACEHOLDER, do not translate")));
325 // _act_grp->add(Gtk::Action::create("MenuText", _("PLACEHOLDER, do not translate")));
326 // _act_grp->add(Gtk::Action::create("MenuHelp", _("PLACEHOLDER, do not translate")));
327 // temporarily replaced with non-gettext version to have a well-sized menu
328 // for testing:
330 _act_grp->add(Gtk::Action::create("MenuFile", "File"));
331 _act_grp->add(Gtk::Action::create("MenuEdit", "Edit"));
332 _act_grp->add(Gtk::Action::create("MenuView", "View"));
333 _act_grp->add(Gtk::Action::create("MenuLayer", "Layer"));
334 _act_grp->add(Gtk::Action::create("MenuObject", "Object"));
335 _act_grp->add(Gtk::Action::create("MenuPath", "Path"));
336 _act_grp->add(Gtk::Action::create("MenuText", "Text"));
337 _act_grp->add(Gtk::Action::create("MenuHelp", "Help"));
339 // File menu
340 _act_grp->add(Gtk::Action::create("New",
341 Gtk::Stock::NEW, Glib::ustring(),
342 _("PLACEHOLDER, do not translate")),
343 sigc::mem_fun(*this, &EditWidget::onActionFileNew));
345 _act_grp->add(Gtk::Action::create("Open",
346 Gtk::Stock::OPEN, Glib::ustring(),
347 _("PLACEHOLDER, do not translate")),
348 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
350 _act_grp->add(Gtk::Action::create("OpenRecent",
351 Stock::OPEN_RECENT));
353 _act_grp->add(Gtk::Action::create("Revert",
354 Gtk::Stock::REVERT_TO_SAVED, Glib::ustring(),
355 _("PLACEHOLDER, do not translate")),
356 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
358 _act_grp->add(Gtk::Action::create("Save",
359 Gtk::Stock::SAVE, Glib::ustring(),
360 _("PLACEHOLDER, do not translate")),
361 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
363 _act_grp->add(Gtk::Action::create("SaveAs",
364 Gtk::Stock::SAVE_AS, Glib::ustring(),
365 _("PLACEHOLDER, do not translate")),
366 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
368 _act_grp->add(Gtk::Action::create("Import",
369 Stock::IMPORT, Glib::ustring(),
370 _("PLACEHOLDER, do not translate")),
371 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
373 _act_grp->add(Gtk::Action::create("Export",
374 Stock::EXPORT, Glib::ustring(),
375 _("PLACEHOLDER, do not translate")),
376 sigc::mem_fun(*this, &EditWidget::onDialogExport));
378 _act_grp->add(Gtk::Action::create("Print",
379 Gtk::Stock::PRINT, Glib::ustring(),
380 _("PLACEHOLDER, do not translate")),
381 sigc::mem_fun(*this, &EditWidget::onActionFilePrint));
383 _act_grp->add(Gtk::Action::create("PrintPreview",
384 Gtk::Stock::PRINT_PREVIEW),
385 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
387 _act_grp->add(Gtk::Action::create("VacuumDefs",
388 Stock::VACUUM_DEFS),
389 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
391 _act_grp->add(Gtk::Action::create("DocumentProperties",
392 Gtk::Stock::PROPERTIES, Glib::ustring(),
393 _("PLACEHOLDER, do not translate")),
394 sigc::mem_fun(*this, &EditWidget::onDialogDocumentProperties));
396 _act_grp->add(Gtk::Action::create("InkscapePreferences",
397 Gtk::Stock::PREFERENCES, Glib::ustring(),
398 _("PLACEHOLDER, do not translate")),
399 sigc::mem_fun(*this, &EditWidget::onDialogInkscapePreferences));
401 _act_grp->add(Gtk::Action::create("Close",
402 Gtk::Stock::CLOSE),
403 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
405 _act_grp->add(Gtk::Action::create("Quit",
406 Gtk::Stock::QUIT),
407 sigc::mem_fun(*this, &EditWidget::onActionFileQuit));
409 // EditWidget menu
410 _act_grp->add(Gtk::Action::create("Undo",
411 Gtk::Stock::UNDO, Glib::ustring(),
412 _("PLACEHOLDER, do not translate")));
414 _act_grp->add(Gtk::Action::create("Redo",
415 Gtk::Stock::REDO, Glib::ustring(),
416 _("PLACEHOLDER, do not translate")));
418 _act_grp->add(Gtk::Action::create("UndoHistory",
419 Stock::UNDO_HISTORY, Glib::ustring(),
420 _("PLACEHOLDER, do not translate")));
422 _act_grp->add(Gtk::Action::create("Cut",
423 Gtk::Stock::CUT, Glib::ustring(),
424 _("PLACEHOLDER, do not translate")));
426 _act_grp->add(Gtk::Action::create("Copy",
427 Gtk::Stock::COPY, Glib::ustring(),
428 _("PLACEHOLDER, do not translate")));
430 _act_grp->add(Gtk::Action::create("Paste",
431 Gtk::Stock::PASTE, Glib::ustring(),
432 _("PLACEHOLDER, do not translate")));
434 _act_grp->add(Gtk::Action::create("PasteInPlace",
435 Stock::PASTE_IN_PLACE));
437 _act_grp->add(Gtk::Action::create("PasteStyle",
438 Stock::PASTE_STYLE));
440 _act_grp->add(Gtk::Action::create("Find",
441 Gtk::Stock::FIND),
442 sigc::mem_fun(*this, &EditWidget::onDialogFind));
444 _act_grp->add(Gtk::Action::create("Duplicate",
445 Stock::DUPLICATE, Glib::ustring(),
446 _("PLACEHOLDER, do not translate")));
448 _act_grp->add(Gtk::Action::create("Clone",
449 Stock::CLONE, Glib::ustring(),
450 _("PLACEHOLDER, do not translate")));
452 _act_grp->add(Gtk::Action::create("CloneUnlink",
453 Stock::CLONE_UNLINK, Glib::ustring(),
454 _("PLACEHOLDER, do not translate")));
456 _act_grp->add(Gtk::Action::create("CloneSelectOrig",
457 Stock::CLONE_SELECT_ORIG));
459 _act_grp->add(Gtk::Action::create("MakeBitmap",
460 Stock::MAKE_BITMAP));
462 _act_grp->add(Gtk::Action::create("Tile",
463 Stock::TILE));
465 _act_grp->add(Gtk::Action::create("Untile",
466 Stock::UNTILE));
468 _act_grp->add(Gtk::Action::create("Delete",
469 Gtk::Stock::DELETE));
471 _act_grp->add(Gtk::Action::create("SelectAll",
472 Stock::SELECT_ALL));
474 _act_grp->add(Gtk::Action::create("SelectAllInAllLayers",
475 Stock::SELECT_ALL_IN_ALL_LAYERS));
477 _act_grp->add(Gtk::Action::create("SelectInvert",
478 Stock::SELECT_INVERT));
480 _act_grp->add(Gtk::Action::create("SelectNone",
481 Stock::SELECT_NONE));
483 _act_grp->add(Gtk::Action::create("XmlEditor",
484 Stock::XML_EDITOR, Glib::ustring(),
485 _("PLACEHOLDER, do not translate")),
486 sigc::mem_fun(*this, &EditWidget::onDialogXmlEditor));
488 // View menu
489 _act_grp->add(Gtk::Action::create("Zoom",
490 Stock::ZOOM));
492 _act_grp->add(Gtk::Action::create("ZoomIn",
493 Stock::ZOOM_IN, Glib::ustring(),
494 _("PLACEHOLDER, do not translate")));
496 _act_grp->add(Gtk::Action::create("ZoomOut",
497 Stock::ZOOM_OUT, Glib::ustring(),
498 _("PLACEHOLDER, do not translate")));
500 _act_grp->add(Gtk::Action::create("Zoom100",
501 Stock::ZOOM_100, Glib::ustring(),
502 _("PLACEHOLDER, do not translate")));
504 _act_grp->add(Gtk::Action::create("Zoom50",
505 Stock::ZOOM_50, Glib::ustring(),
506 _("PLACEHOLDER, do not translate")));
508 _act_grp->add(Gtk::Action::create("Zoom200",
509 Stock::ZOOM_200, Glib::ustring(),
510 _("PLACEHOLDER, do not translate")));
512 _act_grp->add(Gtk::Action::create("ZoomSelection",
513 Stock::ZOOM_SELECTION, Glib::ustring(),
514 _("PLACEHOLDER, do not translate")));
516 _act_grp->add(Gtk::Action::create("ZoomDrawing",
517 Stock::ZOOM_DRAWING, Glib::ustring(),
518 _("PLACEHOLDER, do not translate")));
520 _act_grp->add(Gtk::Action::create("ZoomPage",
521 Stock::ZOOM_PAGE, Glib::ustring(),
522 _("PLACEHOLDER, do not translate")));
524 _act_grp->add(Gtk::Action::create("ZoomWidth",
525 Stock::ZOOM_WIDTH, Glib::ustring(),
526 _("PLACEHOLDER, do not translate")));
528 _act_grp->add(Gtk::Action::create("ZoomPrev",
529 Stock::ZOOM_PREV, Glib::ustring(),
530 _("PLACEHOLDER, do not translate")));
532 _act_grp->add(Gtk::Action::create("ZoomNext",
533 Stock::ZOOM_NEXT, Glib::ustring(),
534 _("PLACEHOLDER, do not translate")));
536 _act_grp->add(Gtk::Action::create("ShowHide",
537 Stock::SHOW_HIDE));
539 _act_grp->add(Gtk::ToggleAction::create("ShowHideCommandsBar",
540 Stock::SHOW_HIDE_COMMANDS_BAR));
542 _act_grp->add(Gtk::ToggleAction::create("ShowHideToolControlsBar",
543 Stock::SHOW_HIDE_TOOL_CONTROLS_BAR));
545 _act_grp->add(Gtk::ToggleAction::create("ShowHideToolsBar",
546 Stock::SHOW_HIDE_TOOLS_BAR));
548 _act_grp->add(Gtk::ToggleAction::create("ShowHideRulers",
549 Stock::SHOW_HIDE_RULERS));
551 _act_grp->add(Gtk::ToggleAction::create("ShowHideScrollbars",
552 Stock::SHOW_HIDE_SCROLLBARS));
554 _act_grp->add(Gtk::ToggleAction::create("ShowHideStatusbar",
555 Stock::SHOW_HIDE_STATUSBAR));
557 _act_grp->add(Gtk::Action::create("ShowHideDialogs",
558 Stock::SHOW_HIDE_DIALOGS));
560 _act_grp->add(Gtk::Action::create("Grid",
561 Stock::GRID));
563 _act_grp->add(Gtk::Action::create("Guides",
564 Stock::GUIDES));
566 _act_grp->add(Gtk::Action::create("Fullscreen",
567 Stock::FULLSCREEN));
569 _act_grp->add(Gtk::Action::create("Messages",
570 Stock::MESSAGES),
571 sigc::mem_fun(*this, &EditWidget::onDialogMessages));
573 _act_grp->add(Gtk::Action::create("Scripts",
574 Stock::SCRIPTS));
576 _act_grp->add(Gtk::Action::create("WindowPrev",
577 Stock::WINDOW_PREV));
579 _act_grp->add(Gtk::Action::create("WindowNext",
580 Stock::WINDOW_NEXT));
582 _act_grp->add(Gtk::Action::create("WindowDuplicate",
583 Stock::WINDOW_DUPLICATE));
585 // Layer menu
586 _act_grp->add(Gtk::Action::create("LayerNew",
587 Stock::LAYER_NEW));
589 _act_grp->add(Gtk::Action::create("LayerRename",
590 Stock::LAYER_RENAME));
592 _act_grp->add(Gtk::Action::create("LayerDuplicate",
593 Stock::LAYER_DUPLICATE));
595 _act_grp->add(Gtk::Action::create("LayerAnchor",
596 Stock::LAYER_ANCHOR));
598 _act_grp->add(Gtk::Action::create("LayerMergeDown",
599 Stock::LAYER_MERGE_DOWN));
601 _act_grp->add(Gtk::Action::create("LayerDelete",
602 Stock::LAYER_DELETE));
604 _act_grp->add(Gtk::Action::create("LayerSelectNext",
605 Stock::LAYER_SELECT_NEXT));
607 _act_grp->add(Gtk::Action::create("LayerSelectPrev",
608 Stock::LAYER_SELECT_PREV));
610 _act_grp->add(Gtk::Action::create("LayerSelectTop",
611 Stock::LAYER_SELECT_TOP));
613 _act_grp->add(Gtk::Action::create("LayerSelectBottom",
614 Stock::LAYER_SELECT_BOTTOM));
616 _act_grp->add(Gtk::Action::create("LayerRaise",
617 Stock::LAYER_RAISE));
619 _act_grp->add(Gtk::Action::create("LayerLower",
620 Stock::LAYER_LOWER));
622 _act_grp->add(Gtk::Action::create("LayerToTop",
623 Stock::LAYER_TO_TOP));
625 _act_grp->add(Gtk::Action::create("LayerToBottom",
626 Stock::LAYER_TO_BOTTOM));
628 // Object menu
629 _act_grp->add(Gtk::Action::create("FillAndStroke",
630 Stock::FILL_STROKE, Glib::ustring(),
631 _("PLACEHOLDER, do not translate")),
632 sigc::mem_fun(*this, &EditWidget::onDialogFillAndStroke));
634 _act_grp->add(Gtk::Action::create("ObjectProperties",
635 Stock::OBJECT_PROPERTIES),
636 sigc::mem_fun(*this, &EditWidget::onDialogObjectProperties));
638 _act_grp->add(Gtk::Action::create("Group",
639 Stock::GROUP, Glib::ustring(),
640 _("PLACEHOLDER, do not translate")));
642 _act_grp->add(Gtk::Action::create("Ungroup",
643 Stock::UNGROUP, Glib::ustring(),
644 _("PLACEHOLDER, do not translate")));
646 _act_grp->add(Gtk::Action::create("Raise",
647 Stock::RAISE, Glib::ustring(),
648 _("PLACEHOLDER, do not translate")));
650 _act_grp->add(Gtk::Action::create("Lower",
651 Stock::LOWER, Glib::ustring(),
652 _("PLACEHOLDER, do not translate")));
654 _act_grp->add(Gtk::Action::create("RaiseToTop",
655 Stock::RAISE_TO_TOP, Glib::ustring(),
656 _("PLACEHOLDER, do not translate")));
658 _act_grp->add(Gtk::Action::create("LowerToBottom",
659 Stock::LOWER_TO_BOTTOM, Glib::ustring(),
660 _("PLACEHOLDER, do not translate")));
662 _act_grp->add(Gtk::Action::create("MoveToNewLayer",
663 Stock::MOVE_TO_NEW_LAYER, Glib::ustring(),
664 _("PLACEHOLDER, do not translate")));
666 _act_grp->add(Gtk::Action::create("MoveToNextLayer",
667 Stock::MOVE_TO_NEXT_LAYER, Glib::ustring(),
668 _("PLACEHOLDER, do not translate")));
670 _act_grp->add(Gtk::Action::create("MoveToPrevLayer",
671 Stock::MOVE_TO_PREV_LAYER, Glib::ustring(),
672 _("PLACEHOLDER, do not translate")));
674 _act_grp->add(Gtk::Action::create("MoveToTopLayer",
675 Stock::MOVE_TO_TOP_LAYER, Glib::ustring(),
676 _("PLACEHOLDER, do not translate")));
678 _act_grp->add(Gtk::Action::create("MoveToBottomLayer",
679 Stock::MOVE_TO_BOTTOM_LAYER, Glib::ustring(),
680 _("PLACEHOLDER, do not translate")));
682 _act_grp->add(Gtk::Action::create("Rotate90CW",
683 Stock::ROTATE_90_CW, Glib::ustring(),
684 _("PLACEHOLDER, do not translate")));
686 _act_grp->add(Gtk::Action::create("Rotate90CCW",
687 Stock::ROTATE_90_CCW, Glib::ustring(),
688 _("PLACEHOLDER, do not translate")));
690 _act_grp->add(Gtk::Action::create("FlipHoriz",
691 Stock::FLIP_HORIZ, Glib::ustring(),
692 _("PLACEHOLDER, do not translate")));
694 _act_grp->add(Gtk::Action::create("FlipVert",
695 Stock::FLIP_VERT, Glib::ustring(),
696 _("PLACEHOLDER, do not translate")));
698 _act_grp->add(Gtk::Action::create("Transformation",
699 Stock::TRANSFORMATION, Glib::ustring(),
700 _("PLACEHOLDER, do not translate")),
701 sigc::mem_fun(*this, &EditWidget::onDialogTransformation));
703 _act_grp->add(Gtk::Action::create("AlignAndDistribute",
704 Stock::ALIGN_DISTRIBUTE, Glib::ustring(),
705 _("PLACEHOLDER, do not translate")),
706 sigc::mem_fun(*this, &EditWidget::onDialogAlignAndDistribute));
708 // Path menu
709 _act_grp->add(Gtk::Action::create("ObjectToPath",
710 Stock::OBJECT_TO_PATH, Glib::ustring(),
711 _("PLACEHOLDER, do not translate")));
713 _act_grp->add(Gtk::Action::create("StrokeToPath",
714 Stock::STROKE_TO_PATH, Glib::ustring(),
715 _("PLACEHOLDER, do not translate")));
717 _act_grp->add(Gtk::Action::create("Trace",
718 Stock::TRACE),
719 sigc::mem_fun(*this, &EditWidget::onDialogTrace));
721 _act_grp->add(Gtk::Action::create("Union",
722 Stock::UNION));
724 _act_grp->add(Gtk::Action::create("Difference",
725 Stock::DIFFERENCE));
727 _act_grp->add(Gtk::Action::create("Intersection",
728 Stock::INTERSECTION));
730 _act_grp->add(Gtk::Action::create("Exclusion",
731 Stock::EXCLUSION));
733 _act_grp->add(Gtk::Action::create("Division",
734 Stock::DIVISION));
736 _act_grp->add(Gtk::Action::create("CutPath",
737 Stock::CUT_PATH));
739 _act_grp->add(Gtk::Action::create("Combine",
740 Stock::COMBINE));
742 _act_grp->add(Gtk::Action::create("BreakApart",
743 Stock::BREAK_APART));
745 _act_grp->add(Gtk::Action::create("Inset",
746 Stock::INSET));
748 _act_grp->add(Gtk::Action::create("Outset",
749 Stock::OUTSET));
751 _act_grp->add(Gtk::Action::create("OffsetDynamic",
752 Stock::OFFSET_DYNAMIC));
754 _act_grp->add(Gtk::Action::create("OffsetLinked",
755 Stock::OFFSET_LINKED));
757 _act_grp->add(Gtk::Action::create("Simplify",
758 Stock::SIMPLIFY));
760 _act_grp->add(Gtk::Action::create("Reverse",
761 Stock::REVERSE));
763 _act_grp->add(Gtk::Action::create("Cleanup",
764 Gtk::Stock::CLEAR,
765 _("PLACEHOLDER, do not translate")));
767 // Text menu
768 _act_grp->add(Gtk::Action::create("TextProperties",
769 Gtk::Stock::SELECT_FONT, Glib::ustring(),
770 _("PLACEHOLDER, do not translate")),
771 sigc::mem_fun(*this, &EditWidget::onDialogTextProperties));
773 _act_grp->add(Gtk::Action::create("PutOnPath",
774 Stock::PUT_ON_PATH));
776 _act_grp->add(Gtk::Action::create("RemoveFromPath",
777 Stock::REMOVE_FROM_PATH));
779 _act_grp->add(Gtk::Action::create("RemoveManualKerns",
780 Stock::REMOVE_MANUAL_KERNS));
782 // Whiteboard menu
783 #ifdef WITH_INKBOARD
784 #endif
786 // About menu
787 _act_grp->add(Gtk::Action::create("KeysAndMouse",
788 Stock::KEYS_MOUSE));
790 _act_grp->add(Gtk::Action::create("Tutorials",
791 Stock::TUTORIALS));
793 _act_grp->add(Gtk::Action::create("About",
794 Stock::ABOUT),
795 sigc::mem_fun(*this, &EditWidget::onDialogAbout));
796 }
798 void
799 EditWidget::initToolbarActions()
800 {
801 // Tools bar
802 Gtk::RadioAction::Group tools;
804 _act_grp->add(Gtk::RadioAction::create(tools, "ToolSelect",
805 Stock::TOOL_SELECT, Glib::ustring(),
806 _("PLACEHOLDER, do not translate")),
807 sigc::mem_fun(*this, &EditWidget::onSelectTool));
809 _act_grp->add(Gtk::RadioAction::create(tools, "ToolNode",
810 Stock::TOOL_NODE, Glib::ustring(),
811 _("PLACEHOLDER, do not translate")),
812 sigc::mem_fun(*this, &EditWidget::onNodeTool));
814 _act_grp->add(Gtk::RadioAction::create(tools, "ToolZoom",
815 Stock::TOOL_ZOOM, Glib::ustring(),
816 _("PLACEHOLDER, do not translate")));
818 _act_grp->add(Gtk::RadioAction::create(tools, "ToolRect",
819 Stock::TOOL_RECT, Glib::ustring(),
820 _("PLACEHOLDER, do not translate")));
822 _act_grp->add(Gtk::RadioAction::create(tools, "ToolArc",
823 Stock::TOOL_ARC, Glib::ustring(),
824 _("PLACEHOLDER, do not translate")));
826 _act_grp->add(Gtk::RadioAction::create(tools, "ToolStar",
827 Stock::TOOL_STAR, Glib::ustring(),
828 _("PLACEHOLDER, do not translate")));
830 _act_grp->add(Gtk::RadioAction::create(tools, "ToolSpiral",
831 Stock::TOOL_SPIRAL, Glib::ustring(),
832 _("PLACEHOLDER, do not translate")));
834 _act_grp->add(Gtk::RadioAction::create(tools, "ToolFreehand",
835 Stock::TOOL_FREEHAND, Glib::ustring(),
836 _("PLACEHOLDER, do not translate")));
838 _act_grp->add(Gtk::RadioAction::create(tools, "ToolPen",
839 Stock::TOOL_PEN, Glib::ustring(),
840 _("PLACEHOLDER, do not translate")));
842 _act_grp->add(Gtk::RadioAction::create(tools, "ToolDynaDraw",
843 Stock::TOOL_DYNADRAW, Glib::ustring(),
844 _("PLACEHOLDER, do not translate")));
846 _act_grp->add(Gtk::RadioAction::create(tools, "ToolText",
847 Stock::TOOL_TEXT, Glib::ustring(),
848 _("PLACEHOLDER, do not translate")));
850 _act_grp->add(Gtk::RadioAction::create(tools, "ToolDropper",
851 Stock::TOOL_DROPPER, Glib::ustring(),
852 _("PLACEHOLDER, do not translate")));
854 // Select Controls bar
855 _act_grp->add(Gtk::ToggleAction::create("TransformStroke",
856 Stock::TRANSFORM_STROKE, Glib::ustring(),
857 _("PLACEHOLDER, do not translate")));
859 _act_grp->add(Gtk::ToggleAction::create("TransformCorners",
860 Stock::TRANSFORM_CORNERS, Glib::ustring(),
861 _("PLACEHOLDER, do not translate")));
863 _act_grp->add(Gtk::ToggleAction::create("TransformGradient",
864 Stock::TRANSFORM_GRADIENT, Glib::ustring(),
865 _("PLACEHOLDER, do not translate")));
867 _act_grp->add(Gtk::ToggleAction::create("TransformPattern",
868 Stock::TRANSFORM_PATTERN, Glib::ustring(),
869 _("PLACEHOLDER, do not translate")));
871 // Node Controls bar
872 _act_grp->add(Gtk::Action::create("NodeInsert",
873 Gtk::Stock::ADD, Glib::ustring(),
874 _("PLACEHOLDER, do not translate")));
876 _act_grp->add(Gtk::Action::create("NodeDelete",
877 Gtk::Stock::REMOVE, Glib::ustring(),
878 _("PLACEHOLDER, do not translate")));
880 _act_grp->add(Gtk::Action::create("NodeJoin",
881 Stock::NODE_JOIN, Glib::ustring(),
882 _("PLACEHOLDER, do not translate")));
884 _act_grp->add(Gtk::Action::create("NodeJoinSegment",
885 Stock::NODE_JOIN_SEGMENT, Glib::ustring(),
886 _("PLACEHOLDER, do not translate")));
888 _act_grp->add(Gtk::Action::create("NodeDeleteSegment",
889 Stock::NODE_DELETE_SEGMENT, Glib::ustring(),
890 _("PLACEHOLDER, do not translate")));
892 _act_grp->add(Gtk::Action::create("NodeBreak",
893 Stock::NODE_BREAK, Glib::ustring(),
894 _("PLACEHOLDER, do not translate")));
896 _act_grp->add(Gtk::Action::create("NodeCorner",
897 Stock::NODE_CORNER, Glib::ustring(),
898 _("PLACEHOLDER, do not translate")));
900 _act_grp->add(Gtk::Action::create("NodeSmooth",
901 Stock::NODE_SMOOTH, Glib::ustring(),
902 _("PLACEHOLDER, do not translate")));
904 _act_grp->add(Gtk::Action::create("NodeSymmetric",
905 Stock::NODE_SYMMETRIC, Glib::ustring(),
906 _("PLACEHOLDER, do not translate")));
908 _act_grp->add(Gtk::Action::create("NodeLine",
909 Stock::NODE_LINE, Glib::ustring(),
910 _("PLACEHOLDER, do not translate")));
912 _act_grp->add(Gtk::Action::create("NodeCurve",
913 Stock::NODE_CURVE, Glib::ustring(),
914 _("PLACEHOLDER, do not translate")));
915 }
917 void
918 EditWidget::initAccelMap()
919 {
920 gchar *filename = g_build_filename(INKSCAPE_UIDIR, "keybindings.rc", NULL);
921 Gtk::AccelMap::load(filename);
922 g_free(filename);
924 // One problem is that the keys 1-6 are zoom accelerators which get
925 // caught as accelerator _before_ any Entry input handler receives them,
926 // for example the zoom status. At the moment, the best way seems to
927 // disable them as accelerators when the Entry gets focus, and enable
928 // them when focus goes elsewhere. The code for this belongs here,
929 // and not in zoom-status.cpp .
931 _zoom_status.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditWidget::onEntryFocusIn));
932 _zoom_status.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditWidget::onEntryFocusOut));
933 }
935 bool
936 EditWidget::onEntryFocusIn (GdkEventFocus* ev)
937 {
938 Gdk::ModifierType m = static_cast<Gdk::ModifierType>(0);
939 Gtk::AccelMap::change_entry ("<Actions>//Zoom100", 0, m, false);
940 Gtk::AccelMap::change_entry ("<Actions>//Zoom50", 0, m, false);
941 Gtk::AccelMap::change_entry ("<Actions>//ZoomSelection", 0, m, false);
942 Gtk::AccelMap::change_entry ("<Actions>//ZoomDrawing", 0, m, false);
943 Gtk::AccelMap::change_entry ("<Actions>//ZoomPage", 0, m, false);
944 Gtk::AccelMap::change_entry ("<Actions>//ZoomWidth", 0, m, false);
945 return false;
946 }
948 bool
949 EditWidget::onEntryFocusOut (GdkEventFocus* ev)
950 {
951 Gdk::ModifierType m = static_cast<Gdk::ModifierType>(0);
952 Gtk::AccelMap::change_entry ("<Actions>//Zoom100", '1', m, false);
953 Gtk::AccelMap::change_entry ("<Actions>//Zoom50", '2', m, false);
954 Gtk::AccelMap::change_entry ("<Actions>//ZoomSelection", '3', m, false);
955 Gtk::AccelMap::change_entry ("<Actions>//ZoomDrawing", '4', m, false);
956 Gtk::AccelMap::change_entry ("<Actions>//ZoomPage", '5', m, false);
957 Gtk::AccelMap::change_entry ("<Actions>//ZoomWidth", '6', m, false);
958 return false;
959 }
961 void
962 EditWidget::initMenuBar()
963 {
964 g_assert(_ui_mgr);
965 Gtk::MenuBar *menu = static_cast<Gtk::MenuBar*>(_ui_mgr->get_widget("/MenuBar"));
966 g_assert(menu != NULL);
967 _main_window_table.attach(*Gtk::manage(menu), 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
968 }
970 void
971 EditWidget::initCommandsBar()
972 {
973 g_assert(_ui_mgr);
974 Toolbox *bar = new Toolbox(static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/CommandsBar")),
975 Gtk::TOOLBAR_ICONS);
976 g_assert(bar != NULL);
977 _toolbars_vbox.pack_start(*Gtk::manage(bar), Gtk::PACK_SHRINK);
978 }
980 void
981 EditWidget::initToolControlsBar()
982 {
983 // TODO: Do UIManager controlled widgets need to be deleted?
984 _select_ctrl = static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/SelectControlsBar"));
985 _node_ctrl = static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/NodeControlsBar"));
987 _tool_ctrl = new Toolbox(_select_ctrl, Gtk::TOOLBAR_ICONS);
989 _toolbars_vbox.pack_start(*Gtk::manage(_tool_ctrl), Gtk::PACK_SHRINK);
990 }
992 void
993 EditWidget::initUriBar()
994 {
995 /// \todo Create an Inkscape::UI::Widget::UriBar class (?)
997 _uri_ctrl = new Gtk::Toolbar();
999 _uri_label.set_label(_("PLACEHOLDER, DO NOT TRANSLATE"));
1000 _uri_ctrl->add(_uri_label);
1001 _uri_ctrl->add(_uri_entry);
1003 _uri_entry.signal_activate()
1004 .connect_notify(sigc::mem_fun(*this, &EditWidget::onUriChanged));
1006 _toolbars_vbox.pack_start(*Gtk::manage(_uri_ctrl), Gtk::PACK_SHRINK);
1007 }
1009 void
1010 EditWidget::initToolsBar()
1011 {
1012 Toolbox *bar = new Toolbox(static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/ToolsBar")),
1013 Gtk::TOOLBAR_ICONS,
1014 Gtk::ORIENTATION_VERTICAL);
1015 g_assert(bar != NULL);
1016 _sub_window_hbox.pack_start(*Gtk::manage(bar), Gtk::PACK_SHRINK);
1017 }
1019 void
1020 EditWidget::initTopRuler()
1021 {
1022 _viewport_table.attach(_top_ruler, 1, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
1024 _tooltips.set_tip (_top_ruler, _top_ruler.get_tip());
1025 }
1027 void
1028 EditWidget::initLeftRuler()
1029 {
1030 _viewport_table.attach(_left_ruler, 0, 1, 1, 2, Gtk::SHRINK, Gtk::FILL|Gtk::EXPAND);
1032 _tooltips.set_tip (_left_ruler, _left_ruler.get_tip());
1033 }
1035 void
1036 EditWidget::initBottomScrollbar()
1037 {
1038 _viewport_table.attach(_bottom_scrollbar, 1, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
1039 _bottom_scrollbar.signal_value_changed().connect (sigc::mem_fun (*this, &EditWidget::onAdjValueChanged));
1040 _bottom_scrollbar.property_adjustment() = new Gtk::Adjustment (0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0);
1041 }
1043 void
1044 EditWidget::initRightScrollbar()
1045 {
1046 _viewport_table.attach(_right_scrollbar, 2, 3, 1, 2, Gtk::SHRINK, Gtk::FILL|Gtk::EXPAND);
1048 _right_scrollbar.signal_value_changed().connect (sigc::mem_fun (*this, &EditWidget::onAdjValueChanged));
1049 _right_scrollbar.property_adjustment() = new Gtk::Adjustment (0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0);
1050 }
1052 void
1053 EditWidget::initStickyZoom()
1054 {
1055 _viewport_table.attach(_sticky_zoom, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
1057 _sticky_zoom.set_active (prefs_get_int_attribute ("options.stickyzoom", "value", 0) != 0);
1058 _tooltips.set_tip (_sticky_zoom, _("Zoom drawing if window size changes"));
1060 /// \todo icon not implemented
1061 }
1063 void
1064 EditWidget::initStatusbar()
1065 {
1066 _statusbar.pack_start (_selected_style_status, false, false, 1);
1067 _statusbar.pack_start (*new Gtk::VSeparator(), false, false, 0);
1069 _tooltips.set_tip (_zoom_status, _("Zoom"));
1071 _layer_selector.reference();
1072 _statusbar.pack_start (_layer_selector, false, false, 1);
1074 _coord_status.property_n_rows() = 2;
1075 _coord_status.property_n_columns() = 5;
1076 _coord_status.property_row_spacing() = 0;
1077 _coord_status.property_column_spacing() = 2;
1078 _coord_eventbox.add (_coord_status);
1079 _tooltips.set_tip (_coord_eventbox, _("Cursor coordinates"));
1080 _coord_status.attach (*new Gtk::VSeparator(), 0,1, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1081 _coord_status.attach (*new Gtk::Label("X:", 0.0, 0.5), 1,2, 0,1, Gtk::FILL,Gtk::FILL, 0,0);
1082 _coord_status.attach (*new Gtk::Label("Y:", 0.0, 0.5), 1,2, 1,2, Gtk::FILL,Gtk::FILL, 0,0);
1083 _coord_status_x.set_text ("0.0");
1084 _coord_status_x.set_alignment (0.0, 0.5);
1085 _coord_status_y.set_text ("0.0");
1086 _coord_status_y.set_alignment (0.0, 0.5);
1087 _coord_status.attach (_coord_status_x, 2,3, 0,1, Gtk::FILL,Gtk::FILL, 0,0);
1088 _coord_status.attach (_coord_status_y, 2,3, 1,2, Gtk::FILL,Gtk::FILL, 0,0);
1089 _coord_status.attach (*new Gtk::Label("Z:", 0.0, 0.5), 3,4, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1090 _coord_status.attach (_zoom_status, 4,5, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1091 sp_set_font_size_smaller (static_cast<GtkWidget*>((void*)_coord_status.gobj()));
1092 _statusbar.pack_end (_coord_eventbox, false, false, 1);
1094 _select_status.property_xalign() = 0.0;
1095 _select_status.property_yalign() = 0.5;
1096 _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."));
1097 // include this again with Gtk+-2.6
1098 #if GTK_VERSION_GE(2,6)
1099 gtk_label_set_ellipsize (GTK_LABEL(_select_status.gobj()), PANGO_ELLIPSIZE_END);
1100 #endif
1101 _select_status.set_size_request (1, -1);
1102 _statusbar.pack_start (_select_status, true, true, 0);
1104 _main_window_table.attach(_statusbar, 0, 1, 3, 4, Gtk::FILL, Gtk::SHRINK);
1105 }
1107 //========================================
1108 //----------implements EditWidgetInterface
1110 void *
1111 EditWidget::getWindow()
1112 {
1113 return this;
1114 }
1116 void
1117 EditWidget::setTitle (gchar const* new_title)
1118 {
1119 set_title (new_title);
1120 }
1122 void
1123 EditWidget::layout()
1124 {
1125 show_all_children();
1126 }
1128 void
1129 EditWidget::present()
1130 {
1131 this->Gtk::Window::present();
1132 }
1134 void
1135 EditWidget::getGeometry (gint &x, gint &y, gint &w, gint &h)
1136 {
1137 get_position (x, y);
1138 get_size (w, h);
1139 }
1141 void
1142 EditWidget::setSize (gint w, gint h)
1143 {
1144 resize (w, h);
1145 }
1147 void
1148 EditWidget::setPosition (NR::Point p)
1149 {
1150 move (int(p[NR::X]), int(p[NR::Y]));
1151 }
1153 /// \param p is already gobj()!
1154 void
1155 EditWidget::setTransient (void* p, int i)
1156 {
1157 gtk_window_set_transient_for (static_cast<GtkWindow*>(p), this->gobj());
1158 if (i==2)
1159 this->Gtk::Window::present();
1160 }
1162 NR::Point
1163 EditWidget::getPointer()
1164 {
1165 int x, y;
1166 get_pointer (x, y);
1167 return NR::Point (x, y);
1168 }
1170 void
1171 EditWidget::setFullscreen()
1172 {
1173 fullscreen();
1174 }
1176 /**
1177 * Shuts down the desktop object for the view being closed. It checks
1178 * to see if the document has been edited, and if so prompts the user
1179 * to save, discard, or cancel. Returns TRUE if the shutdown operation
1180 * is cancelled or if the save is cancelled or fails, FALSE otherwise.
1181 */
1182 bool
1183 EditWidget::shutdown()
1184 {
1185 g_assert (_desktop != NULL);
1186 if (Inkscape::NSApplication::Editor::isDuplicatedView (_desktop))
1187 return false;
1189 SPDocument *doc = _desktop->doc();
1190 if (sp_document_repr_root(doc)->attribute("sodipodi:modified") != NULL)
1191 {
1192 gchar *markup;
1193 /// \todo FIXME !!! obviously this will have problems if the document
1194 /// name contains markup characters
1195 markup = g_strdup_printf(
1196 _("<span weight=\"bold\" size=\"larger\">Save changes to document \"%s\" before closing?</span>\n\n"
1197 "If you close without saving, your changes will be discarded."),
1198 SP_DOCUMENT_NAME(doc));
1200 Gtk::MessageDialog dlg (*this,
1201 markup,
1202 true,
1203 Gtk::MESSAGE_WARNING,
1204 Gtk::BUTTONS_NONE,
1205 true);
1206 g_free(markup);
1207 Gtk::Button close_button (_("Close _without saving"), true);
1208 dlg.add_action_widget (close_button, Gtk::RESPONSE_NO);
1209 close_button.show();
1210 dlg.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1211 dlg.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_YES);
1212 dlg.set_default_response (Gtk::RESPONSE_YES);
1214 int response = dlg.run();
1215 switch (response)
1216 {
1217 case Gtk::RESPONSE_YES:
1218 sp_document_ref(doc);
1219 if (sp_file_save_document(doc)) {
1220 sp_document_unref(doc);
1221 } else { // save dialog cancelled or save failed
1222 sp_document_unref(doc);
1223 return TRUE;
1224 }
1225 break;
1226 case Gtk::RESPONSE_NO:
1227 break;
1228 default: // cancel pressed, or dialog was closed
1229 return TRUE;
1230 break;
1231 }
1232 }
1234 /* Code to check data loss */
1235 bool allow_data_loss = FALSE;
1236 while (sp_document_repr_root(doc)->attribute("inkscape:dataloss") != NULL && allow_data_loss == FALSE)
1237 {
1238 gchar *markup;
1239 /// \todo FIXME !!! obviously this will have problems if the document
1240 /// name contains markup characters
1241 markup = g_strdup_printf(
1242 _("<span weight=\"bold\" size=\"larger\">The file \"%s\" was saved with a format (%s) that may cause data loss!</span>\n\n"
1243 "Do you want to save this file in another format?"),
1244 SP_DOCUMENT_NAME(doc),
1245 Inkscape::Extension::db.get(sp_document_repr_root(doc)->attribute("inkscape:output_extension"))->get_name());
1247 Gtk::MessageDialog dlg (*this,
1248 markup,
1249 true,
1250 Gtk::MESSAGE_WARNING,
1251 Gtk::BUTTONS_NONE,
1252 true);
1253 g_free(markup);
1254 Gtk::Button close_button (_("Close _without saving"), true);
1255 dlg.add_action_widget (close_button, Gtk::RESPONSE_NO);
1256 close_button.show();
1257 dlg.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1258 dlg.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_YES);
1259 dlg.set_default_response (Gtk::RESPONSE_YES);
1261 int response = dlg.run();
1263 switch (response)
1264 {
1265 case Gtk::RESPONSE_YES:
1266 sp_document_ref(doc);
1267 if (sp_file_save_document(doc)) {
1268 sp_document_unref(doc);
1269 } else { // save dialog cancelled or save failed
1270 sp_document_unref(doc);
1271 return TRUE;
1272 }
1273 break;
1274 case Gtk::RESPONSE_NO:
1275 allow_data_loss = TRUE;
1276 break;
1277 default: // cancel pressed, or dialog was closed
1278 return TRUE;
1279 break;
1280 }
1281 }
1283 return false;
1284 }
1287 void
1288 EditWidget::destroy()
1289 {
1290 delete this;
1291 }
1293 void
1294 EditWidget::requestCanvasUpdate()
1295 {
1296 _svg_canvas.widget().queue_draw();
1297 }
1299 void
1300 EditWidget::requestCanvasUpdateAndWait()
1301 {
1302 requestCanvasUpdate();
1304 while (gtk_events_pending())
1305 gtk_main_iteration_do(FALSE);
1306 }
1308 void
1309 EditWidget::enableInteraction()
1310 {
1311 g_return_if_fail(_interaction_disabled_counter > 0);
1313 _interaction_disabled_counter--;
1315 if (_interaction_disabled_counter == 0) {
1316 this->set_sensitive(true);
1317 }
1318 }
1320 void
1321 EditWidget::disableInteraction()
1322 {
1323 if (_interaction_disabled_counter == 0) {
1324 this->set_sensitive(false);
1325 }
1327 _interaction_disabled_counter++;
1328 }
1330 void
1331 EditWidget::activateDesktop()
1332 {
1333 /// \todo active_desktop_indicator not implemented
1334 }
1336 void
1337 EditWidget::deactivateDesktop()
1338 {
1339 /// \todo active_desktop_indicator not implemented
1340 }
1342 void
1343 EditWidget::viewSetPosition (NR::Point p)
1344 {
1345 // p -= _namedview->gridorigin;
1346 /// \todo Why was the origin corrected for the grid origin? (johan)
1348 double lo, up, pos, max;
1349 _top_ruler.get_range (lo, up, pos, max);
1350 _top_ruler.set_range (lo, up, p[NR::X], max);
1351 _left_ruler.get_range (lo, up, pos, max);
1352 _left_ruler.set_range (lo, up, p[NR::Y], max);
1353 }
1355 void
1356 EditWidget::updateRulers()
1357 {
1358 //NR::Point gridorigin = _namedview->gridorigin;
1359 /// \todo Why was the origin corrected for the grid origin? (johan)
1361 NR::Rect const viewbox = _svg_canvas.spobj()->getViewbox();
1362 double lo, up, pos, max;
1363 double const scale = _desktop->current_zoom();
1364 double s = viewbox.min()[NR::X] / scale; //- gridorigin[NR::X];
1365 double e = viewbox.max()[NR::X] / scale; //- gridorigin[NR::X];
1366 _top_ruler.get_range(lo, up, pos, max);
1367 _top_ruler.set_range(s, e, pos, e);
1368 s = viewbox.min()[NR::Y] / -scale; //- gridorigin[NR::Y];
1369 e = viewbox.max()[NR::Y] / -scale; //- gridorigin[NR::Y];
1370 _left_ruler.set_range(s, e, 0 /*gridorigin[NR::Y]*/, e);
1371 /// \todo is that correct?
1372 }
1374 void
1375 EditWidget::updateScrollbars (double scale)
1376 {
1377 // do not call this function before canvas has its size allocated
1378 if (!is_realized() || _update_s_f) {
1379 return;
1380 }
1382 _update_s_f = true;
1384 /* The desktop region we always show unconditionally */
1385 SPDocument *doc = _desktop->doc();
1386 NR::Rect darea = NR::Rect(NR::Point(-sp_document_width(doc),
1387 -sp_document_height(doc)),
1388 NR::Point(2 * sp_document_width(doc),
1389 2 * sp_document_height(doc)));
1390 darea = NR::union_bounds(darea, sp_item_bbox_desktop(SP_ITEM(SP_DOCUMENT_ROOT(doc))));
1392 /* Canvas region we always show unconditionally */
1393 NR::Rect carea(NR::Point(darea.min()[NR::X] * scale - 64,
1394 darea.max()[NR::Y] * -scale - 64),
1395 NR::Point(darea.max()[NR::X] * scale + 64,
1396 darea.min()[NR::Y] * -scale + 64));
1398 NR::Rect const viewbox = _svg_canvas.spobj()->getViewbox();
1400 /* Viewbox is always included into scrollable region */
1401 carea = NR::union_bounds(carea, viewbox);
1403 Gtk::Adjustment *adj = _bottom_scrollbar.get_adjustment();
1404 adj->set_value(viewbox.min()[NR::X]);
1405 adj->set_lower(carea.min()[NR::X]);
1406 adj->set_upper(carea.max()[NR::X]);
1407 adj->set_page_increment(viewbox.dimensions()[NR::X]);
1408 adj->set_step_increment(0.1 * (viewbox.dimensions()[NR::X]));
1409 adj->set_page_size(viewbox.dimensions()[NR::X]);
1411 adj = _right_scrollbar.get_adjustment();
1412 adj->set_value(viewbox.min()[NR::Y]);
1413 adj->set_lower(carea.min()[NR::Y]);
1414 adj->set_upper(carea.max()[NR::Y]);
1415 adj->set_page_increment(viewbox.dimensions()[NR::Y]);
1416 adj->set_step_increment(0.1 * viewbox.dimensions()[NR::Y]);
1417 adj->set_page_size(viewbox.dimensions()[NR::Y]);
1419 _update_s_f = false;
1420 }
1422 void
1423 EditWidget::toggleRulers()
1424 {
1425 if (_top_ruler.is_visible())
1426 {
1427 _top_ruler.hide_all();
1428 _left_ruler.hide_all();
1429 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.rulers" : "window.rulers", "state", 0);
1430 } else {
1431 _top_ruler.show_all();
1432 _left_ruler.show_all();
1433 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.rulers" : "window.rulers", "state", 1);
1434 }
1435 }
1437 void
1438 EditWidget::toggleScrollbars()
1439 {
1440 if (_bottom_scrollbar.is_visible())
1441 {
1442 _bottom_scrollbar.hide_all();
1443 _right_scrollbar.hide_all();
1444 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.scrollbars" : "window.scrollbars", "state", 0);
1445 } else {
1446 _bottom_scrollbar.show_all();
1447 _right_scrollbar.show_all();
1448 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.scrollbars" : "window.scrollbars", "state", 1);
1449 }
1450 }
1452 void
1453 EditWidget::updateZoom()
1454 {
1455 _zoom_status.update();
1456 }
1458 void
1459 EditWidget::letZoomGrabFocus()
1460 {
1461 _zoom_status.grab_focus();
1462 }
1464 void
1465 EditWidget::setToolboxFocusTo (const gchar *)
1466 {
1467 /// \todo not implemented
1468 }
1470 void
1471 EditWidget::setToolboxAdjustmentValue (const gchar *, double)
1472 {
1473 /// \todo not implemented
1474 }
1476 bool
1477 EditWidget::isToolboxButtonActive (gchar const*)
1478 {
1479 /// \todo not implemented
1480 return true;
1481 }
1483 void
1484 EditWidget::setCoordinateStatus (NR::Point p)
1485 {
1486 gchar *cstr = g_strdup_printf ("%6.2f", _dt2r * p[NR::X]);
1487 _coord_status_x.property_label() = cstr;
1488 g_free (cstr);
1489 cstr = g_strdup_printf ("%6.2f", _dt2r * p[NR::Y]);
1490 _coord_status_y.property_label() = cstr;
1491 g_free (cstr);
1492 }
1494 void
1495 EditWidget::setMessage (Inkscape::MessageType type, gchar const* msg)
1496 {
1497 _select_status.set_markup (msg? msg : "");
1498 }
1500 bool
1501 EditWidget::warnDialog (gchar* msg)
1502 {
1503 Gtk::MessageDialog dlg (*this,
1504 msg,
1505 true,
1506 Gtk::MESSAGE_WARNING,
1507 Gtk::BUTTONS_YES_NO,
1508 true);
1509 int r = dlg.run();
1510 return r == Gtk::RESPONSE_YES;
1511 }
1514 void EditWidget::_namedview_modified (SPObject *obj, guint flags) {
1515 SPNamedView *nv = static_cast<SPNamedView *>(obj);
1516 if (flags & SP_OBJECT_MODIFIED_FLAG) {
1517 this->_dt2r = 1.0 / nv->doc_units->unittobase;
1518 this->_top_ruler.update_metric();
1519 this->_left_ruler.update_metric();
1520 this->_tooltips.set_tip(this->_top_ruler, this->_top_ruler.get_tip());
1521 this->_tooltips.set_tip(this->_left_ruler, this->_left_ruler.get_tip());
1522 this->updateRulers();
1523 }
1524 }
1526 void
1527 EditWidget::initEdit (SPDocument *doc)
1528 {
1529 _desktop = new SPDesktop();
1530 _desktop->registerEditWidget (this);
1532 _namedview = sp_document_namedview (doc, 0);
1533 _svg_canvas.init (_desktop);
1534 _desktop->init (_namedview, _svg_canvas.spobj());
1535 sp_namedview_window_from_document (_desktop);
1536 sp_namedview_update_layers_from_document (_desktop);
1537 _dt2r = 1.0 / _namedview->doc_units->unittobase;
1539 /// \todo convert to sigc++ when SPObject hierarchy gets converted
1540 /* Listen on namedview modification */
1541 _namedview_modified_connection = _desktop->namedview->connectModified(sigc::mem_fun(*this, &EditWidget::_namedview_modified));
1542 _layer_selector.setDesktop (_desktop);
1543 _selected_style_status.setDesktop (_desktop);
1545 Inkscape::NSApplication::Editor::addDesktop (_desktop);
1547 _zoom_status.init (_desktop);
1548 _top_ruler.init (_desktop, _svg_canvas.widget());
1549 _left_ruler.init (_desktop, _svg_canvas.widget());
1550 updateRulers();
1551 }
1553 void
1554 EditWidget::destroyEdit()
1555 {
1556 if (_desktop) {
1557 _layer_selector.unreference();
1558 Inkscape::NSApplication::Editor::removeDesktop (_desktop); // clears selection too
1559 _namedview_modified_connection.disconnect();
1560 _desktop->destroy();
1561 Inkscape::GC::release (_desktop);
1562 _desktop = 0;
1563 }
1564 }
1566 //----------end of EditWidgetInterface implementation
1568 //----------start of other callbacks
1570 bool
1571 EditWidget::on_key_press_event (GdkEventKey* event)
1572 {
1573 // this is the original code from helper/window.cpp
1575 unsigned int shortcut;
1576 shortcut = get_group0_keyval (event) |
1577 ( event->state & GDK_SHIFT_MASK ?
1578 SP_SHORTCUT_SHIFT_MASK : 0 ) |
1579 ( event->state & GDK_CONTROL_MASK ?
1580 SP_SHORTCUT_CONTROL_MASK : 0 ) |
1581 ( event->state & GDK_MOD1_MASK ?
1582 SP_SHORTCUT_ALT_MASK : 0 );
1583 return sp_shortcut_invoke (shortcut,
1584 Inkscape::NSApplication::Editor::getActiveDesktop());
1585 }
1587 bool
1588 EditWidget::on_delete_event (GdkEventAny*)
1589 {
1590 return shutdown();
1591 }
1593 bool
1594 EditWidget::on_focus_in_event (GdkEventFocus*)
1595 {
1596 Inkscape::NSApplication::Editor::activateDesktop (_desktop);
1597 _svg_canvas.widget().grab_focus();
1599 return false;
1600 }
1602 void
1603 EditWidget::onWindowSizeAllocate (Gtk::Allocation &newall)
1604 {
1605 if (!is_realized()) return;
1607 const Gtk::Allocation& all = get_allocation();
1608 if ((newall.get_x() == all.get_x()) &&
1609 (newall.get_y() == all.get_y()) &&
1610 (newall.get_width() == all.get_width()) &&
1611 (newall.get_height() == all.get_height())) {
1612 return;
1613 }
1615 NR::Rect const area = _desktop->get_display_area();
1616 double zoom = _desktop->current_zoom();
1618 if (_sticky_zoom.get_active()) {
1619 /* Calculate zoom per pixel */
1620 double const zpsp = zoom / hypot(area.dimensions()[NR::X], area.dimensions()[NR::Y]);
1621 /* Find new visible area */
1622 NR::Rect const newarea = _desktop->get_display_area();
1623 /* Calculate adjusted zoom */
1624 zoom = zpsp * hypot(newarea.dimensions()[NR::X], newarea.dimensions()[NR::Y]);
1625 }
1627 _desktop->zoom_absolute(area.midpoint()[NR::X], area.midpoint()[NR::Y], zoom);
1628 }
1630 void
1631 EditWidget::onWindowRealize()
1632 {
1633 NR::Rect d(NR::Point(0, 0),
1634 NR::Point(sp_document_width(_desktop->doc()), sp_document_height(_desktop->doc())));
1636 if (d.isEmpty(1.0)) {
1637 return;
1638 }
1640 _desktop->set_display_area(d.min()[NR::X], d.min()[NR::Y], d.max()[NR::X], d.max()[NR::Y], 10);
1641 _namedview_modified(_desktop->namedview, SP_OBJECT_MODIFIED_FLAG);
1642 setTitle (SP_DOCUMENT_NAME(_desktop->doc()));
1643 }
1645 void
1646 EditWidget::onAdjValueChanged()
1647 {
1648 if (_update_a_f) return;
1649 _update_a_f = true;
1651 sp_canvas_scroll_to (_svg_canvas.spobj(),
1652 _bottom_scrollbar.get_value(),
1653 _right_scrollbar.get_value(),
1654 false);
1655 updateRulers();
1657 _update_a_f = false;
1658 }
1661 } // namespace View
1662 } // namespace UI
1663 } // namespace Inkscape
1665 /*
1666 Local Variables:
1667 mode:c++
1668 c-file-style:"stroustrup"
1669 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1670 indent-tabs-mode:nil
1671 fill-column:99
1672 End:
1673 */
1674 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :