Factor combobox logic into a new `Selection` subtype

chart_mod_breakup
Tyler Goodlet 2021-09-14 10:34:36 -04:00
parent 6a31c4e160
commit 75e1bf3f6e
1 changed files with 102 additions and 74 deletions

View File

@ -42,12 +42,10 @@ from PyQt5.QtWidgets import (
QStyledItemDelegate, QStyledItemDelegate,
QStyleOptionViewItem, QStyleOptionViewItem,
) )
# import pydantic
from ._event import open_handlers from ._event import open_handlers
from ._style import hcolor, _font, _font_small, DpiAwareFont from ._style import hcolor, _font, _font_small, DpiAwareFont
from ._label import FormatLabel from ._label import FormatLabel
from .. import config
class FontAndChartAwareLineEdit(QLineEdit): class FontAndChartAwareLineEdit(QLineEdit):
@ -71,17 +69,21 @@ class FontAndChartAwareLineEdit(QLineEdit):
if width_in_chars: if width_in_chars:
self._chars = int(width_in_chars) self._chars = int(width_in_chars)
x_size_policy = QSizePolicy.Fixed
else: else:
# chart count which will be used to calculate # chart count which will be used to calculate
# width of input field. # 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) super().__init__(parent)
# size it as we specify # size it as we specify
# https://doc.qt.io/qt-5/qsizepolicy.html#Policy-enum # https://doc.qt.io/qt-5/qsizepolicy.html#Policy-enum
self.setSizePolicy( self.setSizePolicy(
QSizePolicy.Expanding, x_size_policy,
QSizePolicy.Fixed, QSizePolicy.Fixed,
) )
self.setFont(font.font) self.setFont(font.font)
@ -99,11 +101,11 @@ class FontAndChartAwareLineEdit(QLineEdit):
dpi_font = self.dpi_font dpi_font = self.dpi_font
psh.setHeight(dpi_font.px_size) psh.setHeight(dpi_font.px_size)
# space for ``._chars: int`` # make space for ``._chars: int`` for of characters in view
char_w_pxs = dpi_font.boundingRect(self.text()).width() # TODO: somehow this math ain't right?
chars_w = char_w_pxs + 6 # * dpi_font.scale() * self._chars chars_w_pxs = dpi_font.boundingRect('0'*self._chars).width()
psh.setWidth(chars_w) scale = round(dpi_font.scale())
psh.setWidth(chars_w_pxs * scale)
return psh return psh
def set_width_in_chars( def set_width_in_chars(
@ -167,23 +169,93 @@ class FontScaledDelegate(QStyledItemDelegate):
# QStyledItemDelegate.paint(self, painter, option, index) # QStyledItemDelegate.paint(self, painter, option, index)
# NOTE: in theory we can put icons on the RHS side with this hackery: class Selection(QComboBox):
# https://stackoverflow.com/a/64256969
# class ComboBox(QComboBox):
# def __init__(
# self,
# parent=None,
# ) -> None:
# super().__init__(parent=parent)
# def showPopup(self): def __init__(
# print('show') self,
# QComboBox.showPopup(self) parent=None,
# def hidePopup(self): ) -> None:
# # self.setItemDelegate(FontScaledDelegate(self.parent()))
# print('hide') self._items: dict[str, int] = {}
# QComboBox.hidePopup(self)
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: # slew of resources which helped get this where it is:
@ -279,6 +351,7 @@ class FieldsForm(QWidget):
edit = FontAndChartAwareLineEdit( edit = FontAndChartAwareLineEdit(
parent=self, parent=self,
# width_in_chars=6,
) )
edit.setStyleSheet( edit.setStyleSheet(
f"""QLineEdit {{ f"""QLineEdit {{
@ -301,66 +374,23 @@ class FieldsForm(QWidget):
label_name: str, label_name: str,
values: list[str], values: list[str],
) -> QComboBox: ) -> Selection:
# TODO: maybe a distint layout per "field" item? # TODO: maybe a distint layout per "field" item?
label = self.add_field_label(label_name) 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._key = key
select._items: dict[str, int] = {} select.set_items(values)
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)
self.setSizePolicy( self.setSizePolicy(
QSizePolicy.Fixed, QSizePolicy.Fixed,
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() select.show()
self.form.addRow(label, select) self.form.addRow(label, select)
self.fields[key] = select self.fields[key] = select
return select return select
@ -669,7 +699,6 @@ def mk_order_pane_layout(
) -> FieldsForm: ) -> FieldsForm:
font_size: int = _font.px_size - 1 font_size: int = _font.px_size - 1
accounts = config.load_accounts()
# TODO: maybe just allocate the whole fields form here # TODO: maybe just allocate the whole fields form here
# and expect an async ctx entry? # and expect an async ctx entry?
@ -679,7 +708,7 @@ def mk_order_pane_layout(
'account': { 'account': {
'label': '**account**:', 'label': '**account**:',
'type': 'select', 'type': 'select',
'default_value': accounts.keys(), 'default_value': ['paper'],
}, },
'size_unit': { 'size_unit': {
'label': '**allocate**:', 'label': '**allocate**:',
@ -721,7 +750,6 @@ def mk_order_pane_layout(
form, form,
pane_vbox=vbox, pane_vbox=vbox,
label_font_size=font_size, label_font_size=font_size,
) )
# TODO: would be nice to have some better way of reffing these over # TODO: would be nice to have some better way of reffing these over
# monkey patching... # monkey patching...