From 75e1bf3f6e82dda6d95cf4671cdbdf87a6fe8e47 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 14 Sep 2021 10:34:36 -0400 Subject: [PATCH] Factor combobox logic into a new `Selection` subtype --- piker/ui/_forms.py | 176 ++++++++++++++++++++++++++------------------- 1 file changed, 102 insertions(+), 74 deletions(-) diff --git a/piker/ui/_forms.py b/piker/ui/_forms.py index 3d0b2398..cf324ca5 100644 --- a/piker/ui/_forms.py +++ b/piker/ui/_forms.py @@ -42,12 +42,10 @@ from PyQt5.QtWidgets import ( QStyledItemDelegate, QStyleOptionViewItem, ) -# import pydantic from ._event import open_handlers from ._style import hcolor, _font, _font_small, DpiAwareFont from ._label import FormatLabel -from .. import config class FontAndChartAwareLineEdit(QLineEdit): @@ -71,17 +69,21 @@ class FontAndChartAwareLineEdit(QLineEdit): if width_in_chars: self._chars = int(width_in_chars) + x_size_policy = QSizePolicy.Fixed else: # chart count which will be used to calculate # width of input field. - self._chars: int = 9 + self._chars: int = 6 + # fit to surroundingn frame width + x_size_policy = QSizePolicy.Expanding super().__init__(parent) + # size it as we specify # https://doc.qt.io/qt-5/qsizepolicy.html#Policy-enum self.setSizePolicy( - QSizePolicy.Expanding, + x_size_policy, QSizePolicy.Fixed, ) self.setFont(font.font) @@ -99,11 +101,11 @@ class FontAndChartAwareLineEdit(QLineEdit): dpi_font = self.dpi_font psh.setHeight(dpi_font.px_size) - # space for ``._chars: int`` - char_w_pxs = dpi_font.boundingRect(self.text()).width() - chars_w = char_w_pxs + 6 # * dpi_font.scale() * self._chars - psh.setWidth(chars_w) - + # make space for ``._chars: int`` for of characters in view + # TODO: somehow this math ain't right? + chars_w_pxs = dpi_font.boundingRect('0'*self._chars).width() + scale = round(dpi_font.scale()) + psh.setWidth(chars_w_pxs * scale) return psh def set_width_in_chars( @@ -167,23 +169,93 @@ class FontScaledDelegate(QStyledItemDelegate): # QStyledItemDelegate.paint(self, painter, option, index) -# NOTE: in theory we can put icons on the RHS side with this hackery: -# https://stackoverflow.com/a/64256969 -# class ComboBox(QComboBox): -# def __init__( -# self, -# parent=None, -# ) -> None: -# super().__init__(parent=parent) +class Selection(QComboBox): -# def showPopup(self): -# print('show') -# QComboBox.showPopup(self) + def __init__( + self, + parent=None, -# def hidePopup(self): -# # self.setItemDelegate(FontScaledDelegate(self.parent())) -# print('hide') -# QComboBox.hidePopup(self) + ) -> None: + + self._items: dict[str, int] = {} + + super().__init__(parent=parent) + self.setSizeAdjustPolicy(QComboBox.AdjustToContents) + # make line edit expand to surrounding frame + self.setSizePolicy( + QSizePolicy.Expanding, + QSizePolicy.Fixed, + ) + view = self.view() + view.setUniformItemSizes(True) + + # TODO: this doesn't seem to work for the currently selected item? + self.setItemDelegate(FontScaledDelegate(self)) + + def set_style( + self, + + color: str, + font_size: int, + + ) -> None: + + self.setStyleSheet( + f"""QComboBox {{ + color : {hcolor(color)}; + font-size : {font_size}px; + }} + """ + ) + + def set_items( + self, + keys: list[str], + + ) -> None: + '''Write keys to the selection verbatim. + + All other items are cleared beforehand. + ''' + self.clear() + self._items.clear() + + for i, key in enumerate(keys): + strkey = str(key) + self.insertItem(i, strkey) + + # store map of entry keys to row indexes + self._items[strkey] = i + + # compute max item size so that the weird + # "style item delegate" thing can then specify + # that size on each item... + keys.sort() + br = _font.boundingRect(str(keys[-1])) + _, h = br.width(), br.height() + + # TODO: something better then this monkey patch + view = self.view() + + # XXX: see size policy settings of line edit + # view._max_item_size = w, h + + self.setMinimumHeight(h) # at least one entry in view + view.setMaximumHeight(6*h) # limit to 6 items max in view + + icon_size = round(h * 0.75) + self.setIconSize(QSize(icon_size, icon_size)) + + # # NOTE: in theory we can put icons on the RHS side with this hackery: + # # https://stackoverflow.com/a/64256969 + # def showPopup(self): + # print('show') + # QComboBox.showPopup(self) + + # def hidePopup(self): + # # self.setItemDelegate(FontScaledDelegate(self.parent())) + # print('hide') + # QComboBox.hidePopup(self) # slew of resources which helped get this where it is: @@ -279,6 +351,7 @@ class FieldsForm(QWidget): edit = FontAndChartAwareLineEdit( parent=self, + # width_in_chars=6, ) edit.setStyleSheet( f"""QLineEdit {{ @@ -301,66 +374,23 @@ class FieldsForm(QWidget): label_name: str, values: list[str], - ) -> QComboBox: + ) -> Selection: # TODO: maybe a distint layout per "field" item? label = self.add_field_label(label_name) - select = QComboBox(self) + select = Selection(self) + select.set_style(color='gunmetal', font_size=self._font_size) select._key = key - select._items: dict[str, int] = {} - - for i, value in enumerate(values): - strkey = str(value) - select.insertItem(i, strkey) - - # store map of entry keys to row indexes - select._items[strkey] = i - - select.setStyleSheet( - f"""QComboBox {{ - color : {hcolor('gunmetal')}; - font-size : {self._font_size}px; - }} - """ - ) - select.setSizeAdjustPolicy(QComboBox.AdjustToContents) + select.set_items(values) self.setSizePolicy( QSizePolicy.Fixed, QSizePolicy.Fixed, ) - view = select.view() - view.setUniformItemSizes(True) - - # TODO: this doesn't seem to work for the currently selected item? - select.setItemDelegate(FontScaledDelegate(self)) - - # compute maximum item size so that the weird - # "style item delegate" thing can then specify - # that size on each item... - values.sort() - br = _font.boundingRect(str(values[-1])) - _, h = br.width(), br.height() - - icon_size = round(h * 0.75) - select.setIconSize(QSize(icon_size, icon_size)) - - # TODO: something better then this monkey patch - # view._max_item_size = w, h - - # limit to 6 items? - view.setMaximumHeight(6*h) - - # one entry in view - select.setMinimumHeight(h) - select.show() - self.form.addRow(label, select) - self.fields[key] = select - return select @@ -669,7 +699,6 @@ def mk_order_pane_layout( ) -> FieldsForm: font_size: int = _font.px_size - 1 - accounts = config.load_accounts() # TODO: maybe just allocate the whole fields form here # and expect an async ctx entry? @@ -679,7 +708,7 @@ def mk_order_pane_layout( 'account': { 'label': '**account**:', 'type': 'select', - 'default_value': accounts.keys(), + 'default_value': ['paper'], }, 'size_unit': { 'label': '**allocate**:', @@ -721,7 +750,6 @@ def mk_order_pane_layout( form, pane_vbox=vbox, label_font_size=font_size, - ) # TODO: would be nice to have some better way of reffing these over # monkey patching...