force keyboard widget to recalulate layout each resize

main
Jared Beller 2021-01-13 00:20:47 -05:00
parent dc63304827
commit 77473d9df9
No known key found for this signature in database
GPG Key ID: 044B207F4820E3AE
1 changed files with 63 additions and 49 deletions

View File

@ -18,28 +18,32 @@ class KeyWidget:
self.tooltip = "" self.tooltip = ""
self.color = None self.color = None
size = int(round(scale * (KEY_SIZE_RATIO + KEY_SPACING_RATIO)))
spacing = int(round(scale * KEY_SPACING_RATIO))
self.rotation_x = size * desc.rotation_x
self.rotation_y = size * desc.rotation_y
self.rotation_angle = desc.rotation_angle self.rotation_angle = desc.rotation_angle
self.shift_x = shift_x
self.shift_y = shift_y
self.x = size * desc.x
self.y = size * desc.y
self.w = size * desc.width - spacing
self.h = size * desc.height - spacing
self.rect = QRect(self.x, self.y, self.w, self.h)
self.has2 = desc.width2 != desc.width or desc.height2 != desc.height or desc.x2 != 0 or desc.y2 != 0 self.has2 = desc.width2 != desc.width or desc.height2 != desc.height or desc.x2 != 0 or desc.y2 != 0
self.x2 = self.x + size * desc.x2 self.update_position(scale, shift_x, shift_y)
self.y2 = self.y + size * desc.y2
self.w2 = size * desc.width2 - spacing def update_position(self, scale, shift_x=0, shift_y=0):
self.h2 = size * desc.height2 - spacing size = scale * (KEY_SIZE_RATIO + KEY_SPACING_RATIO)
spacing = scale * KEY_SPACING_RATIO
self.rotation_x = size * self.desc.rotation_x
self.rotation_y = size * self.desc.rotation_y
self.shift_x = shift_x
self.shift_y = shift_y
self.x = size * self.desc.x
self.y = size * self.desc.y
self.w = size * self.desc.width - spacing
self.h = size * self.desc.height - spacing
self.rect = QRect(self.x, self.y, self.w, self.h)
self.x2 = self.x + size * self.desc.x2
self.y2 = self.y + size * self.desc.y2
self.w2 = size * self.desc.width2 - spacing
self.h2 = size * self.desc.height2 - spacing
self.bbox = self.calculate_bbox(QRectF(self.x, self.y, self.w, self.h)) self.bbox = self.calculate_bbox(QRectF(self.x, self.y, self.w, self.h))
self.polygon = QPolygonF(self.bbox + [self.bbox[0]]) self.polygon = QPolygonF(self.bbox + [self.bbox[0]])
@ -143,7 +147,7 @@ class KeyboardWidget(QWidget):
self.common_widgets = [] self.common_widgets = []
# layout-specific widgets # layout-specific widgets
self.widgets_for_layout = defaultdict(lambda: defaultdict(list)) self.widgets_for_layout = []
# widgets in current layout # widgets in current layout
self.widgets = [] self.widgets = []
@ -154,60 +158,64 @@ class KeyboardWidget(QWidget):
def set_keys(self, keys, encoders): def set_keys(self, keys, encoders):
self.common_widgets = [] self.common_widgets = []
self.widgets_for_layout = defaultdict(lambda: defaultdict(list)) self.widgets_for_layout = []
self.add_keys([(x, KeyWidget) for x in keys] + [(x, EncoderWidget) for x in encoders]) self.add_keys([(x, KeyWidget) for x in keys] + [(x, EncoderWidget) for x in encoders])
self.update_layout() self.update_layout()
def add_keys(self, keys): def add_keys(self, keys):
scale_factor = self.fontMetrics().height()
for key, cls in keys:
if key.layout_index == -1:
self.common_widgets.append(cls(key, scale_factor))
else:
self.widgets_for_layout.append(cls(key, scale_factor))
def place_widgets(self):
top_x = top_y = 1e6 top_x = top_y = 1e6
scale_factor = self.fontMetrics().height() scale_factor = self.fontMetrics().height()
# find the global top-left position, all the keys will be shifted to the left/up by that position self.widgets = []
for key, cls in keys:
if key.layout_index == -1:
obj = cls(key, scale_factor)
p = obj.polygon.boundingRect().topLeft()
top_x = min(top_x, p.x())
top_y = min(top_y, p.y())
# obtain common widgets, that is, ones which are always displayed and require no extra transforms # find the global top-left position, all the keys will be shifted to the left/up by that position
for key, cls in keys: for widget in self.common_widgets:
if key.layout_index == -1: widget.update_position(scale_factor)
self.common_widgets.append(cls(key, scale_factor, -top_x + KEYBOARD_WIDGET_PADDING, -top_y + KEYBOARD_WIDGET_PADDING)) p = widget.polygon.boundingRect().topLeft()
top_x = min(top_x, p.x())
top_y = min(top_y, p.y())
# place common widgets, that is, ones which are always displayed and require no extra transforms
for widget in self.common_widgets:
widget.update_position(scale_factor, -top_x + KEYBOARD_WIDGET_PADDING, -top_y + KEYBOARD_WIDGET_PADDING)
self.widgets.append(widget)
# top-left position for specific layout # top-left position for specific layout
layout_x = defaultdict(lambda: defaultdict(lambda: 1e6)) layout_x = defaultdict(lambda: defaultdict(lambda: 1e6))
layout_y = defaultdict(lambda: defaultdict(lambda: 1e6)) layout_y = defaultdict(lambda: defaultdict(lambda: 1e6))
# determine top-left position for every layout option # determine top-left position for every layout option
for key, cls in keys: for widget in self.widgets_for_layout:
if key.layout_index != -1: widget.update_position(scale_factor)
obj = cls(key, scale_factor) idx, opt = widget.desc.layout_index, widget.desc.layout_option
idx, opt = key.layout_index, key.layout_option p = widget.polygon.boundingRect().topLeft()
p = obj.polygon.boundingRect().topLeft() layout_x[idx][opt] = min(layout_x[idx][opt], p.x())
layout_x[idx][opt] = min(layout_x[idx][opt], p.x()) layout_y[idx][opt] = min(layout_y[idx][opt], p.y())
layout_y[idx][opt] = min(layout_y[idx][opt], p.y())
# obtain widgets for all layout options now that we know how to shift them # obtain widgets for all layout options now that we know how to shift them
for key, cls in keys: for widget in self.widgets_for_layout:
if key.layout_index != -1: idx, opt = widget.desc.layout_index, widget.desc.layout_option
idx, opt = key.layout_index, key.layout_option if opt == self.layout_editor.get_choice(idx):
shift_x = layout_x[idx][opt] - layout_x[idx][0] shift_x = layout_x[idx][opt] - layout_x[idx][0]
shift_y = layout_y[idx][opt] - layout_y[idx][0] shift_y = layout_y[idx][opt] - layout_y[idx][0]
obj = cls(key, scale_factor, -shift_x - top_x + KEYBOARD_WIDGET_PADDING, -shift_y - top_y + KEYBOARD_WIDGET_PADDING) widget.update_position(scale_factor, -shift_x - top_x + KEYBOARD_WIDGET_PADDING, -shift_y - top_y + KEYBOARD_WIDGET_PADDING)
self.widgets_for_layout[idx][opt].append(obj) self.widgets.append(widget)
def update_layout(self): def update_layout(self):
""" Updates self.widgets for the currently active layout """ """ Updates self.widgets for the currently active layout """
# determine widgets for current layout # determine widgets for current layout
self.widgets = [] self.place_widgets()
self.widgets += self.common_widgets
for idx in self.widgets_for_layout.keys():
option = self.layout_editor.get_choice(idx)
self.widgets += self.widgets_for_layout[idx][option]
self.widgets = list(filter(lambda w: not w.desc.decal, self.widgets)) self.widgets = list(filter(lambda w: not w.desc.decal, self.widgets))
self.widgets.sort(key=lambda w: (w.y, w.x)) self.widgets.sort(key=lambda w: (w.y, w.x))
@ -223,6 +231,7 @@ class KeyboardWidget(QWidget):
self.height = max_h + 2 * KEYBOARD_WIDGET_PADDING self.height = max_h + 2 * KEYBOARD_WIDGET_PADDING
self.update() self.update()
self.updateGeometry()
def paintEvent(self, event): def paintEvent(self, event):
qp = QPainter() qp = QPainter()
@ -318,6 +327,9 @@ class KeyboardWidget(QWidget):
self.clicked.emit() self.clicked.emit()
self.update() self.update()
def resizeEvent(self, ev):
self.update_layout()
def select_next(self): def select_next(self):
""" Selects next key based on their order in the keymap """ """ Selects next key based on their order in the keymap """
@ -344,6 +356,8 @@ class KeyboardWidget(QWidget):
QToolTip.showText(ev.globalPos(), key.tooltip) QToolTip.showText(ev.globalPos(), key.tooltip)
else: else:
QToolTip.hideText() QToolTip.hideText()
if ev.type() == QEvent.LayoutRequest:
self.update_layout()
return super().event(ev) return super().event(ev)
def set_enabled(self, val): def set_enabled(self, val):