#!/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_()