411 lines
12 KiB
Python
411 lines
12 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import platform
|
|
import sys
|
|
|
|
import yaml
|
|
|
|
from PyQt5 import QtWidgets, QtGui, QtCore
|
|
|
|
|
|
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.clicked.connect(self.handle_clicked)
|
|
|
|
def handle_clicked(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 FontSelect(QtWidgets.QPushButton):
|
|
def __init__(self, family, style):
|
|
super().__init__()
|
|
self.set_value(family, style)
|
|
self.clicked.connect(self.handle_clicked)
|
|
|
|
def handle_clicked(self):
|
|
font, valid = QtWidgets.QFontDialog.getFont()
|
|
|
|
if valid:
|
|
self.set_value(font.family(), font.styleName())
|
|
|
|
def set_value(self, family, style):
|
|
self.family = family
|
|
self.style = style
|
|
self.setStyleSheet("""
|
|
QPushButton {{
|
|
background-color: white;
|
|
font-family: {0};
|
|
}}
|
|
QPushButton:checked{{
|
|
background-color: white;
|
|
}}
|
|
QPushButton:hover{{
|
|
background-color: white;
|
|
}}
|
|
""".format(family))
|
|
self.setText(self.family)
|
|
self.update()
|
|
|
|
def value(self):
|
|
return {
|
|
'family': self.family,
|
|
'style': self.style
|
|
}
|
|
|
|
|
|
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_item(self, layout, name, widget):
|
|
sub_layout = QtWidgets.QHBoxLayout()
|
|
sub_layout.addWidget(QtWidgets.QLabel(self.prettify(name)))
|
|
sub_layout.addWidget(widget)
|
|
layout.addLayout(sub_layout)
|
|
|
|
def render_section(self, widgets, sup=None, name=None):
|
|
layout = QtWidgets.QVBoxLayout()
|
|
|
|
if name and sup is not None:
|
|
layout.setContentsMargins(10, 0, 0, 0)
|
|
label = QtWidgets.QLabel(self.prettify(name))
|
|
font = label.font()
|
|
font.setBold(True)
|
|
label.setFont(font)
|
|
|
|
sup.addWidget(label)
|
|
|
|
for name, widget in widgets.items():
|
|
if type(widget) is dict:
|
|
sub_layout = self.render_section(widget, layout, name)
|
|
layout.addLayout(sub_layout)
|
|
else:
|
|
self.render_item(layout, name, widget)
|
|
layout.setAlignment(QtCore.Qt.AlignTop)
|
|
return layout
|
|
|
|
def render_state(self):
|
|
self.layout = self.render_section(self.widgets)
|
|
self.setLayout(self.layout)
|
|
|
|
def widget_value(self, widget):
|
|
typ = type(widget)
|
|
if typ is QtWidgets.QComboBox:
|
|
return widget.currentText()
|
|
if typ is QtWidgets.QCheckBox:
|
|
return widget.isChecked()
|
|
if typ is QtWidgets.QLineEdit:
|
|
return widget.text()
|
|
return widget.value()
|
|
|
|
def widgets_to_state(self, widgets):
|
|
state = {}
|
|
for name, widget in widgets.items():
|
|
if type(widget) is dict:
|
|
state[name] = self.widgets_to_state(widget)
|
|
else:
|
|
state[name] = self.widget_value(widget)
|
|
return state
|
|
|
|
def gather_state(self):
|
|
return self.widgets_to_state(self.widgets)
|
|
|
|
|
|
class Debug(ConfigWidget):
|
|
def __init__(self, config):
|
|
super().__init__()
|
|
self.widgets['render_timer'] = QtWidgets.QCheckBox()
|
|
self.widgets['render_timer'].setChecked(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'))
|
|
|
|
normal_config = config.get('normal', {})
|
|
normal = FontSelect(normal_config['family'], normal_config['style'])
|
|
|
|
italic_config = config.get('italic', {})
|
|
italic = FontSelect(italic_config['family'], italic_config['style'])
|
|
|
|
bold_config = config.get('bold', {})
|
|
bold = FontSelect(bold_config['family'], bold_config['style'])
|
|
|
|
self.widgets = {
|
|
'scale_with_dpi': scale_with_dpi,
|
|
'size': size,
|
|
'use_thin_strokes': use_thin_strokes,
|
|
'glyph_offset': {
|
|
'x': glyph_offset_x,
|
|
'y': glyph_offset_y,
|
|
},
|
|
'normal': normal,
|
|
'italic': italic,
|
|
'bold': bold,
|
|
}
|
|
|
|
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')
|
|
)
|
|
|
|
cursor_background = ColorSelect(
|
|
config.get('cursor', {}).get('cursor')
|
|
)
|
|
cursor_foreground = ColorSelect(
|
|
config.get('cursor', {}).get('text')
|
|
)
|
|
|
|
normal_black = ColorSelect(
|
|
config.get('normal', {}).get('black')
|
|
)
|
|
normal_blue = ColorSelect(
|
|
config.get('normal', {}).get('blue')
|
|
)
|
|
normal_cyan = ColorSelect(
|
|
config.get('normal', {}).get('cyan')
|
|
)
|
|
normal_green = ColorSelect(
|
|
config.get('normal', {}).get('green')
|
|
)
|
|
normal_magenta = ColorSelect(
|
|
config.get('normal', {}).get('magenta')
|
|
)
|
|
normal_red = ColorSelect(
|
|
config.get('normal', {}).get('red')
|
|
)
|
|
normal_white = ColorSelect(
|
|
config.get('normal', {}).get('white')
|
|
)
|
|
normal_yellow = ColorSelect(
|
|
config.get('normal', {}).get('yellow')
|
|
)
|
|
|
|
self.widgets = {
|
|
'primary': {
|
|
'background': primary_background,
|
|
'foreground': primary_foreground,
|
|
},
|
|
'cursor': {
|
|
'cursor': cursor_background,
|
|
'text': cursor_foreground,
|
|
},
|
|
'normal': {
|
|
'black': normal_black,
|
|
'blue': normal_blue,
|
|
'cyan': normal_cyan,
|
|
'green': normal_green,
|
|
'magenta': normal_magenta,
|
|
'red': normal_red,
|
|
'white': normal_white,
|
|
'yellow': normal_yellow,
|
|
},
|
|
}
|
|
|
|
self.render_state()
|
|
|
|
|
|
class Window(ConfigWidget):
|
|
decoration_options = (
|
|
['full', 'none'] +
|
|
(['transparent', 'buttonless'] if platform.system() == 'Darwin' else [])
|
|
)
|
|
|
|
startup_options = (
|
|
['Windowed', 'FullScreen', 'Maximized'] +
|
|
(['SimpleFullScreen'] if platform.system() == 'Darwin' else [])
|
|
)
|
|
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))
|
|
|
|
title = QtWidgets.QLineEdit(config.get('title', 'Alacritty'))
|
|
|
|
self.widgets = {
|
|
'title': title,
|
|
'decorations': decorations,
|
|
'startup_mode': startup_mode,
|
|
'dynamic_padding': dynamic_padding,
|
|
'padding': {
|
|
'x': padding_x,
|
|
'y': padding_y,
|
|
},
|
|
'dimensions': {
|
|
'columns': columns,
|
|
'lines': lines,
|
|
}
|
|
}
|
|
|
|
if platform.system() == 'Linux':
|
|
self.widgets['class'] = QtWidgets.QLineEdit(
|
|
config.get('class', 'Alacritty')
|
|
)
|
|
|
|
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()
|
|
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_()
|