Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding numeric input fields inplace of QSpinBox to allow empty text #168

Merged
merged 3 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified eon_timer/resources/themes/default.zip
Binary file not shown.
Binary file modified eon_timer/resources/themes/pokeball.zip
Binary file not shown.
15 changes: 8 additions & 7 deletions eon_timer/settings/action/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from PySide6.QtCore import Qt
from PySide6.QtGui import QIcon, QPixmap
from PySide6.QtWidgets import QColorDialog, QPushButton, QSpinBox
from PySide6.QtWidgets import QColorDialog, QPushButton

from eon_timer.util import const
from eon_timer.util.injector import component
Expand All @@ -15,6 +15,7 @@
from eon_timer.util.pyside.file_selector_widget import FileSelectorWidget
from eon_timer.util.pyside.form import FormWidget
from eon_timer.util.pyside.name_service import NameService
from eon_timer.util.pyside.numeric_input_field import IntInputField
from .model import ActionMode, ActionSettingsModel, ActionSound


Expand Down Expand Up @@ -69,15 +70,15 @@ def __init_components(self) -> None:
self.add_field(self.Field.COLOR, field, name='actionSettingsColor')
self.__set_icon_color(field)
# ----- interval -----
field = QSpinBox()
field = IntInputField()
field.set_range(0, const.INT_MAX)
bindings.bind(field.value, self.interval)
self.add_field(self.Field.INTERVAL, field, name='actionSettingsInterval')
field.setRange(0, const.INT_MAX)
bindings.bind_spinbox(field, self.interval)
# ----- count -----
field = QSpinBox()
field = IntInputField()
field.set_range(0, const.INT_MAX)
bindings.bind(field.value, self.count)
self.add_field(self.Field.COUNT, field, name='actionSettingsCount')
field.setRange(0, const.INT_MAX)
bindings.bind_spinbox(field, self.count)

def __on_sound_changed(self, event: PropertyChangeEvent[ActionSound]) -> None:
self.set_visible(self.Field.CUSTOM_SOUND, event.new_value == ActionSound.CUSTOM)
Expand Down
17 changes: 9 additions & 8 deletions eon_timer/settings/timer/widget.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
from typing import Final

from PySide6.QtCore import Qt
from PySide6.QtWidgets import QCheckBox, QDoubleSpinBox, QSpinBox
from PySide6.QtWidgets import QCheckBox

from eon_timer.util.const import INT_MAX
from eon_timer.util.injector import component
from eon_timer.util.loggers import log_method_calls
from eon_timer.util.properties import bindings
from eon_timer.util.properties.property import FloatProperty, Property, BoolProperty
from eon_timer.util.properties.property import BoolProperty, FloatProperty, Property
from eon_timer.util.properties.property_change import PropertyChangeEvent
from eon_timer.util.pyside import EnumComboBox
from eon_timer.util.pyside.form import FormWidget
from eon_timer.util.pyside.name_service import NameService
from eon_timer.util.pyside.numeric_input_field import FloatInputField, IntInputField
from .model import Console, TimerSettingsModel


Expand Down Expand Up @@ -46,19 +47,19 @@ def __init_components(self) -> None:
name='timerSettingsConsole')
bindings.bind_enum_combobox(field, self.console)
# ----- custom framerate -----
field = QDoubleSpinBox()
field = FloatInputField()
field.set_range(0, INT_MAX)
bindings.bind(field.value, self.custom_framerate)
self.add_field(self.Field.CUSTOM_FRAMERATE, field,
visible=self.console.get() == Console.CUSTOM,
name='timerSettingsCustomFramerate')
field.setRange(0, INT_MAX)
bindings.bind_float_spinbox(field, self.custom_framerate)
self.console.on_change(self.__on_console_changed)
# ----- refresh interval -----
field = QSpinBox()
field = IntInputField()
field.set_range(1, INT_MAX)
bindings.bind(field.value, self.refresh_interval)
self.add_field(self.Field.REFRESH_INTERVAL, field,
name='timerSettingsRefreshInterval')
field.setRange(1, INT_MAX)
bindings.bind_spinbox(field, self.refresh_interval)
# ----- precision calibration -----
field = QCheckBox()
self.add_field(self.Field.PRECISION_CALIBRATION, field,
Expand Down
2 changes: 1 addition & 1 deletion eon_timer/timers/custom/custom_phase.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def __init__(self,
self.unit: Final = EnumProperty(unit)
self.target: Final = IntProperty(value)
self.calibration: Final = FloatProperty(calibration)
self.hit: Final = IntProperty(0, transient=True)
self.hit: Final = IntProperty(None, transient=True)

@classmethod
def read(cls, settings: QSettings) -> Self:
Expand Down
47 changes: 22 additions & 25 deletions eon_timer/timers/custom/custom_phase_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
from typing import Final

from PySide6.QtCore import Qt, Signal
from PySide6.QtWidgets import QDoubleSpinBox, QGroupBox, QHBoxLayout, QLabel, QPushButton, QSizePolicy, QSpinBox, \
QWidget
from PySide6.QtWidgets import QGroupBox, QHBoxLayout, QLabel, QPushButton, QSizePolicy, QWidget

from eon_timer.timers import Calibrator
from eon_timer.util import loggers, pyside
from eon_timer.util import loggers, pyside, strings
from eon_timer.util.const import INT_MAX, INT_MIN
from eon_timer.util.loggers import log_method_calls
from eon_timer.util.properties import bindings
from eon_timer.util.properties.property import IntProperty
from eon_timer.util.properties.property_change import PropertyChangeEvent
from eon_timer.util.pyside import EnumComboBox
from eon_timer.util.pyside.form import FormWidget
from eon_timer.util.pyside.numeric_input_field import BlankBehavior, FloatInputField, IntInputField, Radix
from .custom_phase import CustomPhase


Expand All @@ -39,9 +39,9 @@ def __init__(self,
self.calibrator: Final = calibrator
self.index: Final = IntProperty(index)

self.__target_field: Final = QSpinBox()
self.__calibration_field: Final = QDoubleSpinBox()
self.__hit_field: Final = QSpinBox()
self.__target_field: Final = IntInputField()
self.__calibration_field: Final = FloatInputField()
self.__hit_field: Final = IntInputField()
self.__init_components()

@log_method_calls()
Expand Down Expand Up @@ -77,19 +77,21 @@ def __init_components(self):
form.add_field(self.Field.UNIT, field)
self.__on_unit_changed()
# ----- target -----
self.__target_field.setRange(0, INT_MAX)
bindings.bind_spinbox(self.__target_field, self.model.target)
self.__target_field.valueChanged.connect(self.__on_value_changed)
self.__target_field.set_range(0, INT_MAX)
bindings.bind(self.__target_field.value, self.model.target)
self.__target_field.value.on_change(self.__on_value_changed)
form.add_field(self.Field.TARGET, self.__target_field)
# ----- calibration -----
self.__calibration_field.setRange(INT_MIN, INT_MAX)
bindings.bind_float_spinbox(self.__calibration_field, self.model.calibration)
self.__calibration_field.valueChanged.connect(self.__on_value_changed)
self.__calibration_field.set_range(INT_MIN, INT_MAX)
bindings.bind(self.__calibration_field.value, self.model.calibration)
self.__calibration_field.value.on_change(self.__on_value_changed)
form.add_field(self.Field.CALIBRATION, self.__calibration_field)
# ----- hit_field -----
self.__hit_field.setRange(0, INT_MAX)
bindings.bind_spinbox(self.__hit_field, self.model.hit)
self.__hit_field.set_range(0, INT_MAX)
self.__hit_field.blank_behavior = BlankBehavior.BLANK
bindings.bind(self.__hit_field.value, self.model.hit)
form.add_field(self.Field.HIT, self.__hit_field)
self.__hit_field.setText('')
# ----- remove_btn -----
button = QPushButton(chr(0xf057))
button.setFont('Font Awesome 5 Free')
Expand All @@ -99,13 +101,13 @@ def __init_components(self):
pyside.set_class(button, ['danger'])

def calibrate(self):
if self.hit > 0:
if strings.strip_to_none(self.__hit_field.text()) is not None:
if self.unit != CustomPhase.Unit.MILLISECONDS:
calibration = self.calibrator.to_milliseconds(self.target - self.hit)
else:
calibration = self.target - self.hit
self.model.calibration.add(calibration)
self.model.hit.set(0)
self.model.hit.set(None)

def __update_index(self,
label: QLabel,
Expand All @@ -115,22 +117,17 @@ def __update_index(self,
index = event.new_value
label.setText(f'{index + 1}.')

def __on_value_changed(self):
def __on_value_changed(self, event: PropertyChangeEvent[int | float]):
self.changed.emit()

def __on_unit_changed(self, event: PropertyChangeEvent[CustomPhase.Unit] | None = None):
unit = self.unit
if event is not None:
unit = event.new_value

prefix = '0x' if unit == CustomPhase.Unit.HEX else ''
integer_base = 16 if unit == CustomPhase.Unit.HEX else 10
# ----- target_field -----
self.__target_field.setPrefix(prefix)
self.__target_field.setDisplayIntegerBase(integer_base)
# ----- hit_field -----
self.__hit_field.setPrefix(prefix)
self.__hit_field.setDisplayIntegerBase(integer_base)
radix = Radix.HEXADECIMAL if unit == CustomPhase.Unit.HEX else Radix.DECIMAL
self.__target_field.set_radix(radix)
self.__hit_field.set_radix(radix)

self.changed.emit()

Expand Down
4 changes: 3 additions & 1 deletion eon_timer/timers/custom/timer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Final
from typing import Final, override

from eon_timer.timers.calibrator import Calibrator
from eon_timer.timers.timer import Timer
Expand All @@ -12,6 +12,7 @@ class CustomTimer(Timer[CustomTimerModel]):
def __init__(self, calibrator: Calibrator):
self.calibrator: Final = calibrator

@override
def create(self, model: CustomTimerModel) -> list[float]:
phases = []
for phase in model.phases:
Expand All @@ -23,5 +24,6 @@ def create(self, model: CustomTimerModel) -> list[float]:
phases.append(value)
return phases

@override
def calibrate(self, model: CustomTimerModel):
pass
2 changes: 1 addition & 1 deletion eon_timer/timers/gen3/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Gen3Model(Settings):
pre_timer = IntProperty(5000)
target_frame = IntProperty(1000)
calibration = FloatProperty(0.0)
frame_hit = IntProperty(0, transient=True)
frame_hit = IntProperty(None, transient=True)

@property
@override
Expand Down
13 changes: 6 additions & 7 deletions eon_timer/timers/gen3/timer.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,9 @@ def create(self, model: Gen3Model) -> list[float]:

@override
def calibrate(self, model: Gen3Model):
if model.frame_hit.get() > 0:
offset = self.frame_timer.calibrate(
model.target_frame.get(),
model.frame_hit.get()
)
model.calibration.add(offset)
model.frame_hit.set(0)
offset = self.frame_timer.calibrate(
model.target_frame.get(),
model.frame_hit.get()
)
model.calibration.add(offset)
model.frame_hit.set(None)
65 changes: 38 additions & 27 deletions eon_timer/timers/gen3/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
from typing import Final, override

from PySide6.QtCore import Qt
from PySide6.QtWidgets import QDoubleSpinBox, QGroupBox, QPushButton, QSizePolicy, QSpinBox
from PySide6.QtWidgets import QGroupBox, QPushButton, QSizePolicy

from eon_timer.app_state import AppState
from eon_timer.timers.timer_widget import TimerWidget
from eon_timer.util import const, pyside
from eon_timer.util import const, pyside, strings
from eon_timer.util.injector import component
from eon_timer.util.loggers import log_method_calls
from eon_timer.util.properties import bindings
from eon_timer.util.properties.property_change import PropertyChangeEvent
from eon_timer.util.pyside import EnumComboBox
from eon_timer.util.pyside.form import FormLayout, FormWidget
from eon_timer.util.pyside.name_service import NameService
from eon_timer.util.pyside.numeric_input_field import BlankBehavior, FloatInputField, IntInputField
from .model import Gen3Mode, Gen3Model
from .timer import Gen3Timer

Expand All @@ -35,6 +36,7 @@ def __init__(self,
timer: Gen3Timer,
name_service: NameService) -> None:
self.state: Final = state
self.frame_hit_field: Final = IntInputField()
FormWidget.__init__(self, name_service)
TimerWidget.__init__(self, model, timer)

Expand All @@ -47,9 +49,9 @@ def _init_components(self) -> None:
self._layout.set_content_margins(10, 10, 10, 10)
# ----- mode -----
field = EnumComboBox(Gen3Mode)
self.add_field(self.Field.MODE, field, name='gen3Mode')
bindings.bind_enum_combobox(field, self.model.mode)
self.model.mode.on_change(self.__on_mode_changed)
self.add_field(self.Field.MODE, field, name='gen3Mode')
# ----- form_group -----
form_group = QGroupBox()
self.name_service.set_name(form_group, 'gen3FormGroup')
Expand All @@ -59,20 +61,20 @@ def _init_components(self) -> None:
pyside.set_class(form_group, ['themeable-panel', 'themeable-border'])
form_group.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
# ----- pre_timer -----
field = QSpinBox()
field = IntInputField()
field.set_range(0, const.INT_MAX)
bindings.bind(field.value, self.model.pre_timer)
self.add_field(self.Field.PRE_TIMER, field, layout=form_layout, name='gen3PreTimer')
field.setRange(0, const.INT_MAX)
bindings.bind_spinbox(field, self.model.pre_timer)
# ----- target_frame -----
field = QSpinBox()
field = IntInputField()
field.set_range(0, const.INT_MAX)
bindings.bind(field.value, self.model.target_frame)
self.add_field(self.Field.TARGET_FRAME, field, layout=form_layout, name='gen3TargetFrame')
field.setRange(0, const.INT_MAX)
bindings.bind_spinbox(field, self.model.target_frame)
# ----- calibration -----
field = QDoubleSpinBox()
field = FloatInputField()
field.set_range(const.INT_MIN, const.INT_MAX)
bindings.bind(field.value, self.model.calibration)
self.add_field(self.Field.CALIBRATION, field, layout=form_layout, name='gen3Calibration')
field.setRange(const.INT_MIN, const.INT_MAX)
bindings.bind_float_spinbox(field, self.model.calibration)
# ----- set_target_frame_btn -----
field = QPushButton(self.Field.SET_TARGET_FRAME.value)
self.name_service.set_name(field, 'gen3SetTargetFrameButton')
Expand All @@ -82,10 +84,11 @@ def _init_components(self) -> None:
field.pressed.connect(self.__on_set_target_frame)
field_set.enabled = False
# ----- frame_hit -----
field = QSpinBox()
self.add_field(self.Field.FRAME_HIT, field, name='gen3FrameHit')
field.setRange(0, const.INT_MAX)
bindings.bind_spinbox(field, self.model.frame_hit)
self.frame_hit_field.set_range(0, const.INT_MAX)
self.frame_hit_field.blank_behavior = BlankBehavior.BLANK
bindings.bind(self.frame_hit_field.value, self.model.frame_hit)
self.add_field(self.Field.FRAME_HIT, self.frame_hit_field, name='gen3FrameHit')
self.frame_hit_field.setText('')
# update field visibility
self.__on_mode_changed()

Expand All @@ -102,26 +105,34 @@ def field_changed(field: Gen3TimerWidget.Field,
self.model.target_frame.on_change(functools.partial(field_changed, self.Field.TARGET_FRAME))
self.model.calibration.on_change(functools.partial(field_changed, self.Field.CALIBRATION))

@override
def calibrate(self):
frame_hit = strings.strip_to_none(self.frame_hit_field.text())
if frame_hit is not None:
super().calibrate()
self.frame_hit_field.setText('')

@override
def setDisabled(self, disabled: bool):
self.set_disabled(self.Field.MODE, disabled)
self.set_disabled(self.Field.PRE_TIMER, disabled)
self.set_disabled(self.Field.CALIBRATION, disabled)
self.set_disabled(self.Field.FRAME_HIT, disabled)

mode = self.model.mode.get()
self.set_disabled(self.Field.TARGET_FRAME, self.state.running and mode == Gen3Mode.STANDARD)
self.set_enabled(self.Field.SET_TARGET_FRAME, self.state.running and mode == Gen3Mode.VARIABLE_TARGET)

def __on_mode_changed(self, event: PropertyChangeEvent[Gen3Mode] | None = None) -> None:
mode = event.new_value if event else self.model.mode.get()
self.set_visible(self.Field.SET_TARGET_FRAME,
mode == Gen3Mode.VARIABLE_TARGET)

def __on_set_target_frame(self) -> None:
phase = self.frame_timer.create_phase(
phase = self.timer.frame_timer.create_phase(
self.model.target_frame.get(),
self.model.calibration.get()
)
self.state.set_phase(1, phase)
self.set_disabled(self.Field.TARGET_FRAME, True)
self.set_disabled(self.Field.SET_TARGET_FRAME, True)

def setDisabled(self, disabled: bool):
self.set_disabled(self.Field.MODE, disabled)
self.set_disabled(self.Field.PRE_TIMER, disabled)
self.set_disabled(self.Field.CALIBRATION, disabled)
self.set_disabled(self.Field.FRAME_HIT, disabled)

mode = self.model.mode.get()
self.set_disabled(self.Field.TARGET_FRAME, self.state.running and mode == Gen3Mode.STANDARD)
self.set_enabled(self.Field.SET_TARGET_FRAME, self.state.running and mode == Gen3Mode.VARIABLE_TARGET)
2 changes: 1 addition & 1 deletion eon_timer/timers/gen4/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Gen4Model(Settings):
target_second = IntProperty(50)
calibrated_delay = IntProperty(500)
calibrated_second = IntProperty(14)
delay_hit = IntProperty(0, transient=True)
delay_hit = IntProperty(None, transient=True)

@property
@override
Expand Down
Loading