diff --git a/share/ui/menus.xml b/share/ui/menus.xml
index 5bcaca8cf6cde27be91a62dd8108e4ca2b5c3f05..03cd74d74851342da91b70863d08d8dbcd005d04 100644
--- a/share/ui/menus.xml
+++ b/share/ui/menus.xml
@@ -108,6 +108,7 @@
+
diff --git a/src/desktop.cpp b/src/desktop.cpp
index 46589ca040e8aa1096815650a2ee5c3d7508160f..335afa17d107865722278bd2336cce2a3c7cb6ce 100644
--- a/src/desktop.cpp
+++ b/src/desktop.cpp
@@ -519,6 +519,9 @@ void SPDesktop::displayModeToggle() {
_setDisplayMode(Inkscape::RENDERMODE_OUTLINE);
break;
case Inkscape::RENDERMODE_OUTLINE:
+ _setDisplayMode(Inkscape::RENDERMODE_VISIBLE_HAIRLINES);
+ break;
+ case Inkscape::RENDERMODE_VISIBLE_HAIRLINES:
_setDisplayMode(Inkscape::RENDERMODE_NORMAL);
break;
default:
diff --git a/src/desktop.h b/src/desktop.h
index 379d36a78694dd058e5a5f7407a6e6b5a38b468b..ec6ea99f7f84d51fa1962945a6e8497a3c806652 100644
--- a/src/desktop.h
+++ b/src/desktop.h
@@ -266,6 +266,9 @@ public:
void setDisplayModeOutline() {
_setDisplayMode(Inkscape::RENDERMODE_OUTLINE);
}
+ void setDisplayModeVisibleHairlines() {
+ _setDisplayMode(Inkscape::RENDERMODE_VISIBLE_HAIRLINES);
+ }
void displayModeToggle();
Inkscape::RenderMode _display_mode;
Inkscape::RenderMode getMode() const { return _display_mode; }
diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h
index 8587fbf66f5505a13cd30752175ad1f65290b188..12d192a7cb69fed12665ca938c16834299bb7b80 100644
--- a/src/display/drawing-context.h
+++ b/src/display/drawing-context.h
@@ -52,6 +52,8 @@ public:
void translate(double dx, double dy) { cairo_translate(_ct, dx, dy); }
void scale(Geom::Scale const &s) { cairo_scale(_ct, s[Geom::X], s[Geom::Y]); }
void scale(double sx, double sy) { cairo_scale(_ct, sx, sy); }
+ void device_to_user_distance(double &dx, double &dy) { cairo_device_to_user_distance(_ct, &dx, &dy); }
+ void user_to_device_distance(double &dx, double &dy) { cairo_user_to_device_distance(_ct, &dx, &dy); }
void moveTo(Geom::Point const &p) { cairo_move_to(_ct, p[Geom::X], p[Geom::Y]); }
void lineTo(Geom::Point const &p) { cairo_line_to(_ct, p[Geom::X], p[Geom::Y]); }
diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp
index 63db9475de603e2a01ae18ac3a7a8cb5a10f0ada..05123297ee974ff88d546a5b53231a4f47b47ee5 100644
--- a/src/display/drawing-shape.cpp
+++ b/src/display/drawing-shape.cpp
@@ -185,6 +185,17 @@ DrawingShape::_renderStroke(DrawingContext &dc)
dc.save();
}
_nrstyle.applyStroke(dc);
+
+ // If the draw mode is set to visible hairlines, don't let them get smaller than half a
+ // pixel.
+ if (_drawing.visibleHairlines()) {
+ double half_pixel_size = 0.5, trash = 0.5;
+ dc.device_to_user_distance(half_pixel_size, trash);
+ if (_nrstyle.stroke_width < half_pixel_size) {
+ dc.setLineWidth(half_pixel_size);
+ }
+ }
+
dc.strokePreserve();
dc.newPath(); // clear path
}
@@ -255,6 +266,17 @@ DrawingShape::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigne
}
if (has_stroke) {
_nrstyle.applyStroke(dc);
+
+ // If the draw mode is set to visible hairlines, don't let anything get smaller
+ // than half a pixel.
+ if (_drawing.visibleHairlines()) {
+ double half_pixel_size = 0.5, trash = 0.5;
+ dc.device_to_user_distance(half_pixel_size, trash);
+ if (_nrstyle.stroke_width < half_pixel_size) {
+ dc.setLineWidth(half_pixel_size);
+ }
+ }
+
dc.strokePreserve();
}
dc.newPath(); // clear path
diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp
index 76c392d67c7eeb835e2675e488e9daa436b6fda4..d823012e3d42741aa076238c30b15f7c0172ff3f 100644
--- a/src/display/drawing-text.cpp
+++ b/src/display/drawing-text.cpp
@@ -603,6 +603,17 @@ unsigned DrawingText::_renderItem(DrawingContext &dc, Geom::IntRect const &/*are
}
if (has_stroke) {
_nrstyle.applyStroke(dc);
+
+ // If the draw mode is set to visible hairlines, don't let anything get smaller
+ // than half a pixel.
+ if (_drawing.visibleHairlines()) {
+ double half_pixel_size = 0.5, trash = 0.5;
+ dc.device_to_user_distance(half_pixel_size, trash);
+ if (_nrstyle.stroke_width < half_pixel_size) {
+ dc.setLineWidth(half_pixel_size);
+ }
+ }
+
dc.strokePreserve();
}
}
diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp
index 18c2d98e8fc76da64bfcf113a8cd9d4dd6de0c8b..4b2a2cadfc31797d78a457185df31b42ca5b2d41 100644
--- a/src/display/drawing.cpp
+++ b/src/display/drawing.cpp
@@ -79,9 +79,14 @@ Drawing::outline() const
return renderMode() == RENDERMODE_OUTLINE;
}
bool
+Drawing::visibleHairlines() const
+{
+ return renderMode() == RENDERMODE_VISIBLE_HAIRLINES;
+}
+bool
Drawing::renderFilters() const
{
- return renderMode() == RENDERMODE_NORMAL;
+ return renderMode() == RENDERMODE_NORMAL || renderMode() == RENDERMODE_VISIBLE_HAIRLINES;
}
int
Drawing::blurQuality() const
diff --git a/src/display/drawing.h b/src/display/drawing.h
index 1348f02af0c8e237c84151453b98a173720e963a..931fe8e4682966aa023dec8d917ba8fb935e1ec2 100644
--- a/src/display/drawing.h
+++ b/src/display/drawing.h
@@ -50,6 +50,7 @@ public:
RenderMode renderMode() const;
ColorMode colorMode() const;
bool outline() const;
+ bool visibleHairlines() const;
bool renderFilters() const;
int blurQuality() const;
int filterQuality() const;
diff --git a/src/display/rendermode.h b/src/display/rendermode.h
index cbd35de73f48f59a8fb8d82280b88c3749482d2f..80e6da2ddc10cd3a885ab7d066b3e05889dda76f 100644
--- a/src/display/rendermode.h
+++ b/src/display/rendermode.h
@@ -12,7 +12,8 @@ namespace Inkscape {
enum RenderMode {
RENDERMODE_NORMAL,
RENDERMODE_NO_FILTERS,
- RENDERMODE_OUTLINE
+ RENDERMODE_OUTLINE,
+ RENDERMODE_VISIBLE_HAIRLINES
};
enum ColorMode {
diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp
index 41f5f29a0c7843a66946d032ab7a740c499fed15..f644aa174b70527ce3d394533d44bc4f5014b962 100644
--- a/src/ui/interface.cpp
+++ b/src/ui/interface.cpp
@@ -682,6 +682,8 @@ static gboolean update_view_menu(GtkWidget *widget, cairo_t * /*cr*/, gpointer u
new_state = mode == Inkscape::RENDERMODE_NO_FILTERS;
} else if (!strcmp(action->id, "ViewModeOutline")) {
new_state = mode == Inkscape::RENDERMODE_OUTLINE;
+ } else if (!strcmp(action->id, "ViewModeVisibleHairlines")) {
+ new_state = mode == Inkscape::RENDERMODE_VISIBLE_HAIRLINES;
} else if (!strcmp(action->id, "ViewColorModeNormal")) {
new_state = colormode == Inkscape::COLORMODE_NORMAL;
} else if (!strcmp(action->id, "ViewColorModeGrayscale")) {
diff --git a/src/verbs.cpp b/src/verbs.cpp
index 47c532a3f061416f880f64623a141a8998491536..fe617148a9c9e418d671312f8336cadf2b6801d0 100644
--- a/src/verbs.cpp
+++ b/src/verbs.cpp
@@ -2132,6 +2132,9 @@ void ZoomVerb::perform(SPAction *action, void *data)
case SP_VERB_VIEW_MODE_OUTLINE:
dt->setDisplayModeOutline();
break;
+ case SP_VERB_VIEW_MODE_VISIBLE_HAIRLINES:
+ dt->setDisplayModeVisibleHairlines();
+ break;
case SP_VERB_VIEW_MODE_TOGGLE:
dt->displayModeToggle();
break;
@@ -3108,6 +3111,8 @@ Verb *Verb::_base_verbs[] = {
N_("Switch to normal display without filters"), nullptr),
new ZoomVerb(SP_VERB_VIEW_MODE_OUTLINE, "ViewModeOutline", N_("_Outline"),
N_("Switch to outline (wireframe) display mode"), nullptr),
+ new ZoomVerb(SP_VERB_VIEW_MODE_VISIBLE_HAIRLINES, "ViewModeVisibleHairlines", N_("Visible _Hairlines"),
+ N_("Make sure hairlines are always drawn thick enough to see"), nullptr),
new ZoomVerb(SP_VERB_VIEW_MODE_TOGGLE, "ViewModeToggle", N_("_Toggle"),
N_("Toggle between normal and outline display modes"), nullptr),
new ZoomVerb(SP_VERB_VIEW_COLOR_MODE_NORMAL, "ViewColorModeNormal", N_("_Normal"),
diff --git a/src/verbs.h b/src/verbs.h
index fe17cb2d12cb56d604ba3798a3e5beffa3fb7dc6..fec42cca24e824eec2fb1b4c2c2061c058f3aa39 100644
--- a/src/verbs.h
+++ b/src/verbs.h
@@ -297,6 +297,7 @@ enum {
SP_VERB_VIEW_MODE_NORMAL,
SP_VERB_VIEW_MODE_NO_FILTERS,
SP_VERB_VIEW_MODE_OUTLINE,
+ SP_VERB_VIEW_MODE_VISIBLE_HAIRLINES,
SP_VERB_VIEW_MODE_TOGGLE,
SP_VERB_VIEW_COLOR_MODE_NORMAL,
SP_VERB_VIEW_COLOR_MODE_GRAYSCALE,
diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp
index 35a9df65b230d284bb212752699bd25cab0846c9..1b717f351c5d13484c9417042789ac725f57371e 100644
--- a/src/widgets/desktop-widget.cpp
+++ b/src/widgets/desktop-widget.cpp
@@ -813,6 +813,8 @@ SPDesktopWidget::updateTitle(gchar const* uri)
Name += N_("outline");
} else if (desktop->getMode() == Inkscape::RENDERMODE_NO_FILTERS) {
Name += N_("no filters");
+ } else if (desktop->getMode() == Inkscape::RENDERMODE_VISIBLE_HAIRLINES) {
+ Name += N_("visible hairlines");
}
if (desktop->getColorMode() != Inkscape::COLORMODE_NORMAL &&