1 /**
2 * \brief This class implements the functionality of the window layout, menus,
3 * and signals.
4 *
5 * This is a reimplementation into C++/Gtkmm of Sodipodi's SPDesktopWidget class.
6 * Both SPDesktopWidget and EditWidget adhere to the EditWidgetInterface, so
7 * they both can serve as widget for the same SPDesktop/Edit class.
8 *
9 * Ideally, this class should only contain the handling of the Window (i.e.,
10 * content construction and window signals) and implement its
11 * EditWidgetInterface.
12 *
13 * Authors:
14 * Ralf Stephan <ralf@ark.in-berlin.de>
15 * Bryce W. Harrington <bryce@bryceharrington.org>
16 * Derek P. Moore <derekm@hackunix.org>
17 * Lauris Kaplinski <lauris@kaplinski.com>
18 * Frank Felfe <innerspace@iname.com>
19 *
20 * Copyright (C) 1999-2005 Authors
21 * Copyright (C) 2000-2001 Ximian, Inc.
22 *
23 * Released under GNU GPL. Read the file 'COPYING' for more information.
24 */
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
30 #include <gtk/gtkwindow.h>
31 #include <gtk/gtkversion.h>
32 #include <gtk/gtklabel.h>
33 #include <gtkmm/radioaction.h>
34 #include <gtkmm/menubar.h>
35 #include <gtkmm/messagedialog.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/accelmap.h>
38 #include <gtkmm/separator.h>
39 #include <gtkmm/base.h>
41 #include <sigc++/functors/mem_fun.h>
43 #include "macros.h"
44 #include "path-prefix.h"
45 #include "prefs-utils.h"
46 #include "file.h"
47 #include "application/editor.h"
48 #include "edit-widget.h"
49 #include "ui/stock.h"
50 #include "ui/stock-items.h"
51 #include "ui/icons.h"
53 #include "display/sodipodi-ctrlrect.h"
54 #include "helper/units.h"
55 #include "shortcuts.h"
56 #include "widgets/spw-utilities.h"
57 #include "event-context.h"
58 #include "document.h"
59 #include "sp-namedview.h"
60 #include "sp-item.h"
61 #include "interface.h"
62 #include "extension/db.h"
64 using namespace Inkscape::UI;
65 using namespace Inkscape::UI::Widget;
67 namespace Inkscape {
68 namespace UI {
69 namespace View {
71 EditWidget::EditWidget (SPDocument *doc)
72 : _main_window_table(4),
73 _viewport_table(3,3),
74 _act_grp(Gtk::ActionGroup::create()),
75 _ui_mgr(Gtk::UIManager::create()),
76 _update_s_f(false),
77 _update_a_f(false)
78 {
79 g_warning("Creating new EditWidget");
81 _desktop = 0;
82 Icons::init();
83 Stock::init();
84 initActions();
85 initAccelMap();
86 initUIManager();
87 initLayout();
88 initEdit (doc);
89 g_warning("Done creating new EditWidget");
90 }
92 EditWidget::~EditWidget()
93 {
94 destroyEdit();
95 }
97 void
98 EditWidget::initActions()
99 {
100 initMenuActions();
101 initToolbarActions();
102 }
104 void
105 EditWidget::initUIManager()
106 {
107 _ui_mgr->insert_action_group(_act_grp);
108 add_accel_group(_ui_mgr->get_accel_group());
110 gchar *filename_utf8 = g_build_filename(INKSCAPE_UIDIR, "menus-bars.xml", NULL);
111 if (_ui_mgr->add_ui_from_file(filename_utf8) == 0) {
112 g_warning("Error merging ui from file '%s'", filename_utf8);
113 // fixme-charset: What charset should we pass to g_warning?
114 }
115 g_free(filename_utf8);
116 }
118 void
119 EditWidget::initLayout()
120 {
121 set_title("New document 1 - Inkscape");
122 set_resizable();
123 set_default_size(640, 480);
125 // top level window into which all other portions of the UI get inserted
126 add(_main_window_table);
127 // attach box for horizontal toolbars
128 _main_window_table.attach(_toolbars_vbox, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
129 // attach sub-window for viewport and vertical toolbars
130 _main_window_table.attach(_sub_window_hbox, 0, 1, 2, 3);
131 // viewport table with 3 rows by 3 columns
132 _sub_window_hbox.pack_end(_viewport_table);
134 // Menus and Bars
135 initMenuBar();
136 initCommandsBar();
137 initToolControlsBar();
138 initUriBar();
139 initToolsBar();
141 // Canvas Viewport
142 initLeftRuler();
143 initTopRuler();
144 initStickyZoom();
145 initBottomScrollbar();
146 initRightScrollbar();
147 _viewport_table.attach(_svg_canvas.widget(), 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
148 _svg_canvas.widget().show_all();
151 // The statusbar comes last and appears at the bottom of _main_window_table
152 initStatusbar();
154 signal_size_allocate().connect (sigc::mem_fun (*this, &EditWidget::onWindowSizeAllocate), false);
155 signal_realize().connect (sigc::mem_fun (*this, &EditWidget::onWindowRealize));
156 show_all_children();
157 }
159 void
160 EditWidget::onMenuItem()
161 {
162 g_warning("onMenuItem called");
163 }
165 void
166 EditWidget::onActionFileNew()
167 {
168 // g_warning("onActionFileNew called");
169 sp_file_new_default();
170 }
172 void
173 EditWidget::onActionFileOpen()
174 {
175 // g_warning("onActionFileOpen called");
176 sp_file_open_dialog (NULL, NULL);
177 }
179 void
180 EditWidget::onActionFileQuit()
181 {
182 g_warning("onActionFileQuit");
183 sp_ui_close_all();
184 }
186 void
187 EditWidget::onActionFilePrint()
188 {
189 g_warning("onActionFilePrint");
190 }
192 void
193 EditWidget::onToolbarItem()
194 {
195 g_warning("onToolbarItem called");
196 }
198 void
199 EditWidget::onSelectTool()
200 {
201 _tool_ctrl->remove();
202 _tool_ctrl->add(*_select_ctrl);
203 }
205 void
206 EditWidget::onNodeTool()
207 {
208 _tool_ctrl->remove();
209 _tool_ctrl->add(*_node_ctrl);
210 }
212 void
213 EditWidget::onDialogInkscapePreferences()
214 {
215 _dlg_mgr.showDialog("InkscapePreferences");
216 }
218 void
219 EditWidget::onDialogAbout()
220 {
221 }
223 void
224 EditWidget::onDialogAlignAndDistribute()
225 {
226 _dlg_mgr.showDialog("AlignAndDistribute");
227 }
229 void
230 EditWidget::onDialogDocumentProperties()
231 {
232 // manage (Inkscape::UI::Dialog::DocumentPreferences::create());
233 _dlg_mgr.showDialog("DocumentPreferences");
234 }
236 void
237 EditWidget::onDialogExport()
238 {
239 _dlg_mgr.showDialog("Export");
240 }
242 void
243 EditWidget::onDialogExtensionEditor()
244 {
245 _dlg_mgr.showDialog("ExtensionEditor");
246 }
248 void
249 EditWidget::onDialogFillAndStroke()
250 {
251 _dlg_mgr.showDialog("FillAndStroke");
252 }
254 void
255 EditWidget::onDialogFind()
256 {
257 _dlg_mgr.showDialog("Find");
258 }
260 void
261 EditWidget::onDialogLayerEditor()
262 {
263 _dlg_mgr.showDialog("LayerEditor");
264 }
266 void
267 EditWidget::onDialogMessages()
268 {
269 _dlg_mgr.showDialog("Messages");
270 }
272 void
273 EditWidget::onDialogObjectProperties()
274 {
275 _dlg_mgr.showDialog("ObjectProperties");
276 }
278 void
279 EditWidget::onDialogTextProperties()
280 {
281 _dlg_mgr.showDialog("TextProperties");
282 }
284 void
285 EditWidget::onDialogTrace()
286 {
287 }
289 void
290 EditWidget::onDialogTransformation()
291 {
292 _dlg_mgr.showDialog("Transformation");
293 }
295 void
296 EditWidget::onDialogXmlEditor()
297 {
298 _dlg_mgr.showDialog("XmlEditor");
299 }
301 void
302 EditWidget::onUriChanged()
303 {
304 g_message("onUriChanged called");
306 }
308 // FIXME: strings are replaced by placeholders, NOT to be translated until the code is enabled
309 // See http://sourceforge.net/mailarchive/message.php?msg_id=11746016 for details
311 void
312 EditWidget::initMenuActions()
313 {
314 // _act_grp->add(Gtk::Action::create("MenuFile", _("PLACEHOLDER, do not translate")));
315 // _act_grp->add(Gtk::Action::create("MenuEdit", _("PLACEHOLDER, do not translate")));
316 // _act_grp->add(Gtk::Action::create("MenuView", _("PLACEHOLDER, do not translate")));
317 // _act_grp->add(Gtk::Action::create("MenuLayer", _("PLACEHOLDER, do not translate")));
318 // _act_grp->add(Gtk::Action::create("MenuObject", _("PLACEHOLDER, do not translate")));
319 // _act_grp->add(Gtk::Action::create("MenuPath", _("PLACEHOLDER, do not translate")));
320 // _act_grp->add(Gtk::Action::create("MenuText", _("PLACEHOLDER, do not translate")));
321 // _act_grp->add(Gtk::Action::create("MenuHelp", _("PLACEHOLDER, do not translate")));
322 // temporarily replaced with non-gettext version to have a well-sized menu
323 // for testing:
325 _act_grp->add(Gtk::Action::create("MenuFile", "File"));
326 _act_grp->add(Gtk::Action::create("MenuEdit", "Edit"));
327 _act_grp->add(Gtk::Action::create("MenuView", "View"));
328 _act_grp->add(Gtk::Action::create("MenuLayer", "Layer"));
329 _act_grp->add(Gtk::Action::create("MenuObject", "Object"));
330 _act_grp->add(Gtk::Action::create("MenuPath", "Path"));
331 _act_grp->add(Gtk::Action::create("MenuText", "Text"));
332 _act_grp->add(Gtk::Action::create("MenuHelp", "Help"));
334 // File menu
335 _act_grp->add(Gtk::Action::create("New",
336 Gtk::Stock::NEW, Glib::ustring(),
337 _("PLACEHOLDER, do not translate")),
338 sigc::mem_fun(*this, &EditWidget::onActionFileNew));
340 _act_grp->add(Gtk::Action::create("Open",
341 Gtk::Stock::OPEN, Glib::ustring(),
342 _("PLACEHOLDER, do not translate")),
343 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
345 _act_grp->add(Gtk::Action::create("OpenRecent",
346 Stock::OPEN_RECENT));
348 _act_grp->add(Gtk::Action::create("Revert",
349 Gtk::Stock::REVERT_TO_SAVED, Glib::ustring(),
350 _("PLACEHOLDER, do not translate")),
351 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
353 _act_grp->add(Gtk::Action::create("Save",
354 Gtk::Stock::SAVE, Glib::ustring(),
355 _("PLACEHOLDER, do not translate")),
356 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
358 _act_grp->add(Gtk::Action::create("SaveAs",
359 Gtk::Stock::SAVE_AS, Glib::ustring(),
360 _("PLACEHOLDER, do not translate")),
361 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
363 _act_grp->add(Gtk::Action::create("Import",
364 Stock::IMPORT, Glib::ustring(),
365 _("PLACEHOLDER, do not translate")),
366 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
368 _act_grp->add(Gtk::Action::create("Export",
369 Stock::EXPORT, Glib::ustring(),
370 _("PLACEHOLDER, do not translate")),
371 sigc::mem_fun(*this, &EditWidget::onDialogExport));
373 _act_grp->add(Gtk::Action::create("Print",
374 Gtk::Stock::PRINT, Glib::ustring(),
375 _("PLACEHOLDER, do not translate")),
376 sigc::mem_fun(*this, &EditWidget::onActionFilePrint));
378 _act_grp->add(Gtk::Action::create("PrintPreview",
379 Gtk::Stock::PRINT_PREVIEW),
380 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
382 _act_grp->add(Gtk::Action::create("VacuumDefs",
383 Stock::VACUUM_DEFS),
384 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
386 _act_grp->add(Gtk::Action::create("DocumentProperties",
387 Gtk::Stock::PROPERTIES, Glib::ustring(),
388 _("PLACEHOLDER, do not translate")),
389 sigc::mem_fun(*this, &EditWidget::onDialogDocumentProperties));
391 _act_grp->add(Gtk::Action::create("InkscapePreferences",
392 Gtk::Stock::PREFERENCES, Glib::ustring(),
393 _("PLACEHOLDER, do not translate")),
394 sigc::mem_fun(*this, &EditWidget::onDialogInkscapePreferences));
396 _act_grp->add(Gtk::Action::create("Close",
397 Gtk::Stock::CLOSE),
398 sigc::mem_fun(*this, &EditWidget::onActionFileOpen));
400 _act_grp->add(Gtk::Action::create("Quit",
401 Gtk::Stock::QUIT),
402 sigc::mem_fun(*this, &EditWidget::onActionFileQuit));
404 // EditWidget menu
405 _act_grp->add(Gtk::Action::create("Undo",
406 Gtk::Stock::UNDO, Glib::ustring(),
407 _("PLACEHOLDER, do not translate")));
409 _act_grp->add(Gtk::Action::create("Redo",
410 Gtk::Stock::REDO, Glib::ustring(),
411 _("PLACEHOLDER, do not translate")));
413 _act_grp->add(Gtk::Action::create("UndoHistory",
414 Stock::UNDO_HISTORY, Glib::ustring(),
415 _("PLACEHOLDER, do not translate")));
417 _act_grp->add(Gtk::Action::create("Cut",
418 Gtk::Stock::CUT, Glib::ustring(),
419 _("PLACEHOLDER, do not translate")));
421 _act_grp->add(Gtk::Action::create("Copy",
422 Gtk::Stock::COPY, Glib::ustring(),
423 _("PLACEHOLDER, do not translate")));
425 _act_grp->add(Gtk::Action::create("Paste",
426 Gtk::Stock::PASTE, Glib::ustring(),
427 _("PLACEHOLDER, do not translate")));
429 _act_grp->add(Gtk::Action::create("PasteInPlace",
430 Stock::PASTE_IN_PLACE));
432 _act_grp->add(Gtk::Action::create("PasteStyle",
433 Stock::PASTE_STYLE));
435 _act_grp->add(Gtk::Action::create("Find",
436 Gtk::Stock::FIND),
437 sigc::mem_fun(*this, &EditWidget::onDialogFind));
439 _act_grp->add(Gtk::Action::create("Duplicate",
440 Stock::DUPLICATE, Glib::ustring(),
441 _("PLACEHOLDER, do not translate")));
443 _act_grp->add(Gtk::Action::create("Clone",
444 Stock::CLONE, Glib::ustring(),
445 _("PLACEHOLDER, do not translate")));
447 _act_grp->add(Gtk::Action::create("CloneUnlink",
448 Stock::CLONE_UNLINK, Glib::ustring(),
449 _("PLACEHOLDER, do not translate")));
451 _act_grp->add(Gtk::Action::create("CloneSelectOrig",
452 Stock::CLONE_SELECT_ORIG));
454 _act_grp->add(Gtk::Action::create("MakeBitmap",
455 Stock::MAKE_BITMAP));
457 _act_grp->add(Gtk::Action::create("Tile",
458 Stock::TILE));
460 _act_grp->add(Gtk::Action::create("Untile",
461 Stock::UNTILE));
463 _act_grp->add(Gtk::Action::create("Delete",
464 Gtk::Stock::DELETE));
466 _act_grp->add(Gtk::Action::create("SelectAll",
467 Stock::SELECT_ALL));
469 _act_grp->add(Gtk::Action::create("SelectAllInAllLayers",
470 Stock::SELECT_ALL_IN_ALL_LAYERS));
472 _act_grp->add(Gtk::Action::create("SelectInvert",
473 Stock::SELECT_INVERT));
475 _act_grp->add(Gtk::Action::create("SelectNone",
476 Stock::SELECT_NONE));
478 _act_grp->add(Gtk::Action::create("XmlEditor",
479 Stock::XML_EDITOR, Glib::ustring(),
480 _("PLACEHOLDER, do not translate")),
481 sigc::mem_fun(*this, &EditWidget::onDialogXmlEditor));
483 // View menu
484 _act_grp->add(Gtk::Action::create("Zoom",
485 Stock::ZOOM));
487 _act_grp->add(Gtk::Action::create("ZoomIn",
488 Stock::ZOOM_IN, Glib::ustring(),
489 _("PLACEHOLDER, do not translate")));
491 _act_grp->add(Gtk::Action::create("ZoomOut",
492 Stock::ZOOM_OUT, Glib::ustring(),
493 _("PLACEHOLDER, do not translate")));
495 _act_grp->add(Gtk::Action::create("Zoom100",
496 Stock::ZOOM_100, Glib::ustring(),
497 _("PLACEHOLDER, do not translate")));
499 _act_grp->add(Gtk::Action::create("Zoom50",
500 Stock::ZOOM_50, Glib::ustring(),
501 _("PLACEHOLDER, do not translate")));
503 _act_grp->add(Gtk::Action::create("Zoom200",
504 Stock::ZOOM_200, Glib::ustring(),
505 _("PLACEHOLDER, do not translate")));
507 _act_grp->add(Gtk::Action::create("ZoomSelection",
508 Stock::ZOOM_SELECTION, Glib::ustring(),
509 _("PLACEHOLDER, do not translate")));
511 _act_grp->add(Gtk::Action::create("ZoomDrawing",
512 Stock::ZOOM_DRAWING, Glib::ustring(),
513 _("PLACEHOLDER, do not translate")));
515 _act_grp->add(Gtk::Action::create("ZoomPage",
516 Stock::ZOOM_PAGE, Glib::ustring(),
517 _("PLACEHOLDER, do not translate")));
519 _act_grp->add(Gtk::Action::create("ZoomWidth",
520 Stock::ZOOM_WIDTH, Glib::ustring(),
521 _("PLACEHOLDER, do not translate")));
523 _act_grp->add(Gtk::Action::create("ZoomPrev",
524 Stock::ZOOM_PREV, Glib::ustring(),
525 _("PLACEHOLDER, do not translate")));
527 _act_grp->add(Gtk::Action::create("ZoomNext",
528 Stock::ZOOM_NEXT, Glib::ustring(),
529 _("PLACEHOLDER, do not translate")));
531 _act_grp->add(Gtk::Action::create("ShowHide",
532 Stock::SHOW_HIDE));
534 _act_grp->add(Gtk::ToggleAction::create("ShowHideCommandsBar",
535 Stock::SHOW_HIDE_COMMANDS_BAR));
537 _act_grp->add(Gtk::ToggleAction::create("ShowHideToolControlsBar",
538 Stock::SHOW_HIDE_TOOL_CONTROLS_BAR));
540 _act_grp->add(Gtk::ToggleAction::create("ShowHideToolsBar",
541 Stock::SHOW_HIDE_TOOLS_BAR));
543 _act_grp->add(Gtk::ToggleAction::create("ShowHideRulers",
544 Stock::SHOW_HIDE_RULERS));
546 _act_grp->add(Gtk::ToggleAction::create("ShowHideScrollbars",
547 Stock::SHOW_HIDE_SCROLLBARS));
549 _act_grp->add(Gtk::ToggleAction::create("ShowHideStatusbar",
550 Stock::SHOW_HIDE_STATUSBAR));
552 _act_grp->add(Gtk::Action::create("ShowHideDialogs",
553 Stock::SHOW_HIDE_DIALOGS));
555 _act_grp->add(Gtk::Action::create("Grid",
556 Stock::GRID));
558 _act_grp->add(Gtk::Action::create("Guides",
559 Stock::GUIDES));
561 _act_grp->add(Gtk::Action::create("Fullscreen",
562 Stock::FULLSCREEN));
564 _act_grp->add(Gtk::Action::create("Messages",
565 Stock::MESSAGES),
566 sigc::mem_fun(*this, &EditWidget::onDialogMessages));
568 _act_grp->add(Gtk::Action::create("Scripts",
569 Stock::SCRIPTS));
571 _act_grp->add(Gtk::Action::create("WindowPrev",
572 Stock::WINDOW_PREV));
574 _act_grp->add(Gtk::Action::create("WindowNext",
575 Stock::WINDOW_NEXT));
577 _act_grp->add(Gtk::Action::create("WindowDuplicate",
578 Stock::WINDOW_DUPLICATE));
580 // Layer menu
581 _act_grp->add(Gtk::Action::create("LayerNew",
582 Stock::LAYER_NEW));
584 _act_grp->add(Gtk::Action::create("LayerRename",
585 Stock::LAYER_RENAME));
587 _act_grp->add(Gtk::Action::create("LayerDuplicate",
588 Stock::LAYER_DUPLICATE));
590 _act_grp->add(Gtk::Action::create("LayerAnchor",
591 Stock::LAYER_ANCHOR));
593 _act_grp->add(Gtk::Action::create("LayerMergeDown",
594 Stock::LAYER_MERGE_DOWN));
596 _act_grp->add(Gtk::Action::create("LayerDelete",
597 Stock::LAYER_DELETE));
599 _act_grp->add(Gtk::Action::create("LayerSelectNext",
600 Stock::LAYER_SELECT_NEXT));
602 _act_grp->add(Gtk::Action::create("LayerSelectPrev",
603 Stock::LAYER_SELECT_PREV));
605 _act_grp->add(Gtk::Action::create("LayerSelectTop",
606 Stock::LAYER_SELECT_TOP));
608 _act_grp->add(Gtk::Action::create("LayerSelectBottom",
609 Stock::LAYER_SELECT_BOTTOM));
611 _act_grp->add(Gtk::Action::create("LayerRaise",
612 Stock::LAYER_RAISE));
614 _act_grp->add(Gtk::Action::create("LayerLower",
615 Stock::LAYER_LOWER));
617 _act_grp->add(Gtk::Action::create("LayerToTop",
618 Stock::LAYER_TO_TOP));
620 _act_grp->add(Gtk::Action::create("LayerToBottom",
621 Stock::LAYER_TO_BOTTOM));
623 // Object menu
624 _act_grp->add(Gtk::Action::create("FillAndStroke",
625 Stock::FILL_STROKE, Glib::ustring(),
626 _("PLACEHOLDER, do not translate")),
627 sigc::mem_fun(*this, &EditWidget::onDialogFillAndStroke));
629 _act_grp->add(Gtk::Action::create("ObjectProperties",
630 Stock::OBJECT_PROPERTIES),
631 sigc::mem_fun(*this, &EditWidget::onDialogObjectProperties));
633 _act_grp->add(Gtk::Action::create("Group",
634 Stock::GROUP, Glib::ustring(),
635 _("PLACEHOLDER, do not translate")));
637 _act_grp->add(Gtk::Action::create("Ungroup",
638 Stock::UNGROUP, Glib::ustring(),
639 _("PLACEHOLDER, do not translate")));
641 _act_grp->add(Gtk::Action::create("Raise",
642 Stock::RAISE, Glib::ustring(),
643 _("PLACEHOLDER, do not translate")));
645 _act_grp->add(Gtk::Action::create("Lower",
646 Stock::LOWER, Glib::ustring(),
647 _("PLACEHOLDER, do not translate")));
649 _act_grp->add(Gtk::Action::create("RaiseToTop",
650 Stock::RAISE_TO_TOP, Glib::ustring(),
651 _("PLACEHOLDER, do not translate")));
653 _act_grp->add(Gtk::Action::create("LowerToBottom",
654 Stock::LOWER_TO_BOTTOM, Glib::ustring(),
655 _("PLACEHOLDER, do not translate")));
657 _act_grp->add(Gtk::Action::create("MoveToNewLayer",
658 Stock::MOVE_TO_NEW_LAYER, Glib::ustring(),
659 _("PLACEHOLDER, do not translate")));
661 _act_grp->add(Gtk::Action::create("MoveToNextLayer",
662 Stock::MOVE_TO_NEXT_LAYER, Glib::ustring(),
663 _("PLACEHOLDER, do not translate")));
665 _act_grp->add(Gtk::Action::create("MoveToPrevLayer",
666 Stock::MOVE_TO_PREV_LAYER, Glib::ustring(),
667 _("PLACEHOLDER, do not translate")));
669 _act_grp->add(Gtk::Action::create("MoveToTopLayer",
670 Stock::MOVE_TO_TOP_LAYER, Glib::ustring(),
671 _("PLACEHOLDER, do not translate")));
673 _act_grp->add(Gtk::Action::create("MoveToBottomLayer",
674 Stock::MOVE_TO_BOTTOM_LAYER, Glib::ustring(),
675 _("PLACEHOLDER, do not translate")));
677 _act_grp->add(Gtk::Action::create("Rotate90CW",
678 Stock::ROTATE_90_CW, Glib::ustring(),
679 _("PLACEHOLDER, do not translate")));
681 _act_grp->add(Gtk::Action::create("Rotate90CCW",
682 Stock::ROTATE_90_CCW, Glib::ustring(),
683 _("PLACEHOLDER, do not translate")));
685 _act_grp->add(Gtk::Action::create("FlipHoriz",
686 Stock::FLIP_HORIZ, Glib::ustring(),
687 _("PLACEHOLDER, do not translate")));
689 _act_grp->add(Gtk::Action::create("FlipVert",
690 Stock::FLIP_VERT, Glib::ustring(),
691 _("PLACEHOLDER, do not translate")));
693 _act_grp->add(Gtk::Action::create("Transformation",
694 Stock::TRANSFORMATION, Glib::ustring(),
695 _("PLACEHOLDER, do not translate")),
696 sigc::mem_fun(*this, &EditWidget::onDialogTransformation));
698 _act_grp->add(Gtk::Action::create("AlignAndDistribute",
699 Stock::ALIGN_DISTRIBUTE, Glib::ustring(),
700 _("PLACEHOLDER, do not translate")),
701 sigc::mem_fun(*this, &EditWidget::onDialogAlignAndDistribute));
703 // Path menu
704 _act_grp->add(Gtk::Action::create("ObjectToPath",
705 Stock::OBJECT_TO_PATH, Glib::ustring(),
706 _("PLACEHOLDER, do not translate")));
708 _act_grp->add(Gtk::Action::create("StrokeToPath",
709 Stock::STROKE_TO_PATH, Glib::ustring(),
710 _("PLACEHOLDER, do not translate")));
712 _act_grp->add(Gtk::Action::create("Trace",
713 Stock::TRACE),
714 sigc::mem_fun(*this, &EditWidget::onDialogTrace));
716 _act_grp->add(Gtk::Action::create("Union",
717 Stock::UNION));
719 _act_grp->add(Gtk::Action::create("Difference",
720 Stock::DIFFERENCE));
722 _act_grp->add(Gtk::Action::create("Intersection",
723 Stock::INTERSECTION));
725 _act_grp->add(Gtk::Action::create("Exclusion",
726 Stock::EXCLUSION));
728 _act_grp->add(Gtk::Action::create("Division",
729 Stock::DIVISION));
731 _act_grp->add(Gtk::Action::create("CutPath",
732 Stock::CUT_PATH));
734 _act_grp->add(Gtk::Action::create("Combine",
735 Stock::COMBINE));
737 _act_grp->add(Gtk::Action::create("BreakApart",
738 Stock::BREAK_APART));
740 _act_grp->add(Gtk::Action::create("Inset",
741 Stock::INSET));
743 _act_grp->add(Gtk::Action::create("Outset",
744 Stock::OUTSET));
746 _act_grp->add(Gtk::Action::create("OffsetDynamic",
747 Stock::OFFSET_DYNAMIC));
749 _act_grp->add(Gtk::Action::create("OffsetLinked",
750 Stock::OFFSET_LINKED));
752 _act_grp->add(Gtk::Action::create("Simplify",
753 Stock::SIMPLIFY));
755 _act_grp->add(Gtk::Action::create("Reverse",
756 Stock::REVERSE));
758 _act_grp->add(Gtk::Action::create("Cleanup",
759 Gtk::Stock::CLEAR,
760 _("PLACEHOLDER, do not translate")));
762 // Text menu
763 _act_grp->add(Gtk::Action::create("TextProperties",
764 Gtk::Stock::SELECT_FONT, Glib::ustring(),
765 _("PLACEHOLDER, do not translate")),
766 sigc::mem_fun(*this, &EditWidget::onDialogTextProperties));
768 _act_grp->add(Gtk::Action::create("PutOnPath",
769 Stock::PUT_ON_PATH));
771 _act_grp->add(Gtk::Action::create("RemoveFromPath",
772 Stock::REMOVE_FROM_PATH));
774 _act_grp->add(Gtk::Action::create("RemoveManualKerns",
775 Stock::REMOVE_MANUAL_KERNS));
777 // Whiteboard menu
778 #ifdef WITH_INKBOARD
779 #endif
781 // About menu
782 _act_grp->add(Gtk::Action::create("KeysAndMouse",
783 Stock::KEYS_MOUSE));
785 _act_grp->add(Gtk::Action::create("Tutorials",
786 Stock::TUTORIALS));
788 _act_grp->add(Gtk::Action::create("About",
789 Stock::ABOUT),
790 sigc::mem_fun(*this, &EditWidget::onDialogAbout));
791 }
793 void
794 EditWidget::initToolbarActions()
795 {
796 // Tools bar
797 Gtk::RadioAction::Group tools;
799 _act_grp->add(Gtk::RadioAction::create(tools, "ToolSelect",
800 Stock::TOOL_SELECT, Glib::ustring(),
801 _("PLACEHOLDER, do not translate")),
802 sigc::mem_fun(*this, &EditWidget::onSelectTool));
804 _act_grp->add(Gtk::RadioAction::create(tools, "ToolNode",
805 Stock::TOOL_NODE, Glib::ustring(),
806 _("PLACEHOLDER, do not translate")),
807 sigc::mem_fun(*this, &EditWidget::onNodeTool));
809 _act_grp->add(Gtk::RadioAction::create(tools, "ToolZoom",
810 Stock::TOOL_ZOOM, Glib::ustring(),
811 _("PLACEHOLDER, do not translate")));
813 _act_grp->add(Gtk::RadioAction::create(tools, "ToolRect",
814 Stock::TOOL_RECT, Glib::ustring(),
815 _("PLACEHOLDER, do not translate")));
817 _act_grp->add(Gtk::RadioAction::create(tools, "ToolArc",
818 Stock::TOOL_ARC, Glib::ustring(),
819 _("PLACEHOLDER, do not translate")));
821 _act_grp->add(Gtk::RadioAction::create(tools, "ToolStar",
822 Stock::TOOL_STAR, Glib::ustring(),
823 _("PLACEHOLDER, do not translate")));
825 _act_grp->add(Gtk::RadioAction::create(tools, "ToolSpiral",
826 Stock::TOOL_SPIRAL, Glib::ustring(),
827 _("PLACEHOLDER, do not translate")));
829 _act_grp->add(Gtk::RadioAction::create(tools, "ToolFreehand",
830 Stock::TOOL_FREEHAND, Glib::ustring(),
831 _("PLACEHOLDER, do not translate")));
833 _act_grp->add(Gtk::RadioAction::create(tools, "ToolPen",
834 Stock::TOOL_PEN, Glib::ustring(),
835 _("PLACEHOLDER, do not translate")));
837 _act_grp->add(Gtk::RadioAction::create(tools, "ToolDynaDraw",
838 Stock::TOOL_DYNADRAW, Glib::ustring(),
839 _("PLACEHOLDER, do not translate")));
841 _act_grp->add(Gtk::RadioAction::create(tools, "ToolText",
842 Stock::TOOL_TEXT, Glib::ustring(),
843 _("PLACEHOLDER, do not translate")));
845 _act_grp->add(Gtk::RadioAction::create(tools, "ToolDropper",
846 Stock::TOOL_DROPPER, Glib::ustring(),
847 _("PLACEHOLDER, do not translate")));
849 // Select Controls bar
850 _act_grp->add(Gtk::ToggleAction::create("TransformStroke",
851 Stock::TRANSFORM_STROKE, Glib::ustring(),
852 _("PLACEHOLDER, do not translate")));
854 _act_grp->add(Gtk::ToggleAction::create("TransformCorners",
855 Stock::TRANSFORM_CORNERS, Glib::ustring(),
856 _("PLACEHOLDER, do not translate")));
858 _act_grp->add(Gtk::ToggleAction::create("TransformGradient",
859 Stock::TRANSFORM_GRADIENT, Glib::ustring(),
860 _("PLACEHOLDER, do not translate")));
862 _act_grp->add(Gtk::ToggleAction::create("TransformPattern",
863 Stock::TRANSFORM_PATTERN, Glib::ustring(),
864 _("PLACEHOLDER, do not translate")));
866 // Node Controls bar
867 _act_grp->add(Gtk::Action::create("NodeInsert",
868 Gtk::Stock::ADD, Glib::ustring(),
869 _("PLACEHOLDER, do not translate")));
871 _act_grp->add(Gtk::Action::create("NodeDelete",
872 Gtk::Stock::REMOVE, Glib::ustring(),
873 _("PLACEHOLDER, do not translate")));
875 _act_grp->add(Gtk::Action::create("NodeJoin",
876 Stock::NODE_JOIN, Glib::ustring(),
877 _("PLACEHOLDER, do not translate")));
879 _act_grp->add(Gtk::Action::create("NodeJoinSegment",
880 Stock::NODE_JOIN_SEGMENT, Glib::ustring(),
881 _("PLACEHOLDER, do not translate")));
883 _act_grp->add(Gtk::Action::create("NodeDeleteSegment",
884 Stock::NODE_DELETE_SEGMENT, Glib::ustring(),
885 _("PLACEHOLDER, do not translate")));
887 _act_grp->add(Gtk::Action::create("NodeBreak",
888 Stock::NODE_BREAK, Glib::ustring(),
889 _("PLACEHOLDER, do not translate")));
891 _act_grp->add(Gtk::Action::create("NodeCorner",
892 Stock::NODE_CORNER, Glib::ustring(),
893 _("PLACEHOLDER, do not translate")));
895 _act_grp->add(Gtk::Action::create("NodeSmooth",
896 Stock::NODE_SMOOTH, Glib::ustring(),
897 _("PLACEHOLDER, do not translate")));
899 _act_grp->add(Gtk::Action::create("NodeSymmetric",
900 Stock::NODE_SYMMETRIC, Glib::ustring(),
901 _("PLACEHOLDER, do not translate")));
903 _act_grp->add(Gtk::Action::create("NodeLine",
904 Stock::NODE_LINE, Glib::ustring(),
905 _("PLACEHOLDER, do not translate")));
907 _act_grp->add(Gtk::Action::create("NodeCurve",
908 Stock::NODE_CURVE, Glib::ustring(),
909 _("PLACEHOLDER, do not translate")));
910 }
912 void
913 EditWidget::initAccelMap()
914 {
915 gchar *filename = g_build_filename(INKSCAPE_UIDIR, "keybindings.rc", NULL);
916 Gtk::AccelMap::load(filename);
917 g_free(filename);
919 // One problem is that the keys 1-6 are zoom accelerators which get
920 // caught as accelerator _before_ any Entry input handler receives them,
921 // for example the zoom status. At the moment, the best way seems to
922 // disable them as accelerators when the Entry gets focus, and enable
923 // them when focus goes elsewhere. The code for this belongs here,
924 // and not in zoom-status.cpp .
926 _zoom_status.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditWidget::onEntryFocusIn));
927 _zoom_status.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditWidget::onEntryFocusOut));
928 }
930 bool
931 EditWidget::onEntryFocusIn (GdkEventFocus* ev)
932 {
933 Gdk::ModifierType m = static_cast<Gdk::ModifierType>(0);
934 Gtk::AccelMap::change_entry ("<Actions>//Zoom100", 0, m, false);
935 Gtk::AccelMap::change_entry ("<Actions>//Zoom50", 0, m, false);
936 Gtk::AccelMap::change_entry ("<Actions>//ZoomSelection", 0, m, false);
937 Gtk::AccelMap::change_entry ("<Actions>//ZoomDrawing", 0, m, false);
938 Gtk::AccelMap::change_entry ("<Actions>//ZoomPage", 0, m, false);
939 Gtk::AccelMap::change_entry ("<Actions>//ZoomWidth", 0, m, false);
940 return false;
941 }
943 bool
944 EditWidget::onEntryFocusOut (GdkEventFocus* ev)
945 {
946 Gdk::ModifierType m = static_cast<Gdk::ModifierType>(0);
947 Gtk::AccelMap::change_entry ("<Actions>//Zoom100", '1', m, false);
948 Gtk::AccelMap::change_entry ("<Actions>//Zoom50", '2', m, false);
949 Gtk::AccelMap::change_entry ("<Actions>//ZoomSelection", '3', m, false);
950 Gtk::AccelMap::change_entry ("<Actions>//ZoomDrawing", '4', m, false);
951 Gtk::AccelMap::change_entry ("<Actions>//ZoomPage", '5', m, false);
952 Gtk::AccelMap::change_entry ("<Actions>//ZoomWidth", '6', m, false);
953 return false;
954 }
956 void
957 EditWidget::initMenuBar()
958 {
959 g_assert(_ui_mgr);
960 Gtk::MenuBar *menu = static_cast<Gtk::MenuBar*>(_ui_mgr->get_widget("/MenuBar"));
961 g_assert(menu != NULL);
962 _main_window_table.attach(*Gtk::manage(menu), 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
963 }
965 void
966 EditWidget::initCommandsBar()
967 {
968 g_assert(_ui_mgr);
969 Toolbox *bar = new Toolbox(static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/CommandsBar")),
970 Gtk::TOOLBAR_ICONS);
971 g_assert(bar != NULL);
972 _toolbars_vbox.pack_start(*Gtk::manage(bar), Gtk::PACK_SHRINK);
973 }
975 void
976 EditWidget::initToolControlsBar()
977 {
978 // TODO: Do UIManager controlled widgets need to be deleted?
979 _select_ctrl = static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/SelectControlsBar"));
980 _node_ctrl = static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/NodeControlsBar"));
982 _tool_ctrl = new Toolbox(_select_ctrl, Gtk::TOOLBAR_ICONS);
984 _toolbars_vbox.pack_start(*Gtk::manage(_tool_ctrl), Gtk::PACK_SHRINK);
985 }
987 void
988 EditWidget::initUriBar()
989 {
990 /// \todo Create an Inkscape::UI::Widget::UriBar class (?)
992 _uri_ctrl = new Gtk::Toolbar();
994 _uri_label.set_label(_("PLACEHOLDER, DO NOT TRANSLATE"));
995 _uri_ctrl->add(_uri_label);
996 _uri_ctrl->add(_uri_entry);
998 _uri_entry.signal_activate()
999 .connect_notify(sigc::mem_fun(*this, &EditWidget::onUriChanged));
1001 _toolbars_vbox.pack_start(*Gtk::manage(_uri_ctrl), Gtk::PACK_SHRINK);
1002 }
1004 void
1005 EditWidget::initToolsBar()
1006 {
1007 Toolbox *bar = new Toolbox(static_cast<Gtk::Toolbar*>(_ui_mgr->get_widget("/ToolsBar")),
1008 Gtk::TOOLBAR_ICONS,
1009 Gtk::ORIENTATION_VERTICAL);
1010 g_assert(bar != NULL);
1011 _sub_window_hbox.pack_start(*Gtk::manage(bar), Gtk::PACK_SHRINK);
1012 }
1014 void
1015 EditWidget::initTopRuler()
1016 {
1017 _viewport_table.attach(_top_ruler, 1, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
1019 _tooltips.set_tip (_top_ruler, _top_ruler.get_tip());
1020 }
1022 void
1023 EditWidget::initLeftRuler()
1024 {
1025 _viewport_table.attach(_left_ruler, 0, 1, 1, 2, Gtk::SHRINK, Gtk::FILL|Gtk::EXPAND);
1027 _tooltips.set_tip (_left_ruler, _left_ruler.get_tip());
1028 }
1030 void
1031 EditWidget::initBottomScrollbar()
1032 {
1033 _viewport_table.attach(_bottom_scrollbar, 1, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
1034 _bottom_scrollbar.signal_value_changed().connect (sigc::mem_fun (*this, &EditWidget::onAdjValueChanged));
1035 _bottom_scrollbar.property_adjustment() = new Gtk::Adjustment (0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0);
1036 }
1038 void
1039 EditWidget::initRightScrollbar()
1040 {
1041 _viewport_table.attach(_right_scrollbar, 2, 3, 1, 2, Gtk::SHRINK, Gtk::FILL|Gtk::EXPAND);
1043 _right_scrollbar.signal_value_changed().connect (sigc::mem_fun (*this, &EditWidget::onAdjValueChanged));
1044 _right_scrollbar.property_adjustment() = new Gtk::Adjustment (0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0);
1045 }
1047 void
1048 EditWidget::initStickyZoom()
1049 {
1050 _viewport_table.attach(_sticky_zoom, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
1052 _sticky_zoom.set_active (prefs_get_int_attribute ("options.stickyzoom", "value", 0) != 0);
1053 _tooltips.set_tip (_sticky_zoom, _("Zoom drawing if window size changes"));
1055 /// \todo icon not implemented
1056 }
1058 void
1059 EditWidget::initStatusbar()
1060 {
1061 _statusbar.pack_start (_selected_style_status, false, false, 1);
1062 _statusbar.pack_start (*new Gtk::VSeparator(), false, false, 0);
1064 _tooltips.set_tip (_zoom_status, _("Zoom"));
1066 _layer_selector.reference();
1067 _statusbar.pack_start (_layer_selector, false, false, 1);
1069 _coord_status.property_n_rows() = 2;
1070 _coord_status.property_n_columns() = 5;
1071 _coord_status.property_row_spacing() = 0;
1072 _coord_status.property_column_spacing() = 2;
1073 _coord_eventbox.add (_coord_status);
1074 _tooltips.set_tip (_coord_eventbox, _("Cursor coordinates"));
1075 _coord_status.attach (*new Gtk::VSeparator(), 0,1, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1076 _coord_status.attach (*new Gtk::Label("X:", 0.0, 0.5), 1,2, 0,1, Gtk::FILL,Gtk::FILL, 0,0);
1077 _coord_status.attach (*new Gtk::Label("Y:", 0.0, 0.5), 1,2, 1,2, Gtk::FILL,Gtk::FILL, 0,0);
1078 _coord_status_x.set_text ("0.0");
1079 _coord_status_x.set_alignment (0.0, 0.5);
1080 _coord_status_y.set_text ("0.0");
1081 _coord_status_y.set_alignment (0.0, 0.5);
1082 _coord_status.attach (_coord_status_x, 2,3, 0,1, Gtk::FILL,Gtk::FILL, 0,0);
1083 _coord_status.attach (_coord_status_y, 2,3, 1,2, Gtk::FILL,Gtk::FILL, 0,0);
1084 _coord_status.attach (*new Gtk::Label("Z:", 0.0, 0.5), 3,4, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1085 _coord_status.attach (_zoom_status, 4,5, 0,2, Gtk::FILL,Gtk::FILL, 0,0);
1086 sp_set_font_size_smaller (static_cast<GtkWidget*>((void*)_coord_status.gobj()));
1087 _statusbar.pack_end (_coord_eventbox, false, false, 1);
1089 _select_status.property_xalign() = 0.0;
1090 _select_status.property_yalign() = 0.5;
1091 _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."));
1092 // include this again with Gtk+-2.6
1093 #if GTK_VERSION_GE(2,6)
1094 gtk_label_set_ellipsize (GTK_LABEL(_select_status.gobj()), PANGO_ELLIPSIZE_END);
1095 #endif
1096 _select_status.set_size_request (1, -1);
1097 _statusbar.pack_start (_select_status, true, true, 0);
1099 _main_window_table.attach(_statusbar, 0, 1, 3, 4, Gtk::FILL, Gtk::SHRINK);
1100 }
1102 //========================================
1103 //----------implements EditWidgetInterface
1105 void *
1106 EditWidget::getWindow()
1107 {
1108 return this;
1109 }
1111 void
1112 EditWidget::setTitle (gchar const* new_title)
1113 {
1114 set_title (new_title);
1115 }
1117 void
1118 EditWidget::layout()
1119 {
1120 show_all_children();
1121 }
1123 void
1124 EditWidget::present()
1125 {
1126 this->Gtk::Window::present();
1127 }
1129 void
1130 EditWidget::getGeometry (gint &x, gint &y, gint &w, gint &h)
1131 {
1132 get_position (x, y);
1133 get_size (w, h);
1134 }
1136 void
1137 EditWidget::setSize (gint w, gint h)
1138 {
1139 resize (w, h);
1140 }
1142 void
1143 EditWidget::setPosition (NR::Point p)
1144 {
1145 move (int(p[NR::X]), int(p[NR::Y]));
1146 }
1148 /// \param p is already gobj()!
1149 void
1150 EditWidget::setTransient (void* p, int i)
1151 {
1152 #ifndef WIN32
1153 gtk_window_set_transient_for (static_cast<GtkWindow*>(p), this->gobj());
1154 if (i==2)
1155 this->Gtk::Window::present();
1156 #endif
1157 }
1159 NR::Point
1160 EditWidget::getPointer()
1161 {
1162 int x, y;
1163 get_pointer (x, y);
1164 return NR::Point (x, y);
1165 }
1167 void
1168 EditWidget::setFullscreen()
1169 {
1170 fullscreen();
1171 }
1173 /**
1174 * Shuts down the desktop object for the view being closed. It checks
1175 * to see if the document has been edited, and if so prompts the user
1176 * to save, discard, or cancel. Returns TRUE if the shutdown operation
1177 * is cancelled or if the save is cancelled or fails, FALSE otherwise.
1178 */
1179 bool
1180 EditWidget::shutdown()
1181 {
1182 g_assert (_desktop != NULL);
1183 if (Inkscape::NSApplication::Editor::isDuplicatedView (_desktop))
1184 return false;
1186 SPDocument *doc = _desktop->doc();
1187 if (sp_document_repr_root(doc)->attribute("sodipodi:modified") != NULL)
1188 {
1189 gchar *markup;
1190 /// \todo FIXME !!! obviously this will have problems if the document
1191 /// name contains markup characters
1192 markup = g_strdup_printf(
1193 _("<span weight=\"bold\" size=\"larger\">Save changes to document \"%s\" before closing?</span>\n\n"
1194 "If you close without saving, your changes will be discarded."),
1195 SP_DOCUMENT_NAME(doc));
1197 Gtk::MessageDialog dlg (*this,
1198 markup,
1199 true,
1200 Gtk::MESSAGE_WARNING,
1201 Gtk::BUTTONS_NONE,
1202 true);
1203 g_free(markup);
1204 Gtk::Button close_button (_("Close _without saving"), true);
1205 dlg.add_action_widget (close_button, Gtk::RESPONSE_NO);
1206 close_button.show();
1207 dlg.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1208 dlg.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_YES);
1209 dlg.set_default_response (Gtk::RESPONSE_YES);
1211 int response = dlg.run();
1212 switch (response)
1213 {
1214 case Gtk::RESPONSE_YES:
1215 sp_document_ref(doc);
1216 if (sp_file_save_document(doc)) {
1217 sp_document_unref(doc);
1218 } else { // save dialog cancelled or save failed
1219 sp_document_unref(doc);
1220 return TRUE;
1221 }
1222 break;
1223 case Gtk::RESPONSE_NO:
1224 break;
1225 default: // cancel pressed, or dialog was closed
1226 return TRUE;
1227 break;
1228 }
1229 }
1231 /* Code to check data loss */
1232 bool allow_data_loss = FALSE;
1233 while (sp_document_repr_root(doc)->attribute("inkscape:dataloss") != NULL && allow_data_loss == FALSE)
1234 {
1235 gchar *markup;
1236 /// \todo FIXME !!! obviously this will have problems if the document
1237 /// name contains markup characters
1238 markup = g_strdup_printf(
1239 _("<span weight=\"bold\" size=\"larger\">The file \"%s\" was saved with a format (%s) that may cause data loss!</span>\n\n"
1240 "Do you want to save this file in another format?"),
1241 SP_DOCUMENT_NAME(doc),
1242 Inkscape::Extension::db.get(sp_document_repr_root(doc)->attribute("inkscape:output_extension"))->get_name());
1244 Gtk::MessageDialog dlg (*this,
1245 markup,
1246 true,
1247 Gtk::MESSAGE_WARNING,
1248 Gtk::BUTTONS_NONE,
1249 true);
1250 g_free(markup);
1251 Gtk::Button close_button (_("Close _without saving"), true);
1252 dlg.add_action_widget (close_button, Gtk::RESPONSE_NO);
1253 close_button.show();
1254 dlg.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1255 dlg.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_YES);
1256 dlg.set_default_response (Gtk::RESPONSE_YES);
1258 int response = dlg.run();
1260 switch (response)
1261 {
1262 case Gtk::RESPONSE_YES:
1263 sp_document_ref(doc);
1264 if (sp_file_save_document(doc)) {
1265 sp_document_unref(doc);
1266 } else { // save dialog cancelled or save failed
1267 sp_document_unref(doc);
1268 return TRUE;
1269 }
1270 break;
1271 case Gtk::RESPONSE_NO:
1272 allow_data_loss = TRUE;
1273 break;
1274 default: // cancel pressed, or dialog was closed
1275 return TRUE;
1276 break;
1277 }
1278 }
1280 return false;
1281 }
1284 void
1285 EditWidget::destroy()
1286 {
1287 delete this;
1288 }
1290 void
1291 EditWidget::requestCanvasUpdate()
1292 {
1293 _svg_canvas.widget().queue_draw();
1294 }
1296 void
1297 EditWidget::requestCanvasUpdateAndWait()
1298 {
1299 requestCanvasUpdate();
1301 while (gtk_events_pending())
1302 gtk_main_iteration_do(FALSE);
1303 }
1305 void
1306 EditWidget::activateDesktop()
1307 {
1308 /// \todo active_desktop_indicator not implemented
1309 }
1311 void
1312 EditWidget::deactivateDesktop()
1313 {
1314 /// \todo active_desktop_indicator not implemented
1315 }
1317 void
1318 EditWidget::viewSetPosition (NR::Point p)
1319 {
1320 p -= _namedview->gridorigin;
1321 double lo, up, pos, max;
1322 _top_ruler.get_range (lo, up, pos, max);
1323 _top_ruler.set_range (lo, up, p[NR::X], max);
1324 _left_ruler.get_range (lo, up, pos, max);
1325 _left_ruler.set_range (lo, up, p[NR::Y], max);
1326 }
1328 void
1329 EditWidget::updateRulers()
1330 {
1331 NR::Point origin = _namedview->gridorigin;
1333 NR::Rect const viewbox = _svg_canvas.spobj()->getViewbox();
1334 double lo, up, pos, max;
1335 double const scale = _desktop->current_zoom();
1336 double s = viewbox.min()[NR::X] / scale - origin[NR::X];
1337 double e = viewbox.max()[NR::X] / scale - origin[NR::X];
1338 _top_ruler.get_range(lo, up, pos, max);
1339 _top_ruler.set_range(s, e, pos, e);
1340 s = viewbox.min()[NR::Y] / -scale - origin[NR::Y];
1341 e = viewbox.max()[NR::Y] / -scale - origin[NR::Y];
1342 _left_ruler.set_range(s, e, origin[NR::Y], e);
1343 /// \todo is that correct?
1344 }
1346 void
1347 EditWidget::updateScrollbars (double scale)
1348 {
1349 // do not call this function before canvas has its size allocated
1350 if (!is_realized() || _update_s_f) {
1351 return;
1352 }
1354 _update_s_f = true;
1356 /* The desktop region we always show unconditionally */
1357 SPDocument *doc = _desktop->doc();
1358 NR::Rect const r = sp_item_bbox_desktop(SP_ITEM(SP_DOCUMENT_ROOT(doc)));
1359 NR::Rect darea(NR::Point(MIN(r.min()[NR::X], -sp_document_width(doc)),
1360 MIN(r.min()[NR::Y], -sp_document_height(doc))),
1361 NR::Point(MAX(r.max()[NR::X], 2 * sp_document_width(doc)),
1362 MAX(r.max()[NR::Y], 2 * sp_document_height(doc))));
1364 /* Canvas region we always show unconditionally */
1365 NR::Rect carea(NR::Point(darea.min()[NR::X] * scale - 64,
1366 darea.max()[NR::Y] * -scale - 64),
1367 NR::Point(darea.max()[NR::X] * scale + 64,
1368 darea.min()[NR::Y] * -scale + 64));
1370 NR::Rect const viewbox = _svg_canvas.spobj()->getViewbox();
1372 /* Viewbox is always included into scrollable region */
1373 carea = NR::Rect::union_bounds(carea, viewbox);
1375 Gtk::Adjustment *adj = _bottom_scrollbar.get_adjustment();
1376 adj->set_value(viewbox.min()[NR::X]);
1377 adj->set_lower(carea.min()[NR::X]);
1378 adj->set_upper(carea.max()[NR::X]);
1379 adj->set_page_increment(viewbox.dimensions()[NR::X]);
1380 adj->set_step_increment(0.1 * (viewbox.dimensions()[NR::X]));
1381 adj->set_page_size(viewbox.dimensions()[NR::X]);
1383 adj = _right_scrollbar.get_adjustment();
1384 adj->set_value(viewbox.min()[NR::Y]);
1385 adj->set_lower(carea.min()[NR::Y]);
1386 adj->set_upper(carea.max()[NR::Y]);
1387 adj->set_page_increment(viewbox.dimensions()[NR::Y]);
1388 adj->set_step_increment(0.1 * viewbox.dimensions()[NR::Y]);
1389 adj->set_page_size(viewbox.dimensions()[NR::Y]);
1391 _update_s_f = false;
1392 }
1394 void
1395 EditWidget::toggleRulers()
1396 {
1397 if (_top_ruler.is_visible())
1398 {
1399 _top_ruler.hide_all();
1400 _left_ruler.hide_all();
1401 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.rulers" : "window.rulers", "state", 0);
1402 } else {
1403 _top_ruler.show_all();
1404 _left_ruler.show_all();
1405 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.rulers" : "window.rulers", "state", 1);
1406 }
1407 }
1409 void
1410 EditWidget::toggleScrollbars()
1411 {
1412 if (_bottom_scrollbar.is_visible())
1413 {
1414 _bottom_scrollbar.hide_all();
1415 _right_scrollbar.hide_all();
1416 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.scrollbars" : "window.scrollbars", "state", 0);
1417 } else {
1418 _bottom_scrollbar.show_all();
1419 _right_scrollbar.show_all();
1420 prefs_set_int_attribute (_desktop->is_fullscreen ? "fullscreen.scrollbars" : "window.scrollbars", "state", 1);
1421 }
1422 }
1424 void
1425 EditWidget::updateZoom()
1426 {
1427 _zoom_status.update();
1428 }
1430 void
1431 EditWidget::letZoomGrabFocus()
1432 {
1433 _zoom_status.grab_focus();
1434 }
1436 void
1437 EditWidget::setToolboxFocusTo (const gchar *)
1438 {
1439 /// \todo not implemented
1440 }
1442 void
1443 EditWidget::setToolboxAdjustmentValue (const gchar *, double)
1444 {
1445 /// \todo not implemented
1446 }
1448 bool
1449 EditWidget::isToolboxButtonActive (gchar const*)
1450 {
1451 /// \todo not implemented
1452 return true;
1453 }
1455 void
1456 EditWidget::setCoordinateStatus (NR::Point p)
1457 {
1458 gchar *cstr = g_strdup_printf ("%6.2f", _dt2r * p[NR::X]);
1459 _coord_status_x.property_label() = cstr;
1460 g_free (cstr);
1461 cstr = g_strdup_printf ("%6.2f", _dt2r * p[NR::Y]);
1462 _coord_status_y.property_label() = cstr;
1463 g_free (cstr);
1464 }
1466 void
1467 EditWidget::setMessage (Inkscape::MessageType type, gchar const* msg)
1468 {
1469 _select_status.set_markup (msg? msg : "");
1470 }
1472 bool
1473 EditWidget::warnDialog (gchar* msg)
1474 {
1475 Gtk::MessageDialog dlg (*this,
1476 msg,
1477 true,
1478 Gtk::MESSAGE_WARNING,
1479 Gtk::BUTTONS_YES_NO,
1480 true);
1481 int r = dlg.run();
1482 return r == Gtk::RESPONSE_YES;
1483 }
1486 void EditWidget::_namedview_modified (SPObject *obj, guint flags) {
1487 SPNamedView *nv = static_cast<SPNamedView *>(obj);
1488 if (flags & SP_OBJECT_MODIFIED_FLAG) {
1489 this->_dt2r = 1.0 / nv->doc_units->unittobase;
1490 this->_top_ruler.update_metric();
1491 this->_left_ruler.update_metric();
1492 this->_tooltips.set_tip(this->_top_ruler, this->_top_ruler.get_tip());
1493 this->_tooltips.set_tip(this->_left_ruler, this->_left_ruler.get_tip());
1494 this->updateRulers();
1495 }
1496 }
1498 void
1499 EditWidget::initEdit (SPDocument *doc)
1500 {
1501 _desktop = new SPDesktop();
1502 _desktop->registerEditWidget (this);
1504 _namedview = sp_document_namedview (doc, 0);
1505 _svg_canvas.init (_desktop);
1506 _desktop->init (_namedview, _svg_canvas.spobj());
1507 sp_namedview_window_from_document (_desktop);
1508 _dt2r = 1.0 / _namedview->doc_units->unittobase;
1510 /// \todo convert to sigc++ when SPObject hierarchy gets converted
1511 /* Listen on namedview modification */
1512 _namedview_modified_connection = _desktop->namedview->connectModified(sigc::mem_fun(*this, &EditWidget::_namedview_modified));
1513 _layer_selector.setDesktop (_desktop);
1514 _selected_style_status.setDesktop (_desktop);
1516 Inkscape::NSApplication::Editor::addDesktop (_desktop);
1518 _zoom_status.init (_desktop);
1519 _top_ruler.init (_desktop, _svg_canvas.widget());
1520 _left_ruler.init (_desktop, _svg_canvas.widget());
1521 updateRulers();
1522 }
1524 void
1525 EditWidget::destroyEdit()
1526 {
1527 if (_desktop) {
1528 _layer_selector.unreference();
1529 Inkscape::NSApplication::Editor::removeDesktop (_desktop); // clears selection too
1530 _namedview_modified_connection.disconnect();
1531 _desktop->destroy();
1532 Inkscape::GC::release (_desktop);
1533 _desktop = 0;
1534 }
1535 }
1537 //----------end of EditWidgetInterface implementation
1539 //----------start of other callbacks
1541 bool
1542 EditWidget::on_key_press_event (GdkEventKey* event)
1543 {
1544 // this is the original code from helper/window.cpp
1546 unsigned int shortcut;
1547 shortcut = get_group0_keyval (event) |
1548 ( event->state & GDK_SHIFT_MASK ?
1549 SP_SHORTCUT_SHIFT_MASK : 0 ) |
1550 ( event->state & GDK_CONTROL_MASK ?
1551 SP_SHORTCUT_CONTROL_MASK : 0 ) |
1552 ( event->state & GDK_MOD1_MASK ?
1553 SP_SHORTCUT_ALT_MASK : 0 );
1554 return sp_shortcut_invoke (shortcut,
1555 Inkscape::NSApplication::Editor::getActiveDesktop());
1556 }
1558 bool
1559 EditWidget::on_delete_event (GdkEventAny*)
1560 {
1561 return shutdown();
1562 }
1564 bool
1565 EditWidget::on_focus_in_event (GdkEventFocus*)
1566 {
1567 Inkscape::NSApplication::Editor::activateDesktop (_desktop);
1568 _svg_canvas.widget().grab_focus();
1570 return false;
1571 }
1573 void
1574 EditWidget::onWindowSizeAllocate (Gtk::Allocation &newall)
1575 {
1576 if (!is_realized()) return;
1578 const Gtk::Allocation& all = get_allocation();
1579 if ((newall.get_x() == all.get_x()) &&
1580 (newall.get_y() == all.get_y()) &&
1581 (newall.get_width() == all.get_width()) &&
1582 (newall.get_height() == all.get_height())) {
1583 return;
1584 }
1586 NR::Rect const area = _desktop->get_display_area();
1587 double zoom = _desktop->current_zoom();
1589 if (_sticky_zoom.get_active()) {
1590 /* Calculate zoom per pixel */
1591 double const zpsp = zoom / hypot(area.dimensions()[NR::X], area.dimensions()[NR::Y]);
1592 /* Find new visible area */
1593 NR::Rect const newarea = _desktop->get_display_area();
1594 /* Calculate adjusted zoom */
1595 zoom = zpsp * hypot(newarea.dimensions()[NR::X], newarea.dimensions()[NR::Y]);
1596 }
1598 _desktop->zoom_absolute(area.midpoint()[NR::X], area.midpoint()[NR::Y], zoom);
1599 }
1601 void
1602 EditWidget::onWindowRealize()
1603 {
1604 NR::Rect d(NR::Point(0, 0),
1605 NR::Point(sp_document_width(_desktop->doc()), sp_document_height(_desktop->doc())));
1607 if (fabs(d.dimensions()[NR::X]) < 1.0 || fabs(d.dimensions()[NR::Y]) < 1.0) {
1608 return;
1609 }
1611 _desktop->set_display_area(d.min()[NR::X], d.min()[NR::Y], d.max()[NR::X], d.max()[NR::Y], 10);
1612 _namedview_modified(_desktop->namedview, SP_OBJECT_MODIFIED_FLAG);
1613 setTitle (SP_DOCUMENT_NAME(_desktop->doc()));
1614 }
1616 void
1617 EditWidget::onAdjValueChanged()
1618 {
1619 if (_update_a_f) return;
1620 _update_a_f = true;
1622 sp_canvas_scroll_to (_svg_canvas.spobj(),
1623 _bottom_scrollbar.get_value(),
1624 _right_scrollbar.get_value(),
1625 false);
1626 updateRulers();
1628 _update_a_f = false;
1629 }
1632 } // namespace View
1633 } // namespace UI
1634 } // namespace Inkscape
1636 /*
1637 Local Variables:
1638 mode:c++
1639 c-file-style:"stroustrup"
1640 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1641 indent-tabs-mode:nil
1642 fill-column:99
1643 End:
1644 */
1645 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :