View->Symmetry, bound to the pipe character "|".  Axis is center of the
drawing area.

Bug: does not mirror straight lines

Closes bug: https://gna.org/bugs/?func=detailitem&item_id=18375
---
 brushlib/brush.hpp     |   24 +++++++++++++++++-------
 gui/document.py        |    5 +++++
 gui/menu.xml           |    1 +
 gui/stock.py           |    2 ++
 gui/tileddrawwidget.py |    9 ++++++++-
 gui/toolbar-view.xml   |    1 +
 lib/document.py        |    4 ++--
 lib/layer.py           |    4 ++--
 lib/python_brush.hpp   |    4 ++--
 lib/stroke.py          |    4 ++++
 10 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/brushlib/brush.hpp b/brushlib/brush.hpp
index 458d9df..c81487c 100644
--- a/brushlib/brush.hpp
+++ b/brushlib/brush.hpp
@@ -351,7 +351,7 @@ private:
   //
   // This is only gets called right after update_states_and_setting_values().
   // Returns true if the surface was modified.
-  bool prepare_and_draw_dab (Surface * surface)
+  bool prepare_and_draw_dab (Surface * surface, float symm_axis)
   {
     float x, y, opaque;
     float radius;
@@ -543,10 +543,20 @@ private:
 
     // the functions below will CLAMP most inputs
     hsv_to_rgb_float (&color_h, &color_s, &color_v);
-    return surface->draw_dab (x, y, radius, color_h, color_s, color_v, opaque, 
hardness, eraser_target_alpha,
-                              states[STATE_ACTUAL_ELLIPTICAL_DAB_RATIO], 
states[STATE_ACTUAL_ELLIPTICAL_DAB_ANGLE],
-                              settings_value[BRUSH_LOCK_ALPHA],
-                              settings_value[BRUSH_COLORIZE]);
+
+    bool ret1(false), ret2(false);
+    if(symm_axis > 0) {
+        float xx = symm_axis + (symm_axis-x);
+        ret1 = surface->draw_dab (xx, y, radius, color_h, color_s, color_v, 
opaque, hardness, eraser_target_alpha,
+                                  states[STATE_ACTUAL_ELLIPTICAL_DAB_RATIO], 
states[STATE_ACTUAL_ELLIPTICAL_DAB_ANGLE],
+                                  settings_value[BRUSH_LOCK_ALPHA],
+                                  settings_value[BRUSH_COLORIZE]);
+    }
+    ret2 =  surface->draw_dab (x, y, radius, color_h, color_s, color_v, 
opaque, hardness, eraser_target_alpha,
+                               states[STATE_ACTUAL_ELLIPTICAL_DAB_RATIO], 
states[STATE_ACTUAL_ELLIPTICAL_DAB_ANGLE],
+                               settings_value[BRUSH_LOCK_ALPHA],
+                               settings_value[BRUSH_COLORIZE]);
+    return ret1 || ret2;
   }
 
   // How many dabs will be drawn between the current and the next (x, y, 
pressure, +dt) position?
@@ -600,7 +610,7 @@ public:
   // - paints zero, one or several dabs
   // - decides whether the stroke is finished (for undo/redo)
   // returns true if the stroke is finished or empty
-  bool stroke_to (Surface * surface, float x, float y, float pressure, float 
xtilt, float ytilt, double dtime)
+  bool stroke_to (Surface * surface, float x, float y, float pressure, float 
xtilt, float ytilt, double dtime, float symm_axis = 0)
   {
     //printf("%f %f %f %f\n", (double)dtime, (double)x, (double)y, 
(double)pressure);
 
@@ -739,7 +749,7 @@ public:
       }
     
       update_states_and_setting_values (step_dx, step_dy, step_dpressure, 
step_declination, step_ascension, step_dtime);
-      bool painted_now = prepare_and_draw_dab (surface);
+      bool painted_now = prepare_and_draw_dab (surface, symm_axis);
       if (painted_now) {
         painted = YES;
       } else if (painted == UNKNOWN) {
diff --git a/gui/document.py b/gui/document.py
index 4651571..1e3934f 100644
--- a/gui/document.py
+++ b/gui/document.py
@@ -125,6 +125,9 @@ class Document(object):
             ('RotateRight',  stock.ROTATE_RIGHT, None, None,
                 _("Rotate the view right"),
                 self.rotate_cb),
+            ('Symmetry', stock.SYMMETRY, None, None,
+                _("Symmetry: duplicate strokes mirrored horizontally"),
+                self.symmetry_cb),
             ('MirrorHorizontal', stock.MIRROR_HORIZONTAL, None, None,
                 _("Mirror: flip the view left to right"),
                 self.mirror_horizontal_cb),
@@ -507,6 +510,8 @@ class Document(object):
         self.zoom(action.get_name())
     def rotate_cb(self, action):
         self.rotate(action.get_name())
+    def symmetry_cb(self, action):
+        self.tdw.symmetry()
     def mirror_horizontal_cb(self, action):
         self.tdw.mirror()
     def mirror_vertical_cb(self, action):
diff --git a/gui/menu.xml b/gui/menu.xml
index 0db01d3..0507d69 100644
--- a/gui/menu.xml
+++ b/gui/menu.xml
@@ -50,6 +50,7 @@
       <menuitem action='ZoomOut'/>
       <menuitem action='RotateLeft'/>
       <menuitem action='RotateRight'/>
+      <menuitem action='Symmetry'/>
       <menuitem action='MirrorHorizontal'/>
       <menuitem action='MirrorVertical'/>
       <separator/>
diff --git a/gui/stock.py b/gui/stock.py
index 492e7fe..29bbe35 100644
--- a/gui/stock.py
+++ b/gui/stock.py
@@ -22,6 +22,7 @@ TOOL_SCRATCHPAD = "mypaint-tool-scratchpad"
 TOOL_LAYERS = "mypaint-tool-layers"
 ROTATE_LEFT = "object-rotate-left"
 ROTATE_RIGHT = "object-rotate-right"
+SYMMETRY = "object-symmetry"
 MIRROR_HORIZONTAL = "object-flip-horizontal"
 MIRROR_VERTICAL = "object-flip-vertical"
 BRUSH_BLEND_MODES = "mypaint-brush-blend-modes"
@@ -46,6 +47,7 @@ _stock_items = [
         gdk.CONTROL_MASK, gdk.keyval_from_name("Left"), None),
     (ROTATE_RIGHT, _("Rotate Clockwise"),
         gdk.CONTROL_MASK, gdk.keyval_from_name("Right"), None),
+    (SYMMETRY, _("Symmetry"), 0, ord("|"), None),
     (MIRROR_HORIZONTAL, _("Mirror Horizontal"), 0, ord("i"), None),
     (MIRROR_VERTICAL, _("Mirror Vertical"), 0, ord("u"), None),
     (BRUSH_BLEND_MODES, _("Blend Mode"), 0, 0, None),
diff --git a/gui/tileddrawwidget.py b/gui/tileddrawwidget.py
index 56f7400..904a719 100644
--- a/gui/tileddrawwidget.py
+++ b/gui/tileddrawwidget.py
@@ -96,6 +96,7 @@ class TiledDrawWidget(gtk.DrawingArea):
         self.translation_y = 0.0
         self.scale = 1.0
         self.rotation = 0.0
+        self.symmetrical = False
         self.mirrored = False
 
         self.has_pointer = False
@@ -277,7 +278,10 @@ class TiledDrawWidget(gtk.DrawingArea):
         if dtime < 0.0:
             print 'Time is running backwards, dtime=%f' % dtime
             dtime = 0.0
-        data = (x, y, pressure, xtilt, ytilt)
+        sx = 0
+        if(self.symmetrical):
+            sx = self.get_allocation()[2]/2
+        data = (x, y, pressure, xtilt, ytilt, sx)
         if dtime == 0.0:
             self.motions.append(data)
         elif dtime > 0.0:
@@ -621,6 +625,9 @@ class TiledDrawWidget(gtk.DrawingArea):
         def f(): self.rotation = angle
         self.rotozoom_with_center(f)
 
+    def symmetry(self):
+        self.symmetrical = not self.symmetrical
+
     def mirror(self):
         def f(): self.mirrored = not self.mirrored
         self.rotozoom_with_center(f)
diff --git a/gui/toolbar-view.xml b/gui/toolbar-view.xml
index f26e454..9bf99ba 100644
--- a/gui/toolbar-view.xml
+++ b/gui/toolbar-view.xml
@@ -17,6 +17,7 @@ the Free Software Foundation; either version 2 of the 
License, or
       <toolitem action="ZoomOut"/>
       <toolitem action="RotateLeft"/>
       <toolitem action="RotateRight"/>
+      <toolitem action="Symmetry"/>
       <toolitem action="MirrorHorizontal"/>
       <toolitem action="MirrorVertical"/>
     </placeholder>
diff --git a/lib/document.py b/lib/document.py
index 6822c31..50916af 100644
--- a/lib/document.py
+++ b/lib/document.py
@@ -176,7 +176,7 @@ class Document():
         if not self.layer.is_empty():
             self.do(command.ClearLayer(self))
 
-    def stroke_to(self, dtime, x, y, pressure, xtilt, ytilt):
+    def stroke_to(self, dtime, x, y, pressure, xtilt, ytilt, symm_axis = 0):
         if not self.stroke:
             self.stroke = stroke.Stroke()
             self.stroke.start_recording(self.brush)
@@ -184,7 +184,7 @@ class Document():
         self.stroke.record_event(dtime, x, y, pressure, xtilt, ytilt)
 
         split = self.layer.stroke_to(self.brush, x, y,
-                                pressure, xtilt, ytilt, dtime)
+                                pressure, xtilt, ytilt, dtime, symm_axis)
 
         if split:
             self.split_stroke()
diff --git a/lib/layer.py b/lib/layer.py
index d2abf83..83a53f4 100644
--- a/lib/layer.py
+++ b/lib/layer.py
@@ -69,11 +69,11 @@ class Layer:
     def save_as_png(self, filename, *args, **kwargs):
         self._surface.save_as_png(filename, *args, **kwargs)
 
-    def stroke_to(self, brush, x, y, pressure, xtilt, ytilt, dtime):
+    def stroke_to(self, brush, x, y, pressure, xtilt, ytilt, dtime, symm_axis):
         """Render a part of a stroke."""
         self._surface.begin_atomic()
         split = brush.stroke_to(self._surface, x, y,
-                                    pressure, xtilt, ytilt, dtime)
+                                    pressure, xtilt, ytilt, dtime, symm_axis)
         self._surface.end_atomic()
         return split
 
diff --git a/lib/python_brush.hpp b/lib/python_brush.hpp
index 4ca53ab..9f32989 100644
--- a/lib/python_brush.hpp
+++ b/lib/python_brush.hpp
@@ -43,9 +43,9 @@ public:
 
   // same as stroke_to() but with exception handling, should an
   // exception happen in the surface code (eg. out-of-memory)
-  PyObject* python_stroke_to (Surface * surface, float x, float y, float 
pressure, float xtilt, float ytilt, double dtime)
+  PyObject* python_stroke_to (Surface * surface, float x, float y, float 
pressure, float xtilt, float ytilt, double dtime, float symm_axis = 0)
   {
-    bool res = stroke_to (surface, x, y, pressure, xtilt, ytilt, dtime);
+    bool res = stroke_to (surface, x, y, pressure, xtilt, ytilt, dtime, 
symm_axis);
     if (PyErr_Occurred()) {
       return NULL;
     } else if (res) {
diff --git a/lib/stroke.py b/lib/stroke.py
index ef0202b..214756a 100644
--- a/lib/stroke.py
+++ b/lib/stroke.py
@@ -41,6 +41,10 @@ class Stroke:
     def record_event(self, dtime, x, y, pressure, xtilt,ytilt):
         assert not self.finished
         self.tmp_event_list.append((dtime, x, y, pressure, xtilt,ytilt))
+        if(x < 694):
+            self.tmp_event_list.append((dtime, 694+x, y, pressure, 
xtilt,ytilt))
+        else:
+            self.tmp_event_list.append((dtime, 694-x, y, pressure, 
xtilt,ytilt))
 
     def stop_recording(self):
         assert not self.finished
-- 
1.7.7.3

_______________________________________________
Mypaint-discuss mailing list
[email protected]
https://mail.gna.org/listinfo/mypaint-discuss

Reply via email to