From 8986775160cdb002cbb3ab9ce04bcc2b8dafe2db Mon Sep 17 00:00:00 2001 From: hellerve Date: Tue, 25 Jun 2019 14:51:47 +0200 Subject: [PATCH] gui: initial --- Makefile | 8 +- README.md | 5 +- alacritty_config_gui.py | 272 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 281 insertions(+), 4 deletions(-) create mode 100644 alacritty_config_gui.py diff --git a/Makefile b/Makefile index 7637339..f304308 100644 --- a/Makefile +++ b/Makefile @@ -5,5 +5,11 @@ install: cp alacritty_config.py ${INSTALL_DIR}/alacritty-config chmod u+x ${INSTALL_DIR}/alacritty-config +gui: + pip3 install -Ur requirements.txt + cp alacritty_config_gui.py ${INSTALL_DIR}/alacritty-config-gui + chmod u+x ${INSTALL_DIR}/alacritty-config-gui + uninstall: - rm ${INSTALL_DIR}/alacritty-config + rm -f ${INSTALL_DIR}/alacritty-config + rm -f ${INSTALL_DIR}/alacritty-config-gui diff --git a/README.md b/README.md index d47b179..fe5b9a6 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,8 @@ $ alacritty-config tabspaces '"delete"' ## TODO -Oh, so much! Ideally, I’d like a GUI at least for all the colorful properties and for -selecting fonts. For now the tool is simple and usable enough to be useful, but a simple -GUI would definitely give this a better UX. Another time. +I’m writing a GUI for the configuration currently, but it’s far from complete. The parts +that are already wrapped should work, though!
diff --git a/alacritty_config_gui.py b/alacritty_config_gui.py new file mode 100644 index 0000000..27ef55d --- /dev/null +++ b/alacritty_config_gui.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python3 +import os +import sys + +import yaml + +from PyQt5 import QtWidgets, QtGui + + +ALACRITTY_CONFIG = os.path.expanduser("~/.config/alacritty/alacritty.yml") + + +class ColorSelect(QtWidgets.QPushButton): + def __init__(self, value): + super().__init__() + self.set_value(value.replace('0x', '#')) + self.pressed.connect(self.handle_pressed) + + def handle_pressed(self): + color = QtWidgets.QColorDialog.getColor() + + if color.isValid(): + self.set_value(color.name()) + + def set_value(self, value): + self._value = value + color = QtGui.QColor(self._value) + self.setFlat(True) + self.setAutoFillBackground(True) + self.setStyleSheet(""" + QPushButton {{ + color: {0}; + background-color: {0}; + border-style: outset; + }} + QPushButton:checked{{ + color: {0}; + background-color: {0}; + border-style: outset; + }} + QPushButton:hover{{ + background-color: {0}; + border-style: outset; + }} + """.format(color.name())) + self.update() + + def value(self): + return self._value.replace('#', '0x') + + +class ConfigWidget(QtWidgets.QWidget): + def __init__(self): + super().__init__() + self.widgets = {} + + def prettify(self, s): + return ' '.join(x.capitalize() for x in s.split('_') if x) + + def render_state(self): + self.layout = QtWidgets.QVBoxLayout() + for name, widget in self.widgets.items(): + sub_layout = QtWidgets.QHBoxLayout() + sub_layout.addWidget(QtWidgets.QLabel(self.prettify(name))) + sub_layout.addWidget(widget) + self.layout.addLayout(sub_layout) + self.setLayout(self.layout) + + def gather_state(self): + state = {} + for name, widget in self.widgets.items(): + path = name.split('__') + mut_state = state + for elem in path[:-1]: + if elem not in mut_state: + mut_state[elem] = {} + mut_state = mut_state[elem] + typ = type(widget) + name = path[-1] + if typ is QtWidgets.QComboBox: + mut_state[name] = widget.currentText() + elif typ is QtWidgets.QCheckBox: + mut_state[name] = widget.isChecked() + elif typ is QtWidgets.QLineEdit: + mut_state[name] = widget.text() + else: + mut_state[name] = widget.value() + return state + + +class Debug(ConfigWidget): + def __init__(self, config): + super().__init__() + self.widgets['render_timer'] = QtWidgets.QCheckBox() + self.widgets['render_timer'].setCheckState(config.get('render_timer')) + self.render_state() + + +class Env(ConfigWidget): + def __init__(self, config): + super().__init__() + self.widgets['TERM'] = QtWidgets.QLineEdit(config.get('TERM')) + self.render_state() + + +class Selection(ConfigWidget): + def __init__(self, config): + super().__init__() + self.widgets['semantic_escape_chars'] = QtWidgets.QLineEdit( + config.get('semantic_escape_chars') + ) + self.render_state() + + +class Shell(ConfigWidget): + def __init__(self, config): + super().__init__() + self.widgets['program'] = QtWidgets.QLineEdit(config.get('program')) + self.render_state() + + +class Font(ConfigWidget): + def __init__(self, config): + super().__init__() + glyph_offset_x = QtWidgets.QSpinBox() + glyph_offset_x.setValue(config.get('glyph_offset', {}).get('x')) + glyph_offset_y = QtWidgets.QSpinBox() + glyph_offset_y.setValue(config.get('glyph_offset', {}).get('y')) + scale_with_dpi = QtWidgets.QCheckBox() + scale_with_dpi.setChecked(config.get('scale_with_dpi')) + size = QtWidgets.QDoubleSpinBox() + size.setValue(config.get('size')) + use_thin_strokes = QtWidgets.QCheckBox() + use_thin_strokes.setChecked(config.get('use_thin_strokes')) + + self.widgets = { + 'glyph_offset__x': glyph_offset_x, + 'glyph_offset__y': glyph_offset_y, + 'scale_with_dpi': scale_with_dpi, + 'size': size, + 'use_thin_strokes': use_thin_strokes, + } + + self.render_state() + + +class Colors(ConfigWidget): + def __init__(self, config): + super().__init__() + + primary_background = ColorSelect( + config.get('primary', {}).get('background') + ) + primary_foreground = ColorSelect( + config.get('primary', {}).get('foreground') + ) + + self.widgets = { + 'primary__background': primary_background, + 'primary__foreground': primary_foreground, + } + + self.render_state() + + +class Window(ConfigWidget): + # TODO: transparent and buttonless only on OS X + decoration_options = ['full', 'none', 'transparent', 'buttonless'] + + # TODO: simplewindowed only on OS X + startup_options = ['Windowed', 'FullScreen', 'SimpleWindowed', 'Maximized'] + def __init__(self, config): + super().__init__() + decorations = QtWidgets.QComboBox() + for option in self.decoration_options: + decorations.addItem(option) + dec = config.get('decorations') + if dec in self.decoration_options: + decorations.setCurrentIndex(self.decoration_options.index(dec)) + + startup_mode = QtWidgets.QComboBox() + for mode in self.startup_options: + startup_mode.addItem(mode) + dec = config.get('startup_mode') + if dec in self.startup_options: + startup_mode.setCurrentIndex(self.startup_options.index(dec)) + + columns = QtWidgets.QSpinBox() + columns.setValue(config.get('dimensions', {}).get('columns')) + lines = QtWidgets.QSpinBox() + lines.setValue(config.get('dimensions', {}).get('lines')) + + padding_x = QtWidgets.QSpinBox() + padding_x.setValue(config.get('padding', {}).get('x')) + padding_y = QtWidgets.QSpinBox() + padding_y.setValue(config.get('padding', {}).get('y')) + + dynamic_padding = QtWidgets.QCheckBox() + dynamic_padding.setChecked(config.get('dynamic_padding', False)) + + self.widgets = { + 'decorations': decorations, + 'startup_mode': startup_mode, + 'dimensions__columns': columns, + 'dimensions__lines': lines, + 'padding__x': padding_x, + 'padding__y': padding_y, + 'dynamic_padding': dynamic_padding, + } + + self.render_state() + + +class Config(QtWidgets.QWidget): + def __init__(self, config): + super().__init__() + self.layout = QtWidgets.QVBoxLayout() + self.config = config + self.add_tabs(config) + self.add_buttons() + self.setLayout(self.layout) + + def add_tabs(self, config): + self.tabs = QtWidgets.QTabWidget() + + self.tabs.addTab(Window(config.get('window')), "Window") + self.tabs.addTab(Font(config.get('font')), "Font") + self.tabs.addTab(Debug(config.get('debug')), "Debug") + self.tabs.addTab(Env(config.get('env')), "Env") + self.tabs.addTab(Selection(config.get('selection')), "Selection") + self.tabs.addTab(Shell(config.get('shell')), "Shell") + self.tabs.addTab(Colors(config.get('colors')), "Colors") + + self.layout.addWidget(self.tabs) + + def add_buttons(self): + self.buttons = QtWidgets.QDialogButtonBox() + ok_button = self.buttons.addButton(self.buttons.Ok) + self.buttons.addButton(self.buttons.Cancel) + self.buttons.accepted.connect(self.save) + self.buttons.rejected.connect(sys.exit) + self.layout.addWidget(self.buttons) + + def gather_state(self): + state = self.config + + for idx in range(self.tabs.count()): + tab = self.tabs.widget(idx) + title = self.tabs.tabText(idx).lower() + state[title] = {**state.get(title, {}), **tab.gather_state()} + + return state + + def save(self): + state = self.gather_state() + print(yaml.dump(state)) + with open(ALACRITTY_CONFIG, 'w+') as f: + f.write(yaml.dump(state)) + sys.exit() + + def addDialog(self): + dialog = QtWidgets.QColorDialog() + dialog.show() + + +if __name__ == '__main__': + app = QtWidgets.QApplication([]) + with open(ALACRITTY_CONFIG) as f: + config = yaml.safe_load(f.read()) + conf = Config(config) + conf.show() + app.exec_()