Code

Filter effects dialog:
[inkscape.git] / src / interface.cpp
index bf9b481ee2174d94987f826d7b828f7b7e557821..ea08f170c65b0cf4c14a69e53a6f3231faf0f927 100644 (file)
@@ -69,6 +69,8 @@ using Inkscape::IO::Base64OutputStream;
 
 /* forward declaration */
 static gint sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view);
+static void sp_ui_state_event(GtkWidget *widget, GdkEventWindowState *event, SPDesktop*desktop);
+
 
 /* Drag and Drop */
 typedef enum {
@@ -125,32 +127,82 @@ SPActionEventVector menu_item_event_vector = {
     sp_ui_menu_item_set_name /* set_name */
 };
 
+static const int MIN_ONSCREEN_DISTANCE = 50;
+
 void
 sp_create_window(SPViewWidget *vw, gboolean editable)
 {
     g_return_if_fail(vw != NULL);
     g_return_if_fail(SP_IS_VIEW_WIDGET(vw));
 
-    GtkWidget *w = sp_window_new("", TRUE);
+    GtkWidget *win = sp_window_new("", TRUE);
 
     if (editable) {
-      g_object_set_data(G_OBJECT(vw), "window", w);
+      g_object_set_data(G_OBJECT(vw), "window", win);
       reinterpret_cast<SPDesktopWidget*>(vw)->window =
-        static_cast<GtkWindow*>((void*)w);
+        static_cast<GtkWindow*>((void*)win);
     }
 
     if (editable) {
-        /* fixme: */
-        gtk_window_set_default_size((GtkWindow *) w, 640, 480);
-        g_object_set_data(G_OBJECT(w), "desktop", SP_DESKTOP_WIDGET(vw)->desktop);
-        g_object_set_data(G_OBJECT(w), "desktopwidget", vw);
-        g_signal_connect(G_OBJECT(w), "delete_event", G_CALLBACK(sp_ui_delete), vw->view);
-        g_signal_connect(G_OBJECT(w), "focus_in_event", G_CALLBACK(sp_desktop_widget_set_focus), vw);
+        SPDesktop* desktop = SP_DESKTOP_WIDGET(vw)->desktop;
+
+        /* fixme: doesn't allow making window any smaller than this */
+        gtk_window_set_default_size((GtkWindow *) win, 640, 480);
+        g_object_set_data(G_OBJECT(win), "desktop", desktop);
+        g_object_set_data(G_OBJECT(win), "desktopwidget", vw);
+        g_signal_connect(G_OBJECT(win), "delete_event", G_CALLBACK(sp_ui_delete), vw->view);
+
+        g_signal_connect(G_OBJECT(win), "window_state_event", G_CALLBACK(sp_ui_state_event), static_cast<SPDesktop*>(vw->view));
+        g_signal_connect(G_OBJECT(win), "focus_in_event", G_CALLBACK(sp_desktop_widget_set_focus), vw);
+
+        gint prefs_geometry = 
+            (2==prefs_get_int_attribute("options.savewindowgeometry", "value", 0));
+        if (prefs_geometry) {
+            gint pw = prefs_get_int_attribute("desktop.geometry", "width", -1);
+            gint ph = prefs_get_int_attribute("desktop.geometry", "height", -1);
+            gint px = prefs_get_int_attribute("desktop.geometry", "x", -1);
+            gint py = prefs_get_int_attribute("desktop.geometry", "y", -1);
+            gint full = prefs_get_int_attribute("desktop.geometry", "fullscreen", 0);
+            gint maxed = prefs_get_int_attribute("desktop.geometry", "maximized", 0);
+            if (pw>0 && ph>0) {
+                gint w = MIN(gdk_screen_width(), pw);
+                gint h = MIN(gdk_screen_height(), ph);
+                gint x = MIN(gdk_screen_width() - MIN_ONSCREEN_DISTANCE, px);
+                gint y = MIN(gdk_screen_height() - MIN_ONSCREEN_DISTANCE, py);
+                if (w>0 && h>0 && x>0 && y>0) {
+                    x = MIN(gdk_screen_width() - w, x);
+                    y = MIN(gdk_screen_height() - h, y);
+                }
+                if (w>0 && h>0) {
+                    desktop->setWindowSize(w, h);
+                }
+
+                // Only restore xy for the first window so subsequent windows don't overlap exactly
+                // with first.  (Maybe rule should be only restore xy if it's different from xy of
+                // other desktops?)
+
+                // Empirically it seems that active_desktop==this desktop only the first time a
+                // desktop is created.
+                if (x>0 && y>0) {
+                    SPDesktop *active_desktop = SP_ACTIVE_DESKTOP;
+                    if (active_desktop == desktop || active_desktop==NULL) {
+                        desktop->setWindowPosition(NR::Point(x, y));
+                    }
+                }
+            }
+            if (maxed) {
+                gtk_window_maximize(GTK_WINDOW(win));
+            }
+            if (full) {
+                gtk_window_fullscreen(GTK_WINDOW(win));
+            }
+        }
+
     } else {
-        gtk_window_set_policy(GTK_WINDOW(w), TRUE, TRUE, TRUE);
+        gtk_window_set_policy(GTK_WINDOW(win), TRUE, TRUE, TRUE);
     }
 
-    gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(vw));
+    gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(vw));
     gtk_widget_show(GTK_WIDGET(vw));
 
     if ( completeDropTargets == 0 || completeDropTargetsCount == 0 )
@@ -184,16 +236,16 @@ sp_create_window(SPViewWidget *vw, gboolean editable)
         }
     }
 
-    gtk_drag_dest_set(w,
+    gtk_drag_dest_set(win,
                       GTK_DEST_DEFAULT_ALL,
                       completeDropTargets,
                       completeDropTargetsCount,
                       GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE));
-    g_signal_connect(G_OBJECT(w),
+    g_signal_connect(G_OBJECT(win),
                      "drag_data_received",
                      G_CALLBACK(sp_ui_drag_data_received),
                      NULL);
-    gtk_widget_show(w);
+    gtk_widget_show(win);
 
     // needed because the first ACTIVATE_DESKTOP was sent when there was no window yet
     inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop);
@@ -283,6 +335,53 @@ sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view)
     return view->shutdown();
 }
 
+/**
+ *  sp_ui_state_event
+ *
+ *  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.
+ */
+static void
+sp_ui_state_event(GtkWidget *widget, GdkEventWindowState *event, SPDesktop* desktop)
+{
+    // Record the desktop window's state
+    desktop->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)) {
+        desktop->layoutWidget();
+    }
+/*
+    // debug info
+    g_message("State event desktop=0x%p", desktop);
+    GdkWindowState state = event->new_window_state;
+    GdkWindowState changed = event->changed_mask;
+    if (changed & GDK_WINDOW_STATE_WITHDRAWN) {
+        g_message("-- WIDTHDRAWN = %d", 0!=(state&GDK_WINDOW_STATE_WITHDRAWN));
+    }
+    if (changed & GDK_WINDOW_STATE_ICONIFIED) {
+        g_message("-- ICONIFIED = %d", 0!=(state&GDK_WINDOW_STATE_ICONIFIED));
+    }
+    if (changed & GDK_WINDOW_STATE_MAXIMIZED) {
+        g_message("-- MAXIMIZED = %d", 0!=(state&GDK_WINDOW_STATE_MAXIMIZED));
+    }
+    if (changed & GDK_WINDOW_STATE_STICKY) {
+        g_message("-- STICKY = %d", 0!=(state&GDK_WINDOW_STATE_STICKY));
+    }
+    if (changed & GDK_WINDOW_STATE_FULLSCREEN) {
+        g_message("-- FULLSCREEN = %d", 0!=(state&GDK_WINDOW_STATE_FULLSCREEN));
+    }
+    if (changed & GDK_WINDOW_STATE_ABOVE) {
+        g_message("-- ABOVE = %d", 0!=(state&GDK_WINDOW_STATE_ABOVE));
+    }
+    if (changed & GDK_WINDOW_STATE_BELOW) {
+        g_message("-- BELOW = %d", 0!=(state&GDK_WINDOW_STATE_BELOW));
+    }
+*/
+}
+
 /*
  * Some day when the right-click menus are ready to start working
  * smarter with the verbs, we'll need to change this NULL being
@@ -565,7 +664,7 @@ checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
     Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
 
     gchar const *pref_path;
-    if (reinterpret_cast<SPDesktop*>(view)->is_fullscreen)
+    if (reinterpret_cast<SPDesktop*>(view)->is_fullscreen())
         pref_path = g_strconcat("fullscreen.", pref, NULL);
     else
         pref_path = g_strconcat("window.", pref, NULL);
@@ -585,7 +684,7 @@ checkitem_update(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
     Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
 
     gchar const *pref_path;
-    if (static_cast<SPDesktop*>(view)->is_fullscreen)
+    if ((static_cast<SPDesktop*>(view))->is_fullscreen())
         pref_path = g_strconcat("fullscreen.", pref, NULL);
     else
         pref_path = g_strconcat("window.", pref, NULL);
@@ -936,7 +1035,8 @@ sp_ui_context_menu(Inkscape::UI::View::View *view, SPItem *item)
     }
 
     if (( group && group != dt->currentLayer() ) ||
-        ( dt->currentLayer() != dt->currentRoot() ) ) {
+        ( dt->currentLayer() != dt->currentRoot() && SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) ) {
+        /* Separator */
         sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
     }
 
@@ -974,11 +1074,13 @@ sp_ui_drag_data_received(GtkWidget *widget,
                          guint event_time,
                          gpointer user_data)
 {
+    SPDocument *doc = SP_ACTIVE_DOCUMENT;
+    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+
     switch (info) {
 #if ENABLE_MAGIC_COLORS
         case APP_X_INKY_COLOR:
         {
-            SPDesktop *desktop = SP_ACTIVE_DESKTOP;
             int destX = 0;
             int destY = 0;
             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
@@ -1039,7 +1141,6 @@ sp_ui_drag_data_received(GtkWidget *widget,
                     sp_desktop_apply_css_recursive( item, css, true );
                     item->updateRepr();
 
-                    SPDocument *doc = SP_ACTIVE_DOCUMENT;
                     sp_document_done( doc , SP_VERB_NONE, 
                                       _("Drop color"));
 
@@ -1054,7 +1155,6 @@ sp_ui_drag_data_received(GtkWidget *widget,
 
         case APP_X_COLOR:
         {
-            SPDesktop *desktop = SP_ACTIVE_DESKTOP;
             int destX = 0;
             int destY = 0;
             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
@@ -1081,7 +1181,6 @@ sp_ui_drag_data_received(GtkWidget *widget,
                     sp_desktop_apply_css_recursive( item, css, true );
                     item->updateRepr();
 
-                    SPDocument *doc = SP_ACTIVE_DOCUMENT;
                     sp_document_done( doc , SP_VERB_NONE, 
                                       _("Drop color"));
                 }
@@ -1093,8 +1192,6 @@ sp_ui_drag_data_received(GtkWidget *widget,
         case SVG_XML_DATA: {
             gchar *svgdata = (gchar *)data->data;
 
-            SPDocument *doc = SP_ACTIVE_DOCUMENT;
-
             Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, data->length, SP_SVG_NS_URI);
 
             if (rnewdoc == NULL) {
@@ -1102,20 +1199,20 @@ sp_ui_drag_data_received(GtkWidget *widget,
                 return;
             }
 
-            Inkscape::XML::Node *repr = sp_repr_document_root(rnewdoc);
+            Inkscape::XML::Node *repr = rnewdoc->root();
             gchar const *style = repr->attribute("style");
 
             Inkscape::XML::Node *newgroup = rnewdoc->createElement("svg:g");
             newgroup->setAttribute("style", style);
 
+            Inkscape::XML::Document * xml_doc =  sp_document_repr_doc(doc);
             for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) {
-                Inkscape::XML::Node *newchild = child->duplicate();
+                Inkscape::XML::Node *newchild = child->duplicate(xml_doc);
                 newgroup->appendChild(newchild);
             }
 
             Inkscape::GC::release(rnewdoc);
 
-            SPDesktop *desktop = SP_ACTIVE_DESKTOP;
             // Add it to the current layer
 
             // Greg's edits to add intelligent positioning of svg drops
@@ -1130,8 +1227,11 @@ sp_ui_drag_data_received(GtkWidget *widget,
                 int const saved_pref = prefs_get_int_attribute("options.transform", "pattern", 1);
                 prefs_set_int_attribute("options.transform", "pattern", 1);
                 sp_document_ensure_up_to_date(sp_desktop_document(desktop));
-                NR::Point m( desktop->point() - selection->bounds().midpoint() );
-                sp_selection_move_relative(selection, m);
+                NR::Maybe<NR::Rect> sel_bbox = selection->bounds();
+                if (sel_bbox) {
+                    NR::Point m( desktop->point() - sel_bbox->midpoint() );
+                    sp_selection_move_relative(selection, m);
+                }
                 prefs_set_int_attribute("options.transform", "pattern", saved_pref);
             }
 
@@ -1156,7 +1256,6 @@ sp_ui_drag_data_received(GtkWidget *widget,
             Base64OutputStream b64out(outs);
             b64out.setColumnWidth(0);
 
-            SPDocument *doc = SP_ACTIVE_DOCUMENT;
             Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
 
             Inkscape::XML::Node *newImage = xml_doc->createElement("svg:image");
@@ -1191,8 +1290,6 @@ sp_ui_drag_data_received(GtkWidget *widget,
                 }
             }
 
-            SPDesktop *desktop = SP_ACTIVE_DESKTOP;
-
             // Add it to the current layer
             desktop->currentLayer()->appendChildRepr(newImage);
 
@@ -1244,7 +1341,7 @@ sp_ui_error_dialog(gchar const *message)
     gchar *safeMsg = Inkscape::IO::sanitizeString(message);
 
     dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
-                                 GTK_BUTTONS_CLOSE, safeMsg);
+                                 GTK_BUTTONS_CLOSE, "%s", safeMsg);
     sp_transientize(dlg);
     gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE);
     gtk_dialog_run(GTK_DIALOG(dlg));
@@ -1256,52 +1353,39 @@ bool
 sp_ui_overwrite_file(gchar const *filename)
 {
     bool return_value = FALSE;
-    GtkWidget *dialog;
-    GtkWidget *hbox;
-    GtkWidget *boxdata;
-    gchar *title;
-    gchar *text;
 
     if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
-
-        title = g_strdup_printf(_("Overwrite %s"), filename);
-        dialog = gtk_dialog_new_with_buttons(title,
-                                             NULL,
-                                             (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
-                                             GTK_STOCK_NO,
-                                             GTK_RESPONSE_NO,
-                                             GTK_STOCK_YES,
-                                             GTK_RESPONSE_YES,
-                                             NULL);
-        gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
-
-        sp_transientize(dialog);
-        gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
-
-        hbox = gtk_hbox_new(FALSE, 5);
-
-        // TODO - replace with Inkscape-specific call
-        boxdata = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
-
-        gtk_widget_show(boxdata);
-        gtk_box_pack_start(GTK_BOX(hbox), boxdata, TRUE, TRUE, 5);
-        text = g_strdup_printf(_("The file %s already exists.  Do you want to overwrite that file with the current document?"), filename);
-        boxdata = gtk_label_new(text);
-        gtk_label_set_line_wrap(GTK_LABEL(boxdata), TRUE);
-        gtk_widget_show(boxdata);
-        gtk_box_pack_start(GTK_BOX(hbox), boxdata, FALSE, FALSE, 5);
-        gtk_widget_show(hbox);
-        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 5);
-
-        if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
+        GtkWidget* ancestor = 0;
+        SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+        if ( desktop ) {
+            desktop->getToplevel( ancestor );
+        }
+        GtkWindow *window = GTK_WIDGET_TOPLEVEL(ancestor) ? GTK_WINDOW( ancestor ) : 0;
+        gchar* baseName = g_path_get_basename( filename );
+        gchar* dirName = g_path_get_dirname( filename );
+        GtkWidget* dialog = gtk_message_dialog_new_with_markup( window,
+                                                                (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
+                                                                GTK_MESSAGE_QUESTION,
+                                                                GTK_BUTTONS_NONE,
+                                                                _( "<span weight=\"bold\" size=\"larger\">A file named \"%s\" already exists. Do you want to replace it?</span>\n\n"
+                                                                   "The file already exists in \"%s\". Replacing it will overwrite its contents." ),
+                                                                baseName,
+                                                                dirName
+            );
+        gtk_dialog_add_buttons( GTK_DIALOG(dialog),
+                                GTK_STOCK_CANCEL, GTK_RESPONSE_NO,
+                                _("Replace"), GTK_RESPONSE_YES,
+                                NULL );
+        gtk_dialog_set_default_response( GTK_DIALOG(dialog), GTK_RESPONSE_YES );
+
+        if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_YES ) {
             return_value = TRUE;
         } else {
             return_value = FALSE;
         }
-
         gtk_widget_destroy(dialog);
-        g_free(title);
-        g_free(text);
+        g_free( baseName );
+        g_free( dirName );
     } else {
         return_value = TRUE;
     }