83566c1996798e12254e1a7cbf9d89e715108b54
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 *
21 * Copyright (C) 2006 John Bintz
22 * Copyright (C) 1999-2005 Authors
23 * Copyright (C) 2000-2001 Ximian, Inc.
24 *
25 * Released under GNU GPL. Read the file 'COPYING' for more information.
26 */
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
32 #include <gtk/gtkwindow.h>
33 #include <gtk/gtkversion.h>
34 #include <gtk/gtklabel.h>
35 #include <gtkmm/radioaction.h>
36 #include <gtkmm/menubar.h>
37 #include <gtkmm/messagedialog.h>
38 #include <gtkmm/stock.h>
39 #include <gtkmm/accelmap.h>
40 #include <gtkmm/separator.h>
41 #include <gtkmm/base.h>
43 #include <sigc++/functors/mem_fun.h>
45 #include "macros.h"
46 #include "path-prefix.h"
47 #include "prefs-utils.h"
48 #include "file.h"
49 #include "application/editor.h"
50 #include "edit-widget.h"
51 #include "ui/stock.h"
52 #include "ui/stock-items.h"
53 #include "ui/icons.h"
55 #include "display/sodipodi-ctrlrect.h"
56 #include "helper/units.h"
57 #include "shortcuts.h"
58 #include "widgets/spw-utilities.h"
59 #include "event-context.h"
60 #include "document.h"
61 #include "sp-namedview.h"
62 #include "sp-item.h"
63 #include "interface.h"
64 #include "extension/db.h"
66 using namespace Inkscape::UI;
67 using namespace Inkscape::UI::Widget;
69 namespace Inkscape {
70 namespace UI {
71 namespace View {
73 EditWidget::EditWidget (SPDocument *doc)
74 : _main_window_table(4),
75 _viewport_table(3,3),
76 _act_grp(Gtk::ActionGroup::create()),
77 _ui_mgr(Gtk::UIManager::create()),
78 _update_s_f(false),
79 _update_a_f(false),
80 _interaction_disabled_counter(0)
81 {
82 g_warning("Creating new EditWidget");
84 _desktop = 0;
85 Icons::init();
86 Stock::init();
87 initActions();
88 initAccelMap();
89 initUIManager();
90 initLayout();
91 initEdit (doc);
92 g_warning("Done creating new EditWidget");
93 }
95 EditWidget::~EditWidget()
96 {
97 destroyEdit();
98 }
100 void
101 EditWidget::initActions()
102 {
103 initMenuActions();
104 initToolbarActions();
105 }
107 void
108 EditWidget::initUIManager()
109 {
110 _ui_mgr->insert_action_group(_act_grp);
111 add_accel_group(_ui_mgr->get_accel_group());
113 gchar *filename_utf8 = g_build_filename(INKSCAPE_UIDIR, "menus-bars.xml", NULL);
114 if (_ui_mgr->add_ui_from_file(filename_utf8) == 0) {
115 g_warning("Error merging ui from file '%s'", filename_utf8);
116 // fixme-charset: What charset should we pass to g_warning?
117 }
118 g_free(filename_utf8);
119 }
121 void
122 EditWidget::initLayout()
123 {
124 set_title("New document 1 - Inkscape");
125 set_resizable();
126 set_default_size(640, 480);
128 // top level window into which all other portions of the UI get inserted
129 add(_main_window_table);
130 // attach box for horizontal toolbars
131 _main_window_table.attach(_toolbars_vbox, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
132 // attach sub-window for viewport and vertical toolbars
133 _main_window_table.attach(_sub_window_hbox, 0, 1, 2, 3);
134 // viewport table with 3 rows by 3 columns
135 _sub_window_hbox.pack_end(_viewport_table);
137 // Menus and Bars
138 initMenuBar();
139 initCommandsBar();
140 initToolControlsBar();
141 initUriBar();
142 initToolsBar();
144 // Canvas Viewport
145 initLeftRuler();
146 initTopRuler();
147 initStickyZoom();
148 initBottomScrollbar();
149 initRightScrollbar();
150 _viewport_table.attach(_svg_canvas.widget(), 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
151 _svg_canvas.widget().show_all();
154 // The statusbar comes last and appears at the bottom of _main_window_table
155 initStatusbar();
157 signal_size_allocate().connect (sigc::mem_fun (*this, &EditWidget::onWindowSizeAllocate), false);
158 signal_realize().connect (sigc::mem_fun (*this, &EditWidget::onWindowRealize));
159 show_all_children();
160 }
162 void
163 EditWidget::onMenuItem()
164 {
165 g_warning("onMenuItem called");
166 }
168 void
169 EditWidget::onActionFileNew()
170 {
171 // g_warning("onActionFileNew called");
172 sp_file_new_default();
173 }
175 void
176 EditWidget::onActionFileOpen()
177 {
178 // g_warning("onActionFileOpen called");
179 sp_file_open_dialog (NULL, NULL);
180 }
182 void
183 EditWidget::onActionFileQuit()
184 {
185 g_warning("onActionFileQuit");
186 sp_ui_close_all();
187 }
189 void
190 EditWidget::onActionFilePrint()
191 {
192 g_warning("onActionFilePrint");
193 }
195 void
196 EditWidget::onToolbarItem()
197 {
198 g_warning("onToolbarItem called");
199 }
201 void
202 EditWidget::onSelectTool()
203 {
204 _tool_ctrl->remove();
205 _tool_ctrl->add(*_select_ctrl);
206 }
208 void
209 EditWidget::onNodeTool()
210 {
211 _tool_ctrl->remove();
212 _tool_ctrl->add(*_node_ctrl);
213 }
215 void
216 EditWidget::onDialogInkscapePreferences()
217 {
218 _dlg_mgr.showDialog("InkscapePreferences");
219 }
221 void
222 EditWidget::onDialogAbout()
223 {
224 }
226 void
227 EditWidget::onDialogAlignAndDistribute()
228 {
229 _dlg_mgr.showDialog("AlignAndDistribute");
230 }
232 void
233 EditWidget::onDialogDocumentProperties()
234 {
235 // manage (Inkscape::UI::Dialog::DocumentPreferences::create());
236 _dlg_mgr.showDialog("DocumentPreferences");
237 }
239 void
240 EditWidget::onDialogExport()
241 {
242 _dlg_mgr.showDialog("Export");
243 }
245 void
246 EditWidget::onDialogExtensionEditor()
247 {
248 _dlg_mgr.showDialog("ExtensionEditor");
249 }
251 void
252 EditWidget::onDialogFillAndStroke()
253 {
254 _dlg_mgr.showDialog("FillAndStroke");
255 }
257 void
258 EditWidget::onDialogFind()
259 {
260 _dlg_mgr.showDialog("Find");
261 }
263 void
264 EditWidget::onDialogLayerEditor()
265 {
266 _dlg_mgr.showDialog("LayerEditor");
267 }
269 void
270 EditWidget::onDialogMessages()
271 {
272 _dlg_mgr.showDialog("Messages");
273 }
275 void
276 EditWidget::onDialogObjectProperties()
277 {
278 _dlg_mgr.showDialog("ObjectProperties");
279 }
281 void
282 EditWidget::onDialogTextProperties()
283 {
284 _dlg_mgr.showDialog("TextProperties");
285 }
287 void
288 EditWidget::onDialogTrace()
289 {
290 }
292 void
293 EditWidget::onDialogTransformation()
294 {
295 _dlg_mgr.showDialog("Transformation");
296 }
298 void
299 EditWidget::onDialogXmlEditor()
300 {
301 _dlg_mgr.showDialog("XmlEditor");
302 }
304 void
305 EditWidget::onUriChanged()
306 {
307 g_message("onUriChanged called");
309 }
311 // FIXME: strings are replaced by placeholders, NOT to be translated until the code is enabled
312 // See http://sourceforge.net/mailarchive/message.php?msg_id=11746016 for details
314 void
315 EditWidget::initMenuActions()
316 {
317 // _act_grp->add(Gtk::Action::create("MenuFile", _("PLACEHOLDER, do not translate")));
318 // _act_grp->add(Gtk::Action::create("MenuEdit", _("PLACEHOLDER, do not translate")));
319 // _act_grp->add(Gtk::Action::create("MenuView", _("PLACEHOLDER, do not translate")));
320 // _act_grp->add(Gtk::Action::create("MenuLayer", _("PLACEHOLDER, do not translate")));
321 // _act_grp->add(Gtk::Action::create("MenuObject", _("PLACEHOLDER, do not translate")));
322 // _act_grp->add(Gtk::Action::create("MenuPath", _("PLACEHOLDER, do not translate")));
323 // _act_grp->add(Gtk::Action::create("MenuText", _("PLACEHOLDER, do not translate")));
324 // _act_grp->add(Gtk::Action::create("MenuHelp", _("PLACEHOLDER, do not translate")));
325 // temporarily replaced with non-gettext version to have a well-sized menu
326 // for testing:
328 _act_grp->add(Gtk::Action::create("MenuFile", "File"));
329 _act_grp->add(Gtk::Action::create("MenuEdit", "Edit"));
330 _act_grp->add(Gtk::Action::create("MenuView", "View"));
331 _act_grp->add(Gtk::Action::create("MenuLayer", "Layer"));
332 _act_grp->add(Gtk::Action::create("MenuObject", "Object"));
333 _act_grp->add(Gtk::Action::create("MenuPath", "Path"));
334 _act_grp->add(Gtk::Action::create("MenuText", "Text"));
335 _act_grp->add(Gtk::Action::create("MenuHelp", "Help"));
337 // File menu
338 _act_grp->add(Gtk::Action::create("New",
339 Gtk::Stock::NEW, Glib::ustring(),
340 _("PLACEHOLDER, do not translate")),
341 sigc::mem_fun(*this, &EditWidget::onActionFileNew));
343 _act_grp->add(Gtk::Action::create("Open",
344 Gtk::Stock::OPEN, Glib::ustring(),
345 _("PLACEHOLDER, do not translate")),
346 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
348 _act_grp->add(Gtk::Action::create("OpenRecent",
349 Stock::OPEN_RECENT));
351 _act_grp->add(Gtk::Action::create("Revert",
352 Gtk::Stock::REVERT_TO_SAVED, Glib::ustring(),
353 _("PLACEHOLDER, do not translate")),
354 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
356 _act_grp->add(Gtk::Action::create("Save",
357 Gtk::Stock::SAVE, Glib::ustring(),
358 _("PLACEHOLDER, do not translate")),
359 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
361 _act_grp->add(Gtk::Action::create("SaveAs",
362 Gtk::Stock::SAVE_AS, Glib::ustring(),
363 _("PLACEHOLDER, do not translate")),
364 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
366 _act_grp->add(Gtk::Action::create("Import",
367 Stock::IMPORT, Glib::ustring(),
368 _("PLACEHOLDER, do not translate")),
369 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
371 _act_grp->add(Gtk::Action::create("Export",
372 Stock::EXPORT, Glib::ustring(),
373 _("PLACEHOLDER, do not translate")),
374 sigc::mem_fun(*this, &EditWidget::onDialogExport));
376 _act_grp->add(Gtk::Action::create("Print",
377 Gtk::Stock::PRINT, Glib::ustring(),
378 _("PLACEHOLDER, do not translate")),
379 sigc::mem_fun(*this, &EditWidget::onActionFilePrint));
381 _act_grp->add(Gtk::Action::create("PrintPreview",
382 Gtk::Stock::PRINT_PREVIEW),
383 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
385 _act_grp->add(Gtk::Action::create("VacuumDefs",
386 Stock::VACUUM_DEFS),
387 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
389 _act_grp->add(Gtk::Action::create("DocumentProperties",
390 Gtk::Stock::PROPERTIES, Glib::ustring(),
391 _("PLACEHOLDER, do not translate")),
392 sigc::mem_fun(*this, &EditWidget::onDialogDocumentProperties));
394 _act_grp->add(Gtk::Action::create("InkscapePreferences",
395 Gtk::Stock::PREFERENCES, Glib::ustring(),
396 _("PLACEHOLDER, do not translate")),
397 sigc::mem_fun(*this, &EditWidget::onDialogInkscapePreferences));
399 _act_grp->add(Gtk::Action::create("Close",
400 Gtk::Stock::CLOSE),
401 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
403 _act_grp->add(Gtk::Action::create("Quit",
404 Gtk::Stock::QUIT),
405 sigc::mem_fun(*this, &EditWidget::onActionFileQuit));
407 // EditWidget menu
408 _act_grp->add(Gtk::Action::create("Undo",
409 Gtk::Stock::UNDO, Glib::ustring(),
410 _("PLACEHOLDER, do not translate")));
412 _act_grp->add(Gtk::Action::create("Redo",
413 Gtk::Stock::REDO, Glib::ustring(),
414 _("PLACEHOLDER, do not translate")));
416 _act_grp->add(Gtk::Action::create("UndoHistory",
417 Stock::UNDO_HISTORY, Glib::ustring(),
418 _("PLACEHOLDER, do not translate")));
420 _act_grp->add(Gtk::Action::create("Cut",
421 Gtk::Stock::CUT, Glib::ustring(),
422 _("PLACEHOLDER, do not translate")));
424 _act_grp->add(Gtk::Action::create("Copy",
425 Gtk::Stock::COPY, Glib::ustring(),
426 _("PLACEHOLDER, do not translate")));
428 _act_grp->add(Gtk::Action::create("Paste",
429 Gtk::Stock::PASTE, Glib::ustring(),
430 _("PLACEHOLDER, do not translate")));
432 _act_grp->add(Gtk::Action::create("PasteInPlace",
433 Stock::PASTE_IN_PLACE));
435 _act_grp->add(Gtk::Action::create("PasteStyle",
436 Stock::PASTE_STYLE));
438 _act_grp->add(Gtk::Action::create("Find",
439 Gtk::Stock::FIND),
440 sigc::mem_fun(*this, &EditWidget::onDialogFind));
442 _act_grp->add(Gtk::Action::create("Duplicate",
443 Stock::DUPLICATE, Glib::ustring(),
444 _("PLACEHOLDER, do not translate")));
446 _act_grp->add(Gtk::Action::create("Clone",
447 Stock::CLONE, Glib::ustring(),
448 _("PLACEHOLDER, do not translate")));
450 _act_grp->add(Gtk::Action::create("CloneUnlink",
451 Stock::CLONE_UNLINK, Glib::ustring(),
452 _("PLACEHOLDER, do not translate")));
454 _act_grp->add(Gtk::Action::create("CloneSelectOrig",
455 Stock::CLONE_SELECT_ORIG));
457 _act_grp->add(Gtk::Action::create("MakeBitmap",
458 Stock::MAKE_BITMAP));
460 _act_grp->add(Gtk::Action::create("Tile",
461 Stock::TILE));
463 _act_grp->add(Gtk::Action::create("Untile",
464 Stock::UNTILE));
466 _act_grp->add(Gtk::Action::create("Delete",
467 Gtk::Stock::DELETE));
469 _act_grp->add(Gtk::Action::create("SelectAll",
470 Stock::SELECT_ALL));
472 _act_grp->add(Gtk::Action::create("SelectAllInAllLayers",
473 Stock::SELECT_ALL_IN_ALL_LAYERS));
475 _act_grp->add(Gtk::Action::create("SelectInvert",
476 Stock::SELECT_INVERT));
478 _act_grp->add(Gtk::Action::create("SelectNone",
479 Stock::SELECT_NONE));
481 _act_grp->add(Gtk::Action::create("XmlEditor",
482 Stock::XML_EDITOR, Glib::ustring(),
483 _("PLACEHOLDER, do not translate")),
484 sigc::mem_fun(*this, &EditWidget::onDialogXmlEditor));
486 // View menu
487 _act_grp->add(Gtk::Action::create("Zoom",
488 Stock::ZOOM));
490 _act_grp->add(Gtk::Action::create("ZoomIn",
491 Stock::ZOOM_IN, Glib::ustring(),
492 _("PLACEHOLDER, do not translate")));
494 _act_grp->add(Gtk::Action::create("ZoomOut",
495 Stock::ZOOM_OUT, Glib::ustring(),
496 _("PLACEHOLDER, do not translate")));
498 _act_grp->add(Gtk::Action::create("Zoom100",
499 Stock::ZOOM_100, Glib::ustring(),
500 _("PLACEHOLDER, do not translate")));
502 _act_grp->add(Gtk::Action::create("Zoom50",
503 Stock::ZOOM_50, Glib::ustring(),
504 _("PLACEHOLDER, do not translate")));
506 _act_grp->add(Gtk::Action::create("Zoom200",
507 Stock::ZOOM_200, Glib::ustring(),
508 _("PLACEHOLDER, do not translate")));
510 _act_grp->add(Gtk::Action::create("ZoomSelection",
511 Stock::ZOOM_SELECTION, Glib::ustring(),
512 _("PLACEHOLDER, do not translate")));
514 _act_grp->add(Gtk::Action::create("ZoomDrawing",
515 Stock::ZOOM_DRAWING, Glib::ustring(),
516 _("PLACEHOLDER, do not translate")));
518 _act_grp->add(Gtk::Action::create("ZoomPage",
519 Stock::ZOOM_PAGE, Glib::ustring(),
520 _("PLACEHOLDER, do not translate")));
522 _act_grp->add(Gtk::Action::create("ZoomWidth",
523 Stock::ZOOM_WIDTH, Glib::ustring(),
524 _("PLACEHOLDER, do not translate")));
526 _act_grp->add(Gtk::Action::create("ZoomPrev",
527 Stock::ZOOM_PREV, Glib::ustring(),
528 _("PLACEHOLDER, do not translate")));
530 _act_grp->add(Gtk::Action::create("ZoomNext",
531 Stock::ZOOM_NEXT, Glib::ustring(),
532 _("PLACEHOLDER, do not translate")));
534 _act_grp->add(Gtk::Action::create("ShowHide",
535 Stock::SHOW_HIDE));
537 _act_grp->add(Gtk::ToggleAction::create("ShowHideCommandsBar",
538 Stock::SHOW_HIDE_COMMANDS_BAR));
540 _act_grp->add(Gtk::ToggleAction::create("ShowHideToolControlsBar",
541 Stock::SHOW_HIDE_TOOL_CONTROLS_BAR));
543 _act_grp->add(Gtk::ToggleAction::create("ShowHideToolsBar",
544 Stock::SHOW_HIDE_TOOLS_BAR));
546 _act_grp->add(Gtk::ToggleAction::create("ShowHideRulers",
547 Stock::SHOW_HIDE_RULERS));
549 _act_grp->add(Gtk::ToggleAction::create("ShowHideScrollbars",
550 Stock::SHOW_HIDE_SCROLLBARS));
552 _act_grp->add(Gtk::ToggleAction::create("ShowHideStatusbar",
553 Stock::SHOW_HIDE_STATUSBAR));
555 _act_grp->add(Gtk::Action::create("ShowHideDialogs",
556 Stock::SHOW_HIDE_DIALOGS));
558 _act_grp->add(Gtk::Action::create("Grid",
559 Stock::GRID));
561 _act_grp->add(Gtk::Action::create("Guides",
562 Stock::GUIDES));
564 _act_grp->add(Gtk::Action::create("Fullscreen",
565 Stock::FULLSCREEN));
567 _act_grp->add(Gtk::Action::create("Messages",
568 Stock::MESSAGES),
569 sigc::mem_fun(*this, &EditWidget::onDialogMessages));
571 _act_grp->add(Gtk::Action::create("Scripts",
572 Stock::SCRIPTS));
574 _act_grp->add(Gtk::Action::create("WindowPrev",
575 Stock::WINDOW_PREV));
577 _act_grp->add(Gtk::Action::create("WindowNext",
578 Stock::WINDOW_NEXT));
580 _act_grp->add(Gtk::Action::create("WindowDuplicate",
581 Stock::WINDOW_DUPLICATE));
583 // Layer menu
584 _act_grp->add(Gtk::Action::create("LayerNew",
585 Stock::LAYER_NEW));
587 _act_grp->add(Gtk::Action::create("LayerRename",
588 Stock::LAYER_RENAME));
590 _act_grp->add(Gtk::Action::create("LayerDuplicate",
591 Stock::LAYER_DUPLICATE));
593 _act_grp->add(Gtk::Action::create("LayerAnchor",
594 Stock::LAYER_ANCHOR));
596 _act_grp->add(Gtk::Action::create("LayerMergeDown",
597 Stock::LAYER_MERGE_DOWN));
599 _act_grp->add(Gtk::Action::create("LayerDelete",
600 Stock::LAYER_DELETE));
602 _act_grp->add(Gtk::Action::create("LayerSelectNext",
603 Stock::LAYER_SELECT_NEXT));
605 _act_grp->add(Gtk::Action::create("LayerSelectPrev",
606 Stock::LAYER_SELECT_PREV));
608 _act_grp->add(Gtk::Action::create("LayerSelectTop",
609 Stock::LAYER_SELECT_TOP));
611 _act_grp->add(Gtk::Action::create("LayerSelectBottom",
612 Stock::LAYER_SELECT_BOTTOM));
614 _act_grp->add(Gtk::Action::create("LayerRaise",
615 Stock::LAYER_RAISE));
617 _act_grp->add(Gtk::Action::create("LayerLower",
618 Stock::LAYER_LOWER));
620 _act_grp->add(Gtk::Action::create("LayerToTop",
621 Stock::LAYER_TO_TOP));
623 _act_grp->add(Gtk::Action::create("LayerToBottom",
624 Stock::LAYER_TO_BOTTOM));
626 // Object menu
627 _act_grp->add(Gtk::Action::create("FillAndStroke",
628 Stock::FILL_STROKE, Glib::ustring(),
629 _("PLACEHOLDER, do not translate")),
630 sigc::mem_fun(*this, &EditWidget::onDialogFillAndStroke));
632 _act_grp->add(Gtk::Action::create("ObjectProperties",
633 Stock::OBJECT_PROPERTIES),
634 sigc::mem_fun(*this, &EditWidget::onDialogObjectProperties));
636 _act_grp->add(Gtk::Action::create("Group",
637 Stock::GROUP, Glib::ustring(),
638 _("PLACEHOLDER, do not translate")));
640 _act_grp->add(Gtk::Action::create("Ungroup",
641 Stock::UNGROUP, Glib::ustring(),
642 _("PLACEHOLDER, do not translate")));
644 _act_grp->add(Gtk::Action::create("Raise",
645 Stock::RAISE, Glib::ustring(),
646 _("PLACEHOLDER, do not translate")));
648 _act_grp->add(Gtk::Action::create("Lower",
649 Stock::LOWER, Glib::ustring(),
650 _("PLACEHOLDER, do not translate")));
652 _act_grp->add(Gtk::Action::create("RaiseToTop",
653 Stock::RAISE_TO_TOP, Glib::ustring(),
654 _("PLACEHOLDER, do not translate")));
656 _act_grp->add(Gtk::Action::create("LowerToBottom",
657 Stock::LOWER_TO_BOTTOM, Glib::ustring(),
658 _("PLACEHOLDER, do not translate")));
660 _act_grp->add(Gtk::Action::create("MoveToNewLayer",
661 Stock::MOVE_TO_NEW_LAYER, Glib::ustring(),
662 _("PLACEHOLDER, do not translate")));
664 _act_grp->add(Gtk::Action::create("MoveToNextLayer",
665 Stock::MOVE_TO_NEXT_LAYER, Glib::ustring(),
666 _("PLACEHOLDER, do not translate")));
668 _act_grp->add(Gtk::Action::create("MoveToPrevLayer",
669 Stock::MOVE_TO_PREV_LAYER, Glib::ustring(),
670 _("PLACEHOLDER, do not translate")));
672 _act_grp->add(Gtk::Action::create("MoveToTopLayer",
673 Stock::MOVE_TO_TOP_LAYER, Glib::ustring(),
674 _("PLACEHOLDER, do not translate")));
676 _act_grp->add(Gtk::Action::create("MoveToBottomLayer",
677 Stock::MOVE_TO_BOTTOM_LAYER, Glib::ustring(),
678 _("PLACEHOLDER, do not translate")));
680 _act_grp->add(Gtk::Action::create("Rotate90CW",
681 Stock::ROTATE_90_CW, Glib::ustring(),
682 _("PLACEHOLDER, do not translate")));
684 _act_grp->add(Gtk::Action::create("Rotate90CCW",
685 Stock::ROTATE_90_CCW, Glib::ustring(),
686 _("PLACEHOLDER, do not translate")));
688 _act_grp->add(Gtk::Action::create("FlipHoriz",
689 Stock::FLIP_HORIZ, Glib::ustring(),
690 _("PLACEHOLDER, do not translate")));
692 _act_grp->add(Gtk::Action::create("FlipVert",
693 Stock::FLIP_VERT, Glib::ustring(),
694 _("PLACEHOLDER, do not translate")));
696 _act_grp->add(Gtk::Action::create("Transformation",
697 Stock::TRANSFORMATION, Glib::ustring(),
698 _("PLACEHOLDER, do not translate")),
699 sigc::mem_fun(*this, &EditWidget::onDialogTransformation));
701 _act_grp->add(Gtk::Action::create("AlignAndDistribute",
702 Stock::ALIGN_DISTRIBUTE, Glib::ustring(),
703 _("PLACEHOLDER, do not translate")),
704 sigc::mem_fun(*this, &EditWidget::onDialogAlignAndDistribute));
706 // Path menu
707 _act_grp->add(Gtk::Action::create("ObjectToPath",
708 Stock::OBJECT_TO_PATH, Glib::ustring(),
709 _("PLACEHOLDER, do not translate")));
711 _act_grp->add(Gtk::Action::create("StrokeToPath",
712 Stock::STROKE_TO_PATH, Glib::ustring(),
713 _("PLACEHOLDER, do not translate")));
715 _act_grp->add(Gtk::Action::create("Trace",
716 Stock::TRACE),
717 sigc::mem_fun(*this, &EditWidget::onDialogTrace));
719 _act_grp->add(Gtk::Action::create("Union",
720 Stock::UNION));
722 _act_grp->add(Gtk::Action::create("Difference",
723 Stock::DIFFERENCE));
725 _act_grp->add(Gtk::Action::create("Intersection",
726 Stock::INTERSECTION));
728 _act_grp->add(Gtk::Action::create("Exclusion",
729 Stock::EXCLUSION));
731 _act_grp->add(Gtk::Action::create("Division",
732 Stock::DIVISION));
734 _act_grp->add(Gtk::Action::create("CutPath",
735 Stock::CUT_PATH));
737 _act_grp->add(Gtk::Action::create("Combine",
738 Stock::COMBINE));
740 _act_grp->add(Gtk::Action::create("BreakApart",
741 Stock::BREAK_APART));
743 _act_grp->add(Gtk::Action::create("Inset",
744 Stock::INSET));
746 _act_grp->add(Gtk::Action::create("Outset",
747 Stock::OUTSET));
749 _act_grp->add(Gtk::Action::create("OffsetDynamic",
750 Stock::OFFSET_DYNAMIC));
752 _act_grp->add(Gtk::Action::create("OffsetLinked",
753 Stock::OFFSET_LINKED));
755 _act_grp->add(Gtk::Action::create("Simplify",
756 Stock::SIMPLIFY));
758 _act_grp->add(Gtk::Action::create("Reverse",
759 Stock::REVERSE));
761 _act_grp->add(Gtk::Action::create("Cleanup",
762 Gtk::Stock::CLEAR,
763 _("PLACEHOLDER, do not translate")));
765 // Text menu
766 _act_grp->add(Gtk::Action::create("TextProperties",
767 Gtk::Stock::SELECT_FONT, Glib::ustring(),
768 _("PLACEHOLDER, do not translate")),
769 sigc::mem_fun(*this, &EditWidget::onDialogTextProperties));
771 _act_grp->add(Gtk::Action::create("PutOnPath",
772 Stock::PUT_ON_PATH));
774 _act_grp->add(Gtk::Action::create("RemoveFromPath",
775 Stock::REMOVE_FROM_PATH));
777 _act_grp->add(Gtk::Action::create("RemoveManualKerns",
778 Stock::REMOVE_MANUAL_KERNS));
780 // Whiteboard menu
781 #ifdef WITH_INKBOARD
782 #endif
784 // About menu
785 _act_grp->add(Gtk::Action::create("KeysAndMouse",
786 Stock::KEYS_MOUSE));
788 _act_grp->add(Gtk::Action::create("Tutorials",
789 Stock::TUTORIALS));
791 _act_grp->add(Gtk::Action::create("About",
792 Stock::ABOUT),
793 sigc::mem_fun(*this, &EditWidget::onDialogAbout));
794 }
796 void
797 EditWidget::initToolbarActions()
798 {
799 // Tools bar
800 Gtk::RadioAction::Group tools;
802 _act_grp->add(Gtk::RadioAction::create(tools, "ToolSelect",
803 Stock::TOOL_SELECT, Glib::ustring(),
804 _("PLACEHOLDER, do not translate")),
805 sigc::mem_fun(*this, &EditWidget::onSelectTool));
807 _act_grp->add(Gtk::RadioAction::create(tools, "ToolNode",
808 Stock::TOOL_NODE, Glib::ustring(),
809 _("PLACEHOLDER, do not translate")),
810 sigc::mem_fun(*this, &EditWidget::onNodeTool));
812 _act_grp->add(Gtk::RadioAction::create(tools, "ToolZoom",
813 Stock::TOOL_ZOOM, Glib::ustring(),
814 _("PLACEHOLDER, do not translate")));
816 _act_grp->add(Gtk::RadioAction::create(tools, "ToolRect",
817 Stock::TOOL_RECT, Glib::ustring(),
818 _("PLACEHOLDER, do not translate")));
820 _act_grp->add(Gtk::RadioAction::create(tools, "ToolArc",
821 Stock::TOOL_ARC, Glib::ustring(),
822 _("PLACEHOLDER, do not translate")));
824 _act_grp->add(Gtk::RadioAction::create(tools, "ToolStar",
825 Stock::TOOL_STAR, Glib::ustring(),
826 _("PLACEHOLDER, do not translate")));
828 _act_grp->add(Gtk::RadioAction::create(tools, "ToolSpiral",
829 Stock::TOOL_SPIRAL, Glib::ustring(),
830 _("PLACEHOLDER, do not translate")));
832 _act_grp->add(Gtk::RadioAction::create(tools, "ToolFreehand",
833 Stock::TOOL_FREEHAND, Glib::ustring(),
834 _("PLACEHOLDER, do not translate")));
836 _act_grp->add(Gtk::RadioAction::create(tools, "ToolPen",
837 Stock::TOOL_PEN, Glib::ustring(),
838 _("PLACEHOLDER, do not translate")));
840 _act_grp->add(Gtk::RadioAction::create(tools, "ToolDynaDraw",
841 Stock::TOOL_DYNADRAW, Glib::ustring(),
842 _("PLACEHOLDER, do not translate")));
844 _act_grp->add(Gtk::RadioAction::create(tools, "ToolText",
845 Stock::TOOL_TEXT, Glib::ustring(),
846 _("PLACEHOLDER, do not translate")));
848 _act_grp->add(Gtk::RadioAction::create(tools, "ToolDropper",
849 Stock::TOOL_DROPPER, Glib::ustring(),
850 _("PLACEHOLDER, do not translate")));
852 // Select Controls bar
853 _act_grp->add(Gtk::ToggleAction::create("TransformStroke",
854 Stock::TRANSFORM_STROKE, Glib::ustring(),
855 _("PLACEHOLDER, do not translate")));
857 _act_grp->add(Gtk::ToggleAction::create("TransformCorners",
858 Stock::TRANSFORM_CORNERS, Glib::ustring(),
859 _("PLACEHOLDER, do not translate")));
861 _act_grp->add(Gtk::ToggleAction::create("TransformGradient",
862 Stock::TRANSFORM_GRADIENT, Glib::ustring(),
863 _("PLACEHOLDER, do not translate")));
865 _act_grp->add(Gtk::ToggleAction::create("TransformPattern",
866 Stock::TRANSFORM_PATTERN, Glib::ustring(),
867 _("PLACEHOLDER, do not translate")));
869 // Node Controls bar
870 _act_grp->add(Gtk::Action::create("NodeInsert",
871 Gtk::Stock::ADD, Glib::ustring(),
872 _("PLACEHOLDER, do not translate")));
874 _act_grp->add(Gtk::Action::create("NodeDelete",
875 Gtk::Stock::REMOVE, Glib::ustring(),
876 _("PLACEHOLDER, do not translate")));
878 _act_grp->add(Gtk::Action::create("NodeJoin",
879 Stock::NODE_JOIN, Glib::ustring(),
880 _("PLACEHOLDER, do not translate")));
882 _act_grp->add(Gtk::Action::create("NodeJoinSegment",
883 Stock::NODE_JOIN_SEGMENT, Glib::ustring(),
884 _("PLACEHOLDER, do not translate")));
886 _act_grp->add(Gtk::Action::create("NodeDeleteSegment",
887 Stock::NODE_DELETE_SEGMENT, Glib::ustring(),
888 _("PLACEHOLDER, do not translate")));
890 _act_grp->add(Gtk::Action::create("NodeBreak",
891 Stock::NODE_BREAK, Glib::ustring(),
892 _("PLACEHOLDER, do not translate")));
894 _act_grp->add(Gtk::Action::create("NodeCorner",
895 Stock::NODE_CORNER, Glib::ustring(),
896 _("PLACEHOLDER, do not translate")));
898 _act_grp->add(Gtk::Action::create("NodeSmooth",
899 Stock::NODE_SMOOTH, Glib::ustring(),
900 _("PLACEHOLDER, do not translate")));
902 _act_grp->add(Gtk::Action::create("NodeSymmetric",
903 Stock::NODE_SYMMETRIC, Glib::ustring(),
904 _("PLACEHOLDER, do not translate")));
906 _act_grp->add(Gtk::Action::create("NodeLine",
907 Stock::NODE_LINE, Glib::ustring(),
908 _("PLACEHOLDER, do not translate")));
910 _act_grp->add(Gtk::Action::create("NodeCurve",
911 Stock::NODE_CURVE, Glib::ustring(),
912 _("PLACEHOLDER, do not translate")));
913 }
915 void
916 EditWidget::initAccelMap()
917 {
918 gchar *filename = g_build_filename(INKSCAPE_UIDIR, "keybindings.rc", NULL);
919 Gtk::AccelMap::load(filename);
920 g_free(filename);
922 // One problem is that the keys 1-6 are zoom accelerators which get
923 // caught as accelerator _before_ any Entry input handler receives them,
924 // for example the zoom status. At the moment, the best way seems to
925 // disable them as accelerators when the Entry gets focus, and enable
926 // them when focus goes elsewhere. The code for this belongs here,
927 // and not in zoom-status.cpp .
929 _zoom_status.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditWidget::onEntryFocusIn));
930 _zoom_status.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditWidget::onEntryFocusOut));
931 }
933 bool
934 EditWidget::onEntryFocusIn (GdkEventFocus* ev)
935 {
936 Gdk::ModifierType m = static_cast<Gdk::ModifierType>(0);
937 Gtk::AccelMap::change_entry ("<Actions>//Zoom100", 0, m, false);
938 Gtk::AccelMap::change_entry ("<Actions>//Zoom50", 0, m, false);
939 Gtk::AccelMap::change_entry ("<Actions>//ZoomSelection", 0, m, false);
940 Gtk::AccelMap::change_entry ("<Actions>//ZoomDrawing", 0, m, false);
941 Gtk::AccelMap::change_entry ("<Actions>//ZoomPage", 0, m, false);
942 Gtk::AccelMap::change_entry ("<Actions>//ZoomWidth", 0, m, false);
943 return false;
944 }
946 bool
947 EditWidget::onEntryFocusOut (GdkEventFocus* ev)
948 {
949 Gdk::ModifierType m = static_cast<Gdk::ModifierType>(0);
950 Gtk::AccelMap::change_entry ("<Actions>//Zoom100", '1', m, false);
951 Gtk::AccelMap::change_entry ("<Actions>//Zoom50", '2', m, false);
952 Gtk::AccelMap::change_entry ("<Actions>//ZoomSelection", '3', m, false);
953 Gtk::AccelMap::change_entry ("<Actions>//ZoomDrawing", '4', m, false);
954 Gtk::AccelMap::change_entry ("<Actions>//ZoomPage", '5', m, false);
955 Gtk::AccelMap::change_entry ("<Actions>//ZoomWidth", '6', m, false);
956 return false;
957 }
959 void
960 EditWidget::initMenuBar()
961 {
962 g_assert(_ui_mgr);
963 Gtk::MenuBar *menu = static_cast<Gtk::MenuBar*>(_ui_mgr->get_widget("/MenuBar"));
964 g_assert(menu != NULL);
965 _main_window_table.attach(*Gtk::manage(menu), 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
966 }
968 void
969 EditWidget::initCommandsBar()
970 {
971 g_assert(_ui_mgr);
972 Toolbox *bar = new Toolbox(static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/CommandsBar")),
973 Gtk::TOOLBAR_ICONS);
974 g_assert(bar != NULL);
975 _toolbars_vbox.pack_start(*Gtk::manage(bar), Gtk::PACK_SHRINK);
976 }
978 void
979 EditWidget::initToolControlsBar()
980 {
981 // TODO: Do UIManager controlled widgets need to be deleted?
982 _select_ctrl = static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/SelectControlsBar"));
983 _node_ctrl = static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/NodeControlsBar"));
985 _tool_ctrl = new Toolbox(_select_ctrl, Gtk::TOOLBAR_ICONS);
987 _toolbars_vbox.pack_start(*Gtk::manage(_tool_ctrl), Gtk::PACK_SHRINK);
988 }
990 void
991 EditWidget::initUriBar()
992 {
993 /// \todo Create an Inkscape::UI::Widget::UriBar class (?)
995 _uri_ctrl = new Gtk::Toolbar();
997 _uri_label.set_label(_("PLACEHOLDER, DO NOT TRANSLATE"));
998 _uri_ctrl->add(_uri_label);
999 _uri_ctrl->add(_uri_entry);
1001 _uri_entry.signal_activate()
1002 .connect_notify(sigc::mem_fun(*this, &EditWidget::onUriChanged));
1004 _toolbars_vbox.pack_start(*Gtk::manage(_uri_ctrl), Gtk::PACK_SHRINK);
1005 }
1007 void
1008 EditWidget::initToolsBar()
1009 {
1010 Toolbox *bar = new Toolbox(static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/ToolsBar")),
1011 Gtk::TOOLBAR_ICONS,
1012 Gtk::ORIENTATION_VERTICAL);
1013 g_assert(bar != NULL);
1014 _sub_window_hbox.pack_start(*Gtk::manage(bar), Gtk::PACK_SHRINK);
1015 }
1017 void
1018 EditWidget::initTopRuler()
1019 {
1020 _viewport_table.attach(_top_ruler, 1, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
1022 _tooltips.set_tip (_top_ruler, _top_ruler.get_tip());
1023 }
1025 void
1026 EditWidget::initLeftRuler()
1027 {
1028 _viewport_table.attach(_left_ruler, 0, 1, 1, 2, Gtk::SHRINK, Gtk::FILL|Gtk::EXPAND);
1030 _tooltips.set_tip (_left_ruler, _left_ruler.get_tip());
1031 }
1033 void
1034 EditWidget::initBottomScrollbar()
1035 {
1036 _viewport_table.attach(_bottom_scrollbar, 1, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
1037 _bottom_scrollbar.signal_value_changed().connect (sigc::mem_fun (*this, &EditWidget::onAdjValueChanged));
1038 _bottom_scrollbar.property_adjustment() = new Gtk::Adjustment (0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0);
1039 }
1041 void
1042 EditWidget::initRightScrollbar()
1043 {
1044 _viewport_table.attach(_right_scrollbar, 2, 3, 1, 2, Gtk::SHRINK, Gtk::FILL|Gtk::EXPAND);
1046 _right_scrollbar.signal_value_changed().connect (sigc::mem_fun (*this, &EditWidget::onAdjValueChanged));
1047 _right_scrollbar.property_adjustment() = new Gtk::Adjustment (0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0);
1048 }
1050 void
1051 EditWidget::initStickyZoom()
1052 {
1053 _viewport_table.attach(_sticky_zoom, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
1055 _sticky_zoom.set_active (prefs_get_int_attribute ("options.stickyzoom", "value", 0) != 0);
1056 _tooltips.set_tip (_sticky_zoom, _("Zoom drawing if window size changes"));
1058 /// \todo icon not implemented
1059 }
1061 void
1062 EditWidget::initStatusbar()
1063 {
1064 _statusbar.pack_start (_selected_style_status, false, false, 1);
1065 _statusbar.pack_start (*new Gtk::VSeparator(), false, false, 0);
1067 _tooltips.set_tip (_zoom_status, _("Zoom"));
1069 _layer_selector.reference();
1070 _statusbar.pack_start (_layer_selector, false, false, 1);
1072 _coord_status.property_n_rows() = 2;
1073 _coord_status.property_n_columns() = 5;
1074 _coord_status.property_row_spacing() = 0;
1075 _coord_status.property_column_spacing() = 2;
1076 _coord_eventbox.add (_coord_status);
1077 _tooltips.set_tip (_coord_eventbox, _("Cursor coordinates"));
1078 _coord_status.attach (*new Gtk::VSeparator(), 0,1, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1079 _coord_status.attach (*new Gtk::Label("X:", 0.0, 0.5), 1,2, 0,1, Gtk::FILL,Gtk::FILL, 0,0);
1080 _coord_status.attach (*new Gtk::Label("Y:", 0.0, 0.5), 1,2, 1,2, Gtk::FILL,Gtk::FILL, 0,0);
1081 _coord_status_x.set_text ("0.0");
1082 _coord_status_x.set_alignment (0.0, 0.5);
1083 _coord_status_y.set_text ("0.0");
1084 _coord_status_y.set_alignment (0.0, 0.5);
1085 _coord_status.attach (_coord_status_x, 2,3, 0,1, Gtk::FILL,Gtk::FILL, 0,0);
1086 _coord_status.attach (_coord_status_y, 2,3, 1,2, Gtk::FILL,Gtk::FILL, 0,0);
1087 _coord_status.attach (*new Gtk::Label("Z:", 0.0, 0.5), 3,4, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1088 _coord_status.attach (_zoom_status, 4,5, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1089 sp_set_font_size_smaller (static_cast<GtkWidget*>((void*)_coord_status.gobj()));
1090 _statusbar.pack_end (_coord_eventbox, false, false, 1);
1092 _select_status.property_xalign() = 0.0;
1093 _select_status.property_yalign() = 0.5;
1094 _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."));
1095 // include this again with Gtk+-2.6
1096 #if GTK_VERSION_GE(2,6)
1097 gtk_label_set_ellipsize (GTK_LABEL(_select_status.gobj()), PANGO_ELLIPSIZE_END);
1098 #endif
1099 _select_status.set_size_request (1, -1);
1100 _statusbar.pack_start (_select_status, true, true, 0);
1102 _main_window_table.attach(_statusbar, 0, 1, 3, 4, Gtk::FILL, Gtk::SHRINK);
1103 }
1105 //========================================
1106 //----------implements EditWidgetInterface
1108 void *
1109 EditWidget::getWindow()
1110 {
1111 return this;
1112 }
1114 void
1115 EditWidget::setTitle (gchar const* new_title)
1116 {
1117 set_title (new_title);
1118 }
1120 void
1121 EditWidget::layout()
1122 {
1123 show_all_children();
1124 }
1126 void
1127 EditWidget::present()
1128 {
1129 this->Gtk::Window::present();
1130 }
1132 void
1133 EditWidget::getGeometry (gint &x, gint &y, gint &w, gint &h)
1134 {
1135 get_position (x, y);
1136 get_size (w, h);
1137 }
1139 void
1140 EditWidget::setSize (gint w, gint h)
1141 {
1142 resize (w, h);
1143 }
1145 void
1146 EditWidget::setPosition (NR::Point p)
1147 {
1148 move (int(p[NR::X]), int(p[NR::Y]));
1149 }
1151 /// \param p is already gobj()!
1152 void
1153 EditWidget::setTransient (void* p, int i)
1154 {
1155 #ifndef WIN32
1156 gtk_window_set_transient_for (static_cast<GtkWindow*>(p), this->gobj());
1157 if (i==2)
1158 this->Gtk::Window::present();
1159 #endif
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 double lo, up, pos, max;
1347 _top_ruler.get_range (lo, up, pos, max);
1348 _top_ruler.set_range (lo, up, p[NR::X], max);
1349 _left_ruler.get_range (lo, up, pos, max);
1350 _left_ruler.set_range (lo, up, p[NR::Y], max);
1351 }
1353 void
1354 EditWidget::updateRulers()
1355 {
1356 NR::Point origin = _namedview->gridorigin;
1358 NR::Rect const viewbox = _svg_canvas.spobj()->getViewbox();
1359 double lo, up, pos, max;
1360 double const scale = _desktop->current_zoom();
1361 double s = viewbox.min()[NR::X] / scale - origin[NR::X];
1362 double e = viewbox.max()[NR::X] / scale - origin[NR::X];
1363 _top_ruler.get_range(lo, up, pos, max);
1364 _top_ruler.set_range(s, e, pos, e);
1365 s = viewbox.min()[NR::Y] / -scale - origin[NR::Y];
1366 e = viewbox.max()[NR::Y] / -scale - origin[NR::Y];
1367 _left_ruler.set_range(s, e, origin[NR::Y], e);
1368 /// \todo is that correct?
1369 }
1371 void
1372 EditWidget::updateScrollbars (double scale)
1373 {
1374 // do not call this function before canvas has its size allocated
1375 if (!is_realized() || _update_s_f) {
1376 return;
1377 }
1379 _update_s_f = true;
1381 /* The desktop region we always show unconditionally */
1382 SPDocument *doc = _desktop->doc();
1383 NR::Rect const r = sp_item_bbox_desktop(SP_ITEM(SP_DOCUMENT_ROOT(doc)));
1384 NR::Rect darea(NR::Point(MIN(r.min()[NR::X], -sp_document_width(doc)),
1385 MIN(r.min()[NR::Y], -sp_document_height(doc))),
1386 NR::Point(MAX(r.max()[NR::X], 2 * sp_document_width(doc)),
1387 MAX(r.max()[NR::Y], 2 * sp_document_height(doc))));
1389 /* Canvas region we always show unconditionally */
1390 NR::Rect carea(NR::Point(darea.min()[NR::X] * scale - 64,
1391 darea.max()[NR::Y] * -scale - 64),
1392 NR::Point(darea.max()[NR::X] * scale + 64,
1393 darea.min()[NR::Y] * -scale + 64));
1395 NR::Rect const viewbox = _svg_canvas.spobj()->getViewbox();
1397 /* Viewbox is always included into scrollable region */
1398 carea = NR::Rect::union_bounds(carea, viewbox);
1400 Gtk::Adjustment *adj = _bottom_scrollbar.get_adjustment();
1401 adj->set_value(viewbox.min()[NR::X]);
1402 adj->set_lower(carea.min()[NR::X]);
1403 adj->set_upper(carea.max()[NR::X]);
1404 adj->set_page_increment(viewbox.dimensions()[NR::X]);
1405 adj->set_step_increment(0.1 * (viewbox.dimensions()[NR::X]));
1406 adj->set_page_size(viewbox.dimensions()[NR::X]);
1408 adj = _right_scrollbar.get_adjustment();
1409 adj->set_value(viewbox.min()[NR::Y]);
1410 adj->set_lower(carea.min()[NR::Y]);
1411 adj->set_upper(carea.max()[NR::Y]);
1412 adj->set_page_increment(viewbox.dimensions()[NR::Y]);
1413 adj->set_step_increment(0.1 * viewbox.dimensions()[NR::Y]);
1414 adj->set_page_size(viewbox.dimensions()[NR::Y]);
1416 _update_s_f = false;
1417 }
1419 void
1420 EditWidget::toggleRulers()
1421 {
1422 if (_top_ruler.is_visible())
1423 {
1424 _top_ruler.hide_all();
1425 _left_ruler.hide_all();
1426 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.rulers" : "window.rulers", "state", 0);
1427 } else {
1428 _top_ruler.show_all();
1429 _left_ruler.show_all();
1430 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.rulers" : "window.rulers", "state", 1);
1431 }
1432 }
1434 void
1435 EditWidget::toggleScrollbars()
1436 {
1437 if (_bottom_scrollbar.is_visible())
1438 {
1439 _bottom_scrollbar.hide_all();
1440 _right_scrollbar.hide_all();
1441 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.scrollbars" : "window.scrollbars", "state", 0);
1442 } else {
1443 _bottom_scrollbar.show_all();
1444 _right_scrollbar.show_all();
1445 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.scrollbars" : "window.scrollbars", "state", 1);
1446 }
1447 }
1449 void
1450 EditWidget::updateZoom()
1451 {
1452 _zoom_status.update();
1453 }
1455 void
1456 EditWidget::letZoomGrabFocus()
1457 {
1458 _zoom_status.grab_focus();
1459 }
1461 void
1462 EditWidget::setToolboxFocusTo (const gchar *)
1463 {
1464 /// \todo not implemented
1465 }
1467 void
1468 EditWidget::setToolboxAdjustmentValue (const gchar *, double)
1469 {
1470 /// \todo not implemented
1471 }
1473 bool
1474 EditWidget::isToolboxButtonActive (gchar const*)
1475 {
1476 /// \todo not implemented
1477 return true;
1478 }
1480 void
1481 EditWidget::setCoordinateStatus (NR::Point p)
1482 {
1483 gchar *cstr = g_strdup_printf ("%6.2f", _dt2r * p[NR::X]);
1484 _coord_status_x.property_label() = cstr;
1485 g_free (cstr);
1486 cstr = g_strdup_printf ("%6.2f", _dt2r * p[NR::Y]);
1487 _coord_status_y.property_label() = cstr;
1488 g_free (cstr);
1489 }
1491 void
1492 EditWidget::setMessage (Inkscape::MessageType type, gchar const* msg)
1493 {
1494 _select_status.set_markup (msg? msg : "");
1495 }
1497 bool
1498 EditWidget::warnDialog (gchar* msg)
1499 {
1500 Gtk::MessageDialog dlg (*this,
1501 msg,
1502 true,
1503 Gtk::MESSAGE_WARNING,
1504 Gtk::BUTTONS_YES_NO,
1505 true);
1506 int r = dlg.run();
1507 return r == Gtk::RESPONSE_YES;
1508 }
1511 void EditWidget::_namedview_modified (SPObject *obj, guint flags) {
1512 SPNamedView *nv = static_cast<SPNamedView *>(obj);
1513 if (flags & SP_OBJECT_MODIFIED_FLAG) {
1514 this->_dt2r = 1.0 / nv->doc_units->unittobase;
1515 this->_top_ruler.update_metric();
1516 this->_left_ruler.update_metric();
1517 this->_tooltips.set_tip(this->_top_ruler, this->_top_ruler.get_tip());
1518 this->_tooltips.set_tip(this->_left_ruler, this->_left_ruler.get_tip());
1519 this->updateRulers();
1520 }
1521 }
1523 void
1524 EditWidget::initEdit (SPDocument *doc)
1525 {
1526 _desktop = new SPDesktop();
1527 _desktop->registerEditWidget (this);
1529 _namedview = sp_document_namedview (doc, 0);
1530 _svg_canvas.init (_desktop);
1531 _desktop->init (_namedview, _svg_canvas.spobj());
1532 sp_namedview_window_from_document (_desktop);
1533 _dt2r = 1.0 / _namedview->doc_units->unittobase;
1535 /// \todo convert to sigc++ when SPObject hierarchy gets converted
1536 /* Listen on namedview modification */
1537 _namedview_modified_connection = _desktop->namedview->connectModified(sigc::mem_fun(*this, &EditWidget::_namedview_modified));
1538 _layer_selector.setDesktop (_desktop);
1539 _selected_style_status.setDesktop (_desktop);
1541 Inkscape::NSApplication::Editor::addDesktop (_desktop);
1543 _zoom_status.init (_desktop);
1544 _top_ruler.init (_desktop, _svg_canvas.widget());
1545 _left_ruler.init (_desktop, _svg_canvas.widget());
1546 updateRulers();
1547 }
1549 void
1550 EditWidget::destroyEdit()
1551 {
1552 if (_desktop) {
1553 _layer_selector.unreference();
1554 Inkscape::NSApplication::Editor::removeDesktop (_desktop); // clears selection too
1555 _namedview_modified_connection.disconnect();
1556 _desktop->destroy();
1557 Inkscape::GC::release (_desktop);
1558 _desktop = 0;
1559 }
1560 }
1562 //----------end of EditWidgetInterface implementation
1564 //----------start of other callbacks
1566 bool
1567 EditWidget::on_key_press_event (GdkEventKey* event)
1568 {
1569 // this is the original code from helper/window.cpp
1571 unsigned int shortcut;
1572 shortcut = get_group0_keyval (event) |
1573 ( event->state & GDK_SHIFT_MASK ?
1574 SP_SHORTCUT_SHIFT_MASK : 0 ) |
1575 ( event->state & GDK_CONTROL_MASK ?
1576 SP_SHORTCUT_CONTROL_MASK : 0 ) |
1577 ( event->state & GDK_MOD1_MASK ?
1578 SP_SHORTCUT_ALT_MASK : 0 );
1579 return sp_shortcut_invoke (shortcut,
1580 Inkscape::NSApplication::Editor::getActiveDesktop());
1581 }
1583 bool
1584 EditWidget::on_delete_event (GdkEventAny*)
1585 {
1586 return shutdown();
1587 }
1589 bool
1590 EditWidget::on_focus_in_event (GdkEventFocus*)
1591 {
1592 Inkscape::NSApplication::Editor::activateDesktop (_desktop);
1593 _svg_canvas.widget().grab_focus();
1595 return false;
1596 }
1598 void
1599 EditWidget::onWindowSizeAllocate (Gtk::Allocation &newall)
1600 {
1601 if (!is_realized()) return;
1603 const Gtk::Allocation& all = get_allocation();
1604 if ((newall.get_x() == all.get_x()) &&
1605 (newall.get_y() == all.get_y()) &&
1606 (newall.get_width() == all.get_width()) &&
1607 (newall.get_height() == all.get_height())) {
1608 return;
1609 }
1611 NR::Rect const area = _desktop->get_display_area();
1612 double zoom = _desktop->current_zoom();
1614 if (_sticky_zoom.get_active()) {
1615 /* Calculate zoom per pixel */
1616 double const zpsp = zoom / hypot(area.dimensions()[NR::X], area.dimensions()[NR::Y]);
1617 /* Find new visible area */
1618 NR::Rect const newarea = _desktop->get_display_area();
1619 /* Calculate adjusted zoom */
1620 zoom = zpsp * hypot(newarea.dimensions()[NR::X], newarea.dimensions()[NR::Y]);
1621 }
1623 _desktop->zoom_absolute(area.midpoint()[NR::X], area.midpoint()[NR::Y], zoom);
1624 }
1626 void
1627 EditWidget::onWindowRealize()
1628 {
1629 NR::Rect d(NR::Point(0, 0),
1630 NR::Point(sp_document_width(_desktop->doc()), sp_document_height(_desktop->doc())));
1632 if (fabs(d.dimensions()[NR::X]) < 1.0 || fabs(d.dimensions()[NR::Y]) < 1.0) {
1633 return;
1634 }
1636 _desktop->set_display_area(d.min()[NR::X], d.min()[NR::Y], d.max()[NR::X], d.max()[NR::Y], 10);
1637 _namedview_modified(_desktop->namedview, SP_OBJECT_MODIFIED_FLAG);
1638 setTitle (SP_DOCUMENT_NAME(_desktop->doc()));
1639 }
1641 void
1642 EditWidget::onAdjValueChanged()
1643 {
1644 if (_update_a_f) return;
1645 _update_a_f = true;
1647 sp_canvas_scroll_to (_svg_canvas.spobj(),
1648 _bottom_scrollbar.get_value(),
1649 _right_scrollbar.get_value(),
1650 false);
1651 updateRulers();
1653 _update_a_f = false;
1654 }
1657 } // namespace View
1658 } // namespace UI
1659 } // namespace Inkscape
1661 /*
1662 Local Variables:
1663 mode:c++
1664 c-file-style:"stroustrup"
1665 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1666 indent-tabs-mode:nil
1667 fill-column:99
1668 End:
1669 */
1670 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :