diff options
Diffstat (limited to 'src/widgets/dash-selector.cpp')
| -rw-r--r-- | src/widgets/dash-selector.cpp | 578 |
1 files changed, 271 insertions, 307 deletions
diff --git a/src/widgets/dash-selector.cpp b/src/widgets/dash-selector.cpp index 49bca9a98..57f9259e2 100644 --- a/src/widgets/dash-selector.cpp +++ b/src/widgets/dash-selector.cpp @@ -1,4 +1,4 @@ -#define __SP_DASH_SELECTOR_C__ +#define __SP_DASH_SELECTOR_NEW_C__ /* * Optionmenu for selecting dash patterns @@ -6,6 +6,7 @@ * Author: * Lauris Kaplinski <lauris@kaplinski.com> * bulia byak <buliabyak@users.sf.net> + * Maximilian Albert <maximilian.albert@gmail.com> * * Copyright (C) 2002 Lauris Kaplinski * @@ -25,217 +26,189 @@ #include <gtk/gtk.h> #include <glibmm/i18n.h> -#include "../style.h" -#include "../dialogs/dialog-events.h" +#include "style.h" +#include "dialogs/dialog-events.h" + +#include <gtkmm/optionmenu.h> +#include <gtkmm/adjustment.h> +#include <gtkmm/spinbutton.h> + #include "dash-selector.h" -enum {CHANGED, LAST_SIGNAL}; +static double dash_0[] = {-1.0}; +static double dash_1_1[] = {1.0, 1.0, -1.0}; +static double dash_2_1[] = {2.0, 1.0, -1.0}; +static double dash_4_1[] = {4.0, 1.0, -1.0}; +static double dash_1_2[] = {1.0, 2.0, -1.0}; +static double dash_1_4[] = {1.0, 4.0, -1.0}; -struct SPDashSelector { - GtkHBox hbox; +static double *builtin_dashes[] = {dash_0, dash_1_1, dash_2_1, dash_4_1, dash_1_2, dash_1_4, NULL}; - GtkWidget *dash; - GtkObject *offset; -}; +static double **dashes = NULL; -struct SPDashSelectorClass { - GtkHBoxClass parent_class; +static void sp_dash_selector_menu_item_image_realize(Gtk::Image *px, double *pattern); - void (* changed) (SPDashSelector *dsel); -}; +SPDashSelector::SPDashSelector(Inkscape::XML::Node *drepr) { + // TODO: find something more sensible here!! + init_dashes(drepr); -double dash_0[] = {-1.0}; -double dash_1_1[] = {1.0, 1.0, -1.0}; -double dash_2_1[] = {2.0, 1.0, -1.0}; -double dash_4_1[] = {4.0, 1.0, -1.0}; -double dash_1_2[] = {1.0, 2.0, -1.0}; -double dash_1_4[] = {1.0, 4.0, -1.0}; + Gtk::Tooltips *tt = new Gtk::Tooltips(); -double *builtin_dashes[] = {dash_0, dash_1_1, dash_2_1, dash_4_1, dash_1_2, dash_1_4, NULL}; + dash = new Gtk::OptionMenu(); + tt->set_tip(*dash, _("Dash pattern")); + dash->show(); + this->pack_start(*dash, false, false, 0); -static double **dashes = NULL; + Gtk::Menu *m = new Gtk::Menu(); + m->show(); + for (int i = 0; dashes[i]; i++) { + Gtk::MenuItem *mi = menu_item_new(dashes[i]); + mi->show(); + m->append(*mi); + } + dash->set_menu(*m); -static void sp_dash_selector_class_init (SPDashSelectorClass *klass); -static void sp_dash_selector_init (SPDashSelector *dsel); -static GtkWidget *sp_dash_selector_menu_item_new (SPDashSelector *dsel, double *pattern); -static void sp_dash_selector_menu_item_image_realize (GtkWidget *mi, double *pattern); -static void sp_dash_selector_dash_activate (GtkObject *object, SPDashSelector *dsel); -static void sp_dash_selector_offset_value_changed (GtkAdjustment *adj, SPDashSelector *dsel); + offset = new Gtk::Adjustment(0.0, 0.0, 10.0, 0.1, 1.0, 1.0); + Gtk::SpinButton *sb = new Gtk::SpinButton(*offset, 0.1, 2); + tt->set_tip(*sb, _("Pattern offset")); -static GtkHBoxClass *parent_class; -static guint signals[LAST_SIGNAL] = {0}; + sp_dialog_defocus_on_enter_cpp(sb); + sb->show(); + this->pack_start(*sb, false, false, 0); + offset->signal_value_changed().connect(sigc::mem_fun(*this, &SPDashSelector::offset_value_changed)); -GtkType -sp_dash_selector_get_type (void) -{ - static GtkType type = 0; - if (!type) { - GtkTypeInfo info = { - "SPDashSelector", - sizeof (SPDashSelector), - sizeof (SPDashSelectorClass), - (GtkClassInitFunc) sp_dash_selector_class_init, - (GtkObjectInitFunc) sp_dash_selector_init, - NULL, NULL, NULL - }; - type = gtk_type_unique (GTK_TYPE_HBOX, &info); - } - return type; + this->set_data("pattern", dashes[0]); } -static void -sp_dash_selector_class_init (SPDashSelectorClass *klass) -{ - parent_class = (GtkHBoxClass*)gtk_type_class (GTK_TYPE_HBOX); - - signals[CHANGED] = gtk_signal_new ("changed", - (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE), - G_TYPE_FROM_CLASS (klass), - GTK_SIGNAL_OFFSET (SPDashSelectorClass, changed), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); +SPDashSelector::~SPDashSelector() { + // FIXME: for some reason this doesn't get called; does the call to manage() in + // sp_stroke_style_line_widget_new() not processed correctly? + delete dash; + delete offset; } -static void -sp_dash_selector_init (SPDashSelector *dsel) -{ - GtkTooltips *tt = gtk_tooltips_new(); - - dsel->dash = gtk_option_menu_new (); - gtk_tooltips_set_tip (tt, dsel->dash, _("Dash pattern"), NULL); - gtk_widget_show (dsel->dash); - gtk_box_pack_start (GTK_BOX (dsel), dsel->dash, FALSE, FALSE, 0); - - GtkWidget *m = gtk_menu_new (); - gtk_widget_show (m); - for (int i = 0; dashes[i]; i++) { - GtkWidget *mi = sp_dash_selector_menu_item_new (dsel, dashes[i]); - gtk_widget_show (mi); - gtk_menu_append (GTK_MENU (m), mi); - } - gtk_option_menu_set_menu (GTK_OPTION_MENU (dsel->dash), m); - - dsel->offset = gtk_adjustment_new (0.0, 0.0, 10.0, 0.1, 1.0, 1.0); - GtkWidget *sb = gtk_spin_button_new (GTK_ADJUSTMENT (dsel->offset), 0.1, 2); - gtk_tooltips_set_tip (tt, sb, _("Pattern offset"), NULL); - - sp_dialog_defocus_on_enter (sb); - gtk_widget_show (sb); - gtk_box_pack_start (GTK_BOX (dsel), sb, FALSE, FALSE, 0); - gtk_signal_connect (dsel->offset, "value_changed", GTK_SIGNAL_FUNC (sp_dash_selector_offset_value_changed), dsel); - - gtk_object_set_data (GTK_OBJECT (dsel), "pattern", dashes[0]); +void +SPDashSelector::init_dashes(Inkscape::XML::Node *drepr) { + if (!dashes) { + int ndashes = 0; + if (drepr) { + for (Inkscape::XML::Node *dr = drepr->firstChild(); dr; dr = dr->next()) { + if (!strcmp (dr->name(), "dash")) + ndashes += 1; + } + } + + if (ndashes > 0) { + int pos = 0; + SPStyle *style = sp_style_new (NULL); + dashes = g_new (double *, ndashes + 1); + for (Inkscape::XML::Node *dr = drepr->firstChild(); dr; dr = dr->next()) { + if (!strcmp (dr->name(), "dash")) { + sp_style_read_from_repr (style, dr); + if (style->stroke_dash.n_dash > 0) { + dashes[pos] = g_new (double, style->stroke_dash.n_dash + 1); + double *d = dashes[pos]; + int i = 0; + for (; i < style->stroke_dash.n_dash; i++) { + d[i] = style->stroke_dash.dash[i]; + } + d[i] = -1; + } else { + dashes[pos] = dash_0; + } + pos += 1; + } + } + sp_style_unref (style); + dashes[pos] = NULL; + } else { + dashes = builtin_dashes; + } + } } -GtkWidget * -sp_dash_selector_new (Inkscape::XML::Node *drepr) +void +SPDashSelector::set_dash (int ndash, double *dash, double o) { - if (!dashes) { - int ndashes = 0; - if (drepr) { - for (Inkscape::XML::Node *dr = drepr->firstChild(); dr; dr = dr->next()) { - if (!strcmp (dr->name(), "dash")) - ndashes += 1; - } - } - - if (ndashes > 0) { - int pos = 0; - SPStyle *style = sp_style_new (NULL); - dashes = g_new (double *, ndashes + 1); - for (Inkscape::XML::Node *dr = drepr->firstChild(); dr; dr = dr->next()) { - if (!strcmp (dr->name(), "dash")) { - sp_style_read_from_repr (style, dr); - if (style->stroke_dash.n_dash > 0) { - dashes[pos] = g_new (double, style->stroke_dash.n_dash + 1); - double *d = dashes[pos]; - int i = 0; - for (; i < style->stroke_dash.n_dash; i++) { - d[i] = style->stroke_dash.dash[i]; - } - d[i] = -1; - } else { - dashes[pos] = dash_0; - } - pos += 1; - } - } - sp_style_unref (style); - dashes[pos] = NULL; - } else { - dashes = builtin_dashes; - } - } - - GtkWidget *dsel = (GtkWidget*)gtk_type_new (SP_TYPE_DASH_SELECTOR); - - return dsel; + int pos = 0; + if (ndash > 0) { + double delta = 0.0; + for (int i = 0; i < ndash; i++) + delta += dash[i]; + delta /= 1000.0; + + for (int i = 0; dashes[i]; i++) { + double *pattern = dashes[i]; + int np = 0; + while (pattern[np] >= 0.0) + np += 1; + if (np == ndash) { + int j; + for (j = 0; j < ndash; j++) { + if (!NR_DF_TEST_CLOSE (dash[j], pattern[j], delta)) + break; + } + if (j == ndash) { + pos = i; + break; + } + } + } + } + + this->set_data("pattern", dashes[pos]); + this->dash->set_history(pos); + this->offset->set_value(o); } void -sp_dash_selector_set_dash (SPDashSelector *dsel, int ndash, double *dash, double offset) +SPDashSelector::get_dash(int *ndash, double **dash, double *off) { - int pos = 0; - if (ndash > 0) { - double delta = 0.0; - for (int i = 0; i < ndash; i++) - delta += dash[i]; - delta /= 1000.0; - - for (int i = 0; dashes[i]; i++) { - double *pattern = dashes[i]; - int np = 0; - while (pattern[np] >= 0.0) - np += 1; - if (np == ndash) { - int j; - for (j = 0; j < ndash; j++) { - if (!NR_DF_TEST_CLOSE (dash[j], pattern[j], delta)) - break; - } - if (j == ndash) { - pos = i; - break; - } - } - } - } - - gtk_object_set_data (GTK_OBJECT (dsel), "pattern", dashes[pos]); - gtk_option_menu_set_history (GTK_OPTION_MENU (dsel->dash), pos); - gtk_adjustment_set_value (GTK_ADJUSTMENT (dsel->offset), offset); + double *pattern = (double*) this->get_data("pattern"); + + int nd = 0; + while (pattern[nd] >= 0.0) + nd += 1; + + if (nd > 0) { + if (ndash) + *ndash = nd; + if (dash) { + *dash = g_new (double, nd); + memcpy (*dash, pattern, nd * sizeof (double)); + } + if (off) + *off = offset->get_value(); + } else { + if (ndash) + *ndash = 0; + if (dash) + *dash = NULL; + if (off) + *off = 0.0; + } } -void -sp_dash_selector_get_dash (SPDashSelector *dsel, int *ndash, double **dash, double *offset) +Gtk::MenuItem * +SPDashSelector::menu_item_new(double *pattern) { - double *pattern = (double*)gtk_object_get_data (GTK_OBJECT (dsel), "pattern"); - - int nd = 0; - while (pattern[nd] >= 0.0) - nd += 1; - - if (nd > 0) { - if (ndash) - *ndash = nd; - if (dash) { - *dash = g_new (double, nd); - memcpy (*dash, pattern, nd * sizeof (double)); - } - if (offset) - *offset = GTK_ADJUSTMENT (dsel->offset)->value; - } else { - if (ndash) - *ndash = 0; - if (dash) - *dash = NULL; - if (offset) - *offset = 0.0; - } + Gtk::MenuItem *mi = new Gtk::MenuItem(); + Gtk::Image *px = new Gtk::Image(); + + px->show(); + mi->add(*px); + + mi->set_data("pattern", pattern); + mi->set_data("px", px); + mi->signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &SPDashSelector::dash_activate), mi)); + + px->signal_realize().connect(sigc::bind(sigc::ptr_fun(&sp_dash_selector_menu_item_image_realize), px, pattern)); + + return mi; } -bool +static bool all_even_are_zero (double *pattern, int n) { for (int i = 0; i < n; i += 2) { @@ -245,7 +218,7 @@ all_even_are_zero (double *pattern, int n) return true; } -bool +static bool all_odd_are_zero (double *pattern, int n) { for (int i = 1; i < n; i += 2) { @@ -255,134 +228,125 @@ all_odd_are_zero (double *pattern, int n) return true; } -static GtkWidget * -sp_dash_selector_menu_item_new (SPDashSelector *dsel, double *pattern) -{ - GtkWidget *mi = gtk_menu_item_new (); - GtkWidget *px = gtk_image_new_from_pixmap (NULL, NULL); - - gtk_widget_show (px); - gtk_container_add (GTK_CONTAINER (mi), px); - - gtk_object_set_data (GTK_OBJECT (mi), "pattern", pattern); - gtk_object_set_data (GTK_OBJECT (mi), "px", px); - gtk_signal_connect (GTK_OBJECT (mi), "activate", G_CALLBACK (sp_dash_selector_dash_activate), dsel); - - g_signal_connect_after(G_OBJECT(px), "realize", G_CALLBACK(sp_dash_selector_menu_item_image_realize), pattern); - - return mi; -} - -static void sp_dash_selector_menu_item_image_realize (GtkWidget *px, double *pattern) { - GdkPixmap *pixmap = gdk_pixmap_new(px->window, DASH_PREVIEW_LENGTH + 4, 16, -1); - GdkGC *gc = gdk_gc_new (pixmap); - - gdk_rgb_gc_set_foreground (gc, 0xffffffff); - gdk_draw_rectangle (pixmap, gc, TRUE, 0, 0, DASH_PREVIEW_LENGTH + 4, 16); - - // FIXME: all of the below twibblering is due to the limitations of gdk_gc_set_dashes (only integers, no zeroes). - // Perhaps would make sense to rework this with manually drawn dashes. - - // Fill in the integer array of pixel-lengths, for display - gint8 pixels_i[64]; - gdouble pixels_d[64]; - int n_source_dashes = 0; - int n_pixel_dashes = 0; - - signed int i_s, i_p; - for (i_s = 0, i_p = 0; pattern[i_s] >= 0.0; i_s ++, i_p ++) { - pixels_d[i_p] = 0.0; - } - - n_source_dashes = i_s; - - for (i_s = 0, i_p = 0; i_s < n_source_dashes; i_s ++, i_p ++) { - - // calculate the pixel length corresponding to the current dash - gdouble pixels = DASH_PREVIEW_WIDTH * pattern[i_s]; - - if (pixels > 0.0) - pixels_d [i_p] += pixels; - else { - if (i_p >= 1) { - // dash is zero, skip this element in the array, and set pointer backwards so the next dash is added to the previous - i_p -= 2; - } else { - // the first dash is zero; bad luck, gdk cannot start pattern with non-stroke, so we put a 1-pixel stub here - // (it may turn out not shown, though, see special cases below) - pixels_d [i_p] = 1.0; - } - } - } - - n_pixel_dashes = i_p; - - gdouble longest_dash = 0.0; - - // after summation, convert double dash lengths to ints - for (i_p = 0; i_p < n_pixel_dashes; i_p ++) { - pixels_i [i_p] = (gint8) (pixels_d [i_p] + 0.5); - // zero-length dashes are already eliminated, so the <1 dash is short but not zero; - // we approximate it with a one-pixel mark - if (pixels_i [i_p] < 1) - pixels_i [i_p] = 1; - if (i_p % 2 == 0) { // it's a dash - if (pixels_d [i_p] > longest_dash) - longest_dash = pixels_d [i_p]; - } - } - - if (longest_dash > 1e-18 && longest_dash < 0.5) { - // fake "shortening" of one-pixel marks by painting them lighter-than-black - gint rgb = 255 - (gint) (255 * longest_dash / 0.5); - gdk_rgb_gc_set_foreground (gc, SP_RGBA32_U_COMPOSE (rgb, rgb, rgb, rgb)); - } else { - gdk_rgb_gc_set_foreground (gc, 0x00000000); - } - - if (n_source_dashes > 0) { - // special cases: - if (all_even_are_zero (pattern, n_source_dashes)) { - ; // do not draw anything, only gaps are non-zero - } else if (all_odd_are_zero (pattern, n_source_dashes)) { - // draw solid line, only dashes are non-zero - gdk_gc_set_line_attributes (gc, DASH_PREVIEW_WIDTH, - GDK_LINE_SOLID, GDK_CAP_BUTT, - GDK_JOIN_MITER); - gdk_draw_line (pixmap, gc, 4, 8, DASH_PREVIEW_LENGTH, 8); - } else { - // regular pattern with both gaps and dashes non-zero - gdk_gc_set_line_attributes (gc, DASH_PREVIEW_WIDTH, - GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, - GDK_JOIN_MITER); - gdk_gc_set_dashes (gc, 0, pixels_i, n_pixel_dashes); - gdk_draw_line (pixmap, gc, 4, 8, DASH_PREVIEW_LENGTH, 8); - } - } else { - // no pattern, draw solid line - gdk_gc_set_line_attributes (gc, DASH_PREVIEW_WIDTH, - GDK_LINE_SOLID, GDK_CAP_BUTT, - GDK_JOIN_MITER); - gdk_draw_line (pixmap, gc, 4, 8, DASH_PREVIEW_LENGTH, 8); - } - - gdk_gc_unref (gc); - - gtk_image_set_from_pixmap(GTK_IMAGE(px), pixmap, NULL); - gdk_pixmap_unref(pixmap); +static void sp_dash_selector_menu_item_image_realize(Gtk::Image *px, double *pattern) { + Glib::RefPtr<Gdk::Pixmap> pixmap = Gdk::Pixmap::create(px->get_window(), DASH_PREVIEW_LENGTH + 4, 16, -1); + Glib::RefPtr<Gdk::GC> gc = Gdk::GC::create(pixmap); + + gc->set_rgb_fg_color(Gdk::Color("#ffffff")); + pixmap->draw_rectangle(gc, true, 0, 0, DASH_PREVIEW_LENGTH + 4, 16); + + // FIXME: all of the below twibblering is due to the limitations of gdk_gc_set_dashes (only integers, no zeroes). + // Perhaps would make sense to rework this with manually drawn dashes. + + // Fill in the integer array of pixel-lengths, for display + gint8 pixels_i[64]; + gdouble pixels_d[64]; + int n_source_dashes = 0; + int n_pixel_dashes = 0; + + signed int i_s, i_p; + for (i_s = 0, i_p = 0; pattern[i_s] >= 0.0; i_s ++, i_p ++) { + pixels_d[i_p] = 0.0; + } + + n_source_dashes = i_s; + + for (i_s = 0, i_p = 0; i_s < n_source_dashes; i_s ++, i_p ++) { + // calculate the pixel length corresponding to the current dash + gdouble pixels = DASH_PREVIEW_WIDTH * pattern[i_s]; + + if (pixels > 0.0) + pixels_d [i_p] += pixels; + else { + if (i_p >= 1) { + // dash is zero, skip this element in the array, and set pointer backwards + // so the next dash is added to the previous + i_p -= 2; + } else { + // the first dash is zero; bad luck, gdk cannot start pattern with non-stroke, so we + // put a 1-pixel stub here (it may turn out not shown, though, see special cases below) + pixels_d [i_p] = 1.0; + } + } + } + + n_pixel_dashes = i_p; + + gdouble longest_dash = 0.0; + + // after summation, convert double dash lengths to ints + for (i_p = 0; i_p < n_pixel_dashes; i_p ++) { + pixels_i [i_p] = (gint8) (pixels_d [i_p] + 0.5); + // zero-length dashes are already eliminated, so the <1 dash is short but not zero; + // we approximate it with a one-pixel mark + if (pixels_i [i_p] < 1) + pixels_i [i_p] = 1; + if (i_p % 2 == 0) { // it's a dash + if (pixels_d [i_p] > longest_dash) + longest_dash = pixels_d [i_p]; + } + } + + Gdk::Color color; + if (longest_dash > 1e-18 && longest_dash < 0.5) { + // fake "shortening" of one-pixel marks by painting them lighter-than-black + gint rgb = 0xffff - (gint) (0xffff * longest_dash / 0.5); + color.set_rgb(rgb, rgb, rgb); + gc->set_rgb_fg_color(color); + } else { + color.set_rgb(0, 0, 0); + gc->set_rgb_fg_color(color); + } + + if (n_source_dashes > 0) { + // special cases: + if (all_even_are_zero (pattern, n_source_dashes)) { + ; // do not draw anything, only gaps are non-zero + } else if (all_odd_are_zero (pattern, n_source_dashes)) { + // draw solid line, only dashes are non-zero + gc->set_line_attributes(DASH_PREVIEW_WIDTH, + Gdk::LINE_SOLID, Gdk::CAP_BUTT, + Gdk::JOIN_MITER); + pixmap->draw_line(gc, 4, 8, DASH_PREVIEW_LENGTH, 8); + } else { + // regular pattern with both gaps and dashes non-zero + gc->set_line_attributes(DASH_PREVIEW_WIDTH, Gdk::LINE_ON_OFF_DASH, Gdk::CAP_BUTT, Gdk::JOIN_MITER); + gc->set_dashes(0, pixels_i, n_pixel_dashes); + pixmap->draw_line(gc, 4, 8, DASH_PREVIEW_LENGTH, 8); + } + } else { + // no pattern, draw solid line + gc->set_line_attributes(DASH_PREVIEW_WIDTH, Gdk::LINE_SOLID, Gdk::CAP_BUTT, Gdk::JOIN_MITER); + pixmap->draw_line(gc, 4, 8, DASH_PREVIEW_LENGTH, 8); + } + + Glib::RefPtr<Gdk::Bitmap> null_ptr; + px->set(pixmap, null_ptr); } -static void -sp_dash_selector_dash_activate (GtkObject *object, SPDashSelector *dsel) +void +SPDashSelector::dash_activate (Gtk::MenuItem *mi) { - double *pattern = (double*)gtk_object_get_data (object, "pattern"); - gtk_object_set_data (GTK_OBJECT (dsel), "pattern", pattern); + double *pattern = (double*) mi->get_data("pattern"); + this->set_data ("pattern", pattern); - gtk_signal_emit (GTK_OBJECT (dsel), signals[CHANGED]); + changed_signal.emit(); } -static void -sp_dash_selector_offset_value_changed (GtkAdjustment */*adj*/, SPDashSelector *dsel) + +void +SPDashSelector::offset_value_changed() { - gtk_signal_emit (GTK_OBJECT (dsel), signals[CHANGED]); + changed_signal.emit(); } + +/* + 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:encoding=utf-8:textwidth=99 : |
