blob: 76524695fbb6700f3d1676dab7ab8c1a23d2db23 [file] [log] [blame]
Philipp Lecefab922022-04-26 22:06:33 +02001# SPDX-License-Identifier: MPL-2.0
2# Copyright (c) 2022 Philipp Le <philipp@philipple.de>.
3# This Source Code Form is subject to the terms of the Mozilla Public
4# License, v. 2.0. If a copy of the MPL was not distributed with this
5# file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7
8from typing import Type
9from tkinter import ttk, StringVar
10from pydantic import ConstrainedInt, ConstrainedFloat
11
12from .base import make_config_widget_base
13
14
15class NumWidget(make_config_widget_base(ttk.Spinbox)):
16 MODEL_TYPE = int | float
17
18 def sync_out(self) -> None:
19 try:
20 setattr(self.model, self.model_key, self.type_(self._stringvar.get()))
21 self.notify_change()
22 except ValueError:
23 # Tolerate temporarily invalid values
24 pass
25
26 def sync_in(self) -> None:
27 val = getattr(self.model, self.model_key)
28 self._stringvar.set(str(val))
29
30 def _config_widget(self) -> None:
31 self._stringvar = StringVar(self.parent)
32 self.sync_in()
33 self.configure(textvariable=self._stringvar, command=lambda: self.sync_out())
34 self.bind('<KeyRelease>', lambda e: self.sync_out())
35 if issubclass(self.type_, ConstrainedInt):
36 tp: Type[ConstrainedInt] = self.type_
37 self.configure(increment=1)
38 if tp.gt is not None:
39 self.configure(from_=tp.gt + 1)
40 if tp.ge is not None:
41 self.configure(from_=tp.ge)
42 if tp.lt is not None:
43 self.configure(to=tp.lt - 1)
44 if tp.le is not None:
45 self.configure(to=tp.le)
46 elif issubclass(self.type_, ConstrainedFloat):
47 tp: Type[ConstrainedFloat] = self.type_
48 self.configure(increment=tp.multiple_of)
49 if tp.gt is not None:
50 self.configure(from_=tp.gt)
51 if tp.ge is not None:
52 self.configure(from_=tp.ge)
53 if tp.lt is not None:
54 self.configure(to=tp.lt)
55 if tp.le is not None:
56 self.configure(to=tp.le)
57 elif issubclass(self.type_, float):
58 raise TypeError(f'Please use ConstrainedFloat for {self.model_key}')
59 elif issubclass(self.type_, int):
60 raise TypeError(f'Please use ConstrainedInt for {self.model_key}')
61 else:
62 print(f'Unknown type f{repr(self.type_)}')