Code

Add a zoom correction option to preferences (used when zooming to 1:1 etc. to display...
authorcilix42 <cilix42@users.sourceforge.net>
Thu, 4 Sep 2008 16:44:24 +0000 (16:44 +0000)
committercilix42 <cilix42@users.sourceforge.net>
Thu, 4 Sep 2008 16:44:24 +0000 (16:44 +0000)
src/preferences-skeleton.h
src/ui/dialog/inkscape-preferences.cpp
src/ui/dialog/inkscape-preferences.h
src/ui/widget/preferences-widget.cpp
src/ui/widget/preferences-widget.h
src/verbs.cpp

index 78c79ebd102fb249ad47cd8ffa1141e486abc0b3..3ca113e856328e0468fc97403d7f547f059dc672 100644 (file)
@@ -222,6 +222,7 @@ static char const preferences_skeleton[] =
 "    <group id=\"defaultscale\" value=\"2\"/>\n"
 "    <group id=\"maxrecentdocuments\" value=\"36\"/>\n"
 "    <group id=\"zoomincrement\" value=\"1.414213562\"/>\n"
+"    <group id=\"zoomcorrection\" value=\"1.0\" unit=\"mm\"/>\n"
 "    <group id=\"keyscroll\" value=\"15\"/>\n"
 "    <group id=\"wheelscroll\" value=\"40\"/>\n"
 "    <group id=\"spacepans\" value=\"0\"/>\n"
index ef6c030e852377adc250e5cd31d11ea35e0f409f..dcfc4e575bfd006ccf9bfbe49878104f44ed973e 100644 (file)
@@ -960,19 +960,23 @@ void InkscapePreferences::initPageUI()
 
     _misc_small_toolbar.init( "toolbox", "small", sizeLabels, sizeValues, G_N_ELEMENTS(sizeLabels), 0 );
     _page_ui.add_line( false, _("Commands bar icon size"), _misc_small_toolbar, "",
-                           _("Set the size for the commands toolbar to use (requires restart)"), false);
+                              _("Set the size for the commands toolbar to use (requires restart)"), false);
 
     _misc_small_secondary.init( "toolbox", "secondary", sizeLabels, sizeValues, G_N_ELEMENTS(sizeLabels), 1 );
     _page_ui.add_line( false, _("Tool controls bar icon size"), _misc_small_secondary, "",
-                           _("Set the size for the secondary toolbar to use (requires restart)"), false);
+                              _("Set the size for the secondary toolbar to use (requires restart)"), false);
 
     _misc_small_tools.init( "toolbox.tools", "small", sizeLabels, sizeValues, G_N_ELEMENTS(sizeLabels), 0 );
     _page_ui.add_line( false, _("Main toolbar icon size"), _misc_small_tools, "",
-                           _("Set the size for the main tools to use (requires restart)"), false);
+                              _("Set the size for the main tools to use (requires restart)"), false);
 
     _misc_recent.init("options.maxrecentdocuments", "value", 0.0, 1000.0, 1.0, 1.0, 1.0, true, false);
     _page_ui.add_line( false, _("Maximum documents in Open Recent:"), _misc_recent, "",
-                           _("The maximum length of the Open Recent list in the File menu"), false);
+                              _("The maximum length of the Open Recent list in the File menu"), false);
+
+    _ui_zoom_correction.init(300, 30, 1.00, 200.0, 1.0, 10.0, 1.0);
+    _page_ui.add_line( false, _("Zoom correction factor (in %):"), _ui_zoom_correction, "",
+                              _("Adjust the slider until the length of the ruler on your screen matches its real length. This information is used when zooming to 1:1, 1:2, etc., to display objects in their true sizes"), true);
 
     this->AddPage(_page_ui, _("Interface"), PREFS_PAGE_UI);
 }
index 2dd0ca4df33dbe843ba57df726acc4031b178571..a6fc96a3fb3123650c629868f69f19271ad12152 100644 (file)
@@ -166,6 +166,7 @@ protected:
     PrefCheckButton _sel_layer_deselects;
 
     PrefSpinButton  _importexport_export, _misc_recent, _misc_simpl;
+    ZoomCorrRulerSlider _ui_zoom_correction;
     PrefSpinButton  _misc_latency_skew;
     PrefCheckButton _misc_comment, _misc_forkvectors, _misc_scripts, _misc_namedicon_delay;
     PrefCombo       _misc_small_toolbar;
index 6c5473caa062ca39e0e64f0e0257cde57170c024..d4164864b63a0e412b1421c8b935d0a827960dfd 100644 (file)
@@ -242,6 +242,212 @@ void PrefSpinButton::on_value_changed()
     }
 }
 
+const double ZoomCorrRuler::textsize = 7;
+const double ZoomCorrRuler::textpadding = 5;
+
+ZoomCorrRuler::ZoomCorrRuler(int width, int height) :
+    _unitconv(1.0),
+    _border(5)
+{
+    set_size(width, height);
+}
+
+void ZoomCorrRuler::set_size(int x, int y)
+{
+    _min_width = x;
+    _height = y;
+    set_size_request(x + _border*2, y + _border*2);
+}
+
+// The following two functions are borrowed from 2geom's toy-framework-2; if they are useful in
+// other locations, we should perhaps make them (or adapted versions of them) publicly available
+static void
+draw_text(cairo_t *cr, Geom::Point loc, const char* txt, bool bottom = "false",
+          double fontsize = ZoomCorrRuler::textsize, std::string fontdesc = "Sans") {
+    PangoLayout* layout = pango_cairo_create_layout (cr);
+    pango_layout_set_text(layout, txt, -1);
+
+    // set font and size
+    std::ostringstream sizestr;
+    sizestr << fontsize;
+    fontdesc = fontdesc + " " + sizestr.str();
+    PangoFontDescription *font_desc = pango_font_description_from_string(fontdesc.c_str());
+    pango_layout_set_font_description(layout, font_desc);
+    pango_font_description_free (font_desc);
+
+    PangoRectangle logical_extent;
+    pango_layout_get_pixel_extents(layout, NULL, &logical_extent);
+    cairo_move_to(cr, loc[Geom::X], loc[Geom::Y] - (bottom ? logical_extent.height : 0));
+    pango_cairo_show_layout(cr, layout);
+}
+
+static void
+draw_number(cairo_t *cr, Geom::Point pos, double num) {
+    std::ostringstream number;
+    number << num;
+    draw_text(cr, pos, number.str().c_str(), true);
+}
+
+/*
+ * \arg dist The distance between consecutive minor marks
+ * \arg major_interval Number of marks after which to draw a major mark
+ */
+void
+ZoomCorrRuler::draw_marks(Cairo::RefPtr<Cairo::Context> cr, double dist, int major_interval) {
+    const double zoomcorr = prefs_get_double_attribute("options.zoomcorrection", "value", 1.0);
+    double mark = 0;
+    int i = 0;
+    while (mark <= _drawing_width) {
+        cr->move_to(mark, _height);
+        if ((i % major_interval) == 0) {
+            // major mark
+            cr->line_to(mark, 0);
+            Geom::Point textpos(mark + 3, ZoomCorrRuler::textsize + ZoomCorrRuler::textpadding);
+            draw_number(cr->cobj(), textpos, dist * i);
+        } else {
+            // minor mark
+            cr->line_to(mark, ZoomCorrRuler::textsize + 2 * ZoomCorrRuler::textpadding);
+        }
+        mark += dist * zoomcorr / _unitconv;
+        ++i;
+    }
+}
+
+void
+ZoomCorrRuler::redraw() {
+    Glib::RefPtr<Gdk::Window> window = get_window();
+    Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
+
+    int w, h;
+    window->get_size(w, h);
+    _drawing_width = w - _border * 2;
+
+    cr->set_source_rgb(1.0, 1.0, 1.0);
+    cr->set_fill_rule(Cairo::FILL_RULE_WINDING);
+    cr->rectangle(0, 0, w, _height + _border*2);
+    cr->fill();
+
+    cr->set_source_rgb(0.0, 0.0, 0.0);
+    cr->set_line_width(0.5);
+
+    cr->translate(_border, _border); // so that we have a small white border around the ruler
+    cr->move_to (0, _height);
+    cr->line_to (_drawing_width, _height);
+
+    const char *abbr = prefs_get_string_attribute("options.zoomcorrection", "unit");
+    if (!strcmp(abbr, "cm")) {
+        draw_marks(cr, 0.1, 10);
+    } else if (!strcmp(abbr, "ft")) {
+        draw_marks(cr, 1/12.0, 12);
+    } else if (!strcmp(abbr, "in")) {
+        draw_marks(cr, 0.25, 4);
+    } else if (!strcmp(abbr, "m")) {
+        draw_marks(cr, 1/10.0, 10);
+    } else if (!strcmp(abbr, "mm")) {
+        draw_marks(cr, 10, 10);
+    } else if (!strcmp(abbr, "pc")) {
+        draw_marks(cr, 1, 10);
+    } else if (!strcmp(abbr, "pt")) {
+        draw_marks(cr, 10, 10);
+    } else if (!strcmp(abbr, "px")) {
+        draw_marks(cr, 10, 10);
+    } else {
+        draw_marks(cr, 1, 1);
+    }
+    cr->stroke();
+}
+
+bool
+ZoomCorrRuler::on_expose_event(GdkEventExpose *event) {
+    this->redraw();
+    return true;
+}
+
+void
+ZoomCorrRulerSlider::on_slider_value_changed()
+{
+    if (this->is_visible() || freeze) //only take action if user changed value
+    {
+        freeze = true;
+        prefs_set_double_attribute ("options.zoomcorrection", "value", _slider.get_value() / 100.0);
+        _sb.set_value(_slider.get_value());
+        _ruler.redraw();
+        freeze = false;
+    }
+}
+
+void
+ZoomCorrRulerSlider::on_spinbutton_value_changed()
+{
+    if (this->is_visible() || freeze) //only take action if user changed value
+    {
+        freeze = true;
+        prefs_set_double_attribute ("options.zoomcorrection", "value", _sb.get_value() / 100.0);
+        _slider.set_value(_sb.get_value());
+        _ruler.redraw();
+        freeze = false;
+    }
+}
+
+void
+ZoomCorrRulerSlider::on_unit_changed() {
+    if (GPOINTER_TO_INT(_unit.get_data("sensitive")) == 0) {
+        // when the unit menu is initialized, the unit is set to the default but
+        // it needs to be reset later so we don't perform the change in this case
+        return;
+    }
+    prefs_set_string_attribute ("options.zoomcorrection", "unit", _unit.getUnitAbbr().c_str());
+    double conv = _unit.getConversion(_unit.getUnitAbbr(), "px");
+    _ruler.set_unit_conversion(conv);
+    if (_ruler.is_visible()) {
+        _ruler.redraw();
+    }
+}
+
+void
+ZoomCorrRulerSlider::init(int ruler_width, int ruler_height, double lower, double upper,
+                      double step_increment, double page_increment, double default_value)
+{
+    double value = prefs_get_double_attribute_limited ("options.zoomcorrection", "value", default_value, lower, upper) * 100.0;
+
+    freeze = false;
+
+    _ruler.set_size(ruler_width, ruler_height);
+
+    _slider.set_size_request(_ruler.width(), -1);
+    _slider.set_range (lower, upper);
+    _slider.set_increments (step_increment, page_increment);
+    _slider.set_value (value);
+    _slider.set_digits(2);
+
+    _slider.signal_value_changed().connect(sigc::mem_fun(*this, &ZoomCorrRulerSlider::on_slider_value_changed));
+    _sb.signal_value_changed().connect(sigc::mem_fun(*this, &ZoomCorrRulerSlider::on_spinbutton_value_changed));
+    _unit.signal_changed().connect(sigc::mem_fun(*this, &ZoomCorrRulerSlider::on_unit_changed));
+
+    _sb.set_range (lower, upper);
+    _sb.set_increments (step_increment, page_increment);
+    _sb.set_value (value);
+    _sb.set_digits(2);
+
+    _unit.set_data("sensitive", GINT_TO_POINTER(0));
+    _unit.setUnitType(UNIT_TYPE_LINEAR);
+    _unit.set_data("sensitive", GINT_TO_POINTER(1));
+    _unit.setUnit(prefs_get_string_attribute ("options.zoomcorrection", "unit"));
+
+    Gtk::Table *table = Gtk::manage(new Gtk::Table());
+    Gtk::Alignment *alignment1 = Gtk::manage(new Gtk::Alignment(0.5,1,0,0));
+    Gtk::Alignment *alignment2 = Gtk::manage(new Gtk::Alignment(0.5,1,0,0));
+    alignment1->add(_sb);
+    alignment2->add(_unit);
+
+    table->attach(_slider,     0, 1, 0, 1);
+    table->attach(*alignment1, 1, 2, 0, 1, static_cast<Gtk::AttachOptions>(0));
+    table->attach(_ruler,      0, 1, 1, 2);
+    table->attach(*alignment2, 1, 2, 1, 2, static_cast<Gtk::AttachOptions>(0));
+
+    this->pack_start(*table, Gtk::PACK_EXPAND_WIDGET);
+}
+
 void PrefCombo::init(const std::string& prefs_path, const std::string& attr,
                      Glib::ustring labels[], int values[], int num_items, int default_value)
 {
index 0b907ae346b508a4e3bb3186c2938b9abeeb0f85..9f10f8ca864ac6394ced8fde2a7065574262a091 100644 (file)
@@ -22,6 +22,8 @@
 #include <gtkmm/treeview.h>
 #include <gtkmm/radiobutton.h>
 #include <gtkmm/box.h>
+#include <gtkmm/scale.h>
+#include <gtkmm/drawingarea.h>
 #include <gtkmm/frame.h>
 #include <gtkmm/filechooserbutton.h>
 #include <sigc++/sigc++.h>
@@ -82,6 +84,48 @@ protected:
     void on_value_changed();
 };
 
+class ZoomCorrRuler : public Gtk::DrawingArea {
+public:
+    ZoomCorrRuler(int width = 100, int height = 20);
+    void set_size(int x, int y);
+    void set_unit_conversion(double conv) { _unitconv = conv; }
+    void set_cairo_context(Cairo::RefPtr<Cairo::Context> cr);
+    void redraw();
+
+    int width() { return _min_width + _border*2; }
+
+    static const double textsize;
+    static const double textpadding;
+
+private:
+    bool on_expose_event(GdkEventExpose *event);
+    void draw_marks(Cairo::RefPtr<Cairo::Context> cr, double dist, int major_interval);
+
+    double _unitconv;
+    int _min_width;
+    int _height;
+    int _border;
+    int _drawing_width;
+};
+
+class ZoomCorrRulerSlider : public Gtk::VBox
+{
+public:
+    void init(int ruler_width, int ruler_height, double lower, double upper,
+              double step_increment, double page_increment, double default_value);
+
+private:
+    void on_slider_value_changed();
+    void on_spinbutton_value_changed();
+    void on_unit_changed();
+
+    Gtk::SpinButton _sb;
+    UnitMenu        _unit;
+    Gtk::HScale     _slider;
+    ZoomCorrRuler   _ruler;
+    bool freeze; // used to block recursive updates of slider and spinbutton
+};
+
 class PrefCombo : public Gtk::ComboBoxText
 {
 public:
index a19ac77536ee4a489c9b0db20afbefbb587a9997..6b8d0a1fada0b6a1565550ffde5ad1616a9860cf 100644 (file)
@@ -1645,20 +1645,23 @@ ZoomVerb::perform(SPAction *action, void *data, void */*pdata*/)
         }
         case SP_VERB_ZOOM_1_1:
         {
+            double zcorr = prefs_get_double_attribute ("options.zoomcorrection", "value", 1.0);
             NR::Rect const d = dt->get_display_area();
-            dt->zoom_absolute( d.midpoint()[NR::X], d.midpoint()[NR::Y], 1.0 );
+            dt->zoom_absolute( d.midpoint()[NR::X], d.midpoint()[NR::Y], 1.0 * zcorr );
             break;
         }
         case SP_VERB_ZOOM_1_2:
         {
+            double zcorr = prefs_get_double_attribute ("options.zoomcorrection", "value", 1.0);
             NR::Rect const d = dt->get_display_area();
-            dt->zoom_absolute( d.midpoint()[NR::X], d.midpoint()[NR::Y], 0.5);
+            dt->zoom_absolute( d.midpoint()[NR::X], d.midpoint()[NR::Y], 0.5 * zcorr );
             break;
         }
         case SP_VERB_ZOOM_2_1:
         {
+            double zcorr = prefs_get_double_attribute ("options.zoomcorrection", "value", 1.0);
             NR::Rect const d = dt->get_display_area();
-            dt->zoom_absolute( d.midpoint()[NR::X], d.midpoint()[NR::Y], 2.0 );
+            dt->zoom_absolute( d.midpoint()[NR::X], d.midpoint()[NR::Y], 2.0 * zcorr );
             break;
         }
         case SP_VERB_ZOOM_PAGE: