diff --git a/src/interface.cpp b/src/interface.cpp
index e542a19445f95386c740e0602718ade821e8498a..415593b7885ba76dbe76fb259af0cd718708bb4e 100644 (file)
--- a/src/interface.cpp
+++ b/src/interface.cpp
#include "widgets/desktop-widget.h"
#include "sp-item-group.h"
#include "sp-text.h"
+#include "sp-gradient-fns.h"
+#include "sp-gradient.h"
#include "sp-flowtext.h"
#include "sp-namedview.h"
#include "ui/view/view.h"
#include "style.h"
#include "event-context.h"
#include "gradient-drag.h"
+#include "widgets/ege-paint-def.h"
// Include Mac OS X menu synchronization on native OSX build
#ifdef GDK_WINDOWING_QUARTZ
IMAGE_DATA,
APP_X_INKY_COLOR,
APP_X_COLOR,
- APP_X_NOCOLOR,
- APP_X_XCOLOR
+ APP_OSWB_COLOR,
} ui_drop_target_info;
static GtkTargetEntry ui_drop_target_entries [] = {
#if ENABLE_MAGIC_COLORS
{(gchar *)"application/x-inkscape-color", 0, APP_X_INKY_COLOR},
#endif // ENABLE_MAGIC_COLORS
- {(gchar *)"application/x-oswb-nocolor", 0, APP_X_NOCOLOR },
+ {(gchar *)"application/x-oswb-color", 0, APP_OSWB_COLOR },
{(gchar *)"application/x-color", 0, APP_X_COLOR }
};
static GtkTargetEntry *completeDropTargets = 0;
static int completeDropTargetsCount = 0;
+static bool temporarily_block_actions = false;
#define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
gtk_widget_show(GTK_WIDGET(vw));
if (editable) {
- g_object_set_data(G_OBJECT(vw), "window", win);
+ g_object_set_data(G_OBJECT(vw), "window", win);
- SPDesktopWidget *desktop_widget = reinterpret_cast<SPDesktopWidget*>(vw);
- SPDesktop* desktop = desktop_widget->desktop;
+ SPDesktopWidget *desktop_widget = reinterpret_cast<SPDesktopWidget*>(vw);
+ SPDesktop* desktop = desktop_widget->desktop;
- desktop_widget->window = win;
+ 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));
+ 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));
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
gint prefs_geometry =
(2==prefs->getInt("/options/savewindowgeometry/value", 0));
if (prefs_geometry) {
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) {
+ if (w>0 && h>0) {
x = MIN(gdk_screen_width() - w, x);
y = MIN(gdk_screen_height() - h, y);
- }
- if (w>0 && h>0) {
desktop->setWindowSize(w, h);
}
// 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(Geom::Point(x, y));
- }
+ SPDesktop *active_desktop = SP_ACTIVE_DESKTOP;
+ if (active_desktop == desktop || active_desktop==NULL) {
+ desktop->setWindowPosition(Geom::Point(x, y));
}
}
if (maxed) {
void
sp_ui_close_view(GtkWidget */*widget*/)
{
- if (SP_ACTIVE_DESKTOP == NULL) {
+ SPDesktop *dt = SP_ACTIVE_DESKTOP;
+
+ if (dt == NULL) {
return;
}
- if ((SP_ACTIVE_DESKTOP)->shutdown()) {
- return;
+
+ if (dt->shutdown()) {
+ return; // Shutdown operation has been canceled, so do nothing
}
- SP_ACTIVE_DESKTOP->destroyWidget();
+
+ // Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP,
+ // because the user might have changed the focus in the meantime (see bug #381357 on Launchpad)
+ dt->destroyWidget();
}
/* Iterate through all the windows, destroying each in the order they
become active */
while (SP_ACTIVE_DESKTOP) {
- if ((SP_ACTIVE_DESKTOP)->shutdown()) {
- /* The user cancelled the operation, so end doing the close */
+ SPDesktop *dt = SP_ACTIVE_DESKTOP;
+ if (dt->shutdown()) {
+ /* The user canceled the operation, so end doing the close */
return FALSE;
}
- SP_ACTIVE_DESKTOP->destroyWidget();
+ // Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP,
+ // because the user might have changed the focus in the meantime (see bug #381357 on Launchpad)
+ dt->destroyWidget();
}
return TRUE;
static void
sp_ui_menu_activate(void */*object*/, SPAction *action)
{
- sp_action_perform(action, NULL);
+ if (!temporarily_block_actions) {
+ sp_action_perform(action, NULL);
+ }
}
static void
@@ -608,9 +618,8 @@ sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::
sp_ui_menuitem_add_icon(item, action->image);
}
gtk_widget_set_events(item, GDK_KEY_PRESS_MASK);
- g_signal_connect( G_OBJECT(item), "activate",
- G_CALLBACK(sp_ui_menu_activate), action );
-
+ g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
+ g_signal_connect( G_OBJECT(item), "activate", G_CALLBACK(sp_ui_menu_activate), action );
g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select_action), action );
g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect_action), action );
}
@@ -673,6 +682,44 @@ checkitem_update(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_dat
return FALSE;
}
+/**
+ * \brief Callback function to update the status of the radio buttons in the View -> Display mode menu (Normal, No Filters, Outline)
+ */
+
+static gboolean
+update_view_menu(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_data)
+{
+ SPAction *action = (SPAction *) user_data;
+ g_assert(action->id != NULL);
+
+ Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(widget), "view");
+ SPDesktop *dt = static_cast<SPDesktop*>(view);
+ Inkscape::RenderMode mode = dt->getMode();
+
+ bool new_state = false;
+ if (!strcmp(action->id, "ViewModeNormal")) {
+ new_state = mode == Inkscape::RENDERMODE_NORMAL;
+ } else if (!strcmp(action->id, "ViewModeNoFilters")) {
+ new_state = mode == Inkscape::RENDERMODE_NO_FILTERS;
+ } else if (!strcmp(action->id, "ViewModeOutline")) {
+ new_state = mode == Inkscape::RENDERMODE_OUTLINE;
+ } else {
+ g_warning("update_view_menu does not handle this verb");
+ }
+
+ if (new_state) { //only one of the radio buttons has to be activated; the others will automatically be deactivated
+ if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) {
+ // When the GtkMenuItem version of the "activate" signal has been emitted by a GtkRadioMenuItem, there is a second
+ // emission as the most recently active item is toggled to inactive. This is dealt with before the original signal is handled.
+ // This emission however should not invoke any actions, hence we block it here:
+ temporarily_block_actions = true;
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), TRUE);
+ temporarily_block_actions = false;
+ }
+ }
+
+ return FALSE;
+}
void
sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref,
// checkitem_toggled, checkitem_update, 0);
sp_ui_menu_append_check_item_from_verb(m, view, _("Commands Bar"), _("Show or hide the Commands bar (under the menu)"), "commands",
checkitem_toggled, checkitem_update, 0);
- sp_ui_menu_append_check_item_from_verb(m, view, _("Snap controls Bar"), _("Show or hide the snapping controls"), "snaptoolbox",
- checkitem_toggled, checkitem_update, 0);
+ sp_ui_menu_append_check_item_from_verb(m, view, _("Snap Controls Bar"), _("Show or hide the snapping controls"), "snaptoolbox",
+ checkitem_toggled, checkitem_update, 0);
sp_ui_menu_append_check_item_from_verb(m, view, _("Tool Controls Bar"), _("Show or hide the Tool Controls bar"), "toppanel",
checkitem_toggled, checkitem_update, 0);
sp_ui_menu_append_check_item_from_verb(m, view, _("_Toolbox"), _("Show or hide the main toolbox (on the left)"), "toolbox",
a couple of submenus, it is unlikely this will go more than two or
three times.
- In the case of an unreconginzed verb, a menu item is made to identify
+ In the case of an unrecognized verb, a menu item is made to identify
the verb that is missing, and display that. The menu item is also made
insensitive.
*/
@@ -896,6 +943,10 @@ sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI:
if (menu_pntr->attribute("default") != NULL) {
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
}
+ if (verb->get_code() != SP_VERB_NONE) {
+ SPAction *action = verb->get_action(view);
+ g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) update_view_menu, (void *) action);
+ }
} else {
sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view);
group = NULL;
@@ -941,6 +992,9 @@ sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI:
gtk_recent_filter_add_application(inkscape_only_filter, g_get_prgname());
gtk_recent_chooser_add_filter(GTK_RECENT_CHOOSER(recent_menu), inkscape_only_filter);
+ gtk_recent_chooser_set_show_tips (GTK_RECENT_CHOOSER(recent_menu), TRUE);
+ gtk_recent_chooser_set_show_not_found (GTK_RECENT_CHOOSER(recent_menu), FALSE);
+
GtkWidget *recent_item = gtk_menu_item_new_with_mnemonic(_("Open _Recent"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent_item), recent_menu);
GtkWidget *mbar = gtk_menu_bar_new();
#ifdef GDK_WINDOWING_QUARTZ
- ige_mac_menu_set_menu_bar(GTK_MENU_SHELL(mbar));
+ 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;
+ return NULL;
#else
return mbar;
#endif
Geom::Point const button_doc(desktop->dt2doc(button_dt));
if ( data->length == 8 ) {
- gchar c[64] = {0};
+ gchar colorspec[64] = {0};
// Careful about endian issues.
guint16* dataVals = (guint16*)data->data;
- sp_svg_write_color( c, 64,
+ sp_svg_write_color( colorspec, sizeof(colorspec),
SP_RGBA32_U_COMPOSE(
0x0ff & (dataVals[0] >> 8),
0x0ff & (dataVals[1] >> 8),
bool consumed = false;
if (desktop->event_context && desktop->event_context->get_drag()) {
- consumed = desktop->event_context->get_drag()->dropColor(item, c, button_dt);
+ consumed = desktop->event_context->get_drag()->dropColor(item, colorspec, button_dt);
if (consumed) {
sp_document_done( doc , SP_VERB_NONE, _("Drop color on gradient"));
desktop->event_context->get_drag()->updateDraggers();
}
SPCSSAttr *css = sp_repr_css_attr_new();
- sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c );
+ sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", colorspec );
sp_desktop_apply_css_recursive( item, css, true );
item->updateRepr();
}
break;
- case APP_X_NOCOLOR:
- case APP_X_XCOLOR:
+ case APP_OSWB_COLOR:
{
- gchar* c = g_strdup("none"); // temp
- int destX = 0;
- int destY = 0;
- gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
- Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) );
- Geom::Point const button_dt(desktop->w2d(where));
- Geom::Point const button_doc(desktop->dt2doc(button_dt));
+ bool worked = false;
+ Glib::ustring colorspec;
+ if ( data->format == 8 ) {
+ ege::PaintDef color;
+ worked = color.fromMIMEData("application/x-oswb-color",
+ reinterpret_cast<char*>(data->data),
+ data->length,
+ data->format);
+ if ( worked ) {
+ if ( color.getType() == ege::PaintDef::CLEAR ) {
+ colorspec = ""; // TODO check if this is sufficient
+ } else if ( color.getType() == ege::PaintDef::NONE ) {
+ colorspec = "none";
+ } else {
+ unsigned int r = color.getR();
+ unsigned int g = color.getG();
+ unsigned int b = color.getB();
+
+ SPGradient* matches = 0;
+ const GSList *gradients = sp_document_get_resource_list(doc, "gradient");
+ for (const GSList *item = gradients; item; item = item->next) {
+ SPGradient* grad = SP_GRADIENT(item->data);
+ if ( color.descr == grad->id ) {
+ if ( grad->has_stops ) {
+ matches = grad;
+ break;
+ }
+ }
+ }
+ if (matches) {
+ colorspec = "url(#";
+ colorspec += matches->id;
+ colorspec += ")";
+ } else {
+ gchar* tmp = g_strdup_printf("#%02x%02x%02x", r, g, b);
+ colorspec = tmp;
+ g_free(tmp);
+ }
+ }
+ }
+ }
+ if ( worked ) {
+ int destX = 0;
+ int destY = 0;
+ gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
+ Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) );
+ Geom::Point const button_dt(desktop->w2d(where));
+ Geom::Point const button_doc(desktop->dt2doc(button_dt));
- SPItem *item = desktop->item_at_point( where, true );
+ 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();
+ bool consumed = false;
+ if (desktop->event_context && desktop->event_context->get_drag()) {
+ consumed = desktop->event_context->get_drag()->dropColor(item, colorspec.c_str(), button_dt);
+ if (consumed) {
+ sp_document_done( doc , SP_VERB_NONE, _("Drop color on gradient"));
+ desktop->event_context->get_drag()->updateDraggers();
+ }
}
- }
- 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) {
- Geom::Point nearest = get_point_on_Path(livarot_path, position->piece, position->t);
- Geom::Point delta = nearest - button_doc;
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- delta = desktop->d2w(delta);
- double stroke_tolerance =
- ( !SP_OBJECT_STYLE(item)->stroke.isNone() ?
- desktop->current_zoom() *
- SP_OBJECT_STYLE (item)->stroke_width.computed *
- to_2geom(sp_item_i2d_affine(item)).descrim() * 0.5
- : 0.0)
- + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
-
- if (Geom::L2 (delta) < stroke_tolerance) {
- fillnotstroke = false;
+ 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) {
+ Geom::Point nearest = get_point_on_Path(livarot_path, position->piece, position->t);
+ Geom::Point delta = nearest - button_doc;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ delta = desktop->d2w(delta);
+ double stroke_tolerance =
+ ( !SP_OBJECT_STYLE(item)->stroke.isNone() ?
+ desktop->current_zoom() *
+ SP_OBJECT_STYLE (item)->stroke_width.computed *
+ to_2geom(sp_item_i2d_affine(item)).descrim() * 0.5
+ : 0.0)
+ + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
+
+ if (Geom::L2 (delta) < stroke_tolerance) {
+ fillnotstroke = false;
+ }
}
+ delete livarot_path;
}
- delete livarot_path;
- }
- SPCSSAttr *css = sp_repr_css_attr_new();
- sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c );
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", colorspec.c_str() );
- sp_desktop_apply_css_recursive( item, css, true );
- item->updateRepr();
+ sp_desktop_apply_css_recursive( item, css, true );
+ item->updateRepr();
- sp_document_done( doc , SP_VERB_NONE,
- _("Drop color"));
+ sp_document_done( doc , SP_VERB_NONE,
+ _("Drop color"));
+ }
}
- g_free(c);
}
break;
Inkscape::Selection *selection = sp_desktop_selection(desktop);
selection->set(SP_ITEM(new_obj));
- // To move the imported object, we must temporarily set the "transform pattern with
- // object" option.
+
+ // move to mouse pointer
{
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- bool const saved_pref = prefs->getBool("/options/transform/pattern", true);
- prefs->setBool("/options/transform/pattern", true);
sp_document_ensure_up_to_date(sp_desktop_document(desktop));
Geom::OptRect sel_bbox = selection->bounds();
if (sel_bbox) {
Geom::Point m( desktop->point() - sel_bbox->midpoint() );
- sp_selection_move_relative(selection, m);
+ sp_selection_move_relative(selection, m, false);
}
- prefs->setBool("/options/transform/pattern", saved_pref);
}
Inkscape::GC::release(newgroup);
Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
Inkscape::XML::Node *newImage = xml_doc->createElement("svg:image");
gchar *atom_name = gdk_atom_name(data->type);
-
+
// this formula taken from Glib docs
guint needed_size = data->length * 4 / 3 + data->length * 4 / (3 * 72) + 7;
needed_size += 5 + 8 + strlen(atom_name); // 5 bytes for data:, 8 for ;base64,
-
+
gchar *buffer = (gchar *) g_malloc(needed_size), *buf_work = buffer;
buf_work += g_sprintf(buffer, "data:%s;base64,", atom_name);
-
+
gint state = 0, save = 0;
g_base64_encode_step(data->data, data->length, TRUE, buf_work, &state, &save);
g_base64_encode_close(TRUE, buf_work, &state, &save);