diff --git a/src/desktop.cpp b/src/desktop.cpp
index 17ce0907c67e3c6ffc8b9d8cb761737f74248885..4b4d1fe5bcf8358b803cd97e41a2b8b670b26e16 100644 (file)
--- a/src/desktop.cpp
+++ b/src/desktop.cpp
* MenTaLguY <mental@rydia.net>
* bulia byak <buliabyak@users.sf.net>
* Ralf Stephan <ralf@ark.in-berlin.de>
+ * John Bintz <jcoswell@coswellproductions.org>
+ * Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
*
+ * Copyright (C) 2007 Jon A. Cruz
+ * Copyright (C) 2006-2007 Johan Engelen
+ * Copyright (C) 2006 John Bintz
* Copyright (C) 2004 MenTaLguY
* Copyright (C) 1999-2002 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
#endif
#include <glibmm/i18n.h>
+#include <sigc++/functors/mem_fun.h>
+#include <gtkmm.h>
#include "macros.h"
#include "inkscape-private.h"
#include "xml/repr.h"
#include "message-context.h"
#include "layer-manager.h"
+#include "event-log.h"
+#include "display/canvas-grid.h"
-#ifdef WITH_INKBOARD
-#include "jabber_whiteboard/session-manager.h"
-#endif
+#include "display/sp-canvas.h"
namespace Inkscape { namespace XML { class Node; }}
static void _layer_hierarchy_changed(SPObject *top, SPObject *bottom, SPDesktop *desktop);
static void _reconstruction_start(SPDesktop * desktop);
static void _reconstruction_finish(SPDesktop * desktop);
-static void _namedview_modified (SPNamedView *nv, guint flags, SPDesktop *desktop);
+static void _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop);
static void _update_snap_distances (SPDesktop *desktop);
/**
* \pre namedview != NULL.
* \pre canvas != NULL.
*/
-SPDesktop::SPDesktop()
-{
- _dlg_mgr = NULL;
- _widget = 0;
- namedview = NULL;
- selection = NULL;
- acetate = NULL;
- main = NULL;
- grid = NULL;
- guides = NULL;
- drawing = NULL;
- sketch = NULL;
- controls = NULL;
- event_context = 0;
- layer_manager = 0;
-
+SPDesktop::SPDesktop() :
+ _dlg_mgr( 0 ),
+ namedview( 0 ),
+ canvas( 0 ),
+ selection( 0 ),
+ event_context( 0 ),
+ layer_manager( 0 ),
+ event_log( 0 ),
+ acetate( 0 ),
+ main( 0 ),
+ gridgroup( 0 ),
+ guides( 0 ),
+ drawing( 0 ),
+ sketch( 0 ),
+ controls( 0 ),
+ table( 0 ),
+ page( 0 ),
+ page_border( 0 ),
+ current( 0 ),
+ zooms_past( 0 ),
+ zooms_future( 0 ),
+ dkey( 0 ),
+ number( 0 ),
+ window_state(0),
+ interaction_disabled_counter( 0 ),
+ waiting_cursor( false ),
+ guides_active( false ),
+ gr_item( 0 ),
+ gr_point_type( 0 ),
+ gr_point_i( 0 ),
+ gr_fill_or_stroke( true ),
+ _layer_hierarchy( 0 ),
+ _reconstruction_old_layer_id( 0 ),
+ _widget( 0 ),
+ _inkscape( 0 ),
+ _guides_message_context( 0 ),
+ _active( false ),
+ _w2d(),
+ _d2w(),
+ _doc2dt( NR::Matrix(NR::scale(1, -1)) ),
+ grids_visible( true )
+{
_d2w.set_identity();
_w2d.set_identity();
- _doc2dt = NR::Matrix(NR::scale(1, -1));
-
- guides_active = false;
-
- zooms_past = NULL;
- zooms_future = NULL;
-
- is_fullscreen = false;
-
- gr_item = NULL;
- gr_point_num = 0;
- gr_fill_or_stroke = true;
-
- _layer_hierarchy = NULL;
- _active = false;
- selection = Inkscape::GC::release (new Inkscape::Selection (this));
+ selection = Inkscape::GC::release( new Inkscape::Selection(this) );
}
void
SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
-
{
_guides_message_context = new Inkscape::MessageContext(const_cast<Inkscape::MessageStack*>(messageStack()));
SP_CANVAS_ARENA (drawing)->arena->delta = prefs_get_double_attribute ("options.cursortolerance", "value", 1.0); // default is 1 px
- // Start always in normal mode
- SP_CANVAS_ARENA (drawing)->arena->rendermode = RENDERMODE_NORMAL;
- canvas->rendermode = RENDERMODE_NORMAL; // canvas needs that for choosing the best buffer size
+ if (prefs_get_int_attribute("options.startmode", "outline", 0)) {
+ // Start in outline mode
+ setDisplayModeOutline();
+ } else {
+ // Start in normal mode, default
+ setDisplayModeNormal();
+ }
- grid = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
+ gridgroup = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
guides = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
sketch = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
controls = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
_doc2dt[5] = sp_document_height (document);
sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (drawing), _doc2dt);
- g_signal_connect (G_OBJECT (namedview), "modified", G_CALLBACK (_namedview_modified), this);
-
+ _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this));
NRArenaItem *ai = sp_item_invoke_show (SP_ITEM (sp_document_root (document)),
SP_CANVAS_ARENA (drawing)->arena,
/* Ugly hack */
_namedview_modified (namedview, SP_OBJECT_MODIFIED_FLAG, this);
- /* Construct SessionManager
- *
- * SessionManager construction needs to be done after document connection
- */
-#ifdef WITH_INKBOARD
- _whiteboard_session_manager = new Inkscape::Whiteboard::SessionManager(this);
-#endif
-
/* Set up notification of rebuilding the document, this allows
for saving object related settings in the document. */
_reconstruction_start_connection =
/* setup LayerManager */
// (Setting up after the connections are all in place, as it may use some of them)
layer_manager = new Inkscape::LayerManager( this );
+
+ grids_visible = true;
}
_deactivate_connection.disconnect();
_sel_modified_connection.disconnect();
_sel_changed_connection.disconnect();
+ _modified_connection.disconnect();
+ _commit_connection.disconnect();
+ _reconstruction_start_connection.disconnect();
+ _reconstruction_finish_connection.disconnect();
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT (acetate), (gpointer) G_CALLBACK(sp_desktop_root_handler), this);
+ g_signal_handlers_disconnect_by_func(G_OBJECT (main), (gpointer) G_CALLBACK(sp_desktop_root_handler), this);
+ g_signal_handlers_disconnect_by_func(G_OBJECT (drawing), (gpointer) G_CALLBACK(_arena_handler), this);
while (event_context) {
SPEventContext *ec = event_context;
drawing = NULL;
}
-#ifdef WITH_INKBOARD
- if (_whiteboard_session_manager) {
- delete _whiteboard_session_manager;
- }
-#endif
-
delete _guides_message_context;
_guides_message_context = NULL;
- sp_signal_disconnect_by_data (G_OBJECT (namedview), this);
-
g_list_free (zooms_past);
g_list_free (zooms_future);
}
{
SP_CANVAS_ARENA (drawing)->arena->rendermode = RENDERMODE_NORMAL;
canvas->rendermode = RENDERMODE_NORMAL; // canvas needs that for choosing the best buffer size
+ displayMode = RENDERMODE_NORMAL;
sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw
+ _widget->setTitle(SP_DOCUMENT_NAME(sp_desktop_document(this)));
}
void SPDesktop::setDisplayModeOutline()
{
SP_CANVAS_ARENA (drawing)->arena->rendermode = RENDERMODE_OUTLINE;
canvas->rendermode = RENDERMODE_OUTLINE; // canvas needs that for choosing the best buffer size
+ displayMode = RENDERMODE_OUTLINE;
sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw
+ _widget->setTitle(SP_DOCUMENT_NAME(sp_desktop_document(this)));
+}
+
+void SPDesktop::displayModeToggle()
+{
+ if (displayMode == RENDERMODE_OUTLINE)
+ setDisplayModeNormal();
+ else
+ setDisplayModeOutline();
}
/**
}
/**
+ * Sets the current layer of the desktop.
+ *
* Make \a object the top layer.
*/
void SPDesktop::setCurrentLayer(SPObject *object) {
bool SPDesktop::isWithinViewport (SPItem *item) const
{
NR::Rect const viewport = get_display_area();
- NR::Rect const bbox = sp_item_bbox_desktop(item);
- return viewport.contains(bbox);
+ NR::Maybe<NR::Rect> const bbox = sp_item_bbox_desktop(item);
+ if (bbox) {
+ return viewport.contains(*bbox);
+ } else {
+ return true;
+ }
}
///
@@ -516,12 +548,17 @@ SPDesktop::push_event_context (GtkType type, const gchar *config, unsigned int k
_event_context_changed_signal.emit (this, ec);
}
+/**
+ * Sets the coordinate status to a given point
+ */
void
SPDesktop::set_coordinate_status (NR::Point p) {
_widget->setCoordinateStatus(p);
}
-
+/**
+ * \see sp_document_item_from_list_at_point_bottom()
+ */
SPItem *
SPDesktop::item_from_list_at_point_bottom (const GSList *list, NR::Point const p) const
{
@@ -529,6 +566,9 @@ SPDesktop::item_from_list_at_point_bottom (const GSList *list, NR::Point const p
return sp_document_item_from_list_at_point_bottom (dkey, SP_GROUP (doc()->root), list, p);
}
+/**
+ * \see sp_document_item_at_point()
+ */
SPItem *
SPDesktop::item_at_point (NR::Point const p, bool into_groups, SPItem *upto) const
{
@@ -536,6 +576,9 @@ SPDesktop::item_at_point (NR::Point const p, bool into_groups, SPItem *upto) con
return sp_document_item_at_point (doc(), dkey, p, into_groups, upto);
}
+/**
+ * \see sp_document_group_at_point()
+ */
SPItem *
SPDesktop::group_at_point (NR::Point const p) const
{
NR::Rect d(NR::Point(0, 0),
NR::Point(sp_document_width(doc()), sp_document_height(doc())));
- if (d.dimensions()[NR::X] < 1.0 || d.dimensions()[NR::Y] < 1.0) {
+ if (d.isEmpty(1.0)) {
return;
}
void
SPDesktop::zoom_selection()
{
- NR::Rect const d = selection->bounds();
+ NR::Maybe<NR::Rect> const d = selection->bounds();
- if (d.dimensions()[NR::X] < 0.1 || d.dimensions()[NR::Y] < 0.1) {
+ if ( !d || d->isEmpty(0.1) ) {
return;
}
- set_display_area(d, 10);
+ set_display_area(*d, 10);
}
/**
SPItem *docitem = SP_ITEM (sp_document_root (doc()));
g_return_if_fail (docitem != NULL);
- NR::Rect d = sp_item_bbox_desktop(docitem);
+ NR::Maybe<NR::Rect> d = sp_item_bbox_desktop(docitem);
/* Note that the second condition here indicates that
** there are no items in the drawing.
*/
- if ( d.dimensions()[NR::X] < 1.0 || d.dimensions()[NR::Y] < 1.0 ) {
+ if ( !d || d->isEmpty(1.0) ) {
return;
}
- set_display_area(d, 10);
+ set_display_area(*d, 10);
}
/**
* Scroll canvas by specific coordinate amount.
*/
void
-SPDesktop::scroll_world (double dx, double dy)
+SPDesktop::scroll_world (double dx, double dy, bool is_scrolling)
{
g_assert(_widget);
NR::Rect const viewbox = canvas->getViewbox();
- sp_canvas_scroll_to(canvas, viewbox.min()[NR::X] - dx, viewbox.min()[NR::Y] - dy, FALSE);
+ sp_canvas_scroll_to(canvas, viewbox.min()[NR::X] - dx, viewbox.min()[NR::Y] - dy, FALSE, is_scrolling);
_widget->updateRulers();
_widget->updateScrollbars(expansion(_d2w));
return false;
}
+bool
+SPDesktop::is_iconified()
+{
+ return 0!=(window_state & GDK_WINDOW_STATE_ICONIFIED);
+}
+
+void
+SPDesktop::iconify()
+{
+ _widget->setIconified();
+}
+
+bool
+SPDesktop::is_maximized()
+{
+ return 0!=(window_state & GDK_WINDOW_STATE_MAXIMIZED);
+}
+
+void
+SPDesktop::maximize()
+{
+ _widget->setMaximized();
+}
+
+bool
+SPDesktop::is_fullscreen()
+{
+ return 0!=(window_state & GDK_WINDOW_STATE_FULLSCREEN);
+}
+
void
SPDesktop::fullscreen()
{
_widget->setTransient (p, transient_policy);
}
+Gtk::Window*
+SPDesktop::getToplevel( )
+{
+ return _widget->getWindow();
+}
+
void
SPDesktop::presentWindow()
{
return _widget->shutdown();
}
+bool SPDesktop::onDeleteUI (GdkEventAny*)
+{
+ if(shutdown()) return true;
+ destroyWidget();
+ return false;
+}
+
+/**
+ * onWindowStateEvent
+ *
+ * Called when the window changes its maximize/fullscreen/iconify/pinned state.
+ * Since GTK doesn't have a way to query this state information directly, we
+ * record it for the desktop here, and also possibly trigger a layout.
+ */
+bool
+SPDesktop::onWindowStateEvent (GdkEventWindowState* event)
+{
+ // Record the desktop window's state
+ window_state = event->new_window_state;
+
+ // Layout may differ depending on full-screen mode or not
+ GdkWindowState changed = event->changed_mask;
+ if (changed & (GDK_WINDOW_STATE_FULLSCREEN|GDK_WINDOW_STATE_MAXIMIZED)) {
+ layoutWidget();
+ }
+
+ return false;
+}
+
void
SPDesktop::setToolboxFocusTo (gchar const *label)
{
_widget->setToolboxAdjustmentValue (id, val);
}
+void
+SPDesktop::setToolboxSelectOneValue (gchar const* id, gint val)
+{
+ _widget->setToolboxSelectOneValue (id, val);
+}
+
bool
SPDesktop::isToolboxButtonActive (gchar const *id)
{
inkscape_subselection_changed (this);
}
+void
+SPDesktop::updateNow()
+{
+ sp_canvas_update_now(canvas);
+}
+
+void
+SPDesktop::enableInteraction()
+{
+ _widget->enableInteraction();
+}
+
+void SPDesktop::disableInteraction()
+{
+ _widget->disableInteraction();
+}
+
+void SPDesktop::setWaitingCursor()
+{
+ GdkCursor *waiting = gdk_cursor_new(GDK_WATCH);
+ gdk_window_set_cursor(GTK_WIDGET(sp_desktop_canvas(this))->window, waiting);
+ gdk_cursor_unref(waiting);
+ waiting_cursor = true;
+
+ // Stupidly broken GDK cannot just set the new cursor right now - it needs some main loop iterations for that
+ // Since setting waiting_cursor is usually immediately followed by some Real Work, we must run the iterations here
+ // CAUTION: iterations may redraw, and redraw may be interrupted, so you cannot assume that anything is the same
+ // after the call to setWaitingCursor as it was before
+ while( Gtk::Main::events_pending() )
+ Gtk::Main::iteration();
+}
+
+void SPDesktop::clearWaitingCursor()
+{
+ if (waiting_cursor)
+ sp_event_context_update_cursor(sp_desktop_event_context(this));
+}
+
+void SPDesktop::toggleGrid()
+{
+ if (namedview->grids) {
+ if(gridgroup) {
+ grids_visible = !grids_visible;
+ if (grids_visible) {
+ sp_canvas_item_show(SP_CANVAS_ITEM(gridgroup));
+ } else {
+ sp_canvas_item_hide(SP_CANVAS_ITEM(gridgroup));
+ }
+ }
+ } else {
+ //there is no grid present at the moment. add a rectangular grid and make it visible
+ Inkscape::XML::Node *repr = SP_OBJECT_REPR(namedview);
+ Inkscape::CanvasGrid::writeNewGridToRepr(repr, sp_desktop_document(this), Inkscape::GRID_RECTANGULAR);
+ grids_visible = true;
+ sp_canvas_item_show(SP_CANVAS_ITEM(gridgroup));
+ }
+}
+
+
//----------------------------------------------------------------------
// Callback implementations. The virtual ones are connected by the view.
}
}
+void
+SPDesktop::updateCanvasNow()
+{
+ _widget->requestCanvasUpdateAndWait();
+}
+
/**
* Associate document with desktop.
*/
_layer_hierarchy->connectChanged(sigc::bind(sigc::ptr_fun(_layer_hierarchy_changed), this));
_layer_hierarchy->setTop(SP_DOCUMENT_ROOT(doc));
+ /* setup EventLog */
+ event_log = new Inkscape::EventLog(doc);
+ doc->addUndoObserver(*event_log);
+
+ _commit_connection.disconnect();
+ _commit_connection = doc->connectCommit(sigc::mem_fun(*this, &SPDesktop::updateNow));
+
/// \todo fixme: This condition exists to make sure the code
- /// inside is called only once on initialization. But there
+ /// inside is NOT called on initialization, only on replacement. But there
/// are surely more safe methods to accomplish this.
+ // TODO since the comment had reversed logic, check the intent of this block of code:
if (drawing) {
- NRArenaItem *ai;
+ NRArenaItem *ai = 0;
namedview = sp_document_namedview (doc, NULL);
- g_signal_connect (G_OBJECT (namedview), "modified", G_CALLBACK (_namedview_modified), this);
+ _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this));
number = namedview->getViewCount();
ai = sp_item_invoke_show (SP_ITEM (sp_document_root (doc)),
* Namedview_modified callback.
*/
static void
-_namedview_modified (SPNamedView *nv, guint flags, SPDesktop *desktop)
+_namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop)
{
+ SPNamedView *nv=SP_NAMEDVIEW(obj);
+
if (flags & SP_OBJECT_MODIFIED_FLAG) {
/* Recalculate snap distances */
SP_RGBA32_G_U(nv->pagecolor) +
SP_RGBA32_B_U(nv->pagecolor)) >= 384) {
// the background color is light or transparent, use black outline
- SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = 0xff;
+ SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "onlight", 0xff);
} else { // use white outline
- SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = 0xffffffff;
+ SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "ondark", 0xffffffff);
}
}
}
SPNamedView &nv = *desktop->namedview;
- nv.snap_manager.grid.setDistance(sp_convert_distance_full(nv.gridtolerance,
+ //tell all grid snappers
+ for ( GSList const *l = nv.grids; l != NULL; l = l->next) {
+ Inkscape::CanvasGrid *grid = (Inkscape::CanvasGrid*) l->data;
+ grid->snapper->setDistance(sp_convert_distance_full(nv.gridtolerance,
*nv.gridtoleranceunit,
px));
+ }
+
nv.snap_manager.guide.setDistance(sp_convert_distance_full(nv.guidetolerance,
*nv.guidetoleranceunit,
px));