diff --git a/.gitignore b/.gitignore index 319a6c5..f3f99be 100644 --- a/.gitignore +++ b/.gitignore @@ -153,3 +153,5 @@ cython_debug/ output/ .vscode/ +temp/ +config.ini diff --git a/assets/iconEnabled.ico b/assets/icon.ico similarity index 100% rename from assets/iconEnabled.ico rename to assets/icon.ico diff --git a/config.ini b/config.ini deleted file mode 100644 index 6daef17..0000000 --- a/config.ini +++ /dev/null @@ -1,7 +0,0 @@ -[Settings] -monitor_name = LG TV -monitor_serial = nan -multimonitortool_executable = C:/App_Install/multimonitortool-x64/MultiMonitorTool.exe -start_with_windows = no -first_start = no - diff --git a/requirements.txt b/requirements.txt index e10f191..0262081 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,4 @@ win10toast pystray pandas customtkinter -python-tkdnd \ No newline at end of file +CTkMessagebox \ No newline at end of file diff --git a/smct_pkg/config.py b/smct_pkg/config.py index e16c7ee..f547096 100644 --- a/smct_pkg/config.py +++ b/smct_pkg/config.py @@ -1,12 +1,12 @@ import configparser import os +import sys from smct_pkg import ( - multimonitortool, notification, paths, registry, - setup_gui, + ui, ui_strings, ) @@ -31,31 +31,22 @@ def check_for_missing_files(): - # Check for assets folder - if not os.path.exists(paths.ASSETS_DIR_PATH): - os.makedirs(paths.ASSETS_DIR_PATH) # Check for Icons if not os.path.exists(paths.ASSETS_ICON_ENABLED_PATH): notification.send_error( paths.ASSETS_ICON_ENABLED_PATH + ui_strings.FILE_NOT_FOUND ) + sys.exit(1) if not os.path.exists(paths.ASSETS_ICON_DISABLED_PATH): notification.send_error( paths.ASSETS_ICON_DISABLED_PATH + ui_strings.FILE_NOT_FOUND ) - - # Check for MultiMonitorTool - if not os.path.exists(MMT_PATH_VALUE): - notification.send_error(MMT_PATH_VALUE + ui_strings.FILE_NOT_FOUND) + sys.exit(1) # Check for temp folder if not os.path.exists(paths.TEMP_DIR_PATH): os.makedirs(paths.TEMP_DIR_PATH) - # Check for MultiMonitorTool CSV - if not os.path.exists(paths.MMT_CSV_PATH): - multimonitortool.save_mmt_config() - def read_config(): # Check if config.ini file is present @@ -75,18 +66,18 @@ def read_config(): ) FIRST_START_VALUE = _configparser.getboolean(SETTINGS_SECTION, FIRT_START_KEY) + check_for_missing_files() + if START_WITH_WINDOWS_VALUE: registry.add_to_autostart() else: registry.remove_from_autostart() if FIRST_START_VALUE: - setup_gui.init_mmt_selection_frame() + ui.init_mmt_selection_frame() FIRST_START_VALUE = False set_config_value(SETTINGS_SECTION, FIRT_START_KEY, FIRST_START_VALUE) - check_for_missing_files() - def _create_default_config_file(): _configparser["Settings"] = { diff --git a/smct_pkg/notification.py b/smct_pkg/notification.py index 4606928..6ef5f23 100644 --- a/smct_pkg/notification.py +++ b/smct_pkg/notification.py @@ -1,18 +1,5 @@ -import threading +from tkinter import messagebox -from win10toast import ToastNotifier - -# TODO: add Logic def send_error(text): - toaster = ToastNotifier() - toaster.show_toast("Error", text, duration=7) - - -def send_notification(text, duration): - def show_notification(): - toaster = ToastNotifier() - toaster.show_toast("It's your first startup!", text, duration=duration) - - notification_thread = threading.Thread(target=show_notification) - notification_thread.start() + messagebox.showerror("Error", text) diff --git a/smct_pkg/paths.py b/smct_pkg/paths.py index c2338f9..2771400 100644 --- a/smct_pkg/paths.py +++ b/smct_pkg/paths.py @@ -32,3 +32,4 @@ def strip_package_name_from_path(path): MMT_CONFIG_PATH = TEMP_DIR_PATH + r"\MultiMonitorToolConfig" ASSETS_ICON_ENABLED_PATH = ASSETS_DIR_PATH + r"\iconEnabled.png" ASSETS_ICON_DISABLED_PATH = ASSETS_DIR_PATH + r"\iconDisabled.png" +ASSETS_ICO_PATH = ASSETS_DIR_PATH + r"\icon.ico" diff --git a/smct_pkg/tray.py b/smct_pkg/tray.py index b82712a..58d922c 100644 --- a/smct_pkg/tray.py +++ b/smct_pkg/tray.py @@ -8,8 +8,8 @@ ICON = None -icon_enabled_image = Image.open(paths.ASSETS_ICON_ENABLED_PATH) -icon_disabled_image = Image.open(paths.ASSETS_ICON_DISABLED_PATH) +ICON_ENABLED_IMAGE = None +ICON_DISABLED_IMAGE = None def save_mmt_config_clicked(): @@ -19,10 +19,10 @@ def save_mmt_config_clicked(): def icon_tray_clicked(): if multimonitortool.is_monitor_enabled(): multimonitortool.disable_monitor() - ICON.icon = icon_disabled_image + ICON.icon = ICON_DISABLED_IMAGE else: multimonitortool.enable_monitor() - ICON.icon = icon_enabled_image + ICON.icon = ICON_ENABLED_IMAGE def exit_clicked(): @@ -64,6 +64,11 @@ def startup_with_windows_clicked(icon): def init_tray(): + # pylint: disable=global-statement + global ICON_ENABLED_IMAGE, ICON_DISABLED_IMAGE + ICON_ENABLED_IMAGE = Image.open(paths.ASSETS_ICON_ENABLED_PATH) + ICON_DISABLED_IMAGE = Image.open(paths.ASSETS_ICON_DISABLED_PATH) + menu = ( item(ui_strings.APP_NAME, icon_tray_clicked, default=True, visible=False), item( @@ -84,11 +89,10 @@ def init_tray(): first_image_icon = None if multimonitortool.is_monitor_enabled(): - first_image_icon = icon_enabled_image - if not os.path.exists(paths.MMT_CONFIG_PATH): - multimonitortool.save_mmt_config() + first_image_icon = ICON_ENABLED_IMAGE + multimonitortool.save_mmt_config() else: - first_image_icon = icon_disabled_image + first_image_icon = ICON_DISABLED_IMAGE # pylint: disable=global-statement global ICON diff --git a/smct_pkg/setup_gui.py b/smct_pkg/ui.py similarity index 86% rename from smct_pkg/setup_gui.py rename to smct_pkg/ui.py index ea73313..8a8cf15 100644 --- a/smct_pkg/setup_gui.py +++ b/smct_pkg/ui.py @@ -1,13 +1,10 @@ import sys +import os +import shutil import tkinter import customtkinter from customtkinter import filedialog - - -from smct_pkg import ui_strings, config, multimonitortool - -# https://github.com/TomSchimansky/CustomTkinter/tree/master/examples -# https://github.com/TomSchimansky/CustomTkinter +from smct_pkg import ui_strings, config, multimonitortool, paths customtkinter.set_ctk_parent_class(tkinter.Tk) @@ -18,14 +15,19 @@ _root_window = customtkinter.CTk() -_root_window.title(ui_strings.APP_NAME) +_root_window.title(ui_strings.SHORT_NAME) _root_window.resizable(False, False) +_root_window.geometry() + _select_mmt_exe_frame = customtkinter.CTkFrame(master=_root_window) _select_monitor_frame = customtkinter.CTkFrame(master=_root_window) def exit_application(): + # clean up files if setup was interrupted + shutil.rmtree(paths.TEMP_DIR_PATH) + os.remove(paths.CONFIG_PATH) _root_window.destroy() sys.exit(1) @@ -34,7 +36,8 @@ def exit_application(): def init_mmt_selection_frame(): - _root_window.geometry("300x110") + _root_window.iconbitmap(paths.ASSETS_ICO_PATH) + # _root_window.geometry("300x110") _select_mmt_exe_frame.pack(pady=10, padx=10, fill="both", expand=True) select_mmt_label = customtkinter.CTkLabel( @@ -59,9 +62,6 @@ def _browse_button_callback(): title=ui_strings.SELECT_MMT_LABEL, filetypes=[("MultiMonitorTool", "multimonitortool.exe")], ) - # TODO: if using auto-py-to-exe this returns the wrong path? -> crashes - # C:/App_Install/multimonitortool-x64/MultiMonitorTool.exe should the output be - # but its C:\\App_Install\\ etc. fix this. if not _exe_path: print(ui_strings.NO_FILE_SELECTED) else: @@ -76,7 +76,7 @@ def _browse_button_callback(): def _init_monitor_selection_frame(): - _root_window.geometry("300x160") + # _root_window.geometry("300x160") _select_monitor_frame.pack(pady=10, padx=10, fill="both", expand=True) _monitor_selection_label = customtkinter.CTkLabel( diff --git a/smct_pkg/ui_strings.py b/smct_pkg/ui_strings.py index a11b642..6ead045 100644 --- a/smct_pkg/ui_strings.py +++ b/smct_pkg/ui_strings.py @@ -1,7 +1,8 @@ APP_NAME = "SimpleMonitorControlTray" +SHORT_NAME = "SMCT" # UI STRINGS TRAY -FILE_NOT_FOUND = " file not found. Exiting." +FILE_NOT_FOUND = " not found. Exiting." STARTUP_WITH_WINDOWS = "Startup with Windows" SAVE_MONITOR_LAYOUT = "Save current monitor layout" @@ -10,7 +11,7 @@ # GUI STRINGS SELECT_MMT_LABEL = "Please select your MultiMonitorTool.exe" -SELECT_MONITOR_LABEL = "Select a monitor." +SELECT_MONITOR_LABEL = "Select the monitor that will be turned off." NO_FILE_SELECTED = "No file selected. Please select multimonitortool.exe" BROWSE_BUTTON = "Browse..." OK_BUTTON = "OK" diff --git a/temp/MultiMonitorToolConfig b/temp/MultiMonitorToolConfig deleted file mode 100644 index 5603a76..0000000 --- a/temp/MultiMonitorToolConfig +++ /dev/null @@ -1,36 +0,0 @@ -[Monitor0] -Name=\\.\DISPLAY1 -MonitorID=MONITOR\LEN66FB\{4d36e96e-e325-11ce-bfc1-08002be10318}\0008 -SerialNumber=URHK6FCP -BitsPerPixel=32 -Width=2560 -Height=1440 -DisplayFlags=0 -DisplayFrequency=60 -DisplayOrientation=0 -PositionX=2560 -PositionY=0 -[Monitor1] -Name=\\.\DISPLAY2 -MonitorID=MONITOR\ACI27EC\{4d36e96e-e325-11ce-bfc1-08002be10318}\0009 -SerialNumber=#ASNImfyQBwHd -BitsPerPixel=32 -Width=2560 -Height=1440 -DisplayFlags=0 -DisplayFrequency=144 -DisplayOrientation=0 -PositionX=0 -PositionY=0 -[Monitor2] -Name=\\.\DISPLAY3 -MonitorID=MONITOR\GSM0001\{4d36e96e-e325-11ce-bfc1-08002be10318}\0010 -SerialNumber= -BitsPerPixel=32 -Width=1920 -Height=1080 -DisplayFlags=0 -DisplayFrequency=60 -DisplayOrientation=0 -PositionX=1635 -PositionY=-1080 diff --git a/temp/MultiMonitorToolOutput.csv b/temp/MultiMonitorToolOutput.csv deleted file mode 100644 index eae1627..0000000 --- a/temp/MultiMonitorToolOutput.csv +++ /dev/null @@ -1,4 +0,0 @@ -Resolution,Left-Top,Right-Bottom,Active,Disconnected,Primary,Colors,Frequency,Orientation,Maximum Resolution,Name,Adapter,Device ID,Device Key,Monitor ID,Short Monitor ID,Monitor Key,Monitor String,Monitor Name,Monitor Serial Number -0 X 0,"0, 0","0, 0",No,No,No,0,0,Default,1920 X 1080,\\.\DISPLAY3,NVIDIA GeForce RTX 2080 Ti,PCI\VEN_10DE&DEV_1E07&SUBSYS_866A1043&REV_A1,\Registry\Machine\System\CurrentControlSet\Control\Video\{3AB1B141-D3F6-11EE-A460-106FD93C4F11}\0002,MONITOR\GSM0001\{4d36e96e-e325-11ce-bfc1-08002be10318}\0010,GSM0001,\Registry\Machine\System\CurrentControlSet\Control\Class\{4d36e96e-e325-11ce-bfc1-08002be10318}\0010,Generic PnP Monitor,LG TV, -2560 X 1440,"0, 0","2560, 1440",Yes,No,Yes,32,144,Default,2560 X 1440,\\.\DISPLAY2,NVIDIA GeForce RTX 2080 Ti,PCI\VEN_10DE&DEV_1E07&SUBSYS_866A1043&REV_A1,\Registry\Machine\System\CurrentControlSet\Control\Video\{3AB1B141-D3F6-11EE-A460-106FD93C4F11}\0001,MONITOR\ACI27EC\{4d36e96e-e325-11ce-bfc1-08002be10318}\0009,ACI27EC,\Registry\Machine\System\CurrentControlSet\Control\Class\{4d36e96e-e325-11ce-bfc1-08002be10318}\0009,ROG PG279Q,ROG PG279Q,#ASNImfyQBwHd -2560 X 1440,"2560, 0","5120, 1440",Yes,No,No,32,60,Default,2560 X 1440,\\.\DISPLAY1,NVIDIA GeForce RTX 2080 Ti,PCI\VEN_10DE&DEV_1E07&SUBSYS_866A1043&REV_A1,\Registry\Machine\System\CurrentControlSet\Control\Video\{3AB1B141-D3F6-11EE-A460-106FD93C4F11}\0000,MONITOR\LEN66FB\{4d36e96e-e325-11ce-bfc1-08002be10318}\0008,LEN66FB,\Registry\Machine\System\CurrentControlSet\Control\Class\{4d36e96e-e325-11ce-bfc1-08002be10318}\0008,Generic PnP Monitor,C27q-35,URHK6FCP diff --git a/temp/sampleoutput.csv b/temp/sampleoutput.csv deleted file mode 100644 index 3b3ba3b..0000000 --- a/temp/sampleoutput.csv +++ /dev/null @@ -1,4 +0,0 @@ -Resolution,Left-Top,Right-Bottom,Active,Disconnected,Primary,Colors,Frequency,Orientation,Maximum Resolution,Name,Adapter,Device ID,Device Key,Monitor ID,Short Monitor ID,Monitor Key,Monitor String,Monitor Name,Monitor Serial Number -0 X 0,"0, 0","0, 0",No,No,No,0,0,Default,2560 X 1440,\\.\DISPLAY3,NVIDIA GeForce RTX 2080 Ti,PCI\VEN_10DE&DEV_1E07&SUBSYS_866A1043&REV_A1,\Registry\Machine\System\CurrentControlSet\Control\Video\{3AB1B141-D3F6-11EE-A460-106FD93C4F11}\0002,MONITOR\ACI27EC\{4d36e96e-e325-11ce-bfc1-08002be10318}\0009,ACI27EC,\Registry\Machine\System\CurrentControlSet\Control\Class\{4d36e96e-e325-11ce-bfc1-08002be10318}\0009,ROG PG279Q,ROG PG279Q,#ASNImfyQBwHd -1920 X 1080,"-959, -1080","961, 0",Yes,No,No,32,60,Default,1920 X 1080,\\.\DISPLAY2,NVIDIA GeForce RTX 2080 Ti,PCI\VEN_10DE&DEV_1E07&SUBSYS_866A1043&REV_A1,\Registry\Machine\System\CurrentControlSet\Control\Video\{3AB1B141-D3F6-11EE-A460-106FD93C4F11}\0001,MONITOR\GSM0001\{4d36e96e-e325-11ce-bfc1-08002be10318}\0010,GSM0001,\Registry\Machine\System\CurrentControlSet\Control\Class\{4d36e96e-e325-11ce-bfc1-08002be10318}\0010,Generic PnP Monitor,LG TV, -2560 X 1440,"0, 0","2560, 1440",Yes,No,Yes,32,60,Default,2560 X 1440,\\.\DISPLAY1,NVIDIA GeForce RTX 2080 Ti,PCI\VEN_10DE&DEV_1E07&SUBSYS_866A1043&REV_A1,\Registry\Machine\System\CurrentControlSet\Control\Video\{3AB1B141-D3F6-11EE-A460-106FD93C4F11}\0000,MONITOR\LEN66FB\{4d36e96e-e325-11ce-bfc1-08002be10318}\0008,LEN66FB,\Registry\Machine\System\CurrentControlSet\Control\Class\{4d36e96e-e325-11ce-bfc1-08002be10318}\0008,Generic PnP Monitor,C27q-35,URHK6FCP