Factor combobox logic into a new `Selection` subtype
							parent
							
								
									6a31c4e160
								
							
						
					
					
						commit
						75e1bf3f6e
					
				| 
						 | 
				
			
			@ -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...
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue