Skip to content

Commit 4c074ca

Browse files
committed
Replace value_checker decorator by a descriptor for BaseTextBox class. Start to implement skin for textboxes.
1 parent 3dfc73b commit 4c074ca

File tree

4 files changed

+61
-32
lines changed

4 files changed

+61
-32
lines changed

tests/test.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def main(win):
2222
curses.init_pair(3, curses.COLOR_GREEN, 0)
2323

2424
textbox = DialogBox(1, 4,
25-
14, 4,
25+
15, 5,
2626
title="Tim-ats-d",
2727
# title_colors_pair_nb=3,
2828
end_indicator="o")
@@ -36,20 +36,22 @@ def main(win):
3636
}
3737

3838
def display_position(self: DialogBox,
39+
win,
3940
char: str,
4041
char_index: int):
4142
win.addstr(0, 0, str(self.dimensions))
4243
win.refresh()
4344

4445
def display_char_info(self: DialogBox,
46+
win,
4547
char: str,
4648
char_index: str):
4749
win.addstr(5, 0, char + str(char_index))
4850
win.refresh()
4951

5052
for reply in text:
51-
textbox.char_by_char(win,
52-
reply,
53+
textbox.char_by_char(reply,
54+
win,
5355
callbacks=(display_position, display_char_info),
5456
text_attr=(curses.A_ITALIC, curses.A_BOLD),
5557
words_attr=special_words)

visualdialog/box.py

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,46 @@
66
import curses
77
import curses.textpad
88
import functools
9-
from typing import Callable, List, Literal, Sequence, Tuple, Union
9+
from typing import (Any, Callable, List, Literal, NoReturn, Sequence, Tuple,
10+
Union)
1011

1112
from .error import PanicError, ValueNotInBound
12-
from .type import CursesKey, CursesTextAttribute, CursesTextAttributes, CursesWindow
13+
from .type import (CursesKey, CursesTextAttribute, CursesTextAttributes,
14+
CursesWindow)
1315
from .utils import TextAttr, to_tuple
1416

1517

16-
def value_checker(initializer: Callable) -> Callable:
17-
"""A decorator which ensures that correct values are passed to
18-
:class:`BaseTextBox` initializer to avoid unexpected behavior.
18+
class BoundHeight:
19+
"""A descriptor which ensures that correct value is setted to
20+
``BaseTextBox.height`` to avoid unexpected behavior.
1921
"""
20-
def __init__(self,
21-
pos_x, pos_y,
22-
height, width,
23-
title,
24-
*args, **kwargs):
25-
minimum_box_width = 4
22+
def __get__(self, obj: "BaseTextBox", objtype=None):
23+
return obj._height
2624

25+
def __set__(self, obj: "BaseTextBox", value: int) -> NoReturn:
2726
title_box_borders_total_height = 5
28-
minimum_box_height = len(title) + title_box_borders_total_height
27+
minimum_box_height = len(obj.title) + title_box_borders_total_height
28+
29+
if value < minimum_box_height:
30+
raise ValueNotInBound("height must be more than title length + 5")
31+
else:
32+
obj._height = value
33+
2934

30-
if width < minimum_box_width:
31-
raise ValueNotInBound(f"width must be less than {minimum_box_width}")
32-
elif height < minimum_box_height:
33-
raise ValueNotInBound("height must be less than len(title) + 5")
35+
class BoundWidth:
36+
"""A descriptor which ensures that correct value is setted to
37+
``BaseTextBox.width`` to avoid unexpected behavior.
38+
"""
39+
def __get__(self, obj: "BaseTextBox", objtype=None):
40+
return obj._width
3441

35-
initializer(self,
36-
pos_x, pos_y,
37-
height, width,
38-
title,
39-
*args, **kwargs)
42+
def __set__(self, obj: "BaseTextBox", value: int) -> NoReturn:
43+
minimum_box_width = 4
4044

41-
return __init__
45+
if value < minimum_box_width:
46+
raise ValueNotInBound(f"width must be more than {minimum_box_width}")
47+
else:
48+
obj._width = value
4249

4350

4451
class BaseTextBox:
@@ -95,7 +102,8 @@ class BaseTextBox:
95102
:ivar panic_keys: initial value: []:
96103
List of accepted key to raise :exc:`PanicError`.
97104
"""
98-
@value_checker
105+
height, width = BoundHeight(), BoundWidth()
106+
99107
def __init__(
100108
self,
101109
pos_x: int,
@@ -109,9 +117,6 @@ def __init__(
109117
downtime_chars: Sequence[str] = (",", ".", ":", ";", "!", "?"),
110118
downtime_chars_delay: int = 600):
111119
"""Initializes instance of :class:`BaseTextBox`."""
112-
self.pos_x, self.pos_y = pos_x, pos_y
113-
self.height, self.width = height - 1, width - 1
114-
115120
self.title_offsetting_y = 2 if title else 0
116121

117122
# Compensation for left and upper borders of text box.
@@ -127,6 +132,9 @@ def __init__(
127132
self.title_colors = curses.color_pair(title_colors_pair_nb)
128133
self.title_text_attr = to_tuple(title_text_attr)
129134

135+
self.pos_x, self.pos_y = pos_x, pos_y
136+
self.height, self.width = height - 1, width - 1
137+
130138
self.downtime_chars = downtime_chars
131139
self.downtime_chars_delay = downtime_chars_delay
132140

visualdialog/dialog.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,8 +338,7 @@ def _one_by_one(self,
338338
text_attr = to_tuple(text_attr)
339339
colors_pair = curses.color_pair(colors_pair_nb)
340340

341-
wrapped_text = self.text_wrapper.wrap(text)
342-
wrapped_text = chunked(wrapped_text, self.nb_lines_max)
341+
wrapped_text = chunked(self.text_wrapper.wrap(text), self.nb_lines_max)
343342

344343
if flash_screen:
345344
curses.flash()
@@ -429,4 +428,4 @@ def _write_word(self,
429428
+ rand_delay)
430429

431430
for callback in callbacks:
432-
callback(self, win, word)
431+
callback(self, win, word)

visualdialog/skin.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
from typing import Dict, Literal, NamedTuple
3+
4+
5+
TextBoxSkin = Dict[Literal[str], str]
6+
7+
8+
classic: TextBoxSkin = {
9+
"upper_corner": "+",
10+
"side": "|"
11+
}
12+
13+
class Skin(NamedTuple):
14+
upper_corner: str
15+
lower_corner: str = "%"
16+
17+
18+
p = Skin("t")._asdict()
19+
classic.update(p)
20+
print(classic)

0 commit comments

Comments
 (0)