diff options
| author | Denis Declara <declara91@gmail.com> | 2012-03-20 10:09:49 +0000 |
|---|---|---|
| committer | Denis Declara <declara91@gmail.com> | 2012-03-20 10:09:49 +0000 |
| commit | 1cd9c8450500b945614a12a762e06c057ee85bbe (patch) | |
| tree | 9973553a223ef7d6c5f9d18c35766fb3e7296e57 /src/widgets | |
| parent | Fix deprecated Gtk::Widget flags (diff) | |
| parent | desktop cutting plotter dxf output. ignore orphaned clones (Bug 957086) (diff) | |
| download | inkscape-1cd9c8450500b945614a12a762e06c057ee85bbe.tar.gz inkscape-1cd9c8450500b945614a12a762e06c057ee85bbe.zip | |
Merged with trunk
(bzr r11073.1.1)
Diffstat (limited to 'src/widgets')
| -rw-r--r-- | src/widgets/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/widgets/Makefile_insert | 2 | ||||
| -rw-r--r-- | src/widgets/gradient-image.cpp | 31 | ||||
| -rw-r--r-- | src/widgets/gradient-image.h | 1 | ||||
| -rw-r--r-- | src/widgets/gradient-toolbar.cpp | 179 | ||||
| -rw-r--r-- | src/widgets/gradient-vector.cpp | 371 | ||||
| -rw-r--r-- | src/widgets/gradient-vector.h | 9 | ||||
| -rw-r--r-- | src/widgets/paint-selector.cpp | 32 | ||||
| -rw-r--r-- | src/widgets/paint-selector.h | 1 | ||||
| -rw-r--r-- | src/widgets/stroke-marker-selector.cpp | 458 | ||||
| -rw-r--r-- | src/widgets/stroke-marker-selector.h | 104 | ||||
| -rw-r--r-- | src/widgets/stroke-style.cpp | 547 |
12 files changed, 1001 insertions, 736 deletions
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index 418cc5c6f..7b76ccc83 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -30,6 +30,7 @@ set(widgets_SRC sp-xmlview-tree.cpp spinbutton-events.cpp spw-utilities.cpp + stroke-marker-selector.cpp stroke-style.cpp swatch-selector.cpp toolbox.cpp @@ -68,6 +69,7 @@ set(widgets_SRC sp-xmlview-tree.h spinbutton-events.h spw-utilities.h + stroke-marker-selector.h stroke-style.h swatch-selector.h toolbox.h diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert index 86046b918..255767d43 100644 --- a/src/widgets/Makefile_insert +++ b/src/widgets/Makefile_insert @@ -62,6 +62,8 @@ ink_common_sources += \ widgets/sp-xmlview-content.h \ widgets/sp-xmlview-tree.cpp \ widgets/sp-xmlview-tree.h \ + widgets/stroke-marker-selector.cpp \ + widgets/stroke-marker-selector.h \ widgets/stroke-style.cpp \ widgets/stroke-style.h \ widgets/swatch-selector.cpp \ diff --git a/src/widgets/gradient-image.cpp b/src/widgets/gradient-image.cpp index 09a06370d..b835dc36b 100644 --- a/src/widgets/gradient-image.cpp +++ b/src/widgets/gradient-image.cpp @@ -153,6 +153,37 @@ sp_gradient_image_new (SPGradient *gradient) return (GtkWidget *) image; } +GdkPixbuf* +sp_gradient_to_pixbuf (SPGradient *gr, int width, int height) +{ + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + cairo_t *ct = cairo_create(s); + + cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard(); + cairo_set_source(ct, check); + cairo_paint(ct); + cairo_pattern_destroy(check); + + if (gr) { + cairo_pattern_t *p = sp_gradient_create_preview_pattern(gr, width); + cairo_set_source(ct, p); + cairo_paint(ct); + cairo_pattern_destroy(p); + } + + cairo_destroy(ct); + cairo_surface_flush(s); + + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), + GDK_COLORSPACE_RGB, TRUE, 8, + width, height, cairo_image_surface_get_stride(s), + ink_cairo_pixbuf_cleanup, s); + convert_pixbuf_argb32_to_normal(pixbuf); + + return pixbuf; +} + + void sp_gradient_image_set_gradient (SPGradientImage *image, SPGradient *gradient) { diff --git a/src/widgets/gradient-image.h b/src/widgets/gradient-image.h index 0fbed879f..904ce4cac 100644 --- a/src/widgets/gradient-image.h +++ b/src/widgets/gradient-image.h @@ -43,6 +43,7 @@ struct SPGradientImageClass { GType sp_gradient_image_get_type (void); GtkWidget *sp_gradient_image_new (SPGradient *gradient); +GdkPixbuf *sp_gradient_to_pixbuf (SPGradient *gr, int width, int height); void sp_gradient_image_set_gradient (SPGradientImage *gi, SPGradient *gr); #endif diff --git a/src/widgets/gradient-toolbar.cpp b/src/widgets/gradient-toolbar.cpp index 6443e09cb..2e7d6b89d 100644 --- a/src/widgets/gradient-toolbar.cpp +++ b/src/widgets/gradient-toolbar.cpp @@ -141,35 +141,54 @@ void gr_apply_gradient (Inkscape::Selection *selection, GrDrag *drag, SPGradient } } -void gr_item_activate (GtkMenuItem *menuitem, gpointer data) +void gr_combo_box_changed (GtkComboBox *widget, gpointer data) { - SPGradient *gr = static_cast<SPGradient *>(g_object_get_data (G_OBJECT (menuitem), "gradient")); - gr = sp_gradient_ensure_vector_normalized(gr); + GtkTreeIter iter; + if (!gtk_combo_box_get_active_iter (widget, &iter)) { + return; + } - SPDesktop *desktop = static_cast<SPDesktop *>(data); - Inkscape::Selection *selection = sp_desktop_selection (desktop); - SPEventContext *ev = sp_desktop_event_context (desktop); + GtkTreeModel *model = gtk_combo_box_get_model (widget); + SPGradient *gr = NULL; + gtk_tree_model_get (model, &iter, 2, &gr, -1); - gr_apply_gradient (selection, ev? ev->get_drag() : NULL, gr); + if (gr) { + gr = sp_gradient_ensure_vector_normalized(gr); - DocumentUndo::done(sp_desktop_document (desktop), SP_VERB_CONTEXT_GRADIENT, - _("Assign gradient to object")); -} + SPDesktop *desktop = static_cast<SPDesktop *>(data); + Inkscape::Selection *selection = sp_desktop_selection (desktop); + SPEventContext *ev = sp_desktop_event_context (desktop); + + gr_apply_gradient (selection, ev? ev->get_drag() : NULL, gr); + + DocumentUndo::done(sp_desktop_document (desktop), SP_VERB_CONTEXT_GRADIENT, + _("Assign gradient to object")); + } -gchar *gr_prepare_label (SPObject *obj) -{ - const gchar *id = obj->defaultLabel(); - if (strlen(id) > 15 && (!strncmp (id, "#linearGradient", 15) || !strncmp (id, "#radialGradient", 15))) - return g_strdup_printf ("<small>#%s</small>", id+15); - return g_strdup_printf ("<small>%s</small>", id); } + + GtkWidget *gr_vector_list(SPDesktop *desktop, bool selection_empty, SPGradient *gr_selected, bool gr_multi) { SPDocument *document = sp_desktop_document (desktop); - GtkWidget *om = gtk_option_menu_new (); - GtkWidget *m = gtk_menu_new (); + GtkListStore *store; + GtkTreeIter iter; + GtkCellRenderer *renderer; + GtkWidget *combo_box; + + store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); + combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, "pixbuf", 0, NULL); + gtk_cell_renderer_set_padding(renderer, 5, 0); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, "text", 1, NULL); GSList *gl = NULL; const GSList *gradients = document->getResourceList("gradient"); @@ -186,87 +205,65 @@ GtkWidget *gr_vector_list(SPDesktop *desktop, bool selection_empty, SPGradient * if (!gl) { // The document has no gradients - GtkWidget *l = gtk_label_new(""); - gtk_label_set_markup (GTK_LABEL(l), _("<small>No gradients</small>")); - GtkWidget *i = gtk_menu_item_new (); - gtk_container_add (GTK_CONTAINER (i), l); - - gtk_widget_show (i); - gtk_menu_shell_append(GTK_MENU_SHELL (m), i); - gtk_widget_set_sensitive (om, FALSE); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, NULL, 1, _("No gradients"), 2, NULL, -1); + gtk_widget_set_sensitive (combo_box, FALSE); + } else if (selection_empty) { // Document has gradients, but nothing is currently selected. - GtkWidget *l = gtk_label_new(""); - gtk_label_set_markup (GTK_LABEL(l), _("<small>Nothing selected</small>")); - GtkWidget *i = gtk_menu_item_new (); - gtk_container_add (GTK_CONTAINER (i), l); - - gtk_widget_show (i); - gtk_menu_shell_append(GTK_MENU_SHELL (m), i); - gtk_widget_set_sensitive (om, FALSE); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, NULL, 1, _("Nothing selected"), 2, NULL, -1); + gtk_widget_set_sensitive (combo_box, FALSE); + } else { if (gr_selected == NULL) { - GtkWidget *l = gtk_label_new(""); - gtk_label_set_markup (GTK_LABEL(l), _("<small>No gradients in selection</small>")); - GtkWidget *i = gtk_menu_item_new (); - gtk_container_add (GTK_CONTAINER (i), l); - gtk_widget_show (i); - gtk_menu_shell_append(GTK_MENU_SHELL (m), i); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, NULL, 1, _("No gradient"), 2, NULL, -1); + gtk_widget_set_sensitive (combo_box, FALSE); + } if (gr_multi) { - GtkWidget *l = gtk_label_new(""); - gtk_label_set_markup (GTK_LABEL(l), _("<small>Multiple gradients</small>")); - GtkWidget *i = gtk_menu_item_new (); - gtk_container_add (GTK_CONTAINER (i), l); - gtk_widget_show (i); - gtk_menu_shell_append(GTK_MENU_SHELL (m), i); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, NULL, 1, _("Multiple gradients"), 2, NULL, -1); + gtk_widget_set_sensitive (combo_box, FALSE); + } while (gl) { SPGradient *gradient = SP_GRADIENT (gl->data); gl = g_slist_remove (gl, gradient); - GtkWidget *i = gtk_menu_item_new (); - g_object_set_data (G_OBJECT (i), "gradient", gradient); - g_signal_connect (G_OBJECT (i), "activate", G_CALLBACK (gr_item_activate), desktop); - - GtkWidget *image = sp_gradient_image_new (gradient); - - GtkWidget *hb = gtk_hbox_new (FALSE, 4); - GtkWidget *l = gtk_label_new (""); gchar *label = gr_prepare_label(gradient); - gtk_label_set_markup (GTK_LABEL(l), label); + GdkPixbuf *pixb = sp_gradient_to_pixbuf (gradient, 64, 18); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, pixb, 1, label, 2, gradient, -1); g_free (label); - gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5); - gtk_box_pack_start (GTK_BOX (hb), l, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (hb), image, FALSE, FALSE, 0); - - gtk_widget_show_all (i); - - gtk_container_add (GTK_CONTAINER (i), hb); - - gtk_menu_shell_append(GTK_MENU_SHELL (m), i); if (gradient == gr_selected) { pos = idx; } idx ++; } - gtk_widget_set_sensitive (om, TRUE); + gtk_widget_set_sensitive (combo_box, TRUE); } - gtk_option_menu_set_menu (GTK_OPTION_MENU (om), m); /* Select the current gradient, or the Multi/Nothing line */ - if (gr_multi || gr_selected == NULL) - gtk_option_menu_set_history (GTK_OPTION_MENU (om), 0); - else - gtk_option_menu_set_history (GTK_OPTION_MENU (om), pos); + if (gr_multi || gr_selected == NULL) { + gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box) , 0); + } + else { + gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box) , pos); + } + + sp_set_font_size_smaller(combo_box); - return om; + g_signal_connect (G_OBJECT (combo_box), "changed", G_CALLBACK (gr_combo_box_changed), desktop); + + return combo_box; } @@ -377,10 +374,10 @@ static void gr_tb_selection_changed(Inkscape::Selection * /*selection*/, gpointe if (selection) { SPEventContext *ev = sp_desktop_event_context(desktop); - GtkWidget *om = (GtkWidget *) g_object_get_data(G_OBJECT(widget), "menu"); - if (om) { - gtk_widget_destroy(om); - om = 0; + GtkWidget *combo_box = (GtkWidget *) g_object_get_data(G_OBJECT(widget), "combobox"); + if (combo_box) { + gtk_widget_destroy(combo_box); + combo_box = 0; } SPGradient *gr_selected = 0; @@ -391,13 +388,13 @@ static void gr_tb_selection_changed(Inkscape::Selection * /*selection*/, gpointe gr_read_selection(selection, ev ? ev->get_drag() : 0, gr_selected, gr_multi, spr_selected, spr_multi); - om = gr_vector_list(desktop, selection->isEmpty(), gr_selected, gr_multi); - g_object_set_data(G_OBJECT(widget), "menu", om); + combo_box = gr_vector_list(desktop, selection->isEmpty(), gr_selected, gr_multi); + g_object_set_data(G_OBJECT(widget), "combobox", combo_box); GtkWidget *buttons = (GtkWidget *) g_object_get_data(G_OBJECT(widget), "buttons"); gtk_widget_set_sensitive(buttons, (gr_selected && !gr_multi)); - gtk_box_pack_start(GTK_BOX(widget), om, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(widget), combo_box, TRUE, TRUE, 0); gtk_widget_show_all(widget); } @@ -436,13 +433,19 @@ static void gr_disconnect_sigc (GObject */*obj*/, sigc::connection *connection) static void gr_edit (GtkWidget */*button*/, GtkWidget *widget) { - GtkWidget *om = (GtkWidget *) g_object_get_data (G_OBJECT(widget), "menu"); + GtkWidget *combo_box = (GtkWidget *) g_object_get_data (G_OBJECT(widget), "combobox"); spinbutton_defocus(GTK_OBJECT(widget)); - if (om) { - GtkWidget *i = gtk_menu_get_active (GTK_MENU (gtk_option_menu_get_menu (GTK_OPTION_MENU (om)))); - SPGradient *gr = (SPGradient *) g_object_get_data (G_OBJECT(i), "gradient"); + if (combo_box) { + GtkTreeIter iter; + if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX(combo_box), &iter)) { + return; + } + + GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX(combo_box)); + SPGradient *gr = NULL; + gtk_tree_model_get (model, &iter, 2, &gr, -1); if (gr) { GtkWidget *dialog = sp_gradient_vector_editor_new (gr); @@ -469,10 +472,10 @@ GtkWidget * gr_change_widget(SPDesktop *desktop) g_object_set_data(G_OBJECT(widget), "dtw", desktop->canvas); g_object_set_data (G_OBJECT (widget), "desktop", desktop); - GtkWidget *om = gr_vector_list (desktop, selection->isEmpty(), gr_selected, gr_multi); - g_object_set_data (G_OBJECT (widget), "menu", om); + GtkWidget *combo_box = gr_vector_list(desktop, selection->isEmpty(), gr_selected, gr_multi); + g_object_set_data(G_OBJECT(widget), "combobox", combo_box); - gtk_box_pack_start (GTK_BOX (widget), om, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (widget), combo_box, TRUE, TRUE, 0); { GtkWidget *buttons = gtk_hbox_new(FALSE, 1); @@ -628,9 +631,9 @@ sp_gradient_toolbox_new(SPDesktop *desktop) { GtkWidget *vectors = gr_change_widget (desktop); - GtkToolItem *vectors_toolitem = gtk_tool_item_new(); - gtk_container_add(GTK_CONTAINER(vectors_toolitem), vectors); - gtk_toolbar_insert(GTK_TOOLBAR(tbl), vectors_toolitem, -1); + GtkToolItem *vectors_toolitem = gtk_tool_item_new(); + gtk_container_add(GTK_CONTAINER(vectors_toolitem), vectors); + gtk_toolbar_insert(GTK_TOOLBAR(tbl), vectors_toolitem, -1); } gtk_widget_show_all(tbl); diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp index eb421ade6..d6de0c492 100644 --- a/src/widgets/gradient-vector.cpp +++ b/src/widgets/gradient-vector.cpp @@ -63,7 +63,8 @@ static void sp_gvs_defs_release(SPObject *defs, SPGradientVectorSelector *gvs); static void sp_gvs_defs_modified(SPObject *defs, guint flags, SPGradientVectorSelector *gvs); static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs); -static void sp_gvs_gradient_activate(GtkMenuItem *mi, SPGradientVectorSelector *gvs); +static void gr_combo_box_changed (GtkComboBox *widget, SPGradientVectorSelector *gvs); +static SPStop *get_selected_stop( GtkWidget *vb); static GtkVBoxClass *parent_class; static guint signals[LAST_SIGNAL] = {0}; @@ -132,9 +133,23 @@ static void sp_gradient_vector_selector_init(SPGradientVectorSelector *gvs) new (&gvs->defs_release_connection) sigc::connection(); new (&gvs->defs_modified_connection) sigc::connection(); - gvs->menu = gtk_option_menu_new(); - gtk_widget_show(gvs->menu); - gtk_box_pack_start(GTK_BOX(gvs), gvs->menu, TRUE, TRUE, 0); + gvs->store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); + gvs->combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (gvs->store)); + gvs->combo_connection = g_signal_connect (G_OBJECT (gvs->combo_box), "changed", G_CALLBACK (gr_combo_box_changed), gvs); + + GtkCellRenderer *renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (gvs->combo_box), renderer, FALSE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (gvs->combo_box), renderer, "pixbuf", 0, NULL); + gtk_cell_renderer_set_padding(renderer, 5, 0); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (gvs->combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (gvs->combo_box), renderer, "text", 1, NULL); + gtk_cell_renderer_set_padding(renderer, 0, 0); + + gtk_widget_show(gvs->combo_box); + gtk_box_pack_start(GTK_BOX(gvs), gvs->combo_box, TRUE, TRUE, 0); + } static void sp_gradient_vector_selector_destroy(GtkObject *object) @@ -219,7 +234,7 @@ void sp_gradient_vector_selector_set_gradient(SPGradientVectorSelector *gvs, SPD sp_gvs_rebuild_gui_full(gvs); if (!suppress) g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, gr); } else if (gr != gvs->gr) { - // Harder case - keep document, rebuild menus and stuff + // Harder case - keep document, rebuild list and stuff // fixme: (Lauris) suppress = TRUE; sp_gradient_vector_selector_set_gradient(gvs, NULL, NULL); @@ -246,16 +261,19 @@ SPGradient *sp_gradient_vector_selector_get_gradient(SPGradientVectorSelector *g return gvs->gr; } -static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs) +gchar *gr_prepare_label (SPObject *obj) { - /* Clear old menu, if there is any */ - if (gtk_option_menu_get_menu(GTK_OPTION_MENU(gvs->menu))) { - gtk_option_menu_remove_menu(GTK_OPTION_MENU(gvs->menu)); - } + const gchar *id = obj->defaultLabel(); + if (strlen(id) > 15 && (!strncmp (id, "#linearGradient", 15) || !strncmp (id, "#radialGradient", 15))) + return g_strdup_printf ("#%s", id+15); + return g_strdup_printf ("%s", id); +} - /* Create new menu widget */ - GtkWidget *m = gtk_menu_new(); - gtk_widget_show(m); +static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs) +{ + /* Clear old list, if there is any */ + gtk_list_store_clear(gvs->store); + GtkTreeIter iter; /* Pick up all gradients with vectors */ GSList *gl = NULL; @@ -274,112 +292,99 @@ static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs) gint idx = 0; if (!gvs->doc) { - GtkWidget *i; - i = gtk_menu_item_new_with_label(_("No document selected")); - gtk_widget_show(i); - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); - gtk_widget_set_sensitive(gvs->menu, FALSE); + gtk_list_store_append (gvs->store, &iter); + gtk_list_store_set (gvs->store, &iter, 0, NULL, 1, _("No document selected"), 2, NULL, -1); + gtk_widget_set_sensitive (gvs->combo_box, FALSE); + } else if (!gl) { - GtkWidget *i; - i = gtk_menu_item_new_with_label(_("No gradients in document")); - gtk_widget_show(i); - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); - gtk_widget_set_sensitive(gvs->menu, FALSE); + gtk_list_store_append (gvs->store, &iter); + gtk_list_store_set (gvs->store, &iter, 0, NULL, 1, _("No gradients in document"), 2, NULL, -1); + gtk_widget_set_sensitive (gvs->combo_box, FALSE); + } else if (!gvs->gr) { - GtkWidget *i; - i = gtk_menu_item_new_with_label(_("No gradient selected")); - gtk_widget_show(i); - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); - gtk_widget_set_sensitive(gvs->menu, FALSE); + gtk_list_store_append (gvs->store, &iter); + gtk_list_store_set (gvs->store, &iter, 0, NULL, 1, _("No gradient selected"), 2, NULL, -1); + gtk_widget_set_sensitive (gvs->combo_box, FALSE); + } else { while (gl) { SPGradient *gr; - GtkWidget *i, *w; gr = SP_GRADIENT(gl->data); gl = g_slist_remove(gl, gr); /* We have to know: */ /* Gradient destroy */ /* Gradient name change */ - i = gtk_menu_item_new(); - gtk_widget_show(i); - g_object_set_data(G_OBJECT(i), "gradient", gr); - g_signal_connect(G_OBJECT(i), "activate", G_CALLBACK(sp_gvs_gradient_activate), gvs); - - w = sp_gradient_image_new(gr); - gtk_widget_show(w); - - if (gvs->idlabel) { - GtkWidget *hb, *l; - hb = gtk_hbox_new(FALSE, 4); - gtk_widget_show(hb); - l = gtk_label_new(gr->getId()); - gtk_widget_show(l); - gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5); - gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(hb), w, FALSE, FALSE, 0); - w = hb; - } - gtk_container_add(GTK_CONTAINER(i), w); - - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); + gchar *label = gr_prepare_label(gr); + GdkPixbuf *pixb = sp_gradient_to_pixbuf (gr, 64, 18); + gtk_list_store_append (gvs->store, &iter); + gtk_list_store_set (gvs->store, &iter, 0, pixb, 1, label, 2, gr, -1); + g_free (label); if (gr == gvs->gr) { pos = idx; } idx += 1; } - gtk_widget_set_sensitive(gvs->menu, TRUE); + gtk_widget_set_sensitive (gvs->combo_box, TRUE); } - gtk_option_menu_set_menu(GTK_OPTION_MENU(gvs->menu), m); - /* Set history */ - gtk_option_menu_set_history(GTK_OPTION_MENU(gvs->menu), pos); + /* Block signal to prevent recursive loop */ + g_signal_handler_block(G_OBJECT (gvs->combo_box), gvs->combo_connection); + + /* Set selected */ + gtk_combo_box_set_active (GTK_COMBO_BOX(gvs->combo_box) , pos); + + g_signal_handler_unblock(G_OBJECT (gvs->combo_box), gvs->combo_connection); } -static void sp_gvs_gradient_activate(GtkMenuItem *mi, SPGradientVectorSelector *gvs) +static void gr_combo_box_changed (GtkComboBox *widget, SPGradientVectorSelector *gvs) { - SPGradient *gr, *norm; + GtkTreeIter iter; + if (!gtk_combo_box_get_active_iter (widget, &iter)) { + return; + } - gr = (SPGradient*)g_object_get_data(G_OBJECT(mi), "gradient"); - /* Hmmm... bad things may happen here, if actual gradient is something new */ - /* Namely - menuitems etc. will be fucked up */ - /* Hmmm - probably we can just re-set it as menuitem data (Lauris) */ + SPGradient *gr = NULL; + gtk_tree_model_get (GTK_TREE_MODEL(gvs->store), &iter, 2, &gr, -1); - //g_print("SPGradientVectorSelector: gradient %s activated\n", gr->getId()); - //g_message("Setting to gradient %p swatch:%d solid:%d", gr, gr->isSwatch(), gr->isSolid()); + if (gr) { - norm = sp_gradient_ensure_vector_normalized(gr); - if (norm != gr) { - //g_print("SPGradientVectorSelector: become %s after normalization\n", norm->getId()); - /* But be careful that we do not have gradient saved anywhere else */ - g_object_set_data(G_OBJECT(mi), "gradient", norm); - } + SPGradient *norm = sp_gradient_ensure_vector_normalized(gr); + if (norm != gr) { + //g_print("SPGradientVectorSelector: become %s after normalization\n", norm->getId()); + /* But be careful that we do not have gradient saved anywhere else */ + //g_object_set_data(G_OBJECT(mi), "gradient", norm); + gtk_list_store_set (gvs->store, &iter, 2, norm, -1); + } + + /* fixme: Really we would want to use _set_vector */ + /* Detach old */ + if (gvs->gr) { + gvs->gradient_release_connection.disconnect(); + gvs->gr = NULL; + } + /* Attach new */ + if (norm) { + gvs->gradient_release_connection = norm->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs)); + gvs->gr = norm; + } + + g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, norm); + + if (norm != gr) { + /* We do extra undo push here */ + /* If handler has already done it, it is just NOP */ + // FIXME: looks like this is never a valid undo step, consider removing this + DocumentUndo::done(norm->document, SP_VERB_CONTEXT_GRADIENT, + /* TODO: annotate */ "gradient-vector.cpp:350"); + } - /* fixme: Really we would want to use _set_vector */ - /* Detach old */ - if (gvs->gr) { - gvs->gradient_release_connection.disconnect(); - gvs->gr = NULL; - } - /* Attach new */ - if (norm) { - gvs->gradient_release_connection = norm->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs)); - gvs->gr = norm; - } - g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, norm); - if (norm != gr) { - /* We do extra undo push here */ - /* If handler has already done it, it is just NOP */ - // FIXME: looks like this is never a valid undo step, consider removing this - DocumentUndo::done(norm->document, SP_VERB_CONTEXT_GRADIENT, - /* TODO: annotate */ "gradient-vector.cpp:350"); } } - static void sp_gvs_gradient_release(SPObject */*obj*/, SPGradientVectorSelector *gvs) { /* Disconnect gradient */ @@ -445,16 +450,15 @@ static void sp_gradient_vector_gradient_release(SPObject *obj, GtkWidget *widget static void sp_gradient_vector_gradient_modified(SPObject *obj, guint flags, GtkWidget *widget); static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object); static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *object); -static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop); +static void update_stop_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_stop); static gboolean blocked = FALSE; static void grad_edit_dia_stop_added_or_removed(Inkscape::XML::Node */*repr*/, Inkscape::XML::Node */*child*/, Inkscape::XML::Node */*ref*/, gpointer data) { GtkWidget *vb = GTK_WIDGET(data); - GtkWidget *mnu = (GtkWidget *)g_object_get_data(G_OBJECT(vb), "stopmenu"); SPGradient *gradient = (SPGradient *)g_object_get_data(G_OBJECT(vb), "gradient"); - update_stop_list(mnu, gradient, NULL); + update_stop_list(vb, gradient, NULL); } //FIXME!!! We must also listen to attr changes on all children (i.e. stops) too, @@ -511,13 +515,15 @@ static void verify_grad(SPGradient *gradient) } } -static void select_stop_in_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop) +static void select_stop_in_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_stop) { + GtkWidget *combo_box = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(vb), "combo_box")); + int i = 0; for ( SPObject *ochild = gradient->firstChild() ; ochild ; ochild = ochild->getNext() ) { if (SP_IS_STOP(ochild)) { if (ochild == new_stop) { - gtk_option_menu_set_history(GTK_OPTION_MENU(mnu), i); + gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box) , i); break; } i++; @@ -525,7 +531,7 @@ static void select_stop_in_list( GtkWidget *mnu, SPGradient *gradient, SPStop *n } } -static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop) +static void update_stop_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_stop) { if (!SP_IS_GRADIENT(gradient)) { @@ -534,14 +540,19 @@ static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_ blocked = TRUE; - /* Clear old menu, if there is any */ - if (gtk_option_menu_get_menu(GTK_OPTION_MENU(mnu))) { - gtk_option_menu_remove_menu(GTK_OPTION_MENU(mnu)); + /* Clear old list, if there is any */ + GtkWidget *combo_box = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(vb), "combo_box")); + if (!combo_box) { + return; + } + GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model (GTK_COMBO_BOX(combo_box)); + if (!store) { + return; } + gtk_list_store_clear(store); + GtkTreeIter iter; - /* Create new menu widget */ - GtkWidget *m = gtk_menu_new(); - gtk_widget_show(m); + /* Populate the combobox store */ GSList *sl = NULL; if ( gradient->hasStops() ) { for ( SPObject *ochild = gradient->firstChild() ; ochild ; ochild = ochild->getNext() ) { @@ -551,43 +562,33 @@ static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_ } } if (!sl) { - GtkWidget *i = gtk_menu_item_new_with_label(_("No stops in gradient")); - gtk_widget_show(i); - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); - gtk_widget_set_sensitive(mnu, FALSE); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, NULL, 1, _("No stops in gradient"), 2, NULL, -1); + gtk_widget_set_sensitive (combo_box, FALSE); + } else { for (; sl != NULL; sl = sl->next){ if (SP_IS_STOP(sl->data)){ SPStop *stop = SP_STOP(sl->data); - GtkWidget *i = gtk_menu_item_new(); - gtk_widget_show(i); - g_object_set_data(G_OBJECT(i), "stop", stop); - GtkWidget *hb = gtk_hbox_new(FALSE, 4); - Gtk::Widget *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop))); - cpv->show(); - gtk_container_add( GTK_CONTAINER(hb), cpv->gobj() ); - g_object_set_data( G_OBJECT(i), "preview", cpv ); Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(sl->data)->getRepr(); - GtkWidget *l = gtk_label_new(repr->attribute("id")); - gtk_widget_show(l); - gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5); - gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, 0); - gtk_widget_show(hb); - gtk_container_add(GTK_CONTAINER(i), hb); - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); + Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop))); + GdkPixbuf *pb = cpv->toPixbuf(64, 16); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, pb, 1, repr->attribute("id"), 2, stop, -1); + gtk_widget_set_sensitive (combo_box, FALSE); } } - gtk_widget_set_sensitive(mnu, TRUE); + gtk_widget_set_sensitive(combo_box, TRUE); } - gtk_option_menu_set_menu(GTK_OPTION_MENU(mnu), m); /* Set history */ if (new_stop == NULL) { - gtk_option_menu_set_history(GTK_OPTION_MENU(mnu), 0); + gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box) , 0); } else { - select_stop_in_list(mnu, gradient, new_stop); + select_stop_in_list(vb, gradient, new_stop); } blocked = FALSE; @@ -595,10 +596,9 @@ static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_ // user selected existing stop from list -static void sp_grad_edit_select(GtkOptionMenu *mnu, GtkWidget *tbl) +static void sp_grad_edit_combo_box_changed (GtkComboBox *widget, GtkWidget *tbl) { - GObject *item = G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))); - SPStop *stop = SP_STOP(g_object_get_data(item, "stop")); + SPStop *stop = get_selected_stop(tbl); if (!stop) { return; } @@ -649,26 +649,36 @@ static void sp_grad_edit_select(GtkOptionMenu *mnu, GtkWidget *tbl) blocked = FALSE; } - - +static SPStop *get_selected_stop( GtkWidget *vb) +{ + SPStop *stop = NULL; + GtkWidget *combo_box = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(vb), "combo_box")); + if (combo_box) { + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(combo_box), &iter)) { + GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model (GTK_COMBO_BOX(combo_box)); + gtk_tree_model_get (GTK_TREE_MODEL(store), &iter, 2, &stop, -1); + } + } + return stop; +} static void offadjustmentChanged( GtkAdjustment *adjustment, GtkWidget *vb) { if (!blocked) { blocked = TRUE; - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu")); - if ( g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop") ) { - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); - + SPStop *stop = get_selected_stop(vb); + if (stop) { stop->offset = gtk_adjustment_get_value (adjustment); sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset); DocumentUndo::maybeDone(stop->document, "gradient:stop:offset", SP_VERB_CONTEXT_GRADIENT, _("Change gradient stop offset")); - blocked = FALSE; } + + blocked = FALSE; } } @@ -687,11 +697,9 @@ static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb) { SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient")); verify_grad(gradient); - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu")); - - SPStop *stop = static_cast<SPStop *>(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); - if (stop == NULL) { + SPStop *stop = get_selected_stop(vb); + if (!stop) { return; } @@ -734,7 +742,7 @@ static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb) sp_gradient_vector_widget_load_gradient(vb, gradient); Inkscape::GC::release(new_stop_repr); - update_stop_list(GTK_WIDGET(mnu), gradient, newstop); + update_stop_list(GTK_WIDGET(vb), gradient, newstop); GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offspn")); GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offslide")); gtk_widget_set_sensitive(offslide, TRUE); @@ -747,9 +755,11 @@ static void sp_grd_ed_del_stop(GtkWidget */*widget*/, GtkWidget *vb) { SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient")); - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu")); - if (!g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")) return; - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); + SPStop *stop = get_selected_stop(vb); + if (!stop) { + return; + } + if (gradient->vector.stops.size() > 2) { // 2 is the minimum // if we delete first or last stop, move the next/previous to the edge @@ -769,7 +779,7 @@ static void sp_grd_ed_del_stop(GtkWidget */*widget*/, GtkWidget *vb) gradient->getRepr()->removeChild(stop->getRepr()); sp_gradient_vector_widget_load_gradient(vb, gradient); - update_stop_list(GTK_WIDGET(mnu), gradient, NULL); + update_stop_list(GTK_WIDGET(vb), gradient, NULL); DocumentUndo::done(gradient->document, SP_VERB_CONTEXT_GRADIENT, _("Delete gradient stop")); } @@ -792,14 +802,27 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s sp_repr_add_listener(gradient->getRepr(), &grad_edit_dia_repr_events, vb); - /* Stop list */ - GtkWidget *mnu = gtk_option_menu_new(); - /* Create new menu widget */ - update_stop_list(GTK_WIDGET(mnu), gradient, NULL); - g_signal_connect(G_OBJECT(mnu), "changed", G_CALLBACK(sp_grad_edit_select), vb); - gtk_widget_show(mnu); - g_object_set_data(G_OBJECT(vb), "stopmenu", mnu); - gtk_box_pack_start(GTK_BOX(vb), mnu, FALSE, FALSE, 0); + /* ComboBox of stops with 3 columns, + * The color preview, the label and a pointer to the SPStop + */ + GtkListStore *store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); + GtkWidget *combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); + + GtkCellRenderer *renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, "pixbuf", 0, NULL); + gtk_cell_renderer_set_padding(renderer, 5, 0); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, "text", 1, NULL); + gtk_widget_show(combo_box); + gtk_box_pack_start(GTK_BOX(vb), combo_box, FALSE, FALSE, 0); + g_object_set_data(G_OBJECT(vb), "combo_box", combo_box); + + update_stop_list(GTK_WIDGET(vb), gradient, NULL); + + g_signal_connect(G_OBJECT(combo_box), "changed", G_CALLBACK(sp_grad_edit_combo_box_changed), vb); /* Add and Remove buttons */ GtkWidget *hb = gtk_hbox_new(FALSE, 1); @@ -818,7 +841,6 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s gtk_widget_show(hb); gtk_box_pack_start(GTK_BOX(vb),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS); - /* Offset Slider and stuff */ hb = gtk_hbox_new(FALSE, 0); @@ -832,8 +854,12 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s GtkAdjustment *Offset_adj = NULL; Offset_adj= (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.01, 0.0); g_object_set_data(G_OBJECT(vb), "offset", Offset_adj); - GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(mnu))); - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(m)), "stop")); + + SPStop *stop = get_selected_stop(vb); + if (!stop) { + return NULL; + } + gtk_adjustment_set_value(Offset_adj, stop->offset); /* Slider */ @@ -883,7 +909,7 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s sp_gradient_vector_widget_load_gradient(vb, gradient); if (select_stop) { - select_stop_in_list(GTK_WIDGET(mnu), gradient, select_stop); + select_stop_in_list(GTK_WIDGET(vb), gradient, select_stop); } return vb; @@ -1018,8 +1044,10 @@ static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradien gradient->ensureVector(); - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(widget), "stopmenu")); - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); + SPStop *stop = get_selected_stop(widget); + if (!stop) { + return; + } // get the color selector SPColorSelector *csel = SP_COLOR_SELECTOR(g_object_get_data(G_OBJECT(widget), "cselector")); @@ -1030,7 +1058,7 @@ static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradien GtkWidget *w = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "preview")); sp_gradient_image_set_gradient(SP_GRADIENT_IMAGE(w), gradient); - update_stop_list(GTK_WIDGET(mnu), gradient, NULL); + update_stop_list(GTK_WIDGET(widget), gradient, NULL); // Once the user edits a gradient, it stops being auto-collectable if (gradient->getRepr()->attribute("inkscape:collect")) { @@ -1135,9 +1163,10 @@ static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *o ngr->ensureVector(); - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(object), "stopmenu")); - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); - + SPStop *stop = get_selected_stop(GTK_WIDGET(object)); + if (!stop) { + return; + } csel->base->getColorAlpha(stop->specified_color, stop->opacity); stop->currentColor = false; @@ -1170,8 +1199,10 @@ static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *o /* We rely on normalized vector, i.e. stops HAVE to exist */ g_return_if_fail(ngr->getFirstStop() != NULL); - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(object), "stopmenu")); - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); + SPStop *stop = get_selected_stop(GTK_WIDGET(object)); + if (!stop) { + return; + } csel = static_cast<SPColorSelector*>(g_object_get_data(G_OBJECT(object), "cselector")); SPColor color; @@ -1190,8 +1221,20 @@ static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *o blocked = FALSE; - Inkscape::UI::Widget::ColorPreview *cpv = static_cast<Inkscape::UI::Widget::ColorPreview *>(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "preview")); - cpv->setRgba32(sp_stop_get_rgba32(stop)); + // Set the color in the selected stop after change + GtkWidget *combo_box = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(object), "combo_box")); + if (combo_box) { + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(combo_box), &iter)) { + GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model (GTK_COMBO_BOX(combo_box)); + + Inkscape::UI::Widget::ColorPreview *cp = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop))); + GdkPixbuf *pb = cp->toPixbuf(64, 16); + + gtk_list_store_set (store, &iter, 0, pb, /*1, repr->attribute("id"),*/ 2, stop, -1); + } + } + } /* diff --git a/src/widgets/gradient-vector.h b/src/widgets/gradient-vector.h index b198895e7..f33240504 100644 --- a/src/widgets/gradient-vector.h +++ b/src/widgets/gradient-vector.h @@ -29,6 +29,7 @@ #define SP_IS_GRADIENT_VECTOR_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_GRADIENT_VECTOR_SELECTOR)) class SPDocument; +class SPObject; class SPGradient; class SPStop; @@ -42,13 +43,16 @@ struct SPGradientVectorSelector { SPDocument *doc; SPGradient *gr; - /* Vector menu */ - GtkWidget *menu; + /* ComboBox of gradient vectors */ + GtkWidget *combo_box; + GtkListStore *store; sigc::connection gradient_release_connection; sigc::connection defs_release_connection; sigc::connection defs_modified_connection; + gulong combo_connection; + void setSwatched(); }; @@ -71,6 +75,7 @@ SPGradient *sp_gradient_vector_selector_get_gradient (SPGradientVectorSelector * /* fixme: rethink this (Lauris) */ GtkWidget *sp_gradient_vector_editor_new (SPGradient *gradient, SPStop *stop = NULL); +gchar *gr_prepare_label (SPObject *obj); #endif // SEEN_GRADIENT_VECTOR_H diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index d330e2bac..d67160483 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -267,11 +267,18 @@ sp_paint_selector_init(SPPaintSelector *psel) } /* Frame */ - psel->frame = gtk_frame_new(""); + psel->label = gtk_label_new(""); + GtkWidget *lbbox = gtk_hbox_new(FALSE, 4); + gtk_widget_show(psel->label); + gtk_box_pack_start(GTK_BOX(lbbox), psel->label, false, false, 4); + gtk_box_pack_start(GTK_BOX(psel), lbbox, false, false, 4); + + psel->frame = gtk_vbox_new(FALSE, 4); gtk_widget_show(psel->frame); - gtk_container_set_border_width(GTK_CONTAINER(psel->frame), 0); + //gtk_container_set_border_width(GTK_CONTAINER(psel->frame), 0); gtk_box_pack_start(GTK_BOX(psel), psel->frame, TRUE, TRUE, 0); + /* Last used color */ psel->color.set( 0.0, 0.0, 0.0 ); psel->alpha = 1.0; @@ -573,7 +580,7 @@ sp_paint_selector_set_mode_empty(SPPaintSelector *psel) sp_paint_selector_clear_frame(psel); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("No objects")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>No objects</b>")); } static void @@ -584,7 +591,7 @@ sp_paint_selector_set_mode_multiple(SPPaintSelector *psel) sp_paint_selector_clear_frame(psel); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Multiple styles")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Multiple styles</b>")); } static void @@ -595,7 +602,7 @@ sp_paint_selector_set_mode_unset(SPPaintSelector *psel) sp_paint_selector_clear_frame(psel); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Paint is undefined")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Paint is undefined</b>")); } static void @@ -606,7 +613,8 @@ sp_paint_selector_set_mode_none(SPPaintSelector *psel) sp_paint_selector_clear_frame(psel); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("No paint")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>No paint</b>")); + } /* Color paint */ @@ -663,6 +671,7 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec g_signal_connect(G_OBJECT(csel), "changed", G_CALLBACK(sp_paint_selector_color_changed), psel); /* Pack everything to frame */ gtk_container_add(GTK_CONTAINER(psel->frame), vb); + psel->selector = vb; /* Set color */ @@ -670,7 +679,8 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec } - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Flat color")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Flat color</b>")); + #ifdef SP_PS_VERBOSE g_print("Color req\n"); #endif @@ -733,10 +743,10 @@ static void sp_paint_selector_set_mode_gradient(SPPaintSelector *psel, SPPaintSe if (mode == SPPaintSelector::MODE_GRADIENT_LINEAR) { SP_GRADIENT_SELECTOR(gsel)->setMode(SPGradientSelector::MODE_LINEAR); //sp_gradient_selector_set_mode(SP_GRADIENT_SELECTOR(gsel), SP_GRADIENT_SELECTOR_MODE_LINEAR); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Linear gradient")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Linear gradient</b>")); } else { SP_GRADIENT_SELECTOR(gsel)->setMode(SPGradientSelector::MODE_RADIAL); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Radial gradient")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Radial gradient</b>")); } #ifdef SP_PS_VERBOSE g_print("Gradient req\n"); @@ -1016,7 +1026,7 @@ static void sp_paint_selector_set_mode_pattern(SPPaintSelector *psel, SPPaintSel psel->selector = tbl; g_object_set_data(G_OBJECT(psel->selector), "pattern-selector", tbl); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Pattern fill")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Pattern fill</b>")); } #ifdef SP_PS_VERBOSE g_print("Pattern req\n"); @@ -1091,7 +1101,7 @@ static void sp_paint_selector_set_mode_swatch(SPPaintSelector *psel, SPPaintSele psel->selector = GTK_WIDGET(swatchsel->gobj()); g_object_set_data(G_OBJECT(psel->selector), "swatch-selector", swatchsel); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Swatch fill")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Swatch fill</b>")); } #ifdef SP_PS_VERBOSE diff --git a/src/widgets/paint-selector.h b/src/widgets/paint-selector.h index 69cfa602e..7400987ee 100644 --- a/src/widgets/paint-selector.h +++ b/src/widgets/paint-selector.h @@ -72,6 +72,7 @@ struct SPPaintSelector { GtkWidget *evenodd, *nonzero; GtkWidget *frame, *selector; + GtkWidget *label; SPColor color; float alpha; diff --git a/src/widgets/stroke-marker-selector.cpp b/src/widgets/stroke-marker-selector.cpp new file mode 100644 index 000000000..a39ebf8be --- /dev/null +++ b/src/widgets/stroke-marker-selector.cpp @@ -0,0 +1,458 @@ +/** + * @file + * Combobox for selecting dash patterns - implementation. + */ +/* Author: + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Maximilian Albert <maximilian.albert@gmail.com> + * + * Copyright (C) 2002 Lauris Kaplinski + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "stroke-marker-selector.h" + +#include <cstring> +#include <string> +#include <glibmm/i18n.h> +#include <2geom/coord.h> + + +#include "style.h" +#include "dialogs/dialog-events.h" +#include "desktop-handles.h" +#include "desktop-style.h" +#include "preferences.h" +#include "path-prefix.h" +#include "io/sys.h" +#include "marker.h" +#include "sp-defs.h" +#include "sp-root.h" +#include "ui/cache/svg_preview_cache.h" +#include "helper/stock-items.h" + +#include <gtkmm/adjustment.h> +#include "ui/widget/spinbutton.h" + +static Inkscape::UI::Cache::SvgPreview svg_preview_cache; + +MarkerComboBox::MarkerComboBox(gchar const *id) : + Gtk::ComboBox(), + combo_id(id), + updating(false), + is_history(false) +{ + + marker_store = Gtk::ListStore::create(marker_columns); + set_model(marker_store); + pack_start(image_renderer, false); + pack_end(label_renderer, true); + label_renderer.set_padding(5, 0); + image_renderer.set_padding(5, 0); + set_cell_data_func(label_renderer, sigc::mem_fun(*this, &MarkerComboBox::prepareLabelRenderer)); + set_cell_data_func(image_renderer, sigc::mem_fun(*this, &MarkerComboBox::prepareImageRenderer)); + gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(gobj()), MarkerComboBox::separator_cb, NULL, NULL); + + empty_image = new Gtk::Image(); + + sandbox = ink_markers_preview_doc (); + desktop = inkscape_active_desktop(); + doc = sp_desktop_document(desktop); + + init_combo(); + + show(); +} + +MarkerComboBox::~MarkerComboBox() { + delete combo_id; + delete sandbox; +} + +/** + * Init the combobox widget to display markers from markers.svg + */ +void +MarkerComboBox::init_combo() +{ + updating = false; + + if (!doc) { + Gtk::TreeModel::Row row = *(marker_store->append()); + row[marker_columns.label] = _("No document selected"); + row[marker_columns.image] = NULL; + set_sensitive(false); + set_current(NULL); + return; + } + + static SPDocument *markers_doc = NULL; + + // add "None" + Gtk::TreeModel::Row row = *(marker_store->append()); + row[marker_columns.label] = _("None"); + row[marker_columns.marker] = g_strdup("none"); + row[marker_columns.image] = NULL; + + // find and load markers.svg + if (markers_doc == NULL) { + char *markers_source = g_build_filename(INKSCAPE_MARKERSDIR, "markers.svg", NULL); + if (Inkscape::IO::file_test(markers_source, G_FILE_TEST_IS_REGULAR)) { + markers_doc = SPDocument::createNewDoc(markers_source, FALSE); + } + g_free(markers_source); + } + + // suck in from current doc + is_history = true; + sp_marker_list_from_doc(doc); + is_history = false; + + // add separator + Gtk::TreeModel::Row row_sep = *(marker_store->append()); + row_sep[marker_columns.label] = "Separator"; + row_sep[marker_columns.isseparator] = true; + row_sep[marker_columns.image] = NULL; + + // suck in from markers.svg + if (markers_doc) { + doc->ensureUpToDate(); + sp_marker_list_from_doc(markers_doc); + } + + set_sensitive(true); + + /* Set history */ + set_current(NULL); +} + +/** + * Sets the current marker in the marker combobox. + */ +void MarkerComboBox::set_current(SPObject *marker) +{ + updating = true; + + if (marker != NULL) { + bool mark_is_stock = false; + if (marker->getRepr()->attribute("inkscape:stockid")) { + mark_is_stock = true; + } + + gchar *markname = 0; + if (mark_is_stock) { + markname = g_strdup(marker->getRepr()->attribute("inkscape:stockid")); + } else { + markname = g_strdup(marker->getRepr()->attribute("id")); + } + + set_selected(markname); + + g_free (markname); + } + else { + set_selected(NULL); + } + + updating = false; + +} +/** + * Return a uri string representing the current selected marker used for setting the marker style in the document + */ +const gchar * MarkerComboBox::get_active_marker_uri() +{ + /* Get Marker */ + const gchar *markid = get_active()->get_value(marker_columns.marker); + if (!markid) + { + return NULL; + } + + gchar const *marker = ""; + if (strcmp(markid, "none")) { + bool stockid = get_active()->get_value(marker_columns.isstock); + + gchar *markurn = g_strdup(markid); + if (stockid) markurn = g_strconcat("urn:inkscape:marker:",markid,NULL); + SPObject *mark = get_stock_item(markurn); + g_free(markurn); + if (mark) { + Inkscape::XML::Node *repr = mark->getRepr(); + marker = g_strconcat("url(#", repr->attribute("id"), ")", NULL); + } + } else { + marker = g_strdup(markid); + } + + return marker; +} + + +void MarkerComboBox::set_active_history() { + set_selected(get_active()->get_value(marker_columns.marker)); +} + + +void MarkerComboBox::set_selected(const gchar *name) { + + if (!name) { + set_active(0); + return; + } + + for(Gtk::TreeIter iter = marker_store->children().begin(); + iter != marker_store->children().end(); ++iter) { + Gtk::TreeModel::Row row = (*iter); + if (row[marker_columns.marker] && + !strcmp(row[marker_columns.marker], name)) { + set_active(iter); + if (strcmp(name, "none")) + set_history(row); + return; + } + } +} + +void MarkerComboBox::set_history(Gtk::TreeModel::Row match_row) { + + if (!match_row) { + return; + } + + for(Gtk::TreeIter iter = marker_store->children().begin(); + iter != marker_store->children().end(); ++iter) { + Gtk::TreeModel::Row row = (*iter); + if (row[marker_columns.history] && + !strcmp(row[marker_columns.marker], match_row[marker_columns.marker])) { + return; + } + } + + // Add a new row to the history + Gtk::TreeModel::Row row = *(marker_store->insert_after(marker_store->children().begin())); + row[marker_columns.marker] = g_strdup(match_row.get_value(marker_columns.marker)); + row[marker_columns.label] = match_row.get_value(marker_columns.label); + row[marker_columns.isstock] = match_row.get_value(marker_columns.isstock); + row[marker_columns.image] = match_row.get_value(marker_columns.image); + row[marker_columns.history] = true; +} + +/** + * Pick up all markers from source, except those that are in + * current_doc (if non-NULL), and add items to the combo. + */ +void MarkerComboBox::sp_marker_list_from_doc(SPDocument *source) +{ + GSList *ml = get_marker_list(source); + GSList *clean_ml = NULL; + + for (; ml != NULL; ml = ml->next) { + if (!SP_IS_MARKER(ml->data)) + continue; + + // Add to the list of markers we really do wish to show + clean_ml = g_slist_prepend (clean_ml, ml->data); + } + add_markers(clean_ml, source); + + g_slist_free (ml); + g_slist_free (clean_ml); +} + +/** + * Returns a list of markers in the defs of the given source document as a GSList object + * Returns NULL if there are no markers in the document. + */ +GSList *MarkerComboBox::get_marker_list (SPDocument *source) +{ + if (source == NULL) + return NULL; + + GSList *ml = NULL; + SPDefs *defs = source->getDefs(); + for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) + { + if (SP_IS_MARKER(child)) { + ml = g_slist_prepend (ml, child); + } + } + return ml; +} + +/** + * Adds previews of markers in marker_list to the combo + */ +void MarkerComboBox::add_markers (GSList *marker_list, SPDocument *source) +{ + // Do this here, outside of loop, to speed up preview generation: + Inkscape::Drawing drawing; + unsigned const visionkey = SPItem::display_key_new(1); + drawing.setRoot(sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY)); + + for (; marker_list != NULL; marker_list = marker_list->next) { + + Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(marker_list->data)->getRepr(); + bool isstock = (repr->attribute("inkscape:stockid")); + gchar const *markid = repr->attribute("id"); + + // generate preview + Gtk::Image *prv = create_marker_image (22, markid, source, drawing, visionkey); + prv->show(); + + Gtk::TreeModel::Row row = *(marker_store->append()); + row[marker_columns.label] = g_strdup(markid); + row[marker_columns.marker] = g_strdup(markid); + row[marker_columns.isstock] = isstock; + row[marker_columns.image] = prv; + row[marker_columns.history] = is_history; + + } + + sandbox->getRoot()->invoke_hide(visionkey); +} + +/** + * Creates a copy of the marker named mname, determines its visible and renderable + * area in the bounding box, and then renders it. This allows us to fill in + * preview images of each marker in the marker combobox. + */ +Gtk::Image * +MarkerComboBox::create_marker_image(unsigned psize, gchar const *mname, + SPDocument *source, Inkscape::Drawing &drawing, unsigned /*visionkey*/) +{ + // Retrieve the marker named 'mname' from the source SVG document + SPObject const *marker = source->getObjectById(mname); + if (marker == NULL) { + return NULL; + } + + // Create a copy repr of the marker with id="sample" + Inkscape::XML::Document *xml_doc = sandbox->getReprDoc(); + Inkscape::XML::Node *mrepr = marker->getRepr()->duplicate(xml_doc); + mrepr->setAttribute("id", "sample"); + + // Replace the old sample in the sandbox by the new one + Inkscape::XML::Node *defsrepr = sandbox->getObjectById("defs")->getRepr(); + SPObject *oldmarker = sandbox->getObjectById("sample"); + if (oldmarker) { + oldmarker->deleteObject(false); + } + + // TODO - This causes a SIGTRAP on windows + defsrepr->appendChild(mrepr); + + Inkscape::GC::release(mrepr); + +// Uncomment this to get the sandbox documents saved (useful for debugging) + //FILE *fp = fopen (g_strconcat(combo_id, mname, ".svg", NULL), "w"); + //sp_repr_save_stream(sandbox->getReprDoc(), fp); + //fclose (fp); + + // object to render; note that the id is the same as that of the combo we're building + SPObject *object = sandbox->getObjectById(combo_id); + sandbox->getRoot()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + sandbox->ensureUpToDate(); + + if (object == NULL || !SP_IS_ITEM(object)) { + return NULL; // sandbox broken? + } + + SPItem *item = SP_ITEM(object); + // Find object's bbox in document + Geom::OptRect dbox = item->documentVisualBounds(); + + if (!dbox) { + return NULL; + } + + /* Update to renderable state */ + double sf = 0.8; + + gchar *cache_name = g_strconcat(combo_id, mname, NULL); + Glib::ustring key = svg_preview_cache.cache_key(source->getURI(), cache_name, psize); + g_free (cache_name); + Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key)); + + if (!pixbuf) { + pixbuf = Glib::wrap(render_pixbuf(drawing, sf, *dbox, psize)); + svg_preview_cache.set_preview_in_cache(key, pixbuf->gobj()); + } + + // Create widget + Gtk::Image *pb = new Gtk::Image(pixbuf); + + return pb; +} + +void MarkerComboBox::prepareLabelRenderer( Gtk::TreeModel::const_iterator const &row ) { + Glib::ustring name=(*row)[marker_columns.label]; + label_renderer.property_markup() = name.c_str(); +} + +void MarkerComboBox::prepareImageRenderer( Gtk::TreeModel::const_iterator const &row ) { + + Gtk::Image *image = (*row)[marker_columns.image]; + if (image) + image_renderer.property_pixbuf() = image->get_pixbuf(); + else + image_renderer.property_pixbuf() = empty_image->get_pixbuf(); +} + +gboolean MarkerComboBox::separator_cb (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { + + gboolean sep = FALSE; + gtk_tree_model_get(model, iter, 5, &sep, -1); + return sep; +} + +/** + * Returns a new document containing default start, mid, and end markers. + */ +SPDocument *MarkerComboBox::ink_markers_preview_doc () +{ +gchar const *buffer = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" +" <defs id=\"defs\" />" + +" <g id=\"marker-start\">" +" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:url(#sample);marker-mid:none;marker-end:none\"" +" d=\"M 12.5,13 L 25,13\" id=\"path1\" />" +" <rect style=\"fill:none;stroke:none\" id=\"rect2\"" +" width=\"25\" height=\"25\" x=\"0\" y=\"0\" />" +" </g>" + +" <g id=\"marker-mid\">" +" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:none;marker-mid:url(#sample);marker-end:none\"" +" d=\"M 0,113 L 12.5,113 L 25,113\" id=\"path11\" />" +" <rect style=\"fill:none;stroke:none\" id=\"rect22\"" +" width=\"25\" height=\"25\" x=\"0\" y=\"100\" />" +" </g>" + +" <g id=\"marker-end\">" +" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:none;marker-mid:none;marker-end:url(#sample)\"" +" d=\"M 0,213 L 12.5,213\" id=\"path111\" />" +" <rect style=\"fill:none;stroke:none\" id=\"rect222\"" +" width=\"25\" height=\"25\" x=\"0\" y=\"200\" />" +" </g>" + +"</svg>"; + + return SPDocument::createNewDocFromMem (buffer, strlen(buffer), FALSE); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/stroke-marker-selector.h b/src/widgets/stroke-marker-selector.h new file mode 100644 index 000000000..4365b7e2a --- /dev/null +++ b/src/widgets/stroke-marker-selector.h @@ -0,0 +1,104 @@ +#ifndef SEEN_SP_MARKER_SELECTOR_NEW_H +#define SEEN_SP_MARKER_SELECTOR_NEW_H + +/* Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Maximilian Albert <maximilian.albert> (gtkmm-ification) + * + * Copyright (C) 2002 Lauris Kaplinski + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <gtkmm/box.h> +#include <gtkmm/combobox.h> +#include <gtkmm/liststore.h> + +#include <sigc++/signal.h> + +#include "document.h" +#include "inkscape.h" +#include "display/drawing.h" + +namespace Gtk { +class Container; +class Adjustment; +} + +/** + * ComboBox derived class for selecting stroke markers. + */ + +class MarkerComboBox : public Gtk::ComboBox { +public: + MarkerComboBox(gchar const *id); + ~MarkerComboBox(); + + sigc::signal<void> changed_signal; + + void set_current(SPObject *marker); + void set_active_history(); + void set_selected(const gchar *name); + const gchar *get_active_marker_uri(); + bool update() { return updating; }; + gchar const *get_id() { return combo_id; }; + +private: + + Glib::RefPtr<Gtk::ListStore> marker_store; + gchar const *combo_id; + bool updating; + bool is_history; + SPDesktop *desktop; + SPDocument *doc; + SPDocument *sandbox; + Gtk::Image *empty_image; + Gtk::CellRendererText label_renderer; + Gtk::CellRendererPixbuf image_renderer; + + class MarkerColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn<Glib::ustring> label; + Gtk::TreeModelColumn<const gchar *> marker; // ustring doesnt work here on windows due to unicode + Gtk::TreeModelColumn<bool> isstock; + Gtk::TreeModelColumn<Gtk::Image *> image; + Gtk::TreeModelColumn<bool> history; + Gtk::TreeModelColumn<bool> isseparator; + + MarkerColumns() { + add(label); add(marker); add(isstock); add(image); add(history); add(isseparator); + } + }; + MarkerColumns marker_columns; + + void init_combo(); + void set_history(Gtk::TreeModel::Row match_row); + void sp_marker_list_from_doc(SPDocument *source); + GSList *get_marker_list (SPDocument *source); + void add_markers (GSList *marker_list, SPDocument *source); + SPDocument *ink_markers_preview_doc (); + Gtk::Image * create_marker_image(unsigned psize, gchar const *mname, + SPDocument *source, Inkscape::Drawing &drawing, unsigned /*visionkey*/); + + /* + * Callbacks for drawing the combo box + */ + void prepareLabelRenderer( Gtk::TreeModel::const_iterator const &row ); + void prepareImageRenderer( Gtk::TreeModel::const_iterator const &row ); + static gboolean separator_cb (GtkTreeModel *model, GtkTreeIter *iter, gpointer data); + + +}; + +#endif // SEEN_SP_MARKER_SELECTOR_NEW_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index a49a26734..f6afec18e 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -55,27 +55,25 @@ #include "xml/repr.h" #include "stroke-style.h" +#include "stroke-marker-selector.h" #include "fill-style.h" // to get sp_fill_style_widget_set_desktop #include "fill-n-stroke-factory.h" -#include <gtkmm/optionmenu.h> #include "verbs.h" using Inkscape::DocumentUndo; -/** Marker selection option menus */ -static Gtk::OptionMenu * marker_start_menu = NULL; -static Gtk::OptionMenu * marker_mid_menu = NULL; -static Gtk::OptionMenu * marker_end_menu = NULL; -sigc::connection marker_start_menu_connection; -sigc::connection marker_mid_menu_connection; -sigc::connection marker_end_menu_connection; +static MarkerComboBox *start_marker_combobox = NULL; +static MarkerComboBox *mid_marker_combobox = NULL; +static MarkerComboBox *end_marker_combobox = NULL; -static SPObject *ink_extract_marker_name(gchar const *n, SPDocument *doc); -static void ink_markers_menu_update(Gtk::Container* spw, SPMarkerLoc const which); +sigc::connection start_marker_connection; +sigc::connection mid_marker_connection; +sigc::connection end_marker_connection; -static Inkscape::UI::Cache::SvgPreview svg_preview_cache; +static SPObject *ink_extract_marker_name(gchar const *n, SPDocument *doc); +static void ink_markers_combo_update(Gtk::Container* spw, SPMarkerLoc const which); Gtk::Widget *sp_stroke_style_paint_widget_new(void) { @@ -87,8 +85,6 @@ void sp_stroke_style_widget_set_desktop(Gtk::Widget *widget, SPDesktop *desktop) sp_fill_style_widget_set_desktop(widget, desktop); } - - /* Line */ static void sp_stroke_style_line_selection_modified(SPWidget *spw, Inkscape::Selection *selection, guint flags, gpointer data); @@ -105,7 +101,7 @@ static void sp_stroke_style_miterlimit_changed(Gtk::Container *spw); static void sp_stroke_style_any_toggled(Gtk::ToggleButton *tb, Gtk::Container *spw); static void sp_stroke_style_line_dash_changed(Gtk::Container *spw); -static void sp_stroke_style_update_marker_menus(Gtk::Container *spw, GSList const *objects); +static void sp_stroke_style_update_marker_combo(Gtk::Container *spw, GSList const *objects); /** @@ -145,303 +141,12 @@ sp_stroke_radio_button(Gtk::RadioButton *tb, char const *icon, } /** - * Create sa copy of the marker named mname, determines its visible and renderable - * area in menu_id's bounding box, and then renders it. This allows us to fill in - * preview images of each marker in the marker menu. - */ -static Gtk::Image * -sp_marker_prev_new(unsigned psize, gchar const *mname, - SPDocument *source, SPDocument *sandbox, - gchar const *menu_id, Inkscape::Drawing &drawing, unsigned /*visionkey*/) -{ - // Retrieve the marker named 'mname' from the source SVG document - SPObject const *marker = source->getObjectById(mname); - if (marker == NULL) { - return NULL; - } - - // Create a copy repr of the marker with id="sample" - Inkscape::XML::Document *xml_doc = sandbox->getReprDoc(); - Inkscape::XML::Node *mrepr = marker->getRepr()->duplicate(xml_doc); - mrepr->setAttribute("id", "sample"); - - // Replace the old sample in the sandbox by the new one - Inkscape::XML::Node *defsrepr = sandbox->getObjectById("defs")->getRepr(); - SPObject *oldmarker = sandbox->getObjectById("sample"); - if (oldmarker) { - oldmarker->deleteObject(false); - } - defsrepr->appendChild(mrepr); - Inkscape::GC::release(mrepr); - -// Uncomment this to get the sandbox documents saved (useful for debugging) - //FILE *fp = fopen (g_strconcat(menu_id, mname, ".svg", NULL), "w"); - //sp_repr_save_stream(sandbox->getReprDoc(), fp); - //fclose (fp); - - // object to render; note that the id is the same as that of the menu we're building - SPObject *object = sandbox->getObjectById(menu_id); - sandbox->getRoot()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); - sandbox->ensureUpToDate(); - - if (object == NULL || !SP_IS_ITEM(object)) { - return NULL; // sandbox broken? - } - - SPItem *item = SP_ITEM(object); - // Find object's bbox in document - Geom::OptRect dbox = item->documentVisualBounds(); - - if (!dbox) { - return NULL; - } - - /* Update to renderable state */ - double sf = 0.8; - - gchar *cache_name = g_strconcat(menu_id, mname, NULL); - Glib::ustring key = svg_preview_cache.cache_key(source->getURI(), cache_name, psize); - g_free (cache_name); - // TODO: is this correct? - Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key)); - - if (!pixbuf) { - pixbuf = Glib::wrap(render_pixbuf(drawing, sf, *dbox, psize)); - svg_preview_cache.set_preview_in_cache(key, pixbuf->gobj()); - } - - // Create widget - Gtk::Image *pb = new Gtk::Image(pixbuf); - - return pb; -} - -/** - * Returns a list of markers in the defs of the given source document as a GSList object - * Returns NULL if there are no markers in the document. - */ -GSList * -ink_marker_list_get (SPDocument *source) -{ - if (source == NULL) - return NULL; - - GSList *ml = NULL; - SPDefs *defs = source->getDefs(); - for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) - { - if (SP_IS_MARKER(child)) { - ml = g_slist_prepend (ml, child); - } - } - return ml; -} - -#define MARKER_ITEM_MARGIN 0 - -/** - * Adds previews of markers in marker_list to the given menu widget - */ -static void -sp_marker_menu_build (Gtk::Menu *m, GSList *marker_list, SPDocument *source, SPDocument *sandbox, gchar const *menu_id) -{ - // Do this here, outside of loop, to speed up preview generation: - Inkscape::Drawing drawing; - unsigned const visionkey = SPItem::display_key_new(1); - drawing.setRoot(sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY)); - - for (; marker_list != NULL; marker_list = marker_list->next) { - Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(marker_list->data)->getRepr(); - Gtk::MenuItem *i = new Gtk::MenuItem(); - i->show(); - - if (repr->attribute("inkscape:stockid")) { - i->set_data("stockid", (void *) "true"); - } else { - i->set_data("stockid", (void *) "false"); - } - - gchar const *markid = repr->attribute("id"); - i->set_data("marker", (void *) markid); - - Gtk::HBox *hb = new Gtk::HBox(false, MARKER_ITEM_MARGIN); - hb->show(); - - // generate preview - - Gtk::Image *prv = sp_marker_prev_new (22, markid, source, sandbox, menu_id, drawing, visionkey); - prv->show(); - hb->pack_start(*prv, false, false, 6); - - // create label - Gtk::Label *l = new Gtk::Label(repr->attribute("id")); - l->show(); - l->set_alignment(0.0, 0.5); - - hb->pack_start(*l, true, true, 0); - - hb->show(); - i->add(*hb); - - m->append(*i); - } - - sandbox->getRoot()->invoke_hide(visionkey); -} - -/** - * Pick up all markers from source, except those that are in - * current_doc (if non-NULL), and add items to the m menu. - */ -static void sp_marker_list_from_doc(Gtk::Menu *m, SPDocument * /*current_doc*/, SPDocument *source, SPDocument * /*markers_doc*/, SPDocument *sandbox, gchar const *menu_id) -{ - GSList *ml = ink_marker_list_get(source); - GSList *clean_ml = NULL; - - for (; ml != NULL; ml = ml->next) { - if (!SP_IS_MARKER(ml->data)) - continue; - - // Add to the list of markers we really do wish to show - clean_ml = g_slist_prepend (clean_ml, ml->data); - } - sp_marker_menu_build(m, clean_ml, source, sandbox, menu_id); - - g_slist_free (ml); - g_slist_free (clean_ml); -} - -/** - * Returns a new document containing default start, mid, and end markers. - */ -SPDocument * -ink_markers_preview_doc () -{ -gchar const *buffer = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" -" <defs id=\"defs\" />" - -" <g id=\"marker-start\">" -" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:url(#sample);marker-mid:none;marker-end:none\"" -" d=\"M 12.5,13 L 25,13\" id=\"path1\" />" -" <rect style=\"fill:none;stroke:none\" id=\"rect2\"" -" width=\"25\" height=\"25\" x=\"0\" y=\"0\" />" -" </g>" - -" <g id=\"marker-mid\">" -" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:none;marker-mid:url(#sample);marker-end:none\"" -" d=\"M 0,113 L 12.5,113 L 25,113\" id=\"path11\" />" -" <rect style=\"fill:none;stroke:none\" id=\"rect22\"" -" width=\"25\" height=\"25\" x=\"0\" y=\"100\" />" -" </g>" - -" <g id=\"marker-end\">" -" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:none;marker-mid:none;marker-end:url(#sample)\"" -" d=\"M 0,213 L 12.5,213\" id=\"path111\" />" -" <rect style=\"fill:none;stroke:none\" id=\"rect222\"" -" width=\"25\" height=\"25\" x=\"0\" y=\"200\" />" -" </g>" - -"</svg>"; - - return SPDocument::createNewDocFromMem (buffer, strlen(buffer), FALSE); -} - -static void -ink_marker_menu_create_menu(Gtk::Menu *m, gchar const *menu_id, SPDocument *doc, SPDocument *sandbox) -{ - static SPDocument *markers_doc = NULL; - - // add "None" - Gtk::MenuItem *i = new Gtk::MenuItem(); - i->show(); - - i->set_data("marker", (void *) "none"); - - Gtk::HBox *hb = new Gtk::HBox(false, MARKER_ITEM_MARGIN); - hb->show(); - - Gtk::Label *l = new Gtk::Label( _("None") ); - l->show(); - l->set_alignment(0.0, 0.5); - - hb->pack_start(*l, true, true, 0); - - hb->show(); - i->add(*hb); - m->append(*i); - - // find and load markers.svg - if (markers_doc == NULL) { - char *markers_source = g_build_filename(INKSCAPE_MARKERSDIR, "markers.svg", NULL); - if (Inkscape::IO::file_test(markers_source, G_FILE_TEST_IS_REGULAR)) { - markers_doc = SPDocument::createNewDoc(markers_source, FALSE); - } - g_free(markers_source); - } - - // suck in from current doc - sp_marker_list_from_doc(m, NULL, doc, markers_doc, sandbox, menu_id); - - // add separator - { - //Gtk::Separator *i = gtk_separator_menu_item_new(); - Gtk::SeparatorMenuItem *i = new Gtk::SeparatorMenuItem(); - i->show(); - m->append(*i); - } - - // suck in from markers.svg - if (markers_doc) { - doc->ensureUpToDate(); - sp_marker_list_from_doc(m, doc, markers_doc, NULL, sandbox, menu_id); - } - -} - -/** - * Creates a menu widget to display markers from markers.svg - */ -static Gtk::OptionMenu * -ink_marker_menu(Gtk::Widget * /*tbl*/, gchar const *menu_id, SPDocument *sandbox) -{ - SPDesktop *desktop = inkscape_active_desktop(); - SPDocument *doc = sp_desktop_document(desktop); - Gtk::OptionMenu *mnu = new Gtk::OptionMenu(); - - /* Create new menu widget */ - Gtk::Menu *m = new Gtk::Menu(); - m->show(); - - mnu->set_data("updating", (gpointer) FALSE); - - if (!doc) { - Gtk::MenuItem *i = new Gtk::MenuItem(_("No document selected")); - i->show(); - m->append(*i); - mnu->set_sensitive(false); - - } else { - ink_marker_menu_create_menu(m, menu_id, doc, sandbox); - - mnu->set_sensitive(true); - } - - mnu->set_data("menu_id", const_cast<gchar *>(menu_id)); - mnu->set_menu(*m); - - /* Set history */ - mnu->set_history(0); - - return mnu; -} - -/** - * Handles when user selects one of the markers from the marker menu. - * Defines a uri string to refer to it, then applies it to all selected + * Handles when user selects one of the markers from the marker combobox. + * Gets the marker uri string and applies it to all selected * items in the current desktop. */ static void -sp_marker_select(Gtk::OptionMenu *mnu, Gtk::Container *spw, SPMarkerLoc const which) +sp_marker_select(MarkerComboBox *marker_combo, Gtk::Container *spw, SPMarkerLoc const which) { if (spw->get_data("update")) { return; @@ -454,33 +159,17 @@ sp_marker_select(Gtk::OptionMenu *mnu, Gtk::Container *spw, SPMarkerLoc const wh } /* Get Marker */ - if (!mnu->get_menu()->get_active()->get_data("marker")) - { - return; - } - gchar *markid = static_cast<gchar *>(mnu->get_menu()->get_active()->get_data("marker")); - gchar const *marker = ""; - if (strcmp(markid, "none")) { - gchar *stockid = static_cast<gchar *>(mnu->get_menu()->get_active()->get_data("stockid")); - - gchar *markurn = markid; - if (!strcmp(stockid,"true")) markurn = g_strconcat("urn:inkscape:marker:",markid,NULL); - SPObject *mark = get_stock_item(markurn); - if (mark) { - Inkscape::XML::Node *repr = mark->getRepr(); - marker = g_strconcat("url(#", repr->attribute("id"), ")", NULL); - } - } else { - marker = markid; - } + gchar const *marker = marker_combo->get_active_marker_uri(); + + SPCSSAttr *css = sp_repr_css_attr_new(); - gchar const *menu_id = static_cast<gchar const *>(mnu->get_data("menu_id")); - sp_repr_css_set_property(css, menu_id, marker); + gchar const *combo_id = marker_combo->get_id(); + sp_repr_css_set_property(css, combo_id, marker); - // Also update the marker dropdown menus, so the document's markers - // show up at the top of the menu + // Also update the marker combobox, so the document's markers + // show up at the top of the combobox // sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL); - ink_markers_menu_update(spw, which); + ink_markers_combo_update(spw, which); Inkscape::Selection *selection = sp_desktop_selection(desktop); GSList const *items = selection->itemList(); @@ -505,72 +194,26 @@ sp_marker_select(Gtk::OptionMenu *mnu, Gtk::Container *spw, SPMarkerLoc const wh }; -static unsigned int -ink_marker_menu_get_pos(Gtk::Menu *mnu, gchar const *markname) -{ - if (markname == NULL) - markname = static_cast<gchar const *>(mnu->get_active()->get_data("marker")); - - if (markname == NULL) - return 0; - - std::vector<Gtk::Widget *> kids = mnu->get_children(); - unsigned int i = 0; - for (; i < kids.size();) { - gchar const *mark = static_cast<gchar const *>(kids[i]->get_data("marker")); - if (mark && strcmp(mark, markname) == 0) { - break; - } - ++i; - } - - return i; -} - static void -ink_markers_menu_update(Gtk::Container* /*spw*/, SPMarkerLoc const which) { - SPDesktop *desktop = inkscape_active_desktop(); - SPDocument *document = sp_desktop_document(desktop); - SPDocument *sandbox = ink_markers_preview_doc (); - Gtk::Menu *m; - int pos; +ink_markers_combo_update(Gtk::Container* /*spw*/, SPMarkerLoc const which) { - // TODO: this code can be shortened by abstracting out marker_(start|mid|end)_... switch (which) { case SP_MARKER_LOC_START: - marker_start_menu_connection.block(); - pos = ink_marker_menu_get_pos(marker_start_menu->get_menu(), NULL); - m = new Gtk::Menu(); - m->show(); - ink_marker_menu_create_menu(m, "marker-start", document, sandbox); - marker_start_menu->remove_menu(); - marker_start_menu->set_menu(*m); - marker_start_menu->set_history(pos); - marker_start_menu_connection.unblock(); + start_marker_connection.block(); + start_marker_combobox->set_active_history(); + start_marker_connection.unblock(); break; case SP_MARKER_LOC_MID: - marker_mid_menu_connection.block(); - pos = ink_marker_menu_get_pos(marker_mid_menu->get_menu(), NULL); - m = new Gtk::Menu(); - m->show(); - ink_marker_menu_create_menu(m, "marker-mid", document, sandbox); - marker_mid_menu->remove_menu(); - marker_mid_menu->set_menu(*m); - marker_mid_menu->set_history(pos); - marker_mid_menu_connection.unblock(); + mid_marker_connection.block(); + mid_marker_combobox->set_active_history(); + mid_marker_connection.unblock(); break; case SP_MARKER_LOC_END: - marker_end_menu_connection.block(); - pos = ink_marker_menu_get_pos(marker_end_menu->get_menu(), NULL); - m = new Gtk::Menu(); - m->show(); - ink_marker_menu_create_menu(m, "marker-end", document, sandbox); - marker_end_menu->remove_menu(); - marker_end_menu->set_menu(*m); - marker_end_menu->set_history(pos); - marker_end_menu_connection.unblock(); + end_marker_connection.block(); + end_marker_combobox->set_active_history(); + end_marker_connection.unblock(); break; default: g_assert_not_reached(); @@ -675,7 +318,7 @@ Gtk::Container *sp_stroke_style_line_widget_new(void) // TODO: when this is gtkmmified, use an Inkscape::UI::Widget::ScalarUnit instead of the separate // spinbutton and unit selector for stroke width. In sp_stroke_style_line_update, use -// setHundredPercent to remember the aeraged width corresponding to 100%. Then the +// setHundredPercent to remember the averaged width corresponding to 100%. Then the // stroke_width_set_unit will be removed (because ScalarUnit takes care of conversions itself), and // with it, the two remaining calls of stroke_average_width, allowing us to get rid of that // function in desktop-style. @@ -822,48 +465,40 @@ Gtk::Container *sp_stroke_style_line_widget_new(void) i++; /* Drop down marker selectors*/ - // TODO: this code can be shortened by iterating over the possible menus! - - // doing this here once, instead of for each preview, to speed things up - SPDocument *sandbox = ink_markers_preview_doc (); - // TRANSLATORS: Path markers are an SVG feature that allows you to attach arbitrary shapes // (arrowheads, bullets, faces, whatever) to the start, end, or middle nodes of a path. - //spw_label(t, _("_Start Markers:"), 0, i); - marker_start_menu = ink_marker_menu(spw ,"marker-start", sandbox); - spw_label(t, _("_Start Markers:"), 0, i, marker_start_menu); - marker_start_menu->set_tooltip_text(_("Start Markers are drawn on the first node of a path or shape")); - marker_start_menu_connection = marker_start_menu->signal_changed().connect( - sigc::bind<Gtk::OptionMenu *, Gtk::Container *, SPMarkerLoc>( - sigc::ptr_fun(&sp_marker_select), marker_start_menu, spw, SP_MARKER_LOC_START)); - marker_start_menu->show(); - t->attach(*marker_start_menu, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); - spw->set_data("start_mark_menu", marker_start_menu); + start_marker_combobox = manage(new MarkerComboBox("marker-start")); + spw_label(t, _("_Start Markers:"), 0, i, start_marker_combobox); + start_marker_combobox->set_tooltip_text(_("Start Markers are drawn on the first node of a path or shape")); + start_marker_connection = start_marker_combobox->signal_changed().connect( + sigc::bind<MarkerComboBox *, Gtk::Container *, SPMarkerLoc>( + sigc::ptr_fun(&sp_marker_select), start_marker_combobox, spw, SP_MARKER_LOC_START)); + start_marker_combobox->show(); + t->attach(*start_marker_combobox, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); + spw->set_data("start_marker_combobox", start_marker_combobox); i++; - //spw_label(t, _("_Mid Markers:"), 0, i); - marker_mid_menu = ink_marker_menu(spw ,"marker-mid", sandbox); - spw_label(t, _("_Mid Markers:"), 0, i, marker_mid_menu); - marker_mid_menu->set_tooltip_text(_("Mid Markers are drawn on every node of a path or shape except the first and last nodes")); - marker_mid_menu_connection = marker_mid_menu->signal_changed().connect( - sigc::bind<Gtk::OptionMenu *, Gtk::Container *, SPMarkerLoc>( - sigc::ptr_fun(&sp_marker_select), marker_mid_menu,spw, SP_MARKER_LOC_MID)); - marker_mid_menu->show(); - t->attach(*marker_mid_menu, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); - spw->set_data("mid_mark_menu", marker_mid_menu); + mid_marker_combobox = manage(new MarkerComboBox("marker-mid")); + spw_label(t, _("_Mid Markers:"), 0, i, mid_marker_combobox); + mid_marker_combobox->set_tooltip_text(_("Mid Markers are drawn on every node of a path or shape except the first and last nodes")); + mid_marker_connection = mid_marker_combobox->signal_changed().connect( + sigc::bind<MarkerComboBox *, Gtk::Container *, SPMarkerLoc>( + sigc::ptr_fun(&sp_marker_select), mid_marker_combobox, spw, SP_MARKER_LOC_MID)); + mid_marker_combobox->show(); + t->attach(*mid_marker_combobox, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); + spw->set_data("mid_marker_combobox", mid_marker_combobox); i++; - //spw_label(t, _("_End Markers:"), 0, i); - marker_end_menu = ink_marker_menu(spw ,"marker-end", sandbox); - spw_label(t, _("_End Markers:"), 0, i, marker_end_menu); - marker_end_menu->set_tooltip_text(_("End Markers are drawn on the last node of a path or shape")); - marker_end_menu_connection = marker_end_menu->signal_changed().connect( - sigc::bind<Gtk::OptionMenu *, Gtk::Container *, SPMarkerLoc>( - sigc::ptr_fun(&sp_marker_select), marker_end_menu, spw, SP_MARKER_LOC_END)); - marker_end_menu->show(); - t->attach(*marker_end_menu, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); - spw->set_data("end_mark_menu", marker_end_menu); + end_marker_combobox = manage(new MarkerComboBox("marker-end")); + spw_label(t, _("_End Markers:"), 0, i, end_marker_combobox); + end_marker_combobox->set_tooltip_text(_("End Markers are drawn on the last node of a path or shape")); + end_marker_connection = end_marker_combobox->signal_changed().connect( + sigc::bind<MarkerComboBox *, Gtk::Container *, SPMarkerLoc>( + sigc::ptr_fun(&sp_marker_select), end_marker_combobox, spw, SP_MARKER_LOC_END)); + end_marker_combobox->show(); + t->attach(*end_marker_combobox, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); + spw->set_data("end_marker_combobox", end_marker_combobox); i++; // FIXME: we cheat and still use gtk+ signals @@ -1090,7 +725,7 @@ sp_stroke_style_line_update(Gtk::Container *spw, Inkscape::Selection *sel) SPStyle * const style = object->style; /* Markers */ - sp_stroke_style_update_marker_menus(spw, objects); // FIXME: make this desktop query too + sp_stroke_style_update_marker_combo(spw, objects); // FIXME: make this desktop query too /* Dash */ sp_dash_selector_set_from_style(dsel, style); // FIXME: make this desktop query too @@ -1270,6 +905,7 @@ static void sp_stroke_style_any_toggled(Gtk::ToggleButton *tb, Gtk::Container *s return; } + if (tb->get_active()) { gchar const *join @@ -1346,50 +982,18 @@ sp_stroke_style_set_cap_buttons(Gtk::Container *spw, Gtk::ToggleButton *active) tb->set_active(active == tb); } -/** - * Sets the current marker in the marker menu. - */ -static void -ink_marker_menu_set_current(SPObject *marker, Gtk::OptionMenu *mnu) -{ - mnu->set_data("update", GINT_TO_POINTER(TRUE)); - - Gtk::Menu *m = mnu->get_menu(); - if (marker != NULL) { - bool mark_is_stock = false; - if (marker->getRepr()->attribute("inkscape:stockid")) { - mark_is_stock = true; - } - - gchar *markname = 0; - if (mark_is_stock) { - markname = g_strdup(marker->getRepr()->attribute("inkscape:stockid")); - } else { - markname = g_strdup(marker->getRepr()->attribute("id")); - } - - int markpos = ink_marker_menu_get_pos(m, markname); - mnu->set_history(markpos); - - g_free (markname); - } - else { - mnu->set_history(0); - } - mnu->set_data("update", GINT_TO_POINTER(FALSE)); -} /** - * Updates the marker menus to highlight the appropriate marker and scroll to + * Updates the marker combobox to highlight the appropriate marker and scroll to * that marker. */ static void -sp_stroke_style_update_marker_menus(Gtk::Container *spw, GSList const *objects) +sp_stroke_style_update_marker_combo(Gtk::Container *spw, GSList const *objects) { struct { char const *key; int loc; } const keyloc[] = { - { "start_mark_menu", SP_MARKER_LOC_START }, - { "mid_mark_menu", SP_MARKER_LOC_MID }, - { "end_mark_menu", SP_MARKER_LOC_END } + { "start_marker_combobox", SP_MARKER_LOC_START }, + { "mid_marker_combobox", SP_MARKER_LOC_MID }, + { "end_marker_combobox", SP_MARKER_LOC_END } }; bool all_texts = true; @@ -1400,9 +1004,9 @@ sp_stroke_style_update_marker_menus(Gtk::Container *spw, GSList const *objects) } for (unsigned i = 0; i < G_N_ELEMENTS(keyloc); ++i) { - Gtk::OptionMenu *mnu = static_cast<Gtk::OptionMenu *>(spw->get_data(keyloc[i].key)); - // Per SVG spec, text objects cannot have markers; disable menus if only texts are selected - mnu->set_sensitive(!all_texts); + MarkerComboBox *combo = static_cast<MarkerComboBox *>(spw->get_data(keyloc[i].key)); + // Per SVG spec, text objects cannot have markers; disable combobox if only texts are selected + combo->set_sensitive(!all_texts); } // We show markers of the first object in the list only @@ -1412,11 +1016,11 @@ sp_stroke_style_update_marker_menus(Gtk::Container *spw, GSList const *objects) for (unsigned i = 0; i < G_N_ELEMENTS(keyloc); ++i) { // For all three marker types, - // find the corresponding menu - Gtk::OptionMenu *mnu = static_cast<Gtk::OptionMenu *>(spw->get_data(keyloc[i].key)); + // find the corresponding combobox item + MarkerComboBox *combo = static_cast<MarkerComboBox *>(spw->get_data(keyloc[i].key)); // Quit if we're in update state - if (mnu->get_data("update")) { + if (combo->update()) { return; } @@ -1425,13 +1029,14 @@ sp_stroke_style_update_marker_menus(Gtk::Container *spw, GSList const *objects) // Extract the name of the marker that the object uses SPObject *marker = ink_extract_marker_name(object->style->marker[keyloc[i].loc].value, object->document); - // Scroll the menu to that marker - ink_marker_menu_set_current(marker, mnu); + // Scroll the combobox to that marker + combo->set_current(marker); } else { - mnu->set_history(0); + combo->set_current(NULL); } } + } |
