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
