diff options
| author | Kaalleen <36401965+kaalleen@users.noreply.github.com> | 2024-06-14 09:49:57 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-06-14 09:49:57 +0200 |
| commit | dbdba2cda3a66fc42b5bad05e88d33b845a85e2f (patch) | |
| tree | 6d50270e5d687a939ec75c661b1603bc43db1f4e /lib/gui/simulator/simulator_slider.py | |
| parent | 39d9defef4a6c813e40df9a8de254af422af6ccd (diff) | |
Add preferences button to simulator (#2992)
* split simulator panel files
* add view panel to position view options at the side
* fix single simulator start size (macOS)
Diffstat (limited to 'lib/gui/simulator/simulator_slider.py')
| -rw-r--r-- | lib/gui/simulator/simulator_slider.py | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/lib/gui/simulator/simulator_slider.py b/lib/gui/simulator/simulator_slider.py new file mode 100644 index 00000000..9d0b2537 --- /dev/null +++ b/lib/gui/simulator/simulator_slider.py @@ -0,0 +1,234 @@ +# Authors: see git history +# +# Copyright (c) 2024 Authors +# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. +import os +import sys + +import wx + +from ...debug.debug import debug +from ...utils import get_resource_dir + + +class SimulatorSlider(wx.Panel): + PROXY_EVENTS = (wx.EVT_SLIDER,) + + def __init__(self, parent, id=wx.ID_ANY, minValue=1, maxValue=2, **kwargs): + super().__init__(parent, id) + self.control_panel = parent + + kwargs['style'] = wx.SL_HORIZONTAL | wx.SL_VALUE_LABEL | wx.SL_TOP | wx.ALIGN_TOP + + self._height = self.GetTextExtent("M").y * 6 + self.SetMinSize((self._height, self._height)) + + self.marker_lists = { + "trim": MarkerList("trim"), + "jump": MarkerList("jump", 0.17), + "stop": MarkerList("stop", 0.34), + "color_change": MarkerList("color_change", 0.34), + } + self.marker_pen = wx.Pen(wx.Colour(0, 0, 0)) + self.color_sections = [] + self.margin = 15 + self.tab_start = 0 + self.tab_width = 0.15 + self.tab_height = 0.15 + self.color_bar_start = 0.22 + self.color_bar_thickness = 0.17 + self.marker_start = self.color_bar_start + self.marker_end = 0.5 + self.marker_icon_start = 0.5 + self.marker_icon_size = self._height // 6 + + self._min = minValue + self._max = maxValue + self._value = 0 + self._tab_rect = None + + if sys.platform == "darwin": + self.margin = 8 + + self.Bind(wx.EVT_PAINT, self.on_paint) + self.Bind(wx.EVT_ERASE_BACKGROUND, self.on_erase_background) + self.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down) + self.Bind(wx.EVT_LEFT_UP, self.on_mouse_up) + self.Bind(wx.EVT_MOTION, self.on_mouse_motion) + + def SetMax(self, value): + self._max = value + self.Refresh() + + def SetMin(self, value): + self._min = value + self.Refresh() + + def SetValue(self, value): + self._value = value + self.Refresh() + + def GetValue(self): + return self._value + + def clear(self): + self.color_sections = [] + self._min = 1 + self._max = 2 + self._value = 0 + self._tab_rect = None + + for marker_list in self.marker_lists.values(): + marker_list.clear() + + def add_color_section(self, color, start, end): + self.color_sections.append(ColorSection(color, start, end)) + + def add_marker(self, name, location): + self.marker_lists[name].append(location) + self.Refresh() + + def enable_marker_list(self, name, enabled=True): + self.marker_lists[name].enabled = enabled + self.Refresh() + + def disable_marker_list(self, name): + self.marker_lists[name].enabled = False + self.Refresh() + + def toggle_marker_list(self, name): + self.marker_lists[name].enabled = not self.marker_lists[name].enabled + self.Refresh() + + def on_paint(self, event): + dc = wx.BufferedPaintDC(self) + if not sys.platform.startswith("win"): + # Without this, the background color will be white. + background_brush = wx.Brush(self.GetTopLevelParent().GetBackgroundColour(), wx.SOLID) + dc.SetBackground(background_brush) + dc.Clear() + gc = wx.GraphicsContext.Create(dc) + + if self._value < self._min: + return + + width, height = self.GetSize() + min_value = self._min + max_value = self._max + spread = max_value - min_value + + def _value_to_x(value): + return (value - min_value) * (width - 2 * self.margin) / spread + self.margin + + gc.SetPen(wx.NullPen) + for color_section in self.color_sections: + gc.SetBrush(color_section.brush) + + start_x = _value_to_x(color_section.start) + end_x = _value_to_x(color_section.end) + gc.DrawRectangle(start_x, height * self.color_bar_start, + end_x - start_x, height * self.color_bar_thickness) + + if self.control_panel.is_dark_theme(): + gc.SetPen(wx.Pen(wx.Colour(0, 0, 0), 1)) + gc.SetBrush(wx.Brush(wx.Colour(255, 255, 255))) + else: + gc.SetPen(wx.Pen(wx.Colour(255, 255, 255), 1)) + gc.SetBrush(wx.Brush(wx.Colour(0, 0, 0))) + + value_x = _value_to_x(self._value) + tab_height = self.tab_height * height + tab_width = self.tab_width * height + tab_x = value_x - tab_width / 2 + tab_y = height * self.tab_start + self._tab_rect = wx.Rect(round(tab_x), round(tab_y), round(tab_width), round(tab_height)) + gc.DrawRectangle( + value_x - 1.5, 0, + 3, height * (self.color_bar_start + self.color_bar_thickness)) + gc.SetPen(wx.NullPen) + gc.DrawRectangle(value_x - tab_width/2, height * self.tab_start, + tab_width, tab_height) + + gc.SetPen(self.marker_pen) + for marker_list in self.marker_lists.values(): + if marker_list.enabled: + for value in marker_list: + x = _value_to_x(value) + gc.StrokeLine( + x, height * self.marker_start, + x, height * (self.marker_end + marker_list.offset) + ) + gc.DrawBitmap( + marker_list.icon, + x - self.marker_icon_size / 2, height * (self.marker_icon_start + marker_list.offset), + self.marker_icon_size, self.marker_icon_size + ) + + def on_erase_background(self, event): + # supposedly this prevents flickering? + pass + + def is_in_tab(self, point): + return self._tab_rect and self._tab_rect.Inflate(2).Contains(point) + + def set_value_from_position(self, point): + width, height = self.GetSize() + min_value = self._min + max_value = self._max + spread = max_value - min_value + value = round((point.x - self.margin) * spread / (width - 2 * self.margin)) + value = max(value, self._min) + value = min(value, self._max) + self.SetValue(round(value)) + + event = wx.CommandEvent(wx.wxEVT_COMMAND_SLIDER_UPDATED, self.GetId()) + event.SetInt(value) + event.SetEventObject(self) + self.GetEventHandler().ProcessEvent(event) + + def on_mouse_down(self, event): + click_pos = event.GetPosition() + if self.is_in_tab(click_pos): + debug.log("drag start") + self.CaptureMouse() + self.set_value_from_position(click_pos) + self.Refresh() + else: + width, height = self.GetSize() + relative_y = click_pos.y / height + if relative_y > self.color_bar_start and relative_y - self.color_bar_start < self.color_bar_thickness: + self.set_value_from_position(click_pos) + self.Refresh() + + def on_mouse_motion(self, event): + if self.HasCapture() and event.Dragging() and event.LeftIsDown(): + self.set_value_from_position(event.GetPosition()) + self.Refresh() + + def on_mouse_up(self, event): + if self.HasCapture(): + self.ReleaseMouse() + self.set_value_from_position(event.GetPosition()) + self.Refresh() + + +class MarkerList(list): + def __init__(self, icon_name, offset=0, stitch_numbers=()): + super().__init__(self) + icons_dir = get_resource_dir("icons") + self.icon_name = icon_name + self.icon = wx.Image(os.path.join(icons_dir, f"{icon_name}.png")).ConvertToBitmap() + self.offset = offset + self.enabled = False + self.extend(stitch_numbers) + + def __repr__(self): + return f"MarkerList({self.icon_name})" + + +class ColorSection: + def __init__(self, color, start, end): + self.color = color + self.start = start + self.end = end + self.brush = wx.Brush(wx.Colour(*color)) |
