def show_settings(window) -> None: """Shows the settings dialog and allows the user the change deck specific settings. Settings are not saved until OK is clicked.""" ui = window.ui main_window = window deck_id = _deck_id(ui) settings = SettingsDialog(window) dimmers[deck_id].stop() settings.ui.buttonfeedback.addItem("Disabled") settings.ui.buttonfeedback.addItem("Enabled") if api.get_feedback_enabled(deck_id) == "Enabled": settings.ui.buttonfeedback.setCurrentIndex(1) else: settings.ui.buttonfeedback.setCurrentIndex(0) settings.ui.buttonfeedback.currentTextChanged.connect( partial(update_feedback_enabled, ui)) location = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ok.png") settings.ui.removeButton.clicked.connect( api.set_default_custom_image_for_feedback(deck_id)) settings.ui.imageButton.clicked.connect( partial(select_image_for_custom_feedback, main_window)) for label, value in dimmer_options.items(): settings.ui.dim.addItem(f"{label}", userData=value) existing_timeout = api.get_display_timeout(deck_id) existing_index = next((i for i, (k, v) in enumerate(dimmer_options.items()) if v == existing_timeout), None) if existing_index is None: settings.ui.dim.addItem(f"Custom: {existing_timeout}s", userData=existing_timeout) existing_index = settings.ui.dim.count() - 1 settings.ui.dim.setCurrentIndex(existing_index) else: settings.ui.dim.setCurrentIndex(existing_index) settings.ui.label_streamdeck.setText(deck_id) settings.ui.brightness.setValue(api.get_brightness(deck_id)) settings.ui.brightness.valueChanged.connect( partial(change_brightness, deck_id)) if settings.exec_(): # Commit changes if existing_index != settings.ui.dim.currentIndex(): dimmers[deck_id].timeout = settings.ui.dim.currentData() api.set_display_timeout(deck_id, settings.ui.dim.currentData()) set_brightness(window.ui, settings.ui.brightness.value()) else: # User cancelled, reset to original brightness change_brightness(deck_id, api.get_brightness(deck_id)) dimmers[deck_id].reset()
def show_settings(window) -> None: """Shows the settings dialog and allows the user the change deck specific settings. Settings are not saved until OK is clicked.""" ui = window.ui deck_id = _deck_id(ui) settings = SettingsDialog(window) dimmers[deck_id].stop() for label, value in dimmer_options.items(): settings.ui.dim.addItem(f"{label}", userData=value) existing_timeout = api.get_display_timeout(deck_id) existing_index = next((i for i, (k, v) in enumerate(dimmer_options.items()) if v == existing_timeout), None) if existing_index is None: settings.ui.dim.addItem(f"Custom: {existing_timeout}s", userData=existing_timeout) existing_index = settings.ui.dim.count() - 1 settings.ui.dim.setCurrentIndex(existing_index) else: settings.ui.dim.setCurrentIndex(existing_index) existing_brightness_dimmed = api.get_brightness_dimmed(deck_id) settings.ui.brightness_dimmed.setValue(existing_brightness_dimmed) settings.ui.label_streamdeck.setText(deck_id) settings.ui.brightness.setValue(api.get_brightness(deck_id)) settings.ui.brightness.valueChanged.connect( partial(change_brightness, deck_id)) settings.ui.dim.currentIndexChanged.connect( partial(disable_dim_settings, settings)) if settings.exec_(): # Commit changes if existing_index != settings.ui.dim.currentIndex(): dimmers[deck_id].timeout = settings.ui.dim.currentData() api.set_display_timeout(deck_id, settings.ui.dim.currentData()) set_brightness(window.ui, settings.ui.brightness.value()) set_brightness_dimmed(window.ui, settings.ui.brightness_dimmed.value(), settings.ui.brightness.value()) else: # User cancelled, reset to original brightness change_brightness(deck_id, api.get_brightness(deck_id)) dimmers[deck_id].reset()
def sync(ui) -> None: api.ensure_decks_connected() ui.brightness.setValue(api.get_brightness(_deck_id(ui))) ui.pages.setCurrentIndex(api.get_page(_deck_id(ui)))
def start(_exit: bool = False) -> None: show_ui = True if "-h" in sys.argv or "--help" in sys.argv: print(f"Usage: {os.path.basename(sys.argv[0])}") print("Flags:") print(" -h, --help\tShow this message") print(" -n, --no-ui\tRun the program without showing a UI") return elif "-n" in sys.argv or "--no-ui" in sys.argv: show_ui = False app = QApplication(sys.argv) logo = QIcon(LOGO) main_window = MainWindow() ui = main_window.ui main_window.setWindowIcon(logo) tray = QSystemTrayIcon(logo, app) tray.activated.connect(main_window.systray_clicked) menu = QMenu() action_exit = QAction("Exit") action_exit.triggered.connect(app.exit) menu.addAction(action_exit) tray.setContextMenu(menu) ui.text.textChanged.connect(partial(queue_text_change, ui)) ui.command.textChanged.connect(partial(update_button_command, ui)) ui.keys.textChanged.connect(partial(update_button_keys, ui)) ui.write.textChanged.connect(partial(update_button_write, ui)) ui.change_brightness.valueChanged.connect(partial(update_change_brightness, ui)) ui.switch_page.valueChanged.connect(partial(update_switch_page, ui)) ui.imageButton.clicked.connect(partial(select_image, main_window)) ui.removeButton.clicked.connect(partial(remove_image, main_window)) ui.settingsButton.clicked.connect(partial(show_settings, main_window)) api.streamdesk_keys.key_pressed.connect(handle_keypress) items = api.open_decks().items() if len(items) == 0: print("Waiting for Stream Deck(s)...") while len(items) == 0: time.sleep(3) items = api.open_decks().items() for deck_id, deck in items: ui.device_list.addItem(f"{deck['type']} - {deck_id}", userData=deck_id) dimmers[deck_id] = Dimmer( api.get_display_timeout(deck_id), api.get_brightness(deck_id), partial(change_brightness, deck_id), ) dimmers[deck_id].reset() build_device(ui) ui.device_list.currentIndexChanged.connect(partial(build_device, ui)) ui.pages.currentChanged.connect(partial(change_page, ui)) ui.actionExport.triggered.connect(partial(export_config, main_window)) ui.actionImport.triggered.connect(partial(import_config, main_window)) ui.actionExit.triggered.connect(app.exit) timer = QTimer() timer.timeout.connect(partial(sync, ui)) timer.start(1000) api.render() tray.show() if show_ui: main_window.show() if _exit: return else: app.exec_() api.close_decks() sys.exit()
def handle_keypress(deck_id: str, key: int, state: bool) -> None: if state: if dimmers[deck_id].reset(): return keyboard = Controller() page = api.get_page(deck_id) command = api.get_button_command(deck_id, page, key) if command: try: Popen(shlex.split(command)) except Exception as error: print(f"The command '{command}' failed: {error}") keys = api.get_button_keys(deck_id, page, key) if keys: keys = keys.strip().replace(" ", "") for section in keys.split(","): # Since + and , are used to delimit our section and keys to press, # they need to be substituded with keywords. section_keys = [_replace_special_keys(key_name) for key_name in section.split("+")] # Translate string to enum, or just the string itself if not found section_keys = [getattr(Key, key_name.lower(), key_name) for key_name in section_keys] for key_name in section_keys: try: if key_name == "delay": time.sleep(0.5) else: keyboard.press(key_name) except Exception: print(f"Could not press key '{key_name}'") for key_name in section_keys: try: if key_name != "delay": keyboard.release(key_name) except Exception: print(f"Could not release key '{key_name}'") write = api.get_button_write(deck_id, page, key) if write: try: keyboard.type(write) except Exception as error: print(f"Could not complete the write command: {error}") brightness_change = api.get_button_change_brightness(deck_id, page, key) if brightness_change: try: api.change_brightness(deck_id, brightness_change) dimmers[deck_id].brightness = api.get_brightness(deck_id) dimmers[deck_id].reset() except Exception as error: print(f"Could not change brightness: {error}") switch_page = api.get_button_switch_page(deck_id, page, key) if switch_page: api.set_page(deck_id, switch_page - 1)
def start(_exit: bool = False) -> None: show_ui = True if "-h" in sys.argv or "--help" in sys.argv: print(f"Usage: {os.path.basename(sys.argv[0])}") print("Flags:") print(" -h, --help\tShow this message") print(" -n, --no-ui\tRun the program without showing a UI") return elif "-n" in sys.argv or "--no-ui" in sys.argv: show_ui = False app = QApplication(sys.argv) logo = QIcon(LOGO) main_window = MainWindow() ui = main_window.ui main_window.setWindowIcon(logo) tray = QSystemTrayIcon(logo, app) tray.activated.connect(main_window.systray_clicked) menu = QMenu() action_dim = QAction("Dim display (toggle)") action_dim.triggered.connect(dim_all_displays) action_configure = QAction("Configure...") action_configure.triggered.connect(main_window.bring_to_top) menu.addAction(action_dim) menu.addAction(action_configure) menu.addSeparator() action_exit = QAction("Exit") action_exit.triggered.connect(app.exit) menu.addAction(action_exit) tray.setContextMenu(menu) ui.text.textChanged.connect(partial(queue_text_change, ui)) ui.font_Size.valueChanged.connect(partial(update_font_size, ui)) ui.command.textChanged.connect(partial(update_button_command, ui)) ui.keys.textChanged.connect(partial(update_button_keys, ui)) ui.write.textChanged.connect(partial(update_button_write, ui)) ui.change_brightness.valueChanged.connect( partial(update_change_brightness, ui)) ui.switch_page.valueChanged.connect(partial(update_switch_page, ui)) ui.imageButton.clicked.connect(partial(select_image, main_window)) ui.removeButton.clicked.connect(partial(remove_image, main_window)) ui.settingsButton.clicked.connect(partial(show_settings, main_window)) ui.font_Color.addItem("white") ui.font_Color.addItem("black") ui.font_Color.addItem("blue") ui.font_Color.addItem("red") ui.font_Color.addItem("green") ui.font_Color.addItem("purple") ui.font_Color.addItem("cyan") ui.font_Color.addItem("magenta") ui.font_Color.currentTextChanged.connect(partial(update_font_color, ui)) ui.selected_font.addItem("Goblin_One") ui.selected_font.addItem("Open_Sans") ui.selected_font.addItem("Roboto") ui.selected_font.addItem("Lobster") ui.selected_font.addItem("Anton") ui.selected_font.addItem("Pacifico") ui.selected_font.currentTextChanged.connect( partial(update_selected_font, ui)) ui.text_Align.addItem("left") ui.text_Align.addItem("center") ui.text_Align.addItem("right") ui.text_Align.currentTextChanged.connect(partial(update_text_align, ui)) api.streamdesk_keys.key_pressed.connect(handle_keypress) items = api.open_decks().items() if len(items) == 0: print("Waiting for Stream Deck(s)...") while len(items) == 0: time.sleep(3) items = api.open_decks().items() for deck_id, deck in items: ui.device_list.addItem(f"{deck['type']} - {deck_id}", userData=deck_id) ui.target_device.addItem(deck_id) dimmers[deck_id] = Dimmer( api.get_display_timeout(deck_id), api.get_brightness(deck_id), partial(change_brightness, deck_id), ) dimmers[deck_id].reset() build_device(ui) ui.device_list.currentIndexChanged.connect(partial(build_device, ui)) ui.target_device.currentTextChanged.connect( partial(update_target_device, ui)) ui.pages.currentChanged.connect(partial(change_page, ui)) ui.actionExport.triggered.connect(partial(export_config, main_window)) ui.actionImport.triggered.connect(partial(import_config, main_window)) ui.actionCut.triggered.connect(partial(cut_button, main_window)) ui.actionCopy.triggered.connect(partial(copy_button, main_window)) ui.actionCut.setShortcuts([QKeySequence.Cut, QKeySequence("Shift+Del")]) ui.actionCopy.setShortcuts( [QKeySequence.Copy, QKeySequence("Ctrl+Insert")]) ui.actionPaste.setShortcuts( [QKeySequence.Paste, QKeySequence("Shift+Insert")]) ui.actionDelete.setShortcuts([QKeySequence.Delete]) ui.actionPaste.triggered.connect(partial(paste_button, main_window)) ui.actionDelete.triggered.connect(partial(delete_button, main_window)) ui.actionMultiPaste.triggered.connect( partial(multi_paste_Button, main_window)) ui.actionExit.triggered.connect(app.exit) timer = QTimer() timer.timeout.connect(partial(sync, ui)) timer.start(1000) api.render() tray.show() if show_ui: main_window.show() if _exit: return else: app.exec_() api.close_decks() sys.exit()
def handle_keypress(deck_id: str, key: int, state: bool) -> None: if state: if dimmers[deck_id].reset(): return keyboard = Controller() page = api.get_page(deck_id) command = api.get_button_command(deck_id, page, key) if command: try: Popen(shlex.split(command)) except Exception as error: print(f"The command '{command}' failed: {error}") keys = api.get_button_keys(deck_id, page, key) if keys: keys = keys.strip().replace(" ", "") for section in keys.split(","): # Since + and , are used to delimit our section and keys to press, # they need to be substituted with keywords. section_keys = [ _replace_special_keys(key_name) for key_name in section.split("+") ] # Translate string to enum, or just the string itself if not found section_keys = [ getattr(Key, key_name.lower(), key_name) for key_name in section_keys ] for key_name in section_keys: if isinstance(key_name, str) and key_name.startswith("delay"): sleep_time_arg = key_name.split("delay", 1)[1] if sleep_time_arg: try: sleep_time = float(sleep_time_arg) except Exception: print( f"Could not convert sleep time to float '{sleep_time_arg}'" ) sleep_time = 0 else: # default if not specified sleep_time = 0.5 if sleep_time: try: time.sleep(sleep_time) except Exception: print( f"Could not sleep with provided sleep time '{sleep_time}'" ) else: try: keyboard.press(key_name) except Exception: print(f"Could not press key '{key_name}'") for key_name in section_keys: if not (isinstance(key_name, str) and key_name.startswith("delay")): try: keyboard.release(key_name) except Exception: print(f"Could not release key '{key_name}'") write = api.get_button_write(deck_id, page, key) if write: try: keyboard.type(write) except Exception as error: print(f"Could not complete the write command: {error}") brightness_change = api.get_button_change_brightness( deck_id, page, key) if brightness_change: try: api.change_brightness(deck_id, brightness_change) dimmers[deck_id].brightness = api.get_brightness(deck_id) dimmers[deck_id].reset() except Exception as error: print(f"Could not change brightness: {error}") switch_page = api.get_button_switch_page(deck_id, page, key) target_device = api.get_target_device(deck_id, page, key) if switch_page: api.set_page(target_device, switch_page - 1)
def create_app( get_md_action_value: Callable[[int], str], get_md_data_value: Callable[[int], str], key_up_callback: Optional[Callable[[str, int, bool], None]] = None, md_action_callback: Optional[Callable[[int, str], None]] = None, md_data_callback: Optional[Callable[[int, str], None]] = None, ) -> Tuple[QApplication, MainWindow]: """ Sets up the QApplication to use on the main thread without calling app.exec_() """ global _get_md_action_value, _get_md_data_value # pylint: disable=global-statement,invalid-name _get_md_action_value = get_md_action_value _get_md_data_value = get_md_data_value app = QApplication([]) logo = QIcon(LOGO) main_window = MainWindow() ui = main_window.ui main_window.setWindowIcon(logo) tray = QSystemTrayIcon(logo, app) tray.activated.connect(main_window.systray_clicked) menu = QMenu() action_dim = QAction('Dim display (toggle)') action_dim.triggered.connect(dim_all_displays) action_configure = QAction('Configure...') action_configure.triggered.connect(main_window.bring_to_top) menu.addAction(action_dim) menu.addAction(action_configure) menu.addSeparator() action_exit = QAction('Exit') action_exit.triggered.connect(app.exit) menu.addAction(action_exit) tray.setContextMenu(menu) ui.text.textChanged.connect(partial(queue_text_change, ui)) ui.command.textChanged.connect(partial(update_button_command, ui)) ui.keys.textChanged.connect(partial(update_button_keys, ui)) ui.write.textChanged.connect(partial(update_button_write, ui)) ui.change_brightness.valueChanged.connect( partial(update_change_brightness, ui)) ui.switch_page.valueChanged.connect(partial(update_switch_page, ui)) ui.imageButton.clicked.connect(partial(select_image, main_window)) ui.removeButton.clicked.connect(partial(remove_image, main_window)) ui.settingsButton.clicked.connect(partial(show_settings, main_window)) md_label = QLabel(ui.groupBox) md_label.setObjectName('md_label') md_label.setText('MD Action:') ui.formLayout.setWidget(7, QFormLayout.LabelRole, md_label) md_action = QComboBox(ui.groupBox) md_action.setObjectName('md_action') md_action.addItems(_MATERIAL_DECK_ACTIONS) md_action.currentIndexChanged.connect( partial(_md_action_changed, md_action_callback)) ui.formLayout.setWidget(7, QFormLayout.FieldRole, md_action) ui.md_action = md_action md_data_label = QLabel(ui.groupBox) md_data_label.setObjectName('md_data_label') md_data_label.setText('MD Data:') ui.formLayout.setWidget(8, QFormLayout.LabelRole, md_data_label) text_timer = QTimer() text_timer.setSingleShot(True) text_timer.timeout.connect(partial(_md_data_changed, ui, md_data_callback)) md_data = QPlainTextEdit(ui.groupBox) md_data.setObjectName('md_data') md_data.textChanged.connect(lambda: text_timer.start(500)) ui.formLayout.setWidget(8, QFormLayout.FieldRole, md_data) ui.md_data = md_data api.streamdesk_keys.key_pressed.connect( partial(_extended_handle_key_press, key_up_callback)) items = api.open_decks().items() if len(items) == 0: print('Waiting for Stream Deck(s)...') while len(items) == 0: time.sleep(3) items = api.open_decks().items() for deck_id, deck in items: ui.device_list.addItem(f"{deck['type']} - {deck_id}", userData=deck_id) dimmers[deck_id] = Dimmer( api.get_display_timeout(deck_id), api.get_brightness(deck_id), partial(change_brightness, deck_id), ) dimmers[deck_id].reset() build_device(ui) ui.device_list.currentIndexChanged.connect(partial(build_device, ui)) ui.pages.currentChanged.connect(partial(change_page, ui)) ui.actionExport.triggered.connect(partial(export_config, main_window)) ui.actionImport.triggered.connect(partial(import_config, main_window)) ui.actionExit.triggered.connect(app.exit) timer = QTimer() timer.timeout.connect(partial(sync, ui)) timer.start(1000) api.render() tray.show() return (app, main_window)