From 47ad76f513846a8501f84c057b28a146031859b6 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Thu, 8 Aug 2024 09:43:36 -0400 Subject: Show page in simulator (#3120) * add exception logging helpers * wip * show page and drop shadow from SVG * allow toggling page * add page icon * add dark mode icon * showpageshadow * refresh after background change (fix for macOS) * fix params sim background * try a native GraphicsBrush for windows * show page button in standalone simulator only and adapt shadow color * remove doubled line --------- Co-authored-by: Kaalleen --- icons/page.png | Bin 0 -> 3191 bytes icons/page.svg | 97 ++++++++++++++++++++++++++++++++++ icons/page_dark.png | Bin 0 -> 3145 bytes lib/debug/debug.py | 13 +++++ lib/extensions/simulator.py | 29 ++++++++++ lib/gui/simulator/drawing_panel.py | 56 ++++++++++++++++++++ lib/gui/simulator/simulator_panel.py | 4 ++ lib/gui/simulator/simulator_window.py | 3 ++ lib/gui/simulator/view_panel.py | 17 +++++- 9 files changed, 217 insertions(+), 2 deletions(-) create mode 100644 icons/page.png create mode 100644 icons/page.svg create mode 100644 icons/page_dark.png diff --git a/icons/page.png b/icons/page.png new file mode 100644 index 00000000..34cea16c Binary files /dev/null and b/icons/page.png differ diff --git a/icons/page.svg b/icons/page.svg new file mode 100644 index 00000000..55eebeae --- /dev/null +++ b/icons/page.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/icons/page_dark.png b/icons/page_dark.png new file mode 100644 index 00000000..89257dc0 Binary files /dev/null and b/icons/page_dark.png differ diff --git a/lib/debug/debug.py b/lib/debug/debug.py index ab5132e4..d96dd36d 100644 --- a/lib/debug/debug.py +++ b/lib/debug/debug.py @@ -5,6 +5,7 @@ import atexit # to save svg file on exit import time # to measure time of code block, use time.monotonic() instead of time.time() +import traceback from datetime import datetime from contextlib import contextmanager # to measure time of with block @@ -246,6 +247,18 @@ class Debug(object): if self.enabled: self.raw_log("completed %s, duration = %s", label, time.monotonic() - start) + def log_exception(self): + if self.enabled: + self.raw_log(traceback.format_exc()) + + @contextmanager + def log_exceptions(self): + try: + yield + except Exception: + self.log_exception() + raise + # global debug object debug = Debug() diff --git a/lib/extensions/simulator.py b/lib/extensions/simulator.py index 69f74b02..af793f03 100644 --- a/lib/extensions/simulator.py +++ b/lib/extensions/simulator.py @@ -7,6 +7,7 @@ import wx from ..gui.simulator import SimulatorWindow from ..stitch_plan import stitch_groups_to_stitch_plan +from ..svg import convert_length from ..utils.svg_data import get_pagecolor from .base import InkstitchExtension @@ -37,5 +38,33 @@ class Simulator(InkstitchExtension): app.SetTopWindow(simulator) simulator.Show() simulator.load(stitch_plan) + simulator.set_page_specs(self.get_page_specs(stitch_plan)) simulator.go() app.MainLoop() + + def get_page_specs(self, stitch_plan): + svg = self.document.getroot() + width = svg.get('width', 0) + height = svg.get('height', 0) + page_color = "white" + desk_color = "white" + border_color = "black" + show_page_shadow = "true" + + named_view = svg.namedview + if named_view is not None: + page_color = named_view.get('pagecolor', page_color) + desk_color = named_view.get('inkscape:deskcolor', desk_color) + border_color = named_view.get('bordercolor', border_color) + show_page_shadow = named_view.get('inkscape:showpageshadow', show_page_shadow) in ['true', 'yes', 'y', '1', '2'] + + return { + "width": convert_length(width), + "height": convert_length(height), + "x": stitch_plan.bounding_box[0], + "y": stitch_plan.bounding_box[1], + "page_color": page_color, + "desk_color": desk_color, + "border_color": border_color, + "show_page_shadow": show_page_shadow + } diff --git a/lib/gui/simulator/drawing_panel.py b/lib/gui/simulator/drawing_panel.py index 9b705716..0d1b0afe 100644 --- a/lib/gui/simulator/drawing_panel.py +++ b/lib/gui/simulator/drawing_panel.py @@ -7,6 +7,7 @@ import time import wx from numpy import split +from ...debug.debug import debug from ...i18n import _ from ...svg import PIXELS_PER_MM from ...utils.settings import global_settings @@ -59,6 +60,9 @@ class DrawingPanel(wx.Panel): self.width = 0 self.height = 0 self.loaded = False + self.page_specs = {} + self.show_page = True + self.background_color = None # desired simulation speed in stitches per second self.speed = 16 @@ -122,6 +126,34 @@ class DrawingPanel(wx.Panel): self.draw_stitches(canvas) self.draw_scale(canvas) + def draw_page(self, canvas): + self._update_background_color() + + if not self.page_specs or not self.show_page: + return + + with debug.log_exceptions(): + border_color = wx.Colour(self.page_specs['border_color']) + if self.page_specs['show_page_shadow']: + canvas.SetPen(wx.TRANSPARENT_PEN) + canvas.SetBrush(canvas.CreateBrush(wx.Brush(wx.Colour(border_color.Red(), border_color.Green(), border_color.Blue(), alpha=65)))) + canvas.DrawRoundedRectangle( + (-self.page_specs['x'] + 4) * self.PIXEL_DENSITY, (-self.page_specs['y'] + 4) * self.PIXEL_DENSITY, + self.page_specs['width'] * self.PIXEL_DENSITY, self.page_specs['height'] * self.PIXEL_DENSITY, + 1 * self.PIXEL_DENSITY + ) + + pen = canvas.CreatePen( + wx.GraphicsPenInfo(wx.Colour(border_color)).Width(1 * self.PIXEL_DENSITY).Join(wx.JOIN_MITER) + ) + canvas.SetPen(pen) + canvas.SetBrush(wx.Brush(wx.Colour(self.background_color or self.page_specs['page_color']))) + + canvas.DrawRectangle( + -self.page_specs['x'] * self.PIXEL_DENSITY, -self.page_specs['y'] * self.PIXEL_DENSITY, + self.page_specs['width'] * self.PIXEL_DENSITY, self.page_specs['height'] * self.PIXEL_DENSITY + ) + def draw_stitches(self, canvas): canvas.BeginLayer(1) @@ -130,6 +162,8 @@ class DrawingPanel(wx.Panel): transform.Scale(self.zoom / self.PIXEL_DENSITY, self.zoom / self.PIXEL_DENSITY) canvas.SetTransform(transform) + self.draw_page(canvas) + stitch = 0 last_stitch = None @@ -252,6 +286,28 @@ class DrawingPanel(wx.Panel): if hasattr(self.view_panel, 'info_panel'): self.view_panel.info_panel.update() + def set_page_specs(self, page_specs): + self.SetBackgroundColour(page_specs['desk_color']) + self.page_specs = page_specs + + def set_background_color(self, color): + self.background_color = color + # this refresh is necessary for macOS + self.Refresh() + + def _update_background_color(self): + if not self.page_specs: + self.SetBackgroundColour(self.background_color or "#FFFFFF") + else: + if self.show_page: + self.SetBackgroundColour(self.page_specs['desk_color']) + else: + self.SetBackgroundColour(self.background_color or self.page_specs['page_color']) + + def set_show_page(self, show_page): + self.show_page = show_page + self._update_background_color() + def choose_zoom_and_pan(self, event=None): # ignore if EVT_SIZE fired before we load the stitch plan if not self.width and not self.height and event is not None: diff --git a/lib/gui/simulator/simulator_panel.py b/lib/gui/simulator/simulator_panel.py index 593b551a..1cea9214 100644 --- a/lib/gui/simulator/simulator_panel.py +++ b/lib/gui/simulator/simulator_panel.py @@ -30,6 +30,7 @@ class SimulatorPanel(wx.Panel): self.cp.set_drawing_panel(self.dp) self.vp.set_drawing_panel(self.dp) self.vp.set_background_color(wx.Colour(background_color)) + self.dp.set_background_color(wx.Colour(background_color)) dvSizer = wx.BoxSizer(wx.HORIZONTAL) @@ -93,3 +94,6 @@ class SimulatorPanel(wx.Panel): def clear(self): self.dp.clear() self.cp.clear() + + def set_page_specs(self, page_specs): + self.dp.set_page_specs(page_specs) diff --git a/lib/gui/simulator/simulator_window.py b/lib/gui/simulator/simulator_window.py index 2318041b..6ddc6f33 100644 --- a/lib/gui/simulator/simulator_window.py +++ b/lib/gui/simulator/simulator_window.py @@ -53,3 +53,6 @@ class SimulatorWindow(wx.Frame): def go(self): self.panel.go() + + def set_page_specs(self, page_specs): + self.panel.set_page_specs(page_specs) diff --git a/lib/gui/simulator/view_panel.py b/lib/gui/simulator/view_panel.py index 9cfe3331..27a89352 100644 --- a/lib/gui/simulator/view_panel.py +++ b/lib/gui/simulator/view_panel.py @@ -56,6 +56,13 @@ class ViewPanel(ScrolledPanel): self.btnBackgroundColor.SetToolTip(_("Change background color")) self.btnBackgroundColor.Bind(wx.EVT_COLOURPICKER_CHANGED, self.on_update_background_color) + if not self.detach_callback: + self.btnPage = wx.BitmapToggleButton(self, -1, style=self.button_style) + self.btnPage.Bind(wx.EVT_TOGGLEBUTTON, self.toggle_page) + self.btnPage.SetValue(True) + self.btnPage.SetBitmap(self.control_panel.load_icon('page')) + self.btnPage.SetToolTip(_('Show page')) + self.btnSettings = wx.BitmapToggleButton(self, -1, style=self.button_style) self.btnSettings.SetToolTip(_('Open settings dialog')) self.btnSettings.SetBitmap(self.control_panel.load_icon('settings')) @@ -94,6 +101,8 @@ class ViewPanel(ScrolledPanel): settings_sizer = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Settings")), wx.VERTICAL) settings_inner_sizer = wx.BoxSizer(wx.VERTICAL) settings_inner_sizer.Add(self.btnBackgroundColor, 0, wx.EXPAND | wx.ALL, 2) + if not self.detach_callback: + settings_inner_sizer.Add(self.btnPage, 0, wx.EXPAND | wx.ALL, 2) settings_inner_sizer.Add(self.btnSettings, 0, wx.EXPAND | wx.ALL, 2) if self.detach_callback: settings_inner_sizer.Add(self.btnDetachSimulator, 0, wx.ALL, 2) @@ -109,11 +118,10 @@ class ViewPanel(ScrolledPanel): def on_update_background_color(self, event): self.set_background_color(event.Colour) + self.drawing_panel.set_background_color(event.Colour) def set_background_color(self, color): self.btnBackgroundColor.SetColour(color) - self.drawing_panel.SetBackgroundColour(color) - self.drawing_panel.Refresh() def on_toggle_npp_shortcut(self, event): self.btnNpp.SetValue(not self.btnNpp.GetValue()) @@ -122,6 +130,11 @@ class ViewPanel(ScrolledPanel): def toggle_npp(self, event): self.drawing_panel.Refresh() + def toggle_page(self, event): + debug.log("toggle page") + self.drawing_panel.set_show_page(self.btnPage.GetValue()) + self.drawing_panel.Refresh() + def on_marker_button(self, marker_type, event): self.control_panel.slider.enable_marker_list(marker_type, event.GetEventObject().GetValue()) if marker_type == 'jump': -- cgit v1.2.3