#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 0.9.3 on Sat Feb 20 23:24:03 2021
#
import os
import threading

import wx

from src.gui.icons import (icon_CC, icon_down, icon_left, icon_LL, icon_LR,
                           icon_right, icon_UL, icon_up, icon_UR)
from src.gui.mwindow import MWindow
from src.kernel import Job
from .laserrender import (
    DRAW_MODE_FLIPXY,
    DRAW_MODE_INVERT,
    LaserRender, DRAW_MODE_GCODE, DRAW_MODE_CUT, DRAW_MODE_RASTER, DRAW_MODE_ENGRAVE,
    DRAW_MODE_ESTIMATE, DRAW_MODE_ZOOM, DRAW_MODE_REFRESH, DRAW_MODE_ANIMATE,
)
from .widget import (
    GridWidget,
    GuideWidget, RasterImageWidget, VectorEngraveWidget, VectorCutWidget, TimeEstimateWidget, GCodePathsWidget,
    ReticleWidget,
)

MILS_IN_MM = 39.3701

_ = wx.GetTranslation
supported_languages = (
    ("en", u"English", wx.LANGUAGE_ENGLISH),
    ("it", u"italiano", wx.LANGUAGE_ITALIAN),
    ("fr", u"français", wx.LANGUAGE_FRENCH),
    ("de", u"Deutsch", wx.LANGUAGE_GERMAN),
    ("es", u"español", wx.LANGUAGE_SPANISH),
    ("zh", u"Chinese", wx.LANGUAGE_CHINESE),
)


class Silence(MWindow, Job):
    def __init__(self, *args, **kwds):
        super().__init__(815, 624, *args, **kwds)
        Job.__init__(self, job_name="refresh_scene", process=self.refresh_scene, interval=0.05)
        self.context.setting(int, "draw_mode", 0xFF)
        self.context.setting(float, "units_convert", MILS_IN_MM)
        self.context.setting(str, "units_name", "mm")
        self.context.setting(int, "units_marks", 10)
        self.context.setting(int, "units_index", 0)
        self.context.setting(str, "board", "M2")
        self.context.setting(int, "offset_x", 0)
        self.context.setting(int, "offset_y", 0)
        self.context.setting(int, "offset_width", 0)
        self.context.setting(int, "offset_height", 0)
        self._Buffer = None

        self.widget_scene = self.root_context.open("module/Scene")
        self.screen_refresh_is_requested = False
        self.screen_refresh_is_running = False
        self.screen_refresh_lock = threading.Lock()
        self.background_brush = wx.Brush("Grey")

        # Menu Bar
        self.silence_menubar = wx.MenuBar()
        wxglade_tmp_menu = wx.Menu()
        self.silence_menubar.settings_save = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Save Setting File",
            "Opens a dialog box to save a file to write the current settings to. The settings file will contain all of the settings as they are when the settings file is saved (including the name and location of the active design file.)",
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_save,
            id=self.silence_menubar.settings_save.GetId(),
        )
        self.silence_menubar.settings_load = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Load Setting File",
            "Opens a dialog box to select a file to read the settings from. A settings file previously saved can be opens to recover all of the settings as they were when the settings file was saved (including the name and location of the active design file at the time of the save.)",
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_load,
            id=self.silence_menubar.settings_load.GetId(),
        )
        wxglade_tmp_menu.AppendSeparator()
        self.silence_menubar.design_open = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Open Design",
            "Opens a dialog box to select a design file to open.",
        )
        self.Bind(
            wx.EVT_MENU, self.on_menu_open, id=self.silence_menubar.design_open.GetId()
        )
        self.silence_menubar.design_reload = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Reload Design",
            "Reloads the current design. (Re-read the design file information from the storage location)",
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_reload,
            id=self.silence_menubar.design_reload.GetId(),
        )
        wxglade_tmp_menu.AppendSeparator()
        self.silence_menubar.egv_send = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Send EGV File To Laser",
            "Open a file open dialog to select an EGV file to send to the laser controller. The raw data is not interpreted, so there is no preview of the data to be sent to the laser.",
        )
        self.Bind(
            wx.EVT_MENU, self.on_menu_egv, id=self.silence_menubar.egv_send.GetId()
        )
        self.silence_menubar.egv_sav = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Save EGV File",
            "Save the Raster Engrave data to an EGV file. The file will contain the data that would be sent to the laser if the Raster Engrave button was pressed.",
        )
        self.Bind(
            wx.EVT_MENU, self.on_menu_egv_save, id=self.silence_menubar.egv_sav.GetId()
        )
        self.silence_menubar.exit = wxglade_tmp_menu.Append(
            wx.ID_ANY, "Exit", "Exit the program. A dialog box will open to confirm."
        )
        self.Bind(wx.EVT_MENU, self.on_menu_exit, id=self.silence_menubar.exit.GetId())
        self.silence_menubar.Append(wxglade_tmp_menu, "File")
        wxglade_tmp_menu = wx.Menu()
        self.silence_menubar.scene_refresh = wxglade_tmp_menu.Append(
            wx.ID_ANY, "Refresh\tF5", "Refreshes items displayed in the main window."
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_refresh,
            id=self.silence_menubar.scene_refresh.GetId(),
        )
        wxglade_tmp_menu.AppendSeparator()
        self.silence_menubar.view_raster = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Show Raster Image",
            "Toggle the Raster image display on and off. If the display is turned of the data still exists and the Raster Engrave button will still function. The data is just not displayed which may help make the program run faster.",
            wx.ITEM_CHECK,
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_view_raster,
            id=self.silence_menubar.view_raster.GetId(),
        )
        self.silence_menubar.view_engrave = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Show Vector Engrave",
            "Toggle the Vector Engrave line display on and off. If the display is turned of the data still exists and the Vector Engrave button will still function. The data is just not displayed which may help make the program run faster.",
            wx.ITEM_CHECK,
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_view_engrave,
            id=self.silence_menubar.view_engrave.GetId(),
        )
        self.silence_menubar.view_cut = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Show Vector Cut",
            "Toggle the Vector Cut line display on and off. If the display is turned of the data still exists and the Vector Cut button will still function. The data is just not displayed which may help make the program run faster.",
            wx.ITEM_CHECK,
        )
        self.Bind(
            wx.EVT_MENU, self.on_menu_view_cut, id=self.silence_menubar.view_cut.GetId()
        )
        self.silence_menubar.view_gcode = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Show GCode Paths",
            "Toggle the G-Code line display on and off. If the display is turned of the data still exists and the G-Code Run button will still function. The data is just not displayed which may help make the program run faster.",
            wx.ITEM_CHECK,
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_view_gcode,
            id=self.silence_menubar.view_gcode.GetId(),
        )
        wxglade_tmp_menu.AppendSeparator()
        self.silence_menubar.view_estimate = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Show Time Estimate",
            "Toggle the display of time estimates on and off. When one the time estimates for the various operations will be displayed in the lower right corner of the main window. The estimates should be considered rough estimates. The Vector Cut and Vector Engrave estimates are better than the Raster Engrave estimate. The raster engrave estimate assumes the whole page area is raster engraved so it is generally an upper bound on the time required to raster engrave a given design.",
            wx.ITEM_CHECK,
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_view_estimate,
            id=self.silence_menubar.view_estimate.GetId(),
        )
        self.silence_menubar.view_zoom = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Zoom to Design Size",
            "Zoom to the input design size rather than the working area of the laser. This allows for closer inspection of the input design. This is especially useful for small designs.",
            wx.ITEM_CHECK,
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_view_zoom,
            id=self.silence_menubar.view_zoom.GetId(),
        )
        self.silence_menubar.Append(wxglade_tmp_menu, "View")
        wxglade_tmp_menu = wx.Menu()
        self.silence_menubar.tool_raster = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Calculate Raster Time",
            "Calculate the time needed to perform raster",
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_calc_raster,
            id=self.silence_menubar.tool_raster.GetId(),
        )
        self.silence_menubar.tool_hull = wxglade_tmp_menu.Append(
            wx.ID_ANY, "Trace Design Boundary\tCtrl-T", "Trace Design"
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_convex_hull,
            id=self.silence_menubar.tool_hull.GetId(),
        )
        wxglade_tmp_menu.AppendSeparator()
        self.silence_menubar.usb_init = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Initialize Laser\tCtrl-i",
            'Establish connection with the laser controller board, and optionally Home the laser depending on the setting in the General settings window for "Home Upon initialize"',
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_initialize,
            id=self.silence_menubar.usb_init.GetId(),
        )
        wxglade_tmp_menu_sub = wx.Menu()
        self.silence_menubar.usb_reset = wxglade_tmp_menu_sub.Append(
            wx.ID_ANY, "Reset USB", "Reset the USB port."
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_reset_usb,
            id=self.silence_menubar.usb_reset.GetId(),
        )
        self.silence_menubar.usb_release = wxglade_tmp_menu_sub.Append(
            wx.ID_ANY, "Release USB", "Disconnect the laser controller board."
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_release_usb,
            id=self.silence_menubar.usb_release.GetId(),
        )
        wxglade_tmp_menu.Append(wx.ID_ANY, "USB", wxglade_tmp_menu_sub, "")
        self.silence_menubar.Append(wxglade_tmp_menu, "Tools")
        wxglade_tmp_menu = wx.Menu()
        self.silence_menubar.settings_general = wxglade_tmp_menu.Append(
            wx.ID_ANY, "General Settings\tF2", "Opens the General Settings window."
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_settings_general,
            id=self.silence_menubar.settings_general.GetId(),
        )
        self.silence_menubar.settings_raster = wxglade_tmp_menu.Append(
            wx.ID_ANY, "Raster Settings\tF3", "Opens the Raster Settings Window"
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_settings_raster,
            id=self.silence_menubar.settings_raster.GetId(),
        )
        self.silence_menubar.settings_rotary = wxglade_tmp_menu.Append(
            wx.ID_ANY,
            "Rotary Settings\tF4",
            "Shows (or hides) the Advanced Settings in the main window.",
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_settings_rotary,
            id=self.silence_menubar.settings_rotary.GetId(),
        )
        wxglade_tmp_menu.AppendSeparator()
        self.silence_menubar.settings_advanced = wxglade_tmp_menu.Append(
            wx.ID_ANY, "Advanced Settings\tF6", "Toggle advanced settings"
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_settings_advanced,
            id=self.silence_menubar.settings_advanced.GetId(),
        )
        self.silence_menubar.Append(wxglade_tmp_menu, "Setting")
        wxglade_tmp_menu = wx.Menu()
        self.silence_menubar.help_about = wxglade_tmp_menu.Append(
            wx.ID_ANY, "About", "Open a window that identifies the program."
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_help_about,
            id=self.silence_menubar.help_about.GetId(),
        )
        self.silence_menubar.help_webpage = wxglade_tmp_menu.Append(
            wx.ID_ANY, "Webpage", "Opens a new browser window with the web page."
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_help_webpage,
            id=self.silence_menubar.help_webpage.GetId(),
        )
        self.silence_menubar.help_manual = wxglade_tmp_menu.Append(
            wx.ID_ANY, "Manual", "Opens a new browser window to the manual web page."
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_menu_help_manual,
            id=self.silence_menubar.help_manual.GetId(),
        )
        self.silence_menubar.Append(wxglade_tmp_menu, "Help")
        self.SetMenuBar(self.silence_menubar)
        # Menu Bar end
        self.silence_statusbar = self.CreateStatusBar(1)
        self.panel_6 = wx.Panel(self, wx.ID_ANY)
        self.button_usb_init = wx.Button(
            self.panel_6, wx.ID_ANY, "Initialize Laser Cutter"
        )
        self.button_design_open = wx.Button(
            self.panel_6, wx.ID_ANY, "Open\nDesign File"
        )
        self.button_design_reload = wx.Button(
            self.panel_6, wx.ID_ANY, "Reload\nDesign File"
        )
        self.panel_1 = wx.Panel(self.panel_6, wx.ID_ANY)
        self.button_home = wx.Button(self.panel_1, wx.ID_ANY, "Home")
        self.button_unlock_rail = wx.Button(self.panel_1, wx.ID_ANY, "Unlock Rail")
        self.text_jog_step = wx.TextCtrl(self.panel_1, wx.ID_ANY, "10.0")
        self.panel_2 = wx.Panel(self.panel_6, wx.ID_ANY)
        self.button_align_TL = wx.BitmapButton(
            self.panel_2, wx.ID_ANY, icon_UL.GetBitmap(resize=(40, 40))
        )
        self.button_jog_T = wx.BitmapButton(
            self.panel_2, wx.ID_ANY, icon_up.GetBitmap(resize=(40, 40))
        )
        self.button_align_TR = wx.BitmapButton(
            self.panel_2, wx.ID_ANY, icon_UR.GetBitmap(resize=(40, 40))
        )
        self.button_jog_L = wx.BitmapButton(
            self.panel_2, wx.ID_ANY, icon_left.GetBitmap(resize=(40, 40))
        )
        self.button_align_C = wx.BitmapButton(
            self.panel_2, wx.ID_ANY, icon_CC.GetBitmap(resize=(40, 40))
        )
        self.button_jog_R = wx.BitmapButton(
            self.panel_2, wx.ID_ANY, icon_right.GetBitmap(resize=(40, 40))
        )
        self.button_align_BL = wx.BitmapButton(
            self.panel_2, wx.ID_ANY, icon_LL.GetBitmap(resize=(40, 40))
        )
        self.button_jog_B = wx.BitmapButton(
            self.panel_2, wx.ID_ANY, icon_down.GetBitmap(resize=(40, 40))
        )
        self.button_align_BR = wx.BitmapButton(
            self.panel_2, wx.ID_ANY, icon_LR.GetBitmap(resize=(40, 40))
        )
        self.panel_4 = wx.Panel(self.panel_2, wx.ID_ANY)
        self.button_move = wx.Button(self.panel_4, wx.ID_ANY, "Move To")
        self.text_move_x = wx.TextCtrl(
            self.panel_4, wx.ID_ANY, "0.0", style=wx.TE_CENTRE
        )
        self.text_move_y = wx.TextCtrl(
            self.panel_4, wx.ID_ANY, "0.0", style=wx.TE_CENTRE
        )
        self.panel_3 = wx.Panel(self.panel_6, wx.ID_ANY)
        self.button_raster = wx.Button(self.panel_3, wx.ID_ANY, "Raster Engrave")
        self.text_raster_speed = wx.TextCtrl(
            self.panel_3, wx.ID_ANY, "100", style=wx.TE_CENTRE
        )
        self.button_engrave = wx.Button(self.panel_3, wx.ID_ANY, "Vector Engrave")
        self.text_engrave_speed = wx.TextCtrl(
            self.panel_3, wx.ID_ANY, "20", style=wx.TE_CENTRE
        )
        self.button_cut = wx.Button(self.panel_3, wx.ID_ANY, "Vector Cut")
        self.text_cut_speed = wx.TextCtrl(
            self.panel_3, wx.ID_ANY, "10", style=wx.TE_CENTRE
        )
        self.button_pause_stop = wx.Button(self.panel_3, wx.ID_ANY, "Pause/Stop")
        self.advanced_settings = wx.Panel(self, wx.ID_ANY)
        self.checkbox_halftone = wx.CheckBox(
            self.advanced_settings, wx.ID_ANY, "Halftone (Dither)"
        )
        self.checkbox_invert = wx.CheckBox(
            self.advanced_settings, wx.ID_ANY, "Invert Raster Color"
        )
        self.checkbox_mirror = wx.CheckBox(
            self.advanced_settings, wx.ID_ANY, "Mirror Design"
        )
        self.checkbox_rotate = wx.CheckBox(
            self.advanced_settings, wx.ID_ANY, "Rotate Design"
        )
        self.checkbox_csys = wx.CheckBox(
            self.advanced_settings, wx.ID_ANY, "Use Input CSYS"
        )
        self.checkbox_cut_inner = wx.CheckBox(
            self.advanced_settings, wx.ID_ANY, "Cut Inside First"
        )
        self.checkbox_rotary_enable = wx.CheckBox(
            self.advanced_settings, wx.ID_ANY, "Use Rotary Settings"
        )
        self.checkbox_group_engrave = wx.CheckBox(
            self.advanced_settings, wx.ID_ANY, "Group Engrave Tasks"
        )
        self.checkbox_group_vector = wx.CheckBox(
            self.advanced_settings, wx.ID_ANY, "Group Vector Tasks"
        )
        self.text_raster_passes = wx.TextCtrl(self.advanced_settings, wx.ID_ANY, "1")
        self.text_engrave_passes = wx.TextCtrl(self.advanced_settings, wx.ID_ANY, "1")
        self.text_cut_passes = wx.TextCtrl(self.advanced_settings, wx.ID_ANY, "1")
        self.button_hide_advanced = wx.Button(
            self.advanced_settings, wx.ID_ANY, "Hide Advanced"
        )
        self.scene = wx.Panel(self, style=wx.EXPAND | wx.WANTS_CHARS)
        self.scene.SetDoubleBuffered(True)

        self.__set_properties()
        self.__do_layout()

        self.renderer = LaserRender(self.context)

        self.scene.Bind(wx.EVT_PAINT, self.on_paint)
        self.scene.Bind(wx.EVT_ERASE_BACKGROUND, self.on_erase)

        self.scene.Bind(wx.EVT_MOTION, self.on_mouse_move)

        self.scene.Bind(wx.EVT_MOUSEWHEEL, self.on_mousewheel)

        self.scene.Bind(wx.EVT_MIDDLE_DOWN, self.on_mouse_middle_down)
        self.scene.Bind(wx.EVT_MIDDLE_UP, self.on_mouse_middle_up)

        self.scene.Bind(wx.EVT_LEFT_DCLICK, self.on_mouse_double_click)

        self.scene.Bind(wx.EVT_RIGHT_DOWN, self.on_right_mouse_down)
        self.scene.Bind(wx.EVT_RIGHT_UP, self.on_right_mouse_up)

        self.scene.Bind(wx.EVT_LEFT_DOWN, self.on_left_mouse_down)
        self.scene.Bind(wx.EVT_LEFT_UP, self.on_left_mouse_up)

        self.widget_scene.add_scenewidget(ReticleWidget(self.widget_scene))
        self.widget_scene.add_scenewidget(VectorEngraveWidget(self.widget_scene, self.context.elements, self.renderer))
        self.widget_scene.add_scenewidget(VectorCutWidget(self.widget_scene, self.context.elements, self.renderer))
        self.widget_scene.add_scenewidget(GCodePathsWidget(self.widget_scene, self.context.elements, self.renderer))
        self.widget_scene.add_scenewidget(RasterImageWidget(self.widget_scene, self.context.elements, self.renderer))
        self.widget_scene.add_scenewidget(GridWidget(self.widget_scene))
        self.widget_scene.add_interfacewidget(GuideWidget(self.widget_scene))
        self.widget_scene.add_interfacewidget(TimeEstimateWidget(self.widget_scene, self.context.elements))

        try:
            self.scene.Bind(wx.EVT_MAGNIFY, self.on_magnify_mouse)
            self.EnableTouchEvents(wx.TOUCH_ZOOM_GESTURE | wx.TOUCH_PAN_GESTURES)
            self.scene.Bind(wx.EVT_GESTURE_PAN, self.on_gesture)
            self.scene.Bind(wx.EVT_GESTURE_ZOOM, self.on_gesture)
        except AttributeError:
            # Not WX 4.1
            pass

        self.scene.SetFocus()

        self.Bind(wx.EVT_BUTTON, self.on_button_initialize_laser, self.button_usb_init)
        self.Bind(wx.EVT_BUTTON, self.on_button_open_design, self.button_design_open)
        self.Bind(
            wx.EVT_BUTTON, self.on_button_reload_design, self.button_design_reload
        )
        self.Bind(wx.EVT_BUTTON, self.on_button_home, self.button_home)
        self.Bind(wx.EVT_BUTTON, self.on_button_unlock_rail, self.button_unlock_rail)
        self.Bind(wx.EVT_TEXT, self.on_text_jog_step, self.text_jog_step)
        self.Bind(wx.EVT_BUTTON, self.on_button_align_top_left, self.button_align_TL)
        self.Bind(wx.EVT_BUTTON, self.on_button_jog_top, self.button_jog_T)
        self.Bind(wx.EVT_BUTTON, self.on_button_align_top_right, self.button_align_TR)
        self.Bind(wx.EVT_BUTTON, self.on_button_jog_left, self.button_jog_L)
        self.Bind(wx.EVT_BUTTON, self.on_button_align_center, self.button_align_C)
        self.Bind(wx.EVT_BUTTON, self.on_button_jog_right, self.button_jog_R)
        self.Bind(wx.EVT_BUTTON, self.on_button_align_bottom_left, self.button_align_BL)
        self.Bind(wx.EVT_BUTTON, self.on_button_jog_bottom, self.button_jog_B)
        self.Bind(
            wx.EVT_BUTTON, self.on_button_align_bottom_right, self.button_align_BR
        )
        self.Bind(wx.EVT_BUTTON, self.on_button_move, self.button_move)
        self.Bind(wx.EVT_TEXT, self.on_text_move_x, self.text_move_x)
        self.Bind(wx.EVT_TEXT, self.on_text_move_y, self.text_move_y)
        self.Bind(wx.EVT_BUTTON, self.on_button_raster_engrave, self.button_raster)
        self.Bind(wx.EVT_TEXT, self.on_text_raster_speed, self.text_raster_speed)
        self.Bind(wx.EVT_BUTTON, self.on_button_vector_engrave, self.button_engrave)
        self.Bind(wx.EVT_TEXT, self.on_text_engrave_speed, self.text_engrave_speed)
        self.Bind(wx.EVT_BUTTON, self.on_button_vector_cut, self.button_cut)
        self.Bind(wx.EVT_TEXT, self.on_text_cut_speed, self.text_cut_speed)
        self.Bind(wx.EVT_BUTTON, self.on_button_pause_stop, self.button_pause_stop)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_halftone, self.checkbox_halftone)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_invert, self.checkbox_invert)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_mirror, self.checkbox_mirror)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_rotate, self.checkbox_rotate)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_csys, self.checkbox_csys)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_cut_inside, self.checkbox_cut_inner)
        self.Bind(
            wx.EVT_CHECKBOX, self.on_check_use_rotary, self.checkbox_rotary_enable
        )
        self.Bind(
            wx.EVT_CHECKBOX, self.on_check_group_engrave, self.checkbox_group_engrave
        )
        self.Bind(
            wx.EVT_CHECKBOX, self.on_check_group_vector, self.checkbox_group_vector
        )
        self.Bind(
            wx.EVT_TEXT, self.on_text_raster_engrave_passes, self.text_raster_passes
        )
        self.Bind(
            wx.EVT_TEXT, self.on_text_vector_engrave_passes, self.text_engrave_passes
        )
        self.Bind(wx.EVT_TEXT, self.on_text_vector_cut_passes, self.text_cut_passes)
        self.Bind(
            wx.EVT_BUTTON, self.on_button_hide_advanced, self.button_hide_advanced
        )
        # end wxGlade

        self.Bind(wx.EVT_SIZE, self.on_size)

        self.Bind(wx.EVT_DROP_FILES, self.on_drop_file)

        @self.context.console_command("refresh", help="Silence refresh")
        def refresh(command, channel, _, args=tuple(), **kwargs):
            self.Layout()
            self.Update()
            self.Refresh()
            channel(_("Refreshed."))
            return

        @self.context.console_argument(
            "filename",
            type=str,
            help="filename of design to load",
        )
        @self.context.console_command(
            "design_load",
            help="design_load <filename>",
        )
        def plan(command, channel, _, filename=None, args=tuple(), **kwargs):
            self.tryopen(filename)

        self.context.setting(str, "working_file", None)
        self.context.setting(float, "jog_step", 10.0)
        self.context.setting(float, "move_x", 0.0)
        self.context.setting(float, "move_y", 0.0)
        self.context.setting(bool, "halftone", True)
        self.context.setting(bool, "invert", False)
        self.context.setting(bool, "mirror", False)
        self.context.setting(bool, "rotate", False)
        self.context.setting(bool, "csys", False)
        self.context.setting(bool, "cut_inner", True)
        self.context.setting(bool, "rotary_enable", False)
        self.context.setting(bool, "group_engrave", False)
        self.context.setting(bool, "group_vector", False)
        self.text_jog_step.SetValue(str(self.context.jog_step))
        self.text_move_x.SetValue(str(self.context.move_x))
        self.text_move_y.SetValue(str(self.context.move_y))
        self.text_raster_speed.SetValue(str(self.context.raster_settings.speed))
        self.text_engrave_speed.SetValue(str(self.context.engrave_settings.speed))
        self.text_cut_speed.SetValue(str(self.context.cut_settings.speed))
        self.checkbox_halftone.SetValue(self.context.halftone)
        self.checkbox_invert.SetValue(self.context.invert)
        self.checkbox_rotate.SetValue(self.context.rotate)
        self.checkbox_csys.SetValue(self.context.csys)
        self.checkbox_cut_inner.SetValue(self.context.cut_inner)
        self.checkbox_rotary_enable.SetValue(self.context.rotary_enable)
        self.checkbox_group_vector.SetValue(self.context.group_vector)
        self.checkbox_group_engrave.SetValue(self.context.group_engrave)
        self.text_raster_passes.SetValue(str(self.context.raster_settings.implicit_passes))
        self.text_engrave_passes.SetValue(str(self.context.engrave_settings.implicit_passes))
        self.text_cut_passes.SetValue(str(self.context.cut_settings.implicit_passes))
        self.toggle_advance_settings()

        self.context.listen("rotary_enable", self.on_rotary_enable)
        self.context.listen("halftone", self.on_halftone)
        self.context.listen("op_setting_update", self.on_op_setting_update)
        self.context.listen("refresh_scene", self.on_refresh_scene)
        self.context.listen("bed_size", self.on_bed_changed)
        self.context.listen("units", self.on_space_changed)
        self.context.listen("draw_mode", self.on_draw_mode)
        self.context.listen("statusbar", self.on_statusbar)
        self.on_draw_mode(self.context.draw_mode)

        bed_dim = self.context.get_context("bed")
        bed_dim.setting(float, "bed_width", 325.0)
        bed_dim.setting(float, "bed_height", 220.0)
        bbox = (0, 0, bed_dim.bed_width * MILS_IN_MM, bed_dim.bed_height * MILS_IN_MM)
        self.widget_scene.widget_root.focus_viewport_scene(
            bbox, self.scene.ClientSize, 0.1
        )

        self.context.schedule(self)

    def load_or_open(self, filename):
        """
        Loads recent file name given. If the filename cannot be opened attempts open dialog at last known location.
        """
        if os.path.exists(filename):
            try:
                self.load(filename)
            except PermissionError:
                self.tryopen(filename)
        else:
            self.tryopen(filename)

    def tryopen(self, filename):
        """
        Loads an open dialog at given filename to load data.
        """
        files = self.context.load_types()
        if filename is not None:
            defaultFile = os.path.basename(filename)
            defaultDir = os.path.dirname(filename)
        else:
            defaultFile = ""
            defaultDir = "."

        with wx.FileDialog(
                self, _("Open"), defaultDir=defaultDir, defaultFile=defaultFile, wildcard=files, style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
        ) as fileDialog:
            fileDialog.SetFilename(defaultFile)
            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return  # the user changed their mind
            pathname = fileDialog.GetPath()
            self.load(pathname)

    def load(self, pathname):
        self.context.setting(bool, "uniform_svg", False)
        self.context.setting(float, "svg_ppi", 96.0)
        self.context("raster clear\ncut clear\nengrave clear\n")
        self.context.working_file = pathname
        with wx.BusyInfo(_("Loading File...")):
            if pathname.endswith("svg"):
                self.context('inkscape locate input "%s" text2path load makepng load image wizard Gravy\n' % pathname)
                return True

            results = self.context.load(
                pathname,
                channel=self.context.channel("load"),
                svg_ppi=self.context.svg_ppi,
            )
            if pathname.lower().endswith("png") or pathname.lower().endswith("jpg"):
                self.context("image wizard Gravy\n")
            self.request_refresh()
            return bool(results)

    def on_drop_file(self, event):
        """
        Drop file handler

        Accepts multiple files drops.
        """
        accepted = 0
        rejected = 0
        rejected_files = []
        for pathname in event.GetFiles():
            if self.load(pathname):
                accepted += 1
            else:
                rejected += 1
                rejected_files.append(pathname)
        if rejected != 0:
            reject = "\n".join(rejected_files)
            err_msg = _("Some files were unrecognized:\n%s") % reject
            dlg = wx.MessageDialog(
                None, err_msg, _("Error encountered"), wx.OK | wx.ICON_ERROR
            )
            dlg.ShowModal()
            dlg.Destroy()

    def on_halftone(self, *args, **kwargs):
        self.checkbox_halftone.SetValue(self.context.halftone)

    def on_rotary_enable(self, *args, **kwargs):
        self.checkbox_rotary_enable.SetValue(self.context.rotary_enable)

    def on_op_setting_update(self, *args, **kwargs):
        self.text_raster_passes.SetValue(str(self.context.raster_settings.implicit_passes))
        self.text_engrave_passes.SetValue(str(self.context.engrave_settings.implicit_passes))
        self.text_cut_passes.SetValue(str(self.context.cut_settings.implicit_passes))
        self.text_raster_speed.SetValue(str(self.context.raster_settings.speed))
        self.text_engrave_speed.SetValue(str(self.context.engrave_settings.speed))
        self.text_cut_speed.SetValue(str(self.context.cut_settings.speed))

    def window_open(self):
        pass

    def window_close(self):
        self.context("quit\n")
        self.context.unlisten("statusbar", self.on_statusbar)
        self.context.unlisten("rotary_enable", self.on_rotary_enable)
        self.context.unlisten("halftone", self.on_halftone)
        self.context.unlisten("op_setting_update", self.on_op_setting_update)
        self.context.unlisten("bed_size", self.on_bed_changed)
        self.context.unlisten("units", self.on_space_changed)
        self.context.unlisten("draw_mode", self.on_draw_mode)

    def on_statusbar(self, message=None, color=None):
        if message is None:
            silence_statusbar_fields = [
                "Current Position: X=%f Y=%f (W X H)=(%fmm X %fmm)" % (self.context.offset_x, self.context.offset_y, self.context.offset_width, self.context.offset_height),
            ]
        else:
            silence_statusbar_fields = [
                message,
            ]
        if color is None:
            self.silence_statusbar.SetBackgroundColour(wx.WHITE)
        elif color == 1:
            self.silence_statusbar.SetBackgroundColour(wx.CYAN)
        elif color == 2:
            self.silence_statusbar.SetBackgroundColour(wx.YELLOW)
        elif color == 3:
            self.silence_statusbar.SetBackgroundColour(wx.RED)
        elif color == 4:
            self.silence_statusbar.SetBackgroundColour(wx.GREEN)
        elif color == 5:
            self.silence_statusbar.SetBackgroundColour(wx.BLUE)
        for i in range(len(silence_statusbar_fields)):
            self.silence_statusbar.SetStatusText(silence_statusbar_fields[i], i)

    def __set_properties(self):
        # begin wxGlade: Silence.__set_properties
        self.SetTitle("%s v%s" % (self.context._kernel.name, self.context._kernel.version))
        self.silence_statusbar.SetStatusWidths([-1])

        # statusbar fields
        self.on_statusbar(_("Welcome to Silence"))
        self.button_usb_init.SetToolTip(
            'Establish connection with the laser controller board, and optionally Home the laser depending on the setting in the General settings window for "Home Upon initialize"'
        )
        self.button_design_open.SetMinSize((100, 50))
        self.button_design_open.SetToolTip(
            "Opens a dialog box to select a design file to open.\n\nOpen SVG, DXF and G-Code files using file open."
        )
        self.button_design_reload.SetMinSize((100, 50))
        self.button_design_reload.SetToolTip(
            "Reloads the current design. (Re-read the design file information from the storage location)"
        )
        self.button_home.SetToolTip("Sends the laser to its Home position.")
        self.button_unlock_rail.SetToolTip(
            "Turns the stepper motors attached to the X and Y axes off. This allows the user to move the laser head manually."
        )
        self.text_jog_step.SetToolTip(
            "The distance the laser head will move when the laser head is moved (jogged) when the arrow buttons are pressed."
        )
        self.button_align_TL.SetMinSize((50, 50))
        self.button_align_TL.SetToolTip(
            "The four corner buttons and the center button are used to move the laser head to the corners of the loaded design. This is useful to verify that the design will fit in the space available on the material you are using."
        )
        self.button_jog_T.SetMinSize((50, 50))
        self.button_jog_T.SetToolTip(
            "The four arrow buttons move (jog) the laser head in the indicated direction the distance entered in the Jog Step entry field."
        )
        self.button_align_TR.SetMinSize((50, 50))
        self.button_align_TR.SetToolTip(
            "The four corner buttons and the center button are used to move the laser head to the corners of the loaded design. This is useful to verify that the design will fit in the space available on the material you are using."
        )
        self.button_jog_L.SetMinSize((50, 50))
        self.button_jog_L.SetToolTip(
            "The four arrow buttons move (jog) the laser head in the indicated direction the distance entered in the Jog Step entry field."
        )
        self.button_align_C.SetMinSize((50, 50))
        self.button_align_C.SetToolTip(
            "The four corner buttons and the center button are used to move the laser head to the corners of the loaded design. This is useful to verify that the design will fit in the space available on the material you are using."
        )
        self.button_jog_R.SetMinSize((50, 50))
        self.button_jog_R.SetToolTip(
            "The four arrow buttons move (jog) the laser head in the indicated direction the distance entered in the Jog Step entry field."
        )
        self.button_align_BL.SetMinSize((50, 50))
        self.button_align_BL.SetToolTip(
            "The four corner buttons and the center button are used to move the laser head to the corners of the loaded design. This is useful to verify that the design will fit in the space available on the material you are using."
        )
        self.button_jog_B.SetMinSize((50, 50))
        self.button_jog_B.SetToolTip(
            "The four arrow buttons move (jog) the laser head in the indicated direction the distance entered in the Jog Step entry field."
        )
        self.button_align_BR.SetMinSize((50, 50))
        self.button_align_BR.SetToolTip(
            "The four corner buttons and the center button are used to move the laser head to the corners of the loaded design. This is useful to verify that the design will fit in the space available on the material you are using."
        )
        self.button_move.SetMinSize((75, 23))
        self.button_move.SetToolTip(
            "The Move To button will home the laser then move the laser head to the X and Y position entered in the X and Y fields."
        )
        self.text_move_x.SetMinSize((50, 20))
        self.text_move_y.SetMinSize((50, 20))
        self.button_raster.SetMinSize((100, 23))
        self.button_raster.SetToolTip(
            "Start the raster engrave process. This will start the laser."
        )
        self.text_raster_speed.SetMinSize((52, 23))
        self.button_engrave.SetToolTip(
            "Start the vector engrave process. This will start the laser."
        )
        self.text_engrave_speed.SetMinSize((52, 23))
        self.text_engrave_speed.SetForegroundColour(wx.Colour(0, 0, 255))
        self.button_cut.SetMinSize((100, 23))
        self.button_cut.SetToolTip(
            "Start the vector cut process. This will start the laser."
        )
        self.text_cut_speed.SetMinSize((52, 23))
        self.text_cut_speed.SetForegroundColour(wx.Colour(255, 0, 0))
        self.button_pause_stop.SetMinSize((0, 50))
        self.button_pause_stop.SetBackgroundColour(wx.Colour(142, 35, 35))
        self.button_pause_stop.SetToolTip(
            "Stop the running laser job. Pressing this button will pause sending the current job data to the laser and pop up a dialog box asking if you want to cancel the remainder of the job. The laser head may not stop instantly because there is some data that has already been sent to the laser controller board. The laser will finish running the data it has received before it stops."
        )
        self.panel_6.SetMinSize((200, 0))
        self.checkbox_halftone.SetToolTip(
            "Turn on or off halftone (dither). Turning this option on converts any input grayscale images into dots that are spaced to approximate a grayscale image when engraved. This is similar to the process used to produce images for newsprint. The stock controller board does not have the capability to control the laser power so dithering is the only way to get grayscale images using the stock controller. You can also dither the image before loading it."
        )
        self.checkbox_halftone.SetValue(1)
        self.checkbox_invert.SetToolTip(
            "Inverts the colors in the raster image. This has the effect of turning the raster image into the negative of the original image so white is black and so on."
        )
        self.checkbox_mirror.SetToolTip(
            "Mirrors the input design. This option is useful for making stamps or engraving on the back of mirrors."
        )
        self.checkbox_rotate.SetToolTip("Simple rotate the input design by 90 degrees.")
        self.checkbox_csys.SetToolTip(
            "This option causes the reference point for a design to be the origin of the coordinate system of the input DXF file."
        )
        self.checkbox_cut_inner.SetToolTip(
            "When this option is on the paths that are inside of other closed paths will be cut first. This is important sometimes because if the outside part is cut first it can fall out or shift on the cutting table resulting in a misaligned cut for the internal features if they are cut after the outside features."
        )
        self.checkbox_cut_inner.SetValue(1)
        self.checkbox_rotary_enable.SetToolTip(
            "This option causes the program to use the settings in the rotary settings window intended to be used with a rotary devices attached to the y-axis connector on the controller board."
        )
        self.checkbox_group_engrave.SetToolTip(
            'This option combines the buttons for the raster and vector engraving tasks so both tasks are performed with one button click. If the "Group Vector Tasks" is also selected all three buttons are combined into one.'
        )
        self.checkbox_group_vector.SetToolTip(
            'This option combines the buttons for the vector engraving and cutting tasks so both tasks are performed with one button click. If the "Group Engrave Tasks" is also selected all three buttons are combined into one.'
        )
        self.text_raster_passes.SetToolTip(
            "Set the number of time to repeat the raster engrave paths."
        )
        self.text_engrave_passes.SetForegroundColour(wx.Colour(0, 0, 255))
        self.text_engrave_passes.SetToolTip(
            "Set the number of time to repeat the vector engrave paths."
        )
        self.text_cut_passes.SetForegroundColour(wx.Colour(255, 0, 0))
        self.text_cut_passes.SetToolTip(
            "Set the number of time to repeat the vector cut paths."
        )
        self.button_hide_advanced.SetMinSize((0, 50))
        self.button_hide_advanced.SetToolTip(
            "Button to hide the advanced options pane."
        )
        self.scene.SetBackgroundColour(wx.Colour(192, 192, 192))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: Silence.__do_layout
        sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_20 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_19 = wx.BoxSizer(wx.VERTICAL)
        sizer_23 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_22 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_21 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_14 = wx.BoxSizer(wx.VERTICAL)
        sizer_17 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_16 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_15 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_7 = wx.BoxSizer(wx.VERTICAL)
        sizer_11 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_13 = wx.BoxSizer(wx.VERTICAL)
        sizer_12 = wx.BoxSizer(wx.VERTICAL)
        sizer_18 = wx.BoxSizer(wx.VERTICAL)
        sizer_10 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_9 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_8 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4 = wx.BoxSizer(wx.VERTICAL)
        sizer_6 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_5 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_2.Add(self.button_usb_init, 0, wx.EXPAND, 0)
        sizer_3.Add(self.button_design_open, 0, wx.EXPAND, 0)
        sizer_3.Add(self.button_design_reload, 0, wx.EXPAND, 0)
        sizer_2.Add(sizer_3, 0, wx.EXPAND, 0)
        static_line_1 = wx.StaticLine(self.panel_6, wx.ID_ANY)
        sizer_2.Add(static_line_1, 0, wx.EXPAND, 0)
        label_1 = wx.StaticText(self.panel_1, wx.ID_ANY, "Position Controls:")
        sizer_4.Add(label_1, 0, 0, 0)
        sizer_5.Add(self.button_home, 0, 0, 0)
        sizer_5.Add(self.button_unlock_rail, 0, 0, 0)
        sizer_4.Add(sizer_5, 0, wx.EXPAND, 0)
        label_2 = wx.StaticText(self.panel_1, wx.ID_ANY, "Jog Step")
        sizer_6.Add(label_2, 0, 0, 0)
        sizer_6.Add(self.text_jog_step, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        label_3 = wx.StaticText(self.panel_1, wx.ID_ANY, "mm")
        sizer_6.Add(label_3, 0, 0, 0)
        sizer_4.Add(sizer_6, 0, wx.EXPAND, 0)
        self.panel_1.SetSizer(sizer_4)
        sizer_2.Add(self.panel_1, 0, wx.EXPAND, 0)
        sizer_8.Add(self.button_align_TL, 1, 0, 0)
        sizer_8.Add(self.button_jog_T, 1, 0, 0)
        sizer_8.Add(self.button_align_TR, 1, 0, 0)
        sizer_7.Add(sizer_8, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
        sizer_9.Add(self.button_jog_L, 1, 0, 0)
        sizer_9.Add(self.button_align_C, 1, 0, 0)
        sizer_9.Add(self.button_jog_R, 1, 0, 0)
        sizer_7.Add(sizer_9, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
        sizer_10.Add(self.button_align_BL, 1, 0, 0)
        sizer_10.Add(self.button_jog_B, 1, 0, 0)
        sizer_10.Add(self.button_align_BR, 1, 0, 0)
        sizer_7.Add(sizer_10, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
        label_10 = wx.StaticText(self.panel_4, wx.ID_ANY, "")
        sizer_18.Add(label_10, 0, 0, 0)
        sizer_18.Add(self.button_move, 0, 0, 0)
        sizer_11.Add(sizer_18, 2, wx.EXPAND, 0)
        label_4 = wx.StaticText(self.panel_4, wx.ID_ANY, "    X")
        sizer_12.Add(label_4, 0, 0, 0)
        sizer_12.Add(self.text_move_x, 0, 0, 0)
        sizer_11.Add(sizer_12, 2, 0, 0)
        label_5 = wx.StaticText(self.panel_4, wx.ID_ANY, "    Y")
        sizer_13.Add(label_5, 0, 0, 0)
        sizer_13.Add(self.text_move_y, 0, 0, 0)
        sizer_11.Add(sizer_13, 2, wx.EXPAND, 0)
        self.panel_4.SetSizer(sizer_11)
        sizer_7.Add(self.panel_4, 0, wx.EXPAND, 0)
        self.panel_2.SetSizer(sizer_7)
        sizer_2.Add(self.panel_2, 3, wx.EXPAND, 0)
        static_line_2 = wx.StaticLine(self.panel_6, wx.ID_ANY)
        sizer_2.Add(static_line_2, 0, wx.EXPAND, 0)
        sizer_15.Add(self.button_raster, 0, 0, 0)
        sizer_15.Add(self.text_raster_speed, 0, wx.EXPAND, 0)
        label_6 = wx.StaticText(self.panel_3, wx.ID_ANY, "mm/s")
        sizer_15.Add(label_6, 1, 0, 0)
        sizer_14.Add(sizer_15, 0, wx.EXPAND, 0)
        sizer_16.Add(self.button_engrave, 0, 0, 0)
        sizer_16.Add(self.text_engrave_speed, 0, wx.EXPAND, 0)
        label_7 = wx.StaticText(self.panel_3, wx.ID_ANY, "mm/s")
        sizer_16.Add(label_7, 1, 0, 0)
        sizer_14.Add(sizer_16, 0, wx.EXPAND, 0)
        sizer_17.Add(self.button_cut, 1, 0, 0)
        sizer_17.Add(self.text_cut_speed, 1, wx.EXPAND, 0)
        label_8 = wx.StaticText(self.panel_3, wx.ID_ANY, "mm/s")
        sizer_17.Add(label_8, 1, 0, 0)
        sizer_14.Add(sizer_17, 2, wx.EXPAND, 0)
        sizer_14.Add(self.button_pause_stop, 0, wx.EXPAND, 0)
        self.panel_3.SetSizer(sizer_14)
        sizer_2.Add(self.panel_3, 0, wx.EXPAND, 0)
        self.panel_6.SetSizer(sizer_2)
        sizer_1.Add(self.panel_6, 1, wx.EXPAND, 0)
        static_line_8 = wx.StaticLine(
            self.advanced_settings, wx.ID_ANY, style=wx.LI_VERTICAL
        )
        sizer_20.Add(static_line_8, 0, wx.EXPAND, 0)
        label_9 = wx.StaticText(self.advanced_settings, wx.ID_ANY, "Advanced Settings")
        sizer_19.Add(label_9, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
        static_line_3 = wx.StaticLine(self.advanced_settings, wx.ID_ANY)
        sizer_19.Add(static_line_3, 0, wx.EXPAND, 0)
        sizer_19.Add(self.checkbox_halftone, 1, 0, 0)
        sizer_19.Add(self.checkbox_invert, 1, 0, 0)
        static_line_4 = wx.StaticLine(self.advanced_settings, wx.ID_ANY)
        sizer_19.Add(static_line_4, 0, wx.EXPAND, 0)
        sizer_19.Add(self.checkbox_mirror, 1, 0, 0)
        sizer_19.Add(self.checkbox_rotate, 1, 0, 0)
        sizer_19.Add(self.checkbox_csys, 1, 0, 0)
        static_line_5 = wx.StaticLine(self.advanced_settings, wx.ID_ANY)
        sizer_19.Add(static_line_5, 0, wx.EXPAND, 0)
        sizer_19.Add(self.checkbox_cut_inner, 1, 0, 0)
        sizer_19.Add(self.checkbox_rotary_enable, 1, 0, 0)
        sizer_19.Add((20, 20), 100, 0, 0)
        sizer_19.Add(self.checkbox_group_engrave, 1, 0, 0)
        sizer_19.Add(self.checkbox_group_vector, 1, 0, 0)
        static_line_7 = wx.StaticLine(self.advanced_settings, wx.ID_ANY)
        sizer_19.Add(static_line_7, 0, wx.EXPAND, 0)
        label_12 = wx.StaticText(
            self.advanced_settings, wx.ID_ANY, "Raster Eng. Passes"
        )
        sizer_21.Add(label_12, 0, 0, 0)
        sizer_21.Add(self.text_raster_passes, 0, 0, 0)
        sizer_19.Add(sizer_21, 1, wx.EXPAND, 0)
        label_13 = wx.StaticText(
            self.advanced_settings, wx.ID_ANY, "Vector Eng. Passes"
        )
        sizer_22.Add(label_13, 0, 0, 0)
        sizer_22.Add(self.text_engrave_passes, 0, 0, 0)
        sizer_19.Add(sizer_22, 1, wx.EXPAND, 0)
        label_14 = wx.StaticText(self.advanced_settings, wx.ID_ANY, "Vector Cut Passes")
        sizer_23.Add(label_14, 0, 0, 0)
        sizer_23.Add(self.text_cut_passes, 0, 0, 0)
        sizer_19.Add(sizer_23, 1, wx.EXPAND, 0)
        sizer_19.Add(self.button_hide_advanced, 1, wx.EXPAND, 0)
        sizer_20.Add(sizer_19, 0, 0, 0)
        self.advanced_settings.SetSizer(sizer_20)
        sizer_1.Add(self.advanced_settings, 1, wx.EXPAND, 0)
        sizer_1.Add(self.scene, 5, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        self.Layout()
        # end wxGlade

    def toggle_advance_settings(self):
        if self.advanced_settings.IsShown():
            self.advanced_settings.Hide()
        else:
            self.advanced_settings.Show()

        self.context.console("refresh\n")

    def on_menu_save(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("settings_save\n")

    def on_menu_load(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("settings_load\n")

    def on_menu_open(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("design_load\n")

    def on_menu_reload(self, event):  # wxGlade: Silence.<event_handler>
        if self.context.working_file is not None:
            self.context.console("design_load %s\n" % self.context.working_file)

    def on_menu_egv(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("egv_load\n")

    def on_menu_egv_save(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("window open EgvSave\n")

    def on_menu_exit(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("quit\n")

    def on_menu_refresh(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("refresh\n")

    def on_menu_view_raster(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("view_setting toggle raster\n")

    def on_menu_view_engrave(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("view_setting toggle engrave\n")

    def on_menu_view_cut(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("view_setting toggle cut\n")

    def on_menu_view_gcode(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("view_setting toggle gcode\n")

    def on_menu_view_estimate(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("view_setting toggle estimate\n")

    def on_menu_view_zoom(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("view_setting toggle zoom\n")

    def on_menu_calc_raster(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("calculate raster\n")

    def on_menu_convex_hull(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("window open TraceBoundary\n")

    def on_menu_initialize(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("device -p / init Lhystudios activate start\n")

    def on_menu_reset_usb(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("device reset\n")

    def on_menu_release_usb(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("device release\n")

    def on_menu_settings_general(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("window open GeneralSettings\n")

    def on_menu_settings_raster(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("window open RasterSettings\n")

    def on_menu_settings_rotary(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("window open RotarySettings\n")

    def on_menu_settings_advanced(self, event):  # wxGlade: Silence.<event_handler>
        self.toggle_advance_settings()

    def on_menu_help_about(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("webhelp about\n")

    def on_menu_help_webpage(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("webhelp webpage\n")

    def on_menu_help_manual(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("webhelp manual\n")

    def on_button_initialize_laser(self, event):  # wxGlade: Silence.<event_handler>
        if self.context.board == "Moshiboard":
            self.context.console("device -p / init Moshi activate start\n")
        else:
            self.context.console("device -p / init Lhystudios activate start\n")

    def on_button_open_design(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("design_load\n")

    def on_button_reload_design(self, event):  # wxGlade: Silence.<event_handler>
        if self.context.working_file is not None:
            self.context.console("design_load %s\n" % self.context.working_file)

    def on_button_home(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("home\n")

    def on_button_unlock_rail(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("unlock\n")

    def on_text_jog_step(self, event):  # wxGlade: Silence.<event_handler>
        try:
            self.context.jog_step = float(self.text_jog_step.GetValue())
        except ValueError:
            pass

    def on_button_align_top_left(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("align top left\n")

    def on_button_jog_top(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("top %fmm\n" % self.context.jog_step)

    def on_button_align_top_right(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("align top right\n")

    def on_button_jog_left(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("left %fmm\n" % self.context.jog_step)

    def on_button_align_center(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("align center center\n")

    def on_button_jog_right(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("right %fmm\n" % self.context.jog_step)

    def on_button_align_bottom_left(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("align bottom left\n")

    def on_button_jog_bottom(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("bottom %fmm\n" % self.context.jog_step)

    def on_button_align_bottom_right(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("align bottom right\n")

    def on_button_move(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console(
            "move_absolute %fmm %fmm\n" % (self.context.move_x, self.context.move_y)
        )

    def on_text_move_x(self, event):  # wxGlade: Silence.<event_handler>
        try:
            self.context.move_x = float(self.text_move_x.GetValue())
        except ValueError:
            pass

    def on_text_move_y(self, event):  # wxGlade: Silence.<event_handler>
        try:
            self.context.move_y = float(self.text_move_y.GetValue())
        except ValueError:
            pass

    def on_button_raster_engrave(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("raster execute\n")

    def on_text_raster_speed(self, event):  # wxGlade: Silence.<event_handler>
        try:
            self.context.raster_settings.speed = float(self.text_raster_speed.GetValue())
        except ValueError:
            pass

    def on_button_vector_engrave(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("engrave execute\n")

    def on_text_engrave_speed(self, event):  # wxGlade: Silence.<event_handler>
        try:
            self.context.engrave_settings.speed = float(self.text_engrave_speed.GetValue())
        except ValueError:
            pass

    def on_button_vector_cut(self, event):  # wxGlade: Silence.<event_handler>
        self.context.console("cut execute\n")

    def on_text_cut_speed(self, event):  # wxGlade: Silence.<event_handler>
        try:
            self.context.cut_settings.speed = float(self.text_cut_speed.GetValue())
        except ValueError:
            pass

    def on_button_pause_stop(self, event):  # wxGlade: Silence.<event_handler>
        self.context("pause\n")
        dlg = wx.MessageDialog(
            None,
            _("Press OK to abort.\n"
              "Cancel to resume the job."),
            _("Stop Laser Sending?"),
            wx.OK | wx.CANCEL | wx.ICON_WARNING,
        )
        result = dlg.ShowModal()
        if result == wx.ID_OK:
            self.context("abort\n")
        else:
            self.context("pause\n")
            self.context("resume\n")
        dlg.Destroy()

    def on_check_halftone(self, event):  # wxGlade: Silence.<event_handler>
        self.context.halftone = bool(self.checkbox_halftone.GetValue())
        self.context.signal("halftone", self.context.halftone)

    def on_check_invert(self, event):  # wxGlade: Silence.<event_handler>
        self.context.invert = bool(self.checkbox_invert.GetValue())

    def on_check_mirror(self, event):  # wxGlade: Silence.<event_handler>
        self.context.mirror = bool(self.checkbox_mirror.GetValue())

    def on_check_rotate(self, event):  # wxGlade: Silence.<event_handler>
        self.context.rotate = bool(self.checkbox_rotate.GetValue())

    def on_check_csys(self, event):  # wxGlade: Silence.<event_handler>
        self.context.csys = bool(self.checkbox_csys.GetValue())

    def on_check_cut_inside(self, event):  # wxGlade: Silence.<event_handler>
        self.context.cut_inner = bool(self.checkbox_cut_inner.GetValue())

    def on_check_use_rotary(self, event):  # wxGlade: Silence.<event_handler>
        self.context.rotary_enable = bool(self.checkbox_rotary_enable.GetValue())
        self.context.signal("rotary_enable", self.context.rotary_enable)

    def on_check_group_engrave(self, event):  # wxGlade: Silence.<event_handler>
        self.context.group_engrave = bool(self.checkbox_group_engrave.GetValue())

    def on_check_group_vector(self, event):  # wxGlade: Silence.<event_handler>
        self.context.group_vector = bool(self.checkbox_group_vector.GetValue())

    def on_text_raster_engrave_passes(self, event):  # wxGlade: Silence.<event_handler>
        try:
            self.context.raster_settings.passes = int(self.text_raster_passes.GetValue())
        except ValueError:
            pass

    def on_text_vector_engrave_passes(self, event):  # wxGlade: Silence.<event_handler>
        try:
            self.context.engrave_settings.passes = int(self.text_engrave_passes.GetValue())
        except ValueError:
            pass

    def on_text_vector_cut_passes(self, event):  # wxGlade: Silence.<event_handler>
        try:
            self.context.cut_settings.passes = int(self.text_cut_passes.GetValue())
        except ValueError:
            pass

    def on_button_hide_advanced(self, event):  # wxGlade: Silence.<event_handler>
        self.toggle_advance_settings()

    # Scene information

    def on_size(self, event):
        if self.context is None:
            return
        self.Layout()
        self.widget_scene.signal("guide")
        self.request_refresh()

    def set_buffer(self):
        width, height = self.scene.ClientSize
        if width <= 0:
            width = 1
        if height <= 0:
            height = 1
        self._Buffer = wx.Bitmap(width, height)

    def on_paint(self, event):
        try:
            if self._Buffer is None:
                self.update_buffer_ui_thread()
            wx.BufferedPaintDC(self.scene, self._Buffer)
        except RuntimeError:
            pass

    def on_space_changed(self, *args):
        self.widget_scene.signal("grid")
        self.widget_scene.signal("guide")
        self.request_refresh()

    def on_draw_mode(self, mode):
        self.silence_menubar.view_gcode.Check(bool(mode & DRAW_MODE_GCODE))
        self.silence_menubar.view_cut.Check(bool(mode & DRAW_MODE_CUT))
        self.silence_menubar.view_raster.Check(bool(mode & DRAW_MODE_RASTER))
        self.silence_menubar.view_engrave.Check(bool(mode & DRAW_MODE_ENGRAVE))
        self.silence_menubar.view_estimate.Check(bool(mode & DRAW_MODE_ESTIMATE))
        self.silence_menubar.view_zoom.Check(bool(mode & DRAW_MODE_ZOOM))

    def on_bed_changed(self, *args):
        self.widget_scene.signal("grid")
        self.request_refresh()

    def on_refresh_scene(self, *args):
        """
        Called by 'refresh_scene' change. To refresh tree.

        :param args:
        :return:
        """
        self.on_statusbar()
        self.request_refresh()

    def on_erase(self, event):
        pass

    def request_refresh_for_animation(self):
        """Called on the various signals trying to animate the screen."""
        try:
            if self.context.draw_mode & DRAW_MODE_ANIMATE == 0:
                self.request_refresh()
        except AttributeError:
            pass

    def request_refresh(self):
        """Request an update to the scene."""
        try:
            if self.context.draw_mode & DRAW_MODE_REFRESH == 0:
                self.screen_refresh_is_requested = True
        except AttributeError:
            pass

    def refresh_scene(self):
        """Called by the Scheduler at a given the specified framerate."""
        if self.screen_refresh_is_requested and not self.screen_refresh_is_running:
            self.screen_refresh_is_running = True
            if self.screen_refresh_lock.acquire(timeout=1):
                if not wx.IsMainThread():
                    wx.CallAfter(self._refresh_in_ui)
                else:
                    self._refresh_in_ui()
            else:
                self.screen_refresh_is_requested = False
                self.screen_refresh_is_running = False

    def _refresh_in_ui(self):
        """Called by refresh_scene() in the UI thread."""
        if self.context is None:
            return
        self.update_buffer_ui_thread()
        self.scene.Refresh()
        self.scene.Update()
        self.screen_refresh_is_requested = False
        self.screen_refresh_is_running = False
        self.screen_refresh_lock.release()

    def update_buffer_ui_thread(self):
        """Performs the redraw of the data in the UI thread."""
        dm = self.context.draw_mode
        if self._Buffer is None or self._Buffer.GetSize() != self.scene.ClientSize:
            self.set_buffer()
        dc = wx.MemoryDC()
        dc.SelectObject(self._Buffer)
        dc.SetBackground(self.background_brush)
        dc.Clear()
        w, h = dc.Size
        if dm & DRAW_MODE_FLIPXY != 0:
            dc.SetUserScale(-1, -1)
            dc.SetLogicalOrigin(w, h)
        gc = wx.GraphicsContext.Create(dc)
        gc.Size = dc.Size

        # gc.laserpath = self.laserpath
        font = wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD)
        gc.SetFont(font, wx.BLACK)
        if self.widget_scene is not None:
            self.widget_scene.draw(gc)
        if dm & DRAW_MODE_INVERT != 0:
            dc.Blit(0, 0, w, h, dc, 0, 0, wx.SRC_INVERT)
        gc.Destroy()
        del dc

    # Mouse Events.

    def on_mousewheel(self, event):
        if self.scene.HasCapture():
            return
        rotation = event.GetWheelRotation()
        if event.GetWheelAxis() == wx.MOUSE_WHEEL_VERTICAL and not event.ShiftDown():
            if event.HasAnyModifiers():
                if rotation > 1:
                    self.widget_scene.event(event.GetPosition(), "wheelup_ctrl")
                elif rotation < -1:
                    self.widget_scene.event(event.GetPosition(), "wheeldown_ctrl")
            else:
                if rotation > 1:
                    self.widget_scene.event(event.GetPosition(), "wheelup")
                elif rotation < -1:
                    self.widget_scene.event(event.GetPosition(), "wheeldown")
        else:
            if rotation > 1:
                self.widget_scene.event(event.GetPosition(), "wheelleft")
            elif rotation < -1:
                self.widget_scene.event(event.GetPosition(), "wheelright")

    def on_mousewheel_zoom(self, event):
        if self.scene.HasCapture():
            return
        rotation = event.GetWheelRotation()
        if self.context.mouse_zoom_invert:
            rotation = -rotation
        if rotation > 1:
            self.widget_scene.event(event.GetPosition(), "wheelup")
        elif rotation < -1:
            self.widget_scene.event(event.GetPosition(), "wheeldown")

    def on_mouse_middle_down(self, event):
        self.scene.SetFocus()
        if not self.scene.HasCapture():
            self.scene.CaptureMouse()
        self.widget_scene.event(event.GetPosition(), "middledown")

    def on_mouse_middle_up(self, event):
        if self.scene.HasCapture():
            self.scene.ReleaseMouse()
        self.widget_scene.event(event.GetPosition(), "middleup")

    def on_left_mouse_down(self, event):
        self.scene.SetFocus()
        if not self.scene.HasCapture():
            self.scene.CaptureMouse()
        self.widget_scene.event(event.GetPosition(), "leftdown")

    def on_left_mouse_up(self, event):
        if self.scene.HasCapture():
            self.scene.ReleaseMouse()
        self.widget_scene.event(event.GetPosition(), "leftup")

    def on_mouse_double_click(self, event):
        if self.scene.HasCapture():
            return
        self.widget_scene.event(event.GetPosition(), "doubleclick")

    def on_mouse_move(self, event):
        if not event.Dragging():
            self.widget_scene.event(event.GetPosition(), "hover")
            return
        self.widget_scene.event(event.GetPosition(), "move")

    def on_right_mouse_down(self, event):
        self.scene.SetFocus()
        if event.AltDown():
            self.widget_scene.event(event.GetPosition(), "rightdown+alt")
        elif event.ControlDown():
            self.widget_scene.event(event.GetPosition(), "rightdown+control")
        else:
            self.widget_scene.event(event.GetPosition(), "rightdown")

    def on_right_mouse_up(self, event):
        self.widget_scene.event(event.GetPosition(), "rightup")

    def on_magnify_mouse(self, event):
        magnify = event.GetMagnification()
        if magnify > 0:
            self.widget_scene.event(event.GetPosition(), "zoom-in")
        if magnify < 0:
            self.widget_scene.event(event.GetPosition(), "zoom-out")

    def on_gesture(self, event):
        """
        This code requires WXPython 4.1 and the bind will fail otherwise.
        """
        if event.IsGestureStart():
            self.widget_scene.event(event.GetPosition(), "gesture-start")
        elif event.IsGestureEnd():
            self.widget_scene.event(event.GetPosition(), "gesture-end")
        else:
            try:
                zoom = event.GetZoomFactor()
            except AttributeError:
                zoom = 1.0
            self.widget_scene.event(event.GetPosition(), "zoom %f" % zoom)


# end of class Silence
