Code

New crosshairs cursor for geometry context
[inkscape.git] / src / interface.cpp
index f43c31d301b9725cf955a76176bce70002f68afe..0259ecb6602dd52d7f62c0f53e5a7cded9f1d31e 100644 (file)
 #include "svg-view-widget.h"
 #include "widgets/desktop-widget.h"
 #include "sp-item-group.h"
+#include "sp-text.h"
+#include "sp-flowtext.h"
 #include "sp-namedview.h"
+#include "ui/view/view.h"
 
 #include "helper/action.h"
 #include "helper/gnome-utils.h"
 #include "svg/svg-color.h"
 #include "desktop-style.h"
 #include "style.h"
+#include "event-context.h"
+#include "gradient-drag.h"
 
+// Include Mac OS X menu synchronization on native OSX build
+#ifdef GDK_WINDOWING_QUARTZ
+#include "ige-mac-menu.h"
+#endif
 
 using Inkscape::IO::StringOutputStream;
 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 {
     URI_LIST,
@@ -85,15 +89,15 @@ typedef enum {
 } ui_drop_target_info;
 
 static GtkTargetEntry ui_drop_target_entries [] = {
-    {"text/uri-list", 0, URI_LIST},
-    {"image/svg+xml", 0, SVG_XML_DATA},
-    {"image/svg",     0, SVG_DATA},
-    {"image/png",     0, PNG_DATA},
-    {"image/jpeg",    0, JPEG_DATA},
+    {(gchar *)"text/uri-list",                0, URI_LIST        },
+    {(gchar *)"image/svg+xml",                0, SVG_XML_DATA    },
+    {(gchar *)"image/svg",                    0, SVG_DATA        },
+    {(gchar *)"image/png",                    0, PNG_DATA        },
+    {(gchar *)"image/jpeg",                   0, JPEG_DATA       },
 #if ENABLE_MAGIC_COLORS
-    {"application/x-inkscape-color", 0, APP_X_INKY_COLOR},
+    {(gchar *)"application/x-inkscape-color", 0, APP_X_INKY_COLOR},
 #endif // ENABLE_MAGIC_COLORS
-    {"application/x-color", 0, APP_X_COLOR}
+    {(gchar *)"application/x-color",          0, APP_X_COLOR     }
 };
 
 static GtkTargetEntry *completeDropTargets = 0;
@@ -111,6 +115,17 @@ static void sp_ui_drag_data_received(GtkWidget *widget,
                                      guint info,
                                      guint event_time,
                                      gpointer user_data);
+static void sp_ui_drag_motion( GtkWidget *widget,
+                               GdkDragContext *drag_context,
+                               gint x, gint y,
+                               GtkSelectionData *data,
+                               guint info,
+                               guint event_time,
+                               gpointer user_data );
+static void sp_ui_drag_leave( GtkWidget *widget,
+                              GdkDragContext *drag_context,
+                              guint event_time,
+                              gpointer user_data );
 static void sp_ui_menu_item_set_sensitive(SPAction *action,
                                           unsigned int sensitive,
                                           void *data);
@@ -135,26 +150,26 @@ sp_create_window(SPViewWidget *vw, gboolean editable)
     g_return_if_fail(vw != NULL);
     g_return_if_fail(SP_IS_VIEW_WIDGET(vw));
 
-    GtkWidget *win = sp_window_new("", TRUE);
+    Gtk::Window *win = Inkscape::UI::window_new("", TRUE);
 
-    if (editable) {
-      g_object_set_data(G_OBJECT(vw), "window", win);
-      reinterpret_cast<SPDesktopWidget*>(vw)->window =
-        static_cast<GtkWindow*>((void*)win);
-    }
+    gtk_container_add(GTK_CONTAINER(win->gobj()), GTK_WIDGET(vw));
+    gtk_widget_show(GTK_WIDGET(vw));
 
     if (editable) {
-        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);
-
+               g_object_set_data(G_OBJECT(vw), "window", win);
+               
+               SPDesktopWidget *desktop_widget = reinterpret_cast<SPDesktopWidget*>(vw);
+               SPDesktop* desktop = desktop_widget->desktop;
+               
+               desktop_widget->window = win;
+
+        win->set_data("desktop", desktop);
+        win->set_data("desktopwidget", desktop_widget);
+               
+        win->signal_delete_event().connect(sigc::mem_fun(*(SPDesktop*)vw->view, &SPDesktop::onDeleteUI));
+               win->signal_window_state_event().connect(sigc::mem_fun(*desktop, &SPDesktop::onWindowStateEvent));
+               win->signal_focus_in_event().connect(sigc::mem_fun(*desktop_widget, &SPDesktopWidget::onFocusInEvent));
+       
         gint prefs_geometry = 
             (2==prefs_get_int_attribute("options.savewindowgeometry", "value", 0));
         if (prefs_geometry) {
@@ -191,20 +206,17 @@ sp_create_window(SPViewWidget *vw, gboolean editable)
                 }
             }
             if (maxed) {
-                gtk_window_maximize(GTK_WINDOW(win));
+                win->maximize();
             }
             if (full) {
-                gtk_window_fullscreen(GTK_WINDOW(win));
+                win->fullscreen();
             }
         }
 
     } else {
-        gtk_window_set_policy(GTK_WINDOW(win), TRUE, TRUE, TRUE);
+        gtk_window_set_policy(GTK_WINDOW(win->gobj()), TRUE, TRUE, TRUE);
     }
 
-    gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(vw));
-    gtk_widget_show(GTK_WIDGET(vw));
-
     if ( completeDropTargets == 0 || completeDropTargetsCount == 0 )
     {
         std::vector<gchar*> types;
@@ -236,16 +248,26 @@ sp_create_window(SPViewWidget *vw, gboolean editable)
         }
     }
 
-    gtk_drag_dest_set(win,
+    gtk_drag_dest_set((GtkWidget*)win->gobj(),
                       GTK_DEST_DEFAULT_ALL,
                       completeDropTargets,
                       completeDropTargetsCount,
                       GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE));
-    g_signal_connect(G_OBJECT(win),
+
+
+    g_signal_connect(G_OBJECT(win->gobj()),
                      "drag_data_received",
                      G_CALLBACK(sp_ui_drag_data_received),
                      NULL);
-    gtk_widget_show(win);
+    g_signal_connect(G_OBJECT(win->gobj()),
+                     "drag_motion",
+                     G_CALLBACK(sp_ui_drag_motion),
+                     NULL);
+    g_signal_connect(G_OBJECT(win->gobj()),
+                     "drag_leave",
+                     G_CALLBACK(sp_ui_drag_leave),
+                     NULL);
+    win->show();
 
     // needed because the first ACTIVATE_DESKTOP was sent when there was no window yet
     inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop);
@@ -290,7 +312,7 @@ sp_ui_new_view_preview()
  * \param widget unused
  */
 void
-sp_ui_close_view(GtkWidget *widget)
+sp_ui_close_view(GtkWidget */*widget*/)
 {
     if (SP_ACTIVE_DESKTOP == NULL) {
         return;
@@ -329,59 +351,6 @@ sp_ui_close_all(void)
     return TRUE;
 }
 
-static gint
-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
@@ -390,19 +359,19 @@ sp_ui_state_event(GtkWidget *widget, GdkEventWindowState *event, SPDesktop* desk
  * investigate when they're called.
  */
 static void
-sp_ui_menu_activate(void *object, SPAction *action)
+sp_ui_menu_activate(void */*object*/, SPAction *action)
 {
     sp_action_perform(action, NULL);
 }
 
 static void
-sp_ui_menu_select_action(void *object, SPAction *action)
+sp_ui_menu_select_action(void */*object*/, SPAction *action)
 {
     action->view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, action->tip);
 }
 
 static void
-sp_ui_menu_deselect_action(void *object, SPAction *action)
+sp_ui_menu_deselect_action(void */*object*/, SPAction *action)
 {
     action->view->tipsMessageContext()->clear();
 }
@@ -500,9 +469,10 @@ sp_key_name(guint keyval)
     else if (!strcmp(n, "Page_Down"  ))  return "PgDn";
     else if (!strcmp(n, "grave"      ))  return "`";
     else if (!strcmp(n, "numbersign" ))  return "#";
-    else if (!strcmp(n, "bar" ))  return "|";
-    else if (!strcmp(n, "slash" ))  return "/";
-    else if (!strcmp(n, "exclam" ))  return "!";
+    else if (!strcmp(n, "bar"        ))  return "|";
+    else if (!strcmp(n, "slash"      ))  return "/";
+    else if (!strcmp(n, "exclam"     ))  return "!";
+    else if (!strcmp(n, "percent"    ))  return "%";
     else return n;
 }
 
@@ -676,7 +646,7 @@ checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
 }
 
 static gboolean
-checkitem_update(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
+checkitem_update(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_data)
 {
     GtkCheckMenuItem *menuitem=GTK_CHECK_MENU_ITEM(widget);
 
@@ -763,13 +733,13 @@ sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *
 }
 
 static void
-sp_recent_open(GtkWidget *widget, gchar const *uri)
+sp_recent_open(GtkWidget */*widget*/, gchar const *uri)
 {
     sp_file_open(uri, NULL);
 }
 
 static void
-sp_file_new_from_template(GtkWidget *widget, gchar const *uri)
+sp_file_new_from_template(GtkWidget */*widget*/, gchar const *uri)
 {
     sp_file_new(uri);
 }
@@ -977,9 +947,17 @@ sp_ui_main_menubar(Inkscape::UI::View::View *view)
 {
     GtkWidget *mbar = gtk_menu_bar_new();
 
+#ifdef GDK_WINDOWING_QUARTZ
+       ige_mac_menu_set_menu_bar(GTK_MENU_SHELL(mbar));
+#endif
+
     sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view);
 
+#ifdef GDK_WINDOWING_QUARTZ
+       return NULL;
+#else
     return mbar;
+#endif
 }
 
 static void leave_group(GtkMenuItem *, SPDesktop *desktop) {
@@ -1071,8 +1049,8 @@ sp_ui_drag_data_received(GtkWidget *widget,
                          gint x, gint y,
                          GtkSelectionData *data,
                          guint info,
-                         guint event_time,
-                         gpointer user_data)
+                         guint /*event_time*/,
+                         gpointer /*user_data*/)
 {
     SPDocument *doc = SP_ACTIVE_DOCUMENT;
     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
@@ -1089,13 +1067,15 @@ sp_ui_drag_data_received(GtkWidget *widget,
             SPItem *item = desktop->item_at_point( where, true );
             if ( item )
             {
+                bool fillnotstroke = (drag_context->action != GDK_ACTION_MOVE);
+
                 if ( data->length >= 8 ) {
                     cmsHPROFILE srgbProf = cmsCreate_sRGBProfile();
 
                     gchar c[64] = {0};
                     // Careful about endian issues.
                     guint16* dataVals = (guint16*)data->data;
-                    sp_svg_write_color( c, 64,
+                    sp_svg_write_color( c, sizeof(c),
                                         SP_RGBA32_U_COMPOSE(
                                             0x0ff & (dataVals[0] >> 8),
                                             0x0ff & (dataVals[1] >> 8),
@@ -1124,18 +1104,18 @@ sp_ui_drag_data_received(GtkWidget *widget,
                             str = 0;
 
                             sp_object_setAttribute( SP_OBJECT(item),
-                                                    (drag_context->action != GDK_ACTION_MOVE) ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag",
+                                                    fillnotstroke ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag",
                                                     palName.c_str(),
                                                     false );
                             item->updateRepr();
 
-                            sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
+                            sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c );
                             updatePerformed = true;
                         }
                     }
 
                     if ( !updatePerformed ) {
-                        sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
+                        sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c );
                     }
 
                     sp_desktop_apply_css_recursive( item, css, true );
@@ -1159,24 +1139,69 @@ sp_ui_drag_data_received(GtkWidget *widget,
             int destY = 0;
             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
+            NR::Point const button_dt(desktop->w2d(where));
+            NR::Point const button_doc(desktop->dt2doc(button_dt));
+
+            if ( data->length == 8 ) {
+                gchar c[64] = {0};
+                // Careful about endian issues.
+                guint16* dataVals = (guint16*)data->data;
+                sp_svg_write_color( c, 64,
+                                    SP_RGBA32_U_COMPOSE(
+                                        0x0ff & (dataVals[0] >> 8),
+                                        0x0ff & (dataVals[1] >> 8),
+                                        0x0ff & (dataVals[2] >> 8),
+                                        0xff // can't have transparency in the color itself
+                                        //0x0ff & (data->data[3] >> 8),
+                                        ));
+
+                SPItem *item = desktop->item_at_point( where, true );
+
+                bool consumed = false;
+                if (desktop->event_context && desktop->event_context->get_drag()) {
+                    consumed = desktop->event_context->get_drag()->dropColor(item, c, button_dt);
+                    if (consumed) {
+                        sp_document_done( doc , SP_VERB_NONE, _("Drop color on gradient"));
+                        desktop->event_context->get_drag()->updateDraggers();
+                    }
+                }
+
+                //if (!consumed && tools_active(desktop, TOOLS_TEXT)) {
+                //    consumed = sp_text_context_drop_color(c, button_doc);
+                //    if (consumed) {
+                //        sp_document_done( doc , SP_VERB_NONE, _("Drop color on gradient stop"));
+                //    }
+                //}
+
+                if (!consumed && item) {
+                    bool fillnotstroke = (drag_context->action != GDK_ACTION_MOVE);
+                    if (fillnotstroke && 
+                        (SP_IS_SHAPE(item) || SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))) {
+                        Path *livarot_path = Path_for_item(item, true, true);
+                        livarot_path->ConvertWithBackData(0.04);
+
+                        boost::optional<Path::cut_position> position = get_nearest_position_on_Path(livarot_path, button_doc);
+                        if (position) {
+                            NR::Point nearest = get_point_on_Path(livarot_path, position->piece, position->t);
+                            NR::Point delta = nearest - button_doc;
+                            delta = desktop->d2w(delta);
+                            double stroke_tolerance =
+                                ( !SP_OBJECT_STYLE(item)->stroke.isNone() ?
+                                  desktop->current_zoom() *
+                                  SP_OBJECT_STYLE (item)->stroke_width.computed *
+                                  NR::expansion(sp_item_i2d_affine(item)) * 0.5
+                                  : 0.0)
+                                + prefs_get_int_attribute_limited("options.dragtolerance", "value", 0, 0, 100); 
+
+                            if (NR::L2 (delta) < stroke_tolerance) {
+                                fillnotstroke = false;
+                            }
+                        }
+                        delete livarot_path;
+                    }
 
-            SPItem *item = desktop->item_at_point( where, true );
-            if ( item )
-            {
-                if ( data->length == 8 ) {
-                    gchar c[64] = {0};
-                    // Careful about endian issues.
-                    guint16* dataVals = (guint16*)data->data;
-                    sp_svg_write_color( c, 64,
-                                        SP_RGBA32_U_COMPOSE(
-                                            0x0ff & (dataVals[0] >> 8),
-                                            0x0ff & (dataVals[1] >> 8),
-                                            0x0ff & (dataVals[2] >> 8),
-                                            0xff // can't have transparency in the color itself
-                                            //0x0ff & (data->data[3] >> 8),
-                                            ));
                     SPCSSAttr *css = sp_repr_css_attr_new();
-                    sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
+                    sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c );
 
                     sp_desktop_apply_css_recursive( item, css, true );
                     item->updateRepr();
@@ -1227,7 +1252,7 @@ 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::Maybe<NR::Rect> sel_bbox = selection->bounds();
+                boost::optional<NR::Rect> sel_bbox = selection->bounds();
                 if (sel_bbox) {
                     NR::Point m( desktop->point() - sel_bbox->midpoint() );
                     sp_selection_move_relative(selection, m);
@@ -1301,6 +1326,31 @@ sp_ui_drag_data_received(GtkWidget *widget,
     }
 }
 
+#include "gradient-context.h"
+
+void sp_ui_drag_motion( GtkWidget */*widget*/,
+                        GdkDragContext */*drag_context*/,
+                        gint /*x*/, gint /*y*/,
+                        GtkSelectionData */*data*/,
+                        guint /*info*/,
+                        guint /*event_time*/,
+                        gpointer /*user_data*/)
+{
+//     SPDocument *doc = SP_ACTIVE_DOCUMENT;
+//     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+
+
+//     g_message("drag-n-drop motion (%4d, %4d)  at %d", x, y, event_time);
+}
+
+static void sp_ui_drag_leave( GtkWidget */*widget*/,
+                              GdkDragContext */*drag_context*/,
+                              guint /*event_time*/,
+                              gpointer /*user_data*/ )
+{
+//     g_message("drag-n-drop leave                at %d", event_time);
+}
+
 static void
 sp_ui_import_files(gchar *buffer)
 {
@@ -1313,7 +1363,7 @@ sp_ui_import_files(gchar *buffer)
 }
 
 static void
-sp_ui_import_one_file_with_check(gpointer filename, gpointer unused)
+sp_ui_import_one_file_with_check(gpointer filename, gpointer /*unused*/)
 {
     if (filename) {
         if (strlen((char const *)filename) > 2)
@@ -1355,15 +1405,10 @@ sp_ui_overwrite_file(gchar const *filename)
     bool return_value = FALSE;
 
     if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
-        GtkWidget* ancestor = 0;
-        SPDesktop *desktop = SP_ACTIVE_DESKTOP;
-        if ( desktop ) {
-            desktop->getToplevel( ancestor );
-        }
-        GtkWindow *window = GTK_WIDGET_TOPLEVEL(ancestor) ? GTK_WINDOW( ancestor ) : 0;
+        Gtk::Window *window = SP_ACTIVE_DESKTOP->getToplevel();
         gchar* baseName = g_path_get_basename( filename );
         gchar* dirName = g_path_get_dirname( filename );
-        GtkWidget* dialog = gtk_message_dialog_new_with_markup( window,
+        GtkWidget* dialog = gtk_message_dialog_new_with_markup( window->gobj(),
                                                                 (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
                                                                 GTK_MESSAGE_QUESTION,
                                                                 GTK_BUTTONS_NONE,
@@ -1394,13 +1439,13 @@ sp_ui_overwrite_file(gchar const *filename)
 }
 
 static void
-sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data)
+sp_ui_menu_item_set_sensitive(SPAction */*action*/, unsigned int sensitive, void *data)
 {
     return gtk_widget_set_sensitive(GTK_WIDGET(data), sensitive);
 }
 
 static void
-sp_ui_menu_item_set_name(SPAction *action, Glib::ustring name, void *data)
+sp_ui_menu_item_set_name(SPAction */*action*/, Glib::ustring name, void *data)
 {
     void *child = GTK_BIN (data)->child;
     //child is either