Skip to content

Commit

Permalink
feat: impl SiLineEdit, SiLineEditWithDeletionButton, `SiIntSpinBo…
Browse files Browse the repository at this point in the history
…x`, `SiDoubleSpinBox`
  • Loading branch information
ChinaIceF committed Aug 23, 2024
1 parent ed01d92 commit 281796f
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 231 deletions.
48 changes: 46 additions & 2 deletions examples/Gallery for siui/components/page_widgets/page_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor

from siui.components import SiCircularProgressBar, SiOptionCardLinear, SiTitledWidgetGroup, SiWidget, SiLineEdit
from siui.components import SiCircularProgressBar, SiLineEdit, SiOptionCardLinear, SiTitledWidgetGroup, SiWidget, \
SiLineEditWithDeletionButton
from siui.components.combobox import SiComboBox
from siui.components.menu import SiMenu
from siui.components.page import SiPage
from siui.components.progress_bar import SiProgressBar
from siui.components.slider import SiSliderH
from siui.components.spinbox.spinbox import SiSpinBox
from siui.components.spinbox.spinbox import SiIntSpinBox, SiDoubleSpinBox
from siui.components.widgets import (
SiCheckBox,
SiDenseHContainer,
Expand Down Expand Up @@ -380,7 +381,50 @@ def __init__(self, *args, **kwargs):
self.line_edit.body().addPlaceholder(12)
self.line_edit.adjustSize()

# 带删除单行输入组件
self.line_edit_with_del_button = OptionCardPlaneForWidgetDemos(self)
self.line_edit_with_del_button.setSourceCodeURL("https://github.com/ChinaIceF/PyQt-SiliconUI/blob/main/siui/components"
"/widgets/slider/slider.py")
self.line_edit_with_del_button.setTitle("带删除单行输入组件")

self.demo_line_edit_with_del_button = SiLineEditWithDeletionButton(self)
self.demo_line_edit_with_del_button.resize(256, 32)
self.demo_line_edit_with_del_button.lineEdit().setText("点击右侧按钮以删除文字")

self.line_edit_with_del_button.body().addWidget(self.demo_line_edit_with_del_button)
self.line_edit_with_del_button.body().addPlaceholder(12)
self.line_edit_with_del_button.adjustSize()

# 整数微调组件
self.int_spin_box = OptionCardPlaneForWidgetDemos(self)
self.int_spin_box.setSourceCodeURL("https://github.com/ChinaIceF/PyQt-SiliconUI/blob/main/siui/components"
"/widgets/slider/slider.py")
self.int_spin_box.setTitle("整数微调组件")

self.demo_int_spin_box = SiIntSpinBox(self)
self.demo_int_spin_box.resize(256, 32)

self.int_spin_box.body().addWidget(self.demo_int_spin_box)
self.int_spin_box.body().addPlaceholder(12)
self.int_spin_box.adjustSize()

# 浮点数微调组件
self.double_spin_box = OptionCardPlaneForWidgetDemos(self)
self.double_spin_box.setSourceCodeURL("https://github.com/ChinaIceF/PyQt-SiliconUI/blob/main/siui/components"
"/widgets/slider/slider.py")
self.double_spin_box.setTitle("浮点数微调组件")

self.demo_double_spin_box = SiDoubleSpinBox(self)
self.demo_double_spin_box.resize(256, 32)

self.double_spin_box.body().addWidget(self.demo_double_spin_box)
self.double_spin_box.body().addPlaceholder(12)
self.double_spin_box.adjustSize()

group.addWidget(self.line_edit)
group.addWidget(self.line_edit_with_del_button)
group.addWidget(self.int_spin_box)
group.addWidget(self.double_spin_box)

# 滑条
with self.titled_widgets_group as group:
Expand Down
Empty file.
62 changes: 0 additions & 62 deletions siui/components/spinbox/abstract/spinbox.py

This file was deleted.

188 changes: 103 additions & 85 deletions siui/components/spinbox/spinbox.py
Original file line number Diff line number Diff line change
@@ -1,110 +1,128 @@
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIntValidator, QDoubleValidator

from ...core.color import SiColor
from .. import SiLabel, SiSimpleButton, SiWidget
from .abstract.spinbox import ABCSiSpinBox
from ...core.globals import SiGlobal
from siui.components.widgets.button import SiSimpleButton
from siui.components.widgets.line_edit import SiLineEdit
from siui.core.globals import SiGlobal


class SiSpinBoxButton(SiSimpleButton):
class ABCSiSpinBox(SiLineEdit):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.single_step_ = 1
self.value_ = 0
self.minimum_ = 0
self.maximum_ = 99

self.direction_ = Qt.LeftButton
self.button_plus = SiSimpleButton(self)
self.button_plus.resize(24, 24)
self.button_plus.attachment().setSvgSize(12, 12)
self.button_plus.attachment().load(SiGlobal.siui.iconpack.get("ic_fluent_chevron_up_regular"))
self.button_plus.setRepetitiveClicking(True)
self.button_plus.clicked.connect(self.stepForth)

self.indicator_frame = SiWidget(self)
self.button_minus = SiSimpleButton(self)
self.button_minus.resize(24, 24)
self.button_minus.attachment().setSvgSize(12, 12)
self.button_minus.attachment().load(SiGlobal.siui.iconpack.get("ic_fluent_chevron_down_regular"))
self.button_minus.setRepetitiveClicking(True)
self.button_minus.clicked.connect(self.stepBack)

self.indicator_label = SiLabel(self.indicator_frame)
self.indicator_label.lower()
self.container().setSpacing(0)
self.container().addPlaceholder(8, "right")
self.container().addWidget(self.button_plus, "right")
self.container().addPlaceholder(4, "right")
self.container().addWidget(self.button_minus, "right")

# 禁用悬停颜色变化
self.colorGroup().assign(SiColor.BUTTON_HOVER, "#00FFFFFF")
def singleStep(self):
return self.single_step_

self.indicator_label.setOpacity(0)
def setSingleStep(self, step):
self.single_step_ = step

def setThemeColor(self, color_code):
self.colorGroup().assign(SiColor.THEME, color_code)
def minimum(self):
return self.minimum_

def setDirection(self, direction):
self.direction_ = direction
def setMinimum(self, minimum):
self.minimum_ = minimum

def direction(self):
return self.direction_
def maximum(self):
return self.maximum_

def _get_border_radius_stylesheet(self):
if self.direction_ == Qt.LeftButton:
return "border-top-left-radius: 4px; border-bottom-left-radius: 4px;"
elif self.direction_ == Qt.RightButton:
return "border-top-right-radius: 4px; border-bottom-right-radius: 4px;"
def setMaximum(self, maximum):
self.maximum_ = maximum

def _get_indicator_stylesheet(self):
theme_color = self.colorGroup().fromToken(SiColor.THEME)
stylesheet = (f"border-bottom: 3px solid {theme_color};"
f"background-color: {SiColor.trans(theme_color, 0.6)};"
f"{self._get_border_radius_stylesheet()}")
return stylesheet
def value(self):
return self.value_

def _get_color_label_stylesheet(self):
panel_color = self.colorGroup().fromToken(SiColor.INTERFACE_BG_D)
shadow_color = self.colorGroup().fromToken(SiColor.BUTTON_SHADOW)
stylesheet = (f"border-bottom: 3px solid {shadow_color};"
f"background-color: {panel_color};"
f"{self._get_border_radius_stylesheet()}")
return stylesheet
def setValue(self, value):
self.value_ = min(self.maximum_, max(value, self.minimum_))

def stepForth(self):
self.setValue(self.value() + self.singleStep())

def reloadStyleSheet(self):
super().reloadStyleSheet()
self.hoverLabel().setFixedStyleSheet(self._get_border_radius_stylesheet())
self.colorLabel().setFixedStyleSheet(self._get_color_label_stylesheet())
self.indicator_label.setStyleSheet(self._get_indicator_stylesheet())
def stepBack(self):
self.setValue(self.value() - self.singleStep())

def resizeEvent(self, event):
super().resizeEvent(event)
self.indicator_frame.resize(event.size())
self.indicator_label.resize(event.size())
def stepBy(self, step):
self.setValue(self.value() + step)

def enterEvent(self, event):
super().enterEvent(event)
self.indicator_label.setOpacityTo(1)

def leaveEvent(self, event):
super().leaveEvent(event)
self.indicator_label.setOpacityTo(0)
class SiIntSpinBox(ABCSiSpinBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

class SiSpinBox(ABCSiSpinBox):
self.lineEdit().setValidator(QIntValidator())
self.lineEdit().setText(str(self.value()))
self.lineEdit().editingFinished.connect(self.on_editing_finished)

def on_editing_finished(self):
value = int(self.lineEdit().text())
self.setValue(value)
if value < self.minimum() or value > self.maximum():
try:
SiGlobal.siui.windows["MAIN_WINDOW"].LayerRightMessageSidebar().send(
title="输入值超出范围",
text=f"限制输入值为介于 {self.minimum()}{self.maximum()} 的整数\n"
"已修改为最接近的值",
msg_type=3,
icon=SiGlobal.siui.iconpack.get("ic_fluent_warning_regular"),
fold_after=2500,
)
except ValueError:
pass

def setValue(self, value):
super().setValue(value)
self.lineEdit().setText(str(self.value()))


class SiDoubleSpinBox(ABCSiSpinBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

self.button_width = 32

self.button_up = SiSpinBoxButton(self)
self.button_up.setDirection(Qt.RightButton)
self.button_up.setIdleColor(self.colorGroup().fromToken(SiColor.INTERFACE_BG_D))
self.button_up.setThemeColor(self.colorGroup().fromToken(SiColor.SIDE_MSG_THEME_SUCCESS))

self.button_down = SiSpinBoxButton(self)
self.button_down.setDirection(Qt.LeftButton)
self.button_down.setIdleColor(self.colorGroup().fromToken(SiColor.INTERFACE_BG_D))
self.button_down.setThemeColor(self.colorGroup().fromToken(SiColor.SIDE_MSG_THEME_ERROR))

self.body_ = SiLabel(self)
self.body_.setAlignment(Qt.AlignCenter)
self.body_.setText("123")

def reloadStyleSheet(self):
super().reloadStyleSheet()
SiGlobal.siui.reloadStyleSheetRecursively(self.button_up)
SiGlobal.siui.reloadStyleSheetRecursively(self.button_down)
self.body_.setStyleSheet(
f"color: {self.colorGroup().fromToken(SiColor.TEXT_B)};"
f"background-color: {self.colorGroup().fromToken(SiColor.INTERFACE_BG_E)};"
f"border-bottom: 3px solid {self.colorGroup().fromToken(SiColor.BUTTON_SHADOW)}"
)

def resizeEvent(self, event):
super().resizeEvent(event)

self.button_down.setGeometry(0, 0, self.button_width, event.size().height())
self.button_up.setGeometry(event.size().width() - self.button_width, 0, self.button_width, event.size().height())
self.body_.setGeometry(self.button_width, 0, event.size().width() - 2 * self.button_width, event.size().height())
self.setSingleStep(0.1)

self.lineEdit().setValidator(QDoubleValidator())
self.lineEdit().setText(str(self.value()))
self.lineEdit().editingFinished.connect(self.on_editing_finished)

def on_editing_finished(self):
value = float(self.lineEdit().text())
self.setValue(value)
if value < self.minimum() or value > self.maximum():
try:
SiGlobal.siui.windows["MAIN_WINDOW"].LayerRightMessageSidebar().send(
title="输入值超出范围",
text=f"限制输入值为介于 {self.minimum()}{self.maximum()} 的浮点数\n"
"已修改为最接近的值",
msg_type=3,
icon=SiGlobal.siui.iconpack.get("ic_fluent_warning_regular"),
fold_after=2500,
)
except ValueError:
pass

def setValue(self, value):
# 重写以解决浮点数有效位溢出问题
self.value_ = round(min(self.maximum_, max(value, self.minimum_)), 13) # 舍掉一些精度以追求计算准确
self.lineEdit().setText(str(self.value()))
Loading

0 comments on commit 281796f

Please sign in to comment.