~valavanisalex/ubuntu/oneiric/inkscape/inkscape_0.48.1-2ubuntu4

« back to all changes in this revision

Viewing changes to src/widgets/dash-selector.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook, Ted Gould, Kees Cook
  • Date: 2009-06-24 14:00:43 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20090624140043-07stp20mry48hqup
Tags: 0.47~pre0-0ubuntu1
* New upstream release

[ Ted Gould ]
* debian/control: Adding libgsl0 and removing version specifics on boost

[ Kees Cook ]
* debian/watch: updated to run uupdate and mangle pre-release versions.
* Dropped patches that have been taken upstream:
  - 01_mips
  - 02-poppler-0.8.3
  - 03-chinese-inkscape
  - 05_fix_latex_patch
  - 06_gcc-4.4
  - 07_cdr2svg
  - 08_skip-bad-utf-on-pdf-import
  - 09_gtk-clist
  - 10_belarussian
  - 11_libpng
  - 12_desktop
  - 13_slider
  - 100_svg_import_improvements
  - 102_sp_pattern_painter_free
  - 103_bitmap_type_print

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#define __SP_DASH_SELECTOR_C__
 
1
#define __SP_DASH_SELECTOR_NEW_C__
2
2
 
3
 
/*
4
 
 * Optionmenu for selecting dash patterns
5
 
 *
6
 
 * Author:
 
3
/** @file
 
4
 * @brief Option menu for selecting dash patterns - implementation
 
5
 */
 
6
/* Author:
7
7
 *   Lauris Kaplinski <lauris@kaplinski.com>
8
8
 *   bulia byak <buliabyak@users.sf.net>
 
9
 *   Maximilian Albert <maximilian.albert@gmail.com>
9
10
 *
10
11
 * Copyright (C) 2002 Lauris Kaplinski
11
12
 *
25
26
#include <gtk/gtk.h>
26
27
#include <glibmm/i18n.h>
27
28
 
28
 
#include "../style.h"
29
 
#include "../dialogs/dialog-events.h"
 
29
#include "style.h"
 
30
#include "dialogs/dialog-events.h"
 
31
#include "preferences.h"
 
32
 
 
33
#include <gtkmm/optionmenu.h>
 
34
#include <gtkmm/adjustment.h>
 
35
#include <gtkmm/spinbutton.h>
 
36
 
30
37
 
31
38
#include "dash-selector.h"
32
39
 
33
 
enum {CHANGED, LAST_SIGNAL};
34
 
 
35
 
struct SPDashSelector {
36
 
        GtkHBox hbox;
37
 
 
38
 
        GtkWidget *dash;
39
 
        GtkObject *offset;
40
 
};
41
 
 
42
 
struct SPDashSelectorClass {
43
 
        GtkHBoxClass parent_class;
44
 
 
45
 
        void (* changed) (SPDashSelector *dsel);
46
 
};
47
 
 
48
 
double dash_0[] = {-1.0};
49
 
double dash_1_1[] = {1.0, 1.0, -1.0};
50
 
double dash_2_1[] = {2.0, 1.0, -1.0};
51
 
double dash_4_1[] = {4.0, 1.0, -1.0};
52
 
double dash_1_2[] = {1.0, 2.0, -1.0};
53
 
double dash_1_4[] = {1.0, 4.0, -1.0};
54
 
 
55
 
double *builtin_dashes[] = {dash_0, dash_1_1, dash_2_1, dash_4_1, dash_1_2, dash_1_4, NULL};
 
40
gchar const *const SPDashSelector::_prefs_path = "/palette/dashes";
 
41
 
 
42
static double dash_0[] = {-1.0};
 
43
static double dash_1_1[] = {1.0, 1.0, -1.0};
 
44
static double dash_2_1[] = {2.0, 1.0, -1.0};
 
45
static double dash_4_1[] = {4.0, 1.0, -1.0};
 
46
static double dash_1_2[] = {1.0, 2.0, -1.0};
 
47
static double dash_1_4[] = {1.0, 4.0, -1.0};
 
48
 
 
49
static double *builtin_dashes[] = {dash_0, dash_1_1, dash_2_1, dash_4_1, dash_1_2, dash_1_4, NULL};
56
50
 
57
51
static double **dashes = NULL;
58
52
 
59
 
static void sp_dash_selector_class_init (SPDashSelectorClass *klass);
60
 
static void sp_dash_selector_init (SPDashSelector *dsel);
61
 
static GtkWidget *sp_dash_selector_menu_item_new (SPDashSelector *dsel, double *pattern);
62
 
static void sp_dash_selector_menu_item_image_realize (GtkWidget *mi, double *pattern);
63
 
static void sp_dash_selector_dash_activate (GtkObject *object, SPDashSelector *dsel);
64
 
static void sp_dash_selector_offset_value_changed (GtkAdjustment *adj, SPDashSelector *dsel);
65
 
 
66
 
static GtkHBoxClass *parent_class;
67
 
static guint signals[LAST_SIGNAL] = {0};
68
 
 
69
 
GtkType
70
 
sp_dash_selector_get_type (void)
71
 
{
72
 
        static GtkType type = 0;
73
 
        if (!type) {
74
 
                GtkTypeInfo info = {
75
 
                        "SPDashSelector",
76
 
                        sizeof (SPDashSelector),
77
 
                        sizeof (SPDashSelectorClass),
78
 
                        (GtkClassInitFunc) sp_dash_selector_class_init,
79
 
                        (GtkObjectInitFunc) sp_dash_selector_init,
80
 
                        NULL, NULL, NULL
81
 
                };
82
 
                type = gtk_type_unique (GTK_TYPE_HBOX, &info);
83
 
        }
84
 
        return type;
85
 
}
86
 
 
87
 
static void
88
 
sp_dash_selector_class_init (SPDashSelectorClass *klass)
89
 
{
90
 
        parent_class = (GtkHBoxClass*)gtk_type_class (GTK_TYPE_HBOX);
91
 
 
92
 
        signals[CHANGED] = gtk_signal_new ("changed",
93
 
                                           (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
94
 
                                           G_TYPE_FROM_CLASS (klass),
95
 
                                           GTK_SIGNAL_OFFSET (SPDashSelectorClass, changed),
96
 
                                           gtk_marshal_NONE__NONE,
97
 
                                           GTK_TYPE_NONE, 0);
98
 
}
99
 
 
100
 
static void
101
 
sp_dash_selector_init (SPDashSelector *dsel)
102
 
{
103
 
        GtkTooltips *tt = gtk_tooltips_new();
104
 
 
105
 
        dsel->dash = gtk_option_menu_new ();
106
 
        gtk_tooltips_set_tip (tt, dsel->dash, _("Dash pattern"), NULL);
107
 
        gtk_widget_show (dsel->dash);
108
 
        gtk_box_pack_start (GTK_BOX (dsel), dsel->dash, FALSE, FALSE, 0);
109
 
 
110
 
        GtkWidget *m = gtk_menu_new ();
111
 
        gtk_widget_show (m);
112
 
        for (int i = 0; dashes[i]; i++) {
113
 
                GtkWidget *mi = sp_dash_selector_menu_item_new (dsel, dashes[i]);
114
 
                gtk_widget_show (mi);
115
 
                gtk_menu_append (GTK_MENU (m), mi);
116
 
        }
117
 
        gtk_option_menu_set_menu (GTK_OPTION_MENU (dsel->dash), m);
118
 
 
119
 
        dsel->offset = gtk_adjustment_new (0.0, 0.0, 10.0, 0.1, 1.0, 1.0);
120
 
        GtkWidget *sb = gtk_spin_button_new (GTK_ADJUSTMENT (dsel->offset), 0.1, 2);
121
 
        gtk_tooltips_set_tip (tt, sb, _("Pattern offset"), NULL);
122
 
 
123
 
        sp_dialog_defocus_on_enter (sb);
124
 
        gtk_widget_show (sb);
125
 
        gtk_box_pack_start (GTK_BOX (dsel), sb, FALSE, FALSE, 0);
126
 
        gtk_signal_connect (dsel->offset, "value_changed", GTK_SIGNAL_FUNC (sp_dash_selector_offset_value_changed), dsel);
127
 
 
128
 
        gtk_object_set_data (GTK_OBJECT (dsel), "pattern", dashes[0]);
129
 
}
130
 
 
131
 
GtkWidget *
132
 
sp_dash_selector_new (Inkscape::XML::Node *drepr)
133
 
{
134
 
        if (!dashes) {
135
 
                int ndashes = 0;
136
 
                if (drepr) {
137
 
                        for (Inkscape::XML::Node *dr = drepr->firstChild(); dr; dr = dr->next()) {
138
 
                                if (!strcmp (dr->name(), "dash"))
139
 
                                        ndashes += 1;
140
 
                        }
141
 
                }
142
 
 
143
 
                if (ndashes > 0) {
144
 
                        int pos = 0;
145
 
                        SPStyle *style = sp_style_new (NULL);
146
 
                        dashes = g_new (double *, ndashes + 1);
147
 
                        for (Inkscape::XML::Node *dr = drepr->firstChild(); dr; dr = dr->next()) {
148
 
                                if (!strcmp (dr->name(), "dash")) {
149
 
                                        sp_style_read_from_repr (style, dr);
150
 
                                        if (style->stroke_dash.n_dash > 0) {
151
 
                                                dashes[pos] = g_new (double, style->stroke_dash.n_dash + 1);
152
 
                                                double *d = dashes[pos];
153
 
                                                int i = 0;
154
 
                                                for (; i < style->stroke_dash.n_dash; i++) {
155
 
                                                        d[i] = style->stroke_dash.dash[i];
156
 
                                                }
157
 
                                                d[i] = -1;
158
 
                                        } else {
159
 
                                                dashes[pos] = dash_0;
160
 
                                        }
161
 
                                        pos += 1;
162
 
                                }
163
 
                        }
164
 
                        sp_style_unref (style);
165
 
                        dashes[pos] = NULL;
166
 
                } else {
167
 
                        dashes = builtin_dashes;
168
 
                }
169
 
        }
170
 
 
171
 
        GtkWidget *dsel = (GtkWidget*)gtk_type_new (SP_TYPE_DASH_SELECTOR);
172
 
 
173
 
        return dsel;
174
 
}
175
 
 
176
 
void
177
 
sp_dash_selector_set_dash (SPDashSelector *dsel, int ndash, double *dash, double offset)
178
 
{
179
 
        int pos = 0;
180
 
        if (ndash > 0) {
181
 
                double delta = 0.0;
182
 
                for (int i = 0; i < ndash; i++)
183
 
                        delta += dash[i];
184
 
                delta /= 1000.0;
185
 
 
186
 
                for (int i = 0; dashes[i]; i++) {
187
 
                        double *pattern = dashes[i];
188
 
                        int np = 0;
189
 
                        while (pattern[np] >= 0.0)
190
 
                                np += 1;
191
 
                        if (np == ndash) {
192
 
                                int j;
193
 
                                for (j = 0; j < ndash; j++) {
194
 
                                        if (!NR_DF_TEST_CLOSE (dash[j], pattern[j], delta))
195
 
                                                break;
196
 
                                }
197
 
                                if (j == ndash) {
198
 
                                        pos = i;
199
 
                                        break;
200
 
                                }
201
 
                        }
202
 
                }
203
 
        }
204
 
 
205
 
        gtk_object_set_data (GTK_OBJECT (dsel), "pattern", dashes[pos]);
206
 
        gtk_option_menu_set_history (GTK_OPTION_MENU (dsel->dash), pos);
207
 
        gtk_adjustment_set_value (GTK_ADJUSTMENT (dsel->offset), offset);
208
 
}
209
 
 
210
 
void
211
 
sp_dash_selector_get_dash (SPDashSelector *dsel, int *ndash, double **dash, double *offset)
212
 
{
213
 
        double *pattern = (double*)gtk_object_get_data (GTK_OBJECT (dsel), "pattern");
214
 
 
215
 
        int nd = 0;
216
 
        while (pattern[nd] >= 0.0)
217
 
                nd += 1;
218
 
 
219
 
        if (nd > 0) {
220
 
                if (ndash)
221
 
                        *ndash = nd;
222
 
                if (dash) {
223
 
                        *dash = g_new (double, nd);
224
 
                        memcpy (*dash, pattern, nd * sizeof (double));
225
 
                }
226
 
                if (offset)
227
 
                        *offset = GTK_ADJUSTMENT (dsel->offset)->value;
228
 
        } else {
229
 
                if (ndash)
230
 
                        *ndash = 0;
231
 
                if (dash)
232
 
                        *dash = NULL;
233
 
                if (offset)
234
 
                        *offset = 0.0;
235
 
        }
236
 
}
237
 
 
238
 
bool
 
53
static void sp_dash_selector_menu_item_image_realize(Gtk::Image *px, double *pattern);
 
54
 
 
55
SPDashSelector::SPDashSelector() {
 
56
    // TODO: find something more sensible here!!
 
57
    init_dashes();
 
58
 
 
59
    Gtk::Tooltips *tt = new Gtk::Tooltips();
 
60
 
 
61
    dash = new Gtk::OptionMenu();
 
62
    tt->set_tip(*dash, _("Dash pattern"));
 
63
    dash->show();
 
64
    this->pack_start(*dash, false, false, 0);
 
65
 
 
66
    Gtk::Menu *m = new Gtk::Menu();
 
67
    m->show();
 
68
    for (int i = 0; dashes[i]; i++) {
 
69
        Gtk::MenuItem *mi = menu_item_new(dashes[i]);
 
70
        mi->show();
 
71
        m->append(*mi);
 
72
    }
 
73
    dash->set_menu(*m);
 
74
 
 
75
    offset = new Gtk::Adjustment(0.0, 0.0, 10.0, 0.1, 1.0, 0.0);
 
76
    Gtk::SpinButton *sb = new Gtk::SpinButton(*offset, 0.1, 2);
 
77
    tt->set_tip(*sb, _("Pattern offset"));
 
78
 
 
79
    sp_dialog_defocus_on_enter_cpp(sb);
 
80
    sb->show();
 
81
    this->pack_start(*sb, false, false, 0);
 
82
    offset->signal_value_changed().connect(sigc::mem_fun(*this, &SPDashSelector::offset_value_changed));
 
83
 
 
84
    this->set_data("pattern", dashes[0]);
 
85
}
 
86
 
 
87
SPDashSelector::~SPDashSelector() {
 
88
    // FIXME: for some reason this doesn't get called; does the call to manage() in
 
89
    // sp_stroke_style_line_widget_new() not processed correctly?
 
90
    delete dash;
 
91
    delete offset;
 
92
}
 
93
 
 
94
void
 
95
SPDashSelector::init_dashes() {
 
96
    if (!dashes) {
 
97
        
 
98
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
99
        std::vector<Glib::ustring> dash_prefs = prefs->getAllDirs(_prefs_path);
 
100
        
 
101
        if (!dash_prefs.empty()) {
 
102
            int pos = 0;
 
103
            SPStyle *style = sp_style_new (NULL);
 
104
            dashes = g_new (double *, dash_prefs.size() + 1);
 
105
            
 
106
            for (std::vector<Glib::ustring>::iterator i = dash_prefs.begin(); i != dash_prefs.end(); ++i) {
 
107
                sp_style_read_from_prefs(style, *i);
 
108
                
 
109
                if (style->stroke_dash.n_dash > 0) {
 
110
                    dashes[pos] = g_new (double, style->stroke_dash.n_dash + 1);
 
111
                    double *d = dashes[pos];
 
112
                    int i = 0;
 
113
                    for (; i < style->stroke_dash.n_dash; i++) {
 
114
                        d[i] = style->stroke_dash.dash[i];
 
115
                    }
 
116
                    d[i] = -1;
 
117
                } else {
 
118
                    dashes[pos] = dash_0;
 
119
                }
 
120
                pos += 1;
 
121
            }
 
122
            dashes[pos] = NULL;
 
123
        } else {
 
124
            dashes = builtin_dashes;
 
125
        }
 
126
    }
 
127
}
 
128
 
 
129
void
 
130
SPDashSelector::set_dash (int ndash, double *dash, double o)
 
131
{
 
132
    int pos = 0;
 
133
    if (ndash > 0) {
 
134
        double delta = 0.0;
 
135
        for (int i = 0; i < ndash; i++)
 
136
            delta += dash[i];
 
137
        delta /= 1000.0;
 
138
 
 
139
        for (int i = 0; dashes[i]; i++) {
 
140
            double *pattern = dashes[i];
 
141
            int np = 0;
 
142
            while (pattern[np] >= 0.0)
 
143
                np += 1;
 
144
            if (np == ndash) {
 
145
                int j;
 
146
                for (j = 0; j < ndash; j++) {
 
147
                    if (!NR_DF_TEST_CLOSE (dash[j], pattern[j], delta))
 
148
                        break;
 
149
                }
 
150
                if (j == ndash) {
 
151
                    pos = i;
 
152
                    break;
 
153
                }
 
154
            }
 
155
        }
 
156
    }
 
157
 
 
158
    this->set_data("pattern", dashes[pos]);
 
159
    this->dash->set_history(pos);
 
160
    this->offset->set_value(o);
 
161
}
 
162
 
 
163
void
 
164
SPDashSelector::get_dash(int *ndash, double **dash, double *off)
 
165
{
 
166
    double *pattern = (double*) this->get_data("pattern");
 
167
 
 
168
    int nd = 0;
 
169
    while (pattern[nd] >= 0.0)
 
170
        nd += 1;
 
171
 
 
172
    if (nd > 0) {
 
173
        if (ndash)
 
174
            *ndash = nd;
 
175
        if (dash) {
 
176
            *dash = g_new (double, nd);
 
177
            memcpy (*dash, pattern, nd * sizeof (double));
 
178
        }
 
179
        if (off)
 
180
            *off = offset->get_value();
 
181
    } else {
 
182
        if (ndash)
 
183
            *ndash = 0;
 
184
        if (dash)
 
185
            *dash = NULL;
 
186
        if (off)
 
187
            *off = 0.0;
 
188
    }
 
189
}
 
190
 
 
191
Gtk::MenuItem *
 
192
SPDashSelector::menu_item_new(double *pattern)
 
193
{
 
194
    Gtk::MenuItem *mi = new Gtk::MenuItem();
 
195
    Gtk::Image *px = new Gtk::Image();
 
196
 
 
197
    px->show();
 
198
    mi->add(*px);
 
199
 
 
200
    mi->set_data("pattern", pattern);
 
201
    mi->set_data("px", px);
 
202
    mi->signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &SPDashSelector::dash_activate), mi));
 
203
 
 
204
    px->signal_realize().connect(sigc::bind(sigc::ptr_fun(&sp_dash_selector_menu_item_image_realize), px, pattern));
 
205
 
 
206
    return mi;
 
207
}
 
208
 
 
209
static bool
239
210
all_even_are_zero (double *pattern, int n)
240
211
{
241
212
        for (int i = 0; i < n; i += 2) {
245
216
        return true;
246
217
}
247
218
 
248
 
bool
 
219
static bool
249
220
all_odd_are_zero (double *pattern, int n)
250
221
{
251
222
        for (int i = 1; i < n; i += 2) {
255
226
        return true;
256
227
}
257
228
 
258
 
static GtkWidget *
259
 
sp_dash_selector_menu_item_new (SPDashSelector *dsel, double *pattern)
260
 
{
261
 
        GtkWidget *mi = gtk_menu_item_new ();
262
 
        GtkWidget *px = gtk_image_new_from_pixmap (NULL, NULL);
263
 
 
264
 
        gtk_widget_show (px);
265
 
        gtk_container_add (GTK_CONTAINER (mi), px);
266
 
 
267
 
        gtk_object_set_data (GTK_OBJECT (mi), "pattern", pattern);
268
 
        gtk_object_set_data (GTK_OBJECT (mi), "px", px);
269
 
        gtk_signal_connect (GTK_OBJECT (mi), "activate", G_CALLBACK (sp_dash_selector_dash_activate), dsel);
270
 
 
271
 
        g_signal_connect_after(G_OBJECT(px), "realize", G_CALLBACK(sp_dash_selector_menu_item_image_realize), pattern);
272
 
 
273
 
        return mi;
274
 
}
275
 
 
276
 
static void sp_dash_selector_menu_item_image_realize (GtkWidget *px, double *pattern) {
277
 
        GdkPixmap *pixmap = gdk_pixmap_new(px->window, DASH_PREVIEW_LENGTH + 4, 16, -1);
278
 
        GdkGC *gc = gdk_gc_new (pixmap);
279
 
 
280
 
        gdk_rgb_gc_set_foreground (gc, 0xffffffff);
281
 
        gdk_draw_rectangle (pixmap, gc, TRUE, 0, 0, DASH_PREVIEW_LENGTH + 4, 16);
282
 
 
283
 
        // FIXME: all of the below twibblering is due to the limitations of gdk_gc_set_dashes (only integers, no zeroes).
284
 
        // Perhaps would make sense to rework this with manually drawn dashes.
285
 
 
286
 
        // Fill in the integer array of pixel-lengths, for display
287
 
        gint8 pixels_i[64];
288
 
        gdouble pixels_d[64];
289
 
        int n_source_dashes = 0;
290
 
        int n_pixel_dashes = 0;
291
 
 
292
 
        signed int i_s, i_p;
293
 
        for (i_s = 0, i_p = 0; pattern[i_s] >= 0.0; i_s ++, i_p ++) {
294
 
                pixels_d[i_p] = 0.0;
295
 
        }
296
 
 
297
 
        n_source_dashes = i_s;
298
 
 
299
 
        for (i_s = 0, i_p = 0; i_s < n_source_dashes; i_s ++, i_p ++) {
300
 
 
301
 
                // calculate the pixel length corresponding to the current dash
302
 
                gdouble pixels = DASH_PREVIEW_WIDTH * pattern[i_s];
303
 
 
304
 
                if (pixels > 0.0)
305
 
                        pixels_d [i_p] += pixels;
306
 
                else {
307
 
                        if (i_p >= 1) {
308
 
                                // dash is zero, skip this element in the array, and set pointer backwards so the next dash is added to the previous
309
 
                                i_p -= 2;
310
 
                        } else {
311
 
                                // the first dash is zero; bad luck, gdk cannot start pattern with non-stroke, so we put a 1-pixel stub here
312
 
                                // (it may turn out not shown, though, see special cases below)
313
 
                                pixels_d [i_p] = 1.0;
314
 
                        }
315
 
                }
316
 
        }
317
 
 
318
 
        n_pixel_dashes = i_p;
319
 
 
320
 
        gdouble longest_dash = 0.0;
321
 
 
322
 
        // after summation, convert double dash lengths to ints
323
 
        for (i_p = 0; i_p < n_pixel_dashes; i_p ++) {
324
 
                pixels_i [i_p] = (gint8) (pixels_d [i_p] + 0.5);
325
 
                // zero-length dashes are already eliminated, so the <1 dash is short but not zero;
326
 
                // we approximate it with a one-pixel mark
327
 
                if (pixels_i [i_p] < 1)
328
 
                        pixels_i [i_p] = 1;
329
 
                if (i_p % 2 == 0) { // it's a dash
330
 
                        if (pixels_d [i_p] > longest_dash)
331
 
                                longest_dash = pixels_d [i_p];
332
 
                }
333
 
        }
334
 
 
335
 
        if (longest_dash > 1e-18 && longest_dash < 0.5) {
336
 
                // fake "shortening" of one-pixel marks by painting them lighter-than-black
337
 
                gint rgb = 255 - (gint) (255 * longest_dash / 0.5);
338
 
                gdk_rgb_gc_set_foreground (gc, SP_RGBA32_U_COMPOSE (rgb, rgb, rgb, rgb));
339
 
        } else {
340
 
                gdk_rgb_gc_set_foreground (gc, 0x00000000);
341
 
        }
342
 
 
343
 
        if (n_source_dashes > 0) {
344
 
                // special cases:
345
 
                if (all_even_are_zero (pattern, n_source_dashes)) {
346
 
                        ; // do not draw anything, only gaps are non-zero
347
 
                } else if (all_odd_are_zero (pattern, n_source_dashes)) {
348
 
                        // draw solid line, only dashes are non-zero
349
 
                        gdk_gc_set_line_attributes (gc, DASH_PREVIEW_WIDTH,
350
 
                                                                                GDK_LINE_SOLID, GDK_CAP_BUTT,
351
 
                                                                                GDK_JOIN_MITER);
352
 
                        gdk_draw_line (pixmap, gc, 4, 8, DASH_PREVIEW_LENGTH, 8);
353
 
                } else {
354
 
                        // regular pattern with both gaps and dashes non-zero
355
 
                        gdk_gc_set_line_attributes (gc, DASH_PREVIEW_WIDTH,
356
 
                                                                                GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT,
357
 
                                                                                GDK_JOIN_MITER);
358
 
                        gdk_gc_set_dashes (gc, 0, pixels_i, n_pixel_dashes);
359
 
                        gdk_draw_line (pixmap, gc, 4, 8, DASH_PREVIEW_LENGTH, 8);
360
 
                }
361
 
        } else {
362
 
                // no pattern, draw solid line
363
 
                gdk_gc_set_line_attributes (gc, DASH_PREVIEW_WIDTH,
364
 
                                                                        GDK_LINE_SOLID, GDK_CAP_BUTT,
365
 
                                                                        GDK_JOIN_MITER);
366
 
                gdk_draw_line (pixmap, gc, 4, 8, DASH_PREVIEW_LENGTH, 8);
367
 
        }
368
 
 
369
 
        gdk_gc_unref (gc);
370
 
 
371
 
        gtk_image_set_from_pixmap(GTK_IMAGE(px), pixmap, NULL);
372
 
        gdk_pixmap_unref(pixmap);
373
 
}
374
 
 
375
 
static void
376
 
sp_dash_selector_dash_activate (GtkObject *object, SPDashSelector *dsel)
377
 
{
378
 
        double *pattern = (double*)gtk_object_get_data (object, "pattern");
379
 
        gtk_object_set_data (GTK_OBJECT (dsel), "pattern", pattern);
380
 
 
381
 
        gtk_signal_emit (GTK_OBJECT (dsel), signals[CHANGED]);
382
 
}
383
 
 
384
 
static void
385
 
sp_dash_selector_offset_value_changed (GtkAdjustment *adj, SPDashSelector *dsel)
386
 
{
387
 
        gtk_signal_emit (GTK_OBJECT (dsel), signals[CHANGED]);
388
 
}
 
229
static void sp_dash_selector_menu_item_image_realize(Gtk::Image *px, double *pattern) {
 
230
    Glib::RefPtr<Gdk::Pixmap> pixmap = Gdk::Pixmap::create(px->get_window(), DASH_PREVIEW_LENGTH + 4, 16, -1);
 
231
    Glib::RefPtr<Gdk::GC> gc = Gdk::GC::create(pixmap);
 
232
 
 
233
    gc->set_rgb_fg_color(Gdk::Color("#ffffff"));
 
234
    pixmap->draw_rectangle(gc, true, 0, 0, DASH_PREVIEW_LENGTH + 4, 16);
 
235
 
 
236
    // FIXME: all of the below twibblering is due to the limitations of gdk_gc_set_dashes (only integers, no zeroes).
 
237
    // Perhaps would make sense to rework this with manually drawn dashes.
 
238
 
 
239
    // Fill in the integer array of pixel-lengths, for display
 
240
    gint8 pixels_i[64];
 
241
    gdouble pixels_d[64];
 
242
    int n_source_dashes = 0;
 
243
    int n_pixel_dashes = 0;
 
244
 
 
245
    signed int i_s, i_p;
 
246
    for (i_s = 0, i_p = 0; pattern[i_s] >= 0.0; i_s ++, i_p ++) {
 
247
        pixels_d[i_p] = 0.0;
 
248
    }
 
249
 
 
250
    n_source_dashes = i_s;
 
251
 
 
252
    for (i_s = 0, i_p = 0; i_s < n_source_dashes; i_s ++, i_p ++) {
 
253
        // calculate the pixel length corresponding to the current dash
 
254
        gdouble pixels = DASH_PREVIEW_WIDTH * pattern[i_s];
 
255
 
 
256
        if (pixels > 0.0)
 
257
            pixels_d [i_p] += pixels;
 
258
        else {
 
259
            if (i_p >= 1) {
 
260
                // dash is zero, skip this element in the array, and set pointer backwards
 
261
                // so the next dash is added to the previous
 
262
                i_p -= 2;
 
263
            } else {
 
264
                // the first dash is zero; bad luck, gdk cannot start pattern with non-stroke, so we
 
265
                // put a 1-pixel stub here (it may turn out not shown, though, see special cases below)
 
266
                pixels_d [i_p] = 1.0;
 
267
            }
 
268
        }
 
269
    }
 
270
 
 
271
    n_pixel_dashes = i_p;
 
272
 
 
273
    gdouble longest_dash = 0.0;
 
274
 
 
275
    // after summation, convert double dash lengths to ints
 
276
    for (i_p = 0; i_p < n_pixel_dashes; i_p ++) {
 
277
        pixels_i [i_p] = (gint8) (pixels_d [i_p] + 0.5);
 
278
        // zero-length dashes are already eliminated, so the <1 dash is short but not zero;
 
279
        // we approximate it with a one-pixel mark
 
280
        if (pixels_i [i_p] < 1)
 
281
            pixels_i [i_p] = 1;
 
282
        if (i_p % 2 == 0) { // it's a dash
 
283
            if (pixels_d [i_p] > longest_dash)
 
284
                longest_dash = pixels_d [i_p];
 
285
        }
 
286
    }
 
287
 
 
288
    Gdk::Color color;
 
289
    if (longest_dash > 1e-18 && longest_dash < 0.5) {
 
290
        // fake "shortening" of one-pixel marks by painting them lighter-than-black
 
291
        gint rgb = 0xffff - (gint) (0xffff * longest_dash / 0.5);
 
292
        color.set_rgb(rgb, rgb, rgb);
 
293
        gc->set_rgb_fg_color(color);
 
294
    } else {
 
295
        color.set_rgb(0, 0, 0);
 
296
        gc->set_rgb_fg_color(color);
 
297
    }
 
298
 
 
299
    if (n_source_dashes > 0) {
 
300
        // special cases:
 
301
        if (all_even_are_zero (pattern, n_source_dashes)) {
 
302
            ; // do not draw anything, only gaps are non-zero
 
303
        } else if (all_odd_are_zero (pattern, n_source_dashes)) {
 
304
            // draw solid line, only dashes are non-zero
 
305
            gc->set_line_attributes(DASH_PREVIEW_WIDTH,
 
306
                                    Gdk::LINE_SOLID, Gdk::CAP_BUTT,
 
307
                                    Gdk::JOIN_MITER);
 
308
            pixmap->draw_line(gc, 4, 8, DASH_PREVIEW_LENGTH, 8);
 
309
        } else {
 
310
            // regular pattern with both gaps and dashes non-zero
 
311
            gc->set_line_attributes(DASH_PREVIEW_WIDTH, Gdk::LINE_ON_OFF_DASH, Gdk::CAP_BUTT, Gdk::JOIN_MITER);
 
312
            gc->set_dashes(0, pixels_i, n_pixel_dashes);
 
313
            pixmap->draw_line(gc, 4, 8, DASH_PREVIEW_LENGTH, 8);
 
314
        }
 
315
    } else {
 
316
        // no pattern, draw solid line
 
317
        gc->set_line_attributes(DASH_PREVIEW_WIDTH, Gdk::LINE_SOLID, Gdk::CAP_BUTT, Gdk::JOIN_MITER);
 
318
        pixmap->draw_line(gc, 4, 8, DASH_PREVIEW_LENGTH, 8);
 
319
    }
 
320
 
 
321
    Glib::RefPtr<Gdk::Bitmap> null_ptr;
 
322
    px->set(pixmap, null_ptr);
 
323
}
 
324
 
 
325
void
 
326
SPDashSelector::dash_activate (Gtk::MenuItem *mi)
 
327
{
 
328
    double *pattern = (double*) mi->get_data("pattern");
 
329
    this->set_data ("pattern", pattern);
 
330
 
 
331
    changed_signal.emit();
 
332
}
 
333
 
 
334
 
 
335
void
 
336
SPDashSelector::offset_value_changed()
 
337
{
 
338
    changed_signal.emit();
 
339
}
 
340
 
 
341
/*
 
342
  Local Variables:
 
343
  mode:c++
 
344
  c-file-style:"stroustrup"
 
345
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
346
  indent-tabs-mode:nil
 
347
  fill-column:99
 
348
  End:
 
349
*/
 
350
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :