diff options
Diffstat (limited to '')
-rw-r--r-- | src/ui/widget/dash-selector.cpp | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/src/ui/widget/dash-selector.cpp b/src/ui/widget/dash-selector.cpp new file mode 100644 index 0000000..897b964 --- /dev/null +++ b/src/ui/widget/dash-selector.cpp @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @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 v2+, read the file 'COPYING' for more information. + */ + +#include "dash-selector.h" + +#include <cstring> + +#include <glibmm/i18n.h> + +#include <2geom/coord.h> + +#include "preferences.h" + +#include "display/cairo-utils.h" + +#include "style.h" + +#include "ui/dialog-events.h" +#include "ui/widget/spinbutton.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +gchar const *const DashSelector::_prefs_path = "/palette/dashes"; + +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}; + +static size_t BD_LEN = 7; // must correspond to the number of entries in the next line +static double *builtin_dashes[] = {dash_0, dash_1_1, dash_2_1, dash_4_1, dash_1_2, dash_1_4, nullptr}; + +static double **dashes = nullptr; + +DashSelector::DashSelector() + : preview_width(80), + preview_height(16), + preview_lineheight(2) +{ + set_spacing(4); + + // TODO: find something more sensible here!! + init_dashes(); + + dash_store = Gtk::ListStore::create(dash_columns); + dash_combo.set_model(dash_store); + dash_combo.pack_start(image_renderer); + dash_combo.set_cell_data_func(image_renderer, sigc::mem_fun(*this, &DashSelector::prepareImageRenderer)); + dash_combo.set_tooltip_text(_("Dash pattern")); + dash_combo.get_style_context()->add_class("combobright"); + dash_combo.show(); + dash_combo.signal_changed().connect( sigc::mem_fun(*this, &DashSelector::on_selection) ); + + this->pack_start(dash_combo, true, true, 0); + + offset = Gtk::Adjustment::create(0.0, 0.0, 10.0, 0.1, 1.0, 0.0); + offset->signal_value_changed().connect(sigc::mem_fun(*this, &DashSelector::offset_value_changed)); + auto sb = new Inkscape::UI::Widget::SpinButton(offset, 0.1, 2); + sb->set_tooltip_text(_("Pattern offset")); + sp_dialog_defocus_on_enter_cpp(sb); + sb->show(); + + this->pack_start(*sb, false, false, 0); + + int np=0; + while (dashes[np]){ np++;} + for (int i = 0; i<np-1; i++) { // all but the custom one go this way + // Add the dashes to the combobox + Gtk::TreeModel::Row row = *(dash_store->append()); + row[dash_columns.dash] = dashes[i]; + row[dash_columns.pixbuf] = Glib::wrap(sp_dash_to_pixbuf(dashes[i])); + } + // add the custom one + Gtk::TreeModel::Row row = *(dash_store->append()); + row[dash_columns.dash] = dashes[np-1]; + row[dash_columns.pixbuf] = Glib::wrap(sp_text_to_pixbuf((char *)"Custom")); + + this->set_data("pattern", dashes[0]); +} + +DashSelector::~DashSelector() { + // FIXME: for some reason this doesn't get called; does the call to manage() in + // sp_stroke_style_line_widget_new() not processed correctly? +} + +void DashSelector::prepareImageRenderer( Gtk::TreeModel::const_iterator const &row ) { + + Glib::RefPtr<Gdk::Pixbuf> pixbuf = (*row)[dash_columns.pixbuf]; + image_renderer.property_pixbuf() = pixbuf; +} + +void DashSelector::init_dashes() { + + if (!dashes) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + std::vector<Glib::ustring> dash_prefs = prefs->getAllDirs(_prefs_path); + + int pos = 0; + if (!dash_prefs.empty()) { + SPStyle style; + dashes = g_new (double *, dash_prefs.size() + 2); // +1 for custom slot, +1 for terminator slot + + for (auto & dash_pref : dash_prefs) { + style.readFromPrefs( dash_pref ); + + if (!style.stroke_dasharray.values.empty()) { + dashes[pos] = g_new (double, style.stroke_dasharray.values.size() + 1); + double *d = dashes[pos]; + unsigned i = 0; + for (; i < style.stroke_dasharray.values.size(); i++) { + d[i] = style.stroke_dasharray.values[i].value; + } + d[i] = -1; + } else { + dashes[pos] = dash_0; + } + pos += 1; + } + } else { // This code may never execute - a new preferences.xml is created for a new user. Maybe if the user deletes dashes from preferences.xml? + dashes = g_new (double *, BD_LEN + 2); // +1 for custom slot, +1 for terminator slot + unsigned i; + for(i=0;i<BD_LEN;i++) { + dashes[i] = builtin_dashes[i]; + } + pos = BD_LEN; + } + // make a place to hold the custom dashes, up to 15 positions long (+ terminator) + dashes[pos] = g_new (double, 16); + double *d = dashes[pos]; + int i=0; + for(i=0;i<15;i++){ d[i]=i; } // have to put something in there, this is a pattern hopefully nobody would choose + d[15]=-1.0; + // final terminator + dashes[++pos] = nullptr; + } +} + +void DashSelector::set_dash (int ndash, double *dash, double o) +{ + int pos = -1; // Allows custom patterns to remain unscathed by this. + int count = 0; // will hold the NULL terminator at the end of the dashes list + 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++,count++) { + 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 (!Geom::are_near(dash[j], pattern[j], delta)) { + break; + } + } + if (j == ndash) { + pos = i; + break; + } + } + } + } + else if(ndash==0) { + pos = 0; + } + if(pos>=0){ + this->set_data("pattern", dashes[pos]); + this->dash_combo.set_active(pos); + this->offset->set_value(o); + if(pos == 10) { + this->offset->set_value(10.0); + } + } + else { // Hit a custom pattern in the SVG, write it into the combobox. + count--; // the one slot for custom patterns + double *d = dashes[count]; + int i=0; + for(i=0;i< (ndash > 15 ? 15 : ndash) ;i++) { + d[i]=dash[i]; + } // store the custom pattern + d[ndash]=-1.0; //terminate it + this->set_data("pattern", dashes[count]); + this->dash_combo.set_active(count); + this->offset->set_value(o); // what does this do???? + } +} + +void DashSelector::get_dash(int *ndash, double **dash, double *off) +{ + 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 = nullptr; + if (off) + *off = 0.0; + } +} + +/** + * Fill a pixbuf with the dash pattern using standard cairo drawing + */ +GdkPixbuf* DashSelector::sp_dash_to_pixbuf(double *pattern) +{ + int n_dashes; + for (n_dashes = 0; pattern[n_dashes] >= 0.0; n_dashes ++) ; + + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, preview_width, preview_height); + cairo_t *ct = cairo_create(s); + + cairo_set_line_width (ct, preview_lineheight); + cairo_scale (ct, preview_lineheight, 1); + //cairo_set_source_rgb (ct, 0, 0, 0); + cairo_move_to (ct, 0, preview_height/2); + cairo_line_to (ct, preview_width, preview_height/2); + cairo_set_dash(ct, pattern, n_dashes, 0); + cairo_stroke (ct); + + cairo_destroy(ct); + cairo_surface_flush(s); + + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); + return pixbuf; +} + +/** + * Fill a pixbuf with a text label using standard cairo drawing + */ +GdkPixbuf* DashSelector::sp_text_to_pixbuf(char *text) +{ + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, preview_width, preview_height); + cairo_t *ct = cairo_create(s); + + cairo_select_font_face (ct, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (ct, 12.0); + cairo_set_source_rgb (ct, 0.0, 0.0, 0.0); + cairo_move_to (ct, 16.0, 13.0); + cairo_show_text (ct, text); + + cairo_stroke (ct); + + cairo_destroy(ct); + cairo_surface_flush(s); + + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); + return pixbuf; +} + +void DashSelector::on_selection () +{ + double *pattern = dash_combo.get_active()->get_value(dash_columns.dash); + this->set_data ("pattern", pattern); + + changed_signal.emit(); +} + +void DashSelector::offset_value_changed() +{ + changed_signal.emit(); +} +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +/* + 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 : |