Skip to content

Commit

Permalink
Added three new border types.
Browse files Browse the repository at this point in the history
Improved text input example.
Fix pad width in text pad after text deletion.
  • Loading branch information
salt-die committed Oct 29, 2023
1 parent a682627 commit 9155692
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 42 deletions.
2 changes: 1 addition & 1 deletion batgrl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
batgrl - badass terminal graphics library
"""

__version__ = "0.30.0"
__version__ = "0.30.1"
17 changes: 15 additions & 2 deletions batgrl/gadgets/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@
"heavy_dashed",
"heavy_dashed_2",
"heavy_dashed_3",
"near",
"mcgugan_tall",
"mcgugan_wide",
]
"""Border styles for :meth:`batgrl.text_gadget.Text.add_border`."""

Expand Down Expand Up @@ -319,6 +322,9 @@ def add_border(
"heavy_dashed": "┏┓╏╏╍╍┗┛",
"heavy_dashed_2": "┏┓┇┇┅┅┗┛",
"heavy_dashed_3": "┏┓┋┋┉┉┗┛",
"near": " ▕▏▁▔ ",
"mcgugan_tall": "▕▏▕▏▔▁▕▏",
"mcgugan_wide": "▁▁▏▕▁▔▔▔",
}
tl, tr, lv, rv, th, bh, bl, br = BORDER_STYLES[style]

Expand All @@ -333,8 +339,15 @@ def add_border(
canvas[-1, -1] = style_char(br, bold=bold)

if color_pair is not None:
self.colors[[0, -1]] = color_pair
self.colors[:, [0, -1]] = color_pair
if style == "mcgugan_tall":
self.colors[[0, -1], :, :3] = color_pair[:3]
self.colors[:, [0, -1]] = color_pair
elif style == "mcgugan_wide":
self.colors[[0, -1]] = color_pair
self.colors[:, [0, -1], :3] = color_pair[:3]
else:
self.colors[[0, -1]] = color_pair
self.colors[:, [0, -1]] = color_pair

def add_syntax_highlighting(
self, lexer: Lexer | None = None, style: Style = Neptune
Expand Down
17 changes: 6 additions & 11 deletions batgrl/gadgets/text_pad.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,12 +234,7 @@ def update_theme(self):

def on_size(self):
super().on_size()
port_width = self._scroll_view.port_width
if port_width > self._pad.width:
self._pad.width = port_width
elif port_width < self._pad.width:
self._pad.width = max(port_width, max(self._line_lengths) + 1)

self._pad.width = max(self._scroll_view.port_width, max(self._line_lengths) + 1)
self._highlight_selection()

def on_focus(self):
Expand Down Expand Up @@ -316,10 +311,11 @@ def cursor(self, cursor: Point):
self._scroll_view._scroll_up(-rel_y)

max_x = self._scroll_view.port_width - 1
if (rel_x := x + self._pad.x) > max_x:
rel_x = x + self._pad.x
if rel_x > max_x:
self._scroll_view._scroll_right(rel_x - max_x)
elif rel_x < 0:
self._scroll_view._scroll_left(-rel_x)
self._scroll_view._scroll_right(rel_x)

if self.is_selecting:
self._selection_end = self.cursor
Expand Down Expand Up @@ -411,8 +407,6 @@ def _del_text(self, start: Point, end: Point):

len_end = ll[ey] - ex
len_start = ll[sy] = sx + len_end
if len_start >= pad.width:
pad.width = len_start + 1

canvas[sy, sx:len_start] = canvas[ey, ex : ex + len_end]
canvas[sy, len_start:] = pad.default_char
Expand All @@ -422,6 +416,7 @@ def _del_text(self, start: Point, end: Point):
pad.height -= ey - sy

del ll[sy + 1 : ey + 1]
pad.width = max(max(ll) + 1, self._scroll_view.port_width)

self.unselect()
self._last_x = None
Expand Down Expand Up @@ -830,7 +825,7 @@ def _ascii(self, key):

def on_key(self, key_event: KeyEvent) -> bool | None:
if not self.is_focused:
return
return super().on_key(key_event)

if key_event.mods == Mods.NO_MODS and len(key_event.key) == 1:
self._ascii(key_event.key)
Expand Down
7 changes: 4 additions & 3 deletions batgrl/gadgets/textbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,9 @@ def cursor(self, cursor: int):
self._placeholder_gadget.is_enabled = False

max_x = self.width - 1
if (rel_x := cursor + self._box.x) > max_x:
self._box.x += max_x - rel_x
rel_x = cursor + self._box.x
if rel_x > max_x:
self._box.x -= rel_x - max_x
elif rel_x < 0:
self._box.x -= rel_x

Expand Down Expand Up @@ -713,7 +714,7 @@ def _ascii(self, key):

def on_key(self, key_event: KeyEvent) -> bool | None:
if not self.is_focused:
return
return super().on_key(key_event)

if key_event.mods == Mods.NO_MODS and len(key_event.key) == 1:
self._ascii(key_event.key)
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/borders.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

class BordersApp(App):
async def on_start(self):
grid_layout = GridLayout(grid_columns=7, grid_rows=2)
grid_layout = GridLayout(grid_columns=6, grid_rows=3)
for border, color in zip(Border.__args__, border_colors):
gadget = Text(size=(3, 17))
gadget.add_border(border, bold=True, color_pair=color)
Expand Down
67 changes: 43 additions & 24 deletions examples/basic/text_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
from batgrl.gadgets.text import Text
from batgrl.gadgets.text_pad import TextPad
from batgrl.gadgets.textbox import Textbox
from batgrl.gadgets.window import Window

PRIMARY = DEFAULT_COLOR_THEME.primary
SECONDARY = DEFAULT_COLOR_THEME.data_table_selected
ACTIVE_BORDER = *DEFAULT_COLOR_THEME.titlebar_normal.fg_color, *SECONDARY.bg_color
INACTIVE_BORDER = *DEFAULT_COLOR_THEME.titlebar_inactive.fg_color, *SECONDARY.bg_color

JABBERWOCKY = """
Jabberwocky
Expand Down Expand Up @@ -46,37 +50,52 @@
"""


class TextPadApp(App):
async def on_start(self):
window = Window(pos=(5, 5), size=(15, 30), title="Textpad")
tp = TextPad()
window.view = tp
tp.text = JABBERWOCKY
class BorderOnFocus:
def on_focus(self):
super().on_focus()
self.parent.add_border("mcgugan_wide", bold=True, color_pair=ACTIVE_BORDER)

def on_blur(self):
super().on_blur()
self.parent.add_border("mcgugan_wide", bold=False, color_pair=INACTIVE_BORDER)


class BorderedOnFocusTextbox(BorderOnFocus, Textbox):
...

# `enter_callback` expects a callable with the textbox as the only argument.
def enter_callback(textbox):
textbox.text = ""

textbox = Textbox(
class BorderedOnFocusTextPad(BorderOnFocus, TextPad):
...


class TextPadApp(App):
async def on_start(self):
textbox = BorderedOnFocusTextbox(
pos=(1, 3),
size=(1, 31),
enter_callback=enter_callback,
enter_callback=lambda box: setattr(box, "text", ""),
placeholder="Search...",
max_chars=50,
)

border = Text(
pos=(1, 0),
size=(3, 35),
pos_hint={"x_hint": 0.5, "anchor": "top"},
default_color_pair=DEFAULT_COLOR_THEME.textbox_primary,
textbox_border = Text(pos=(2, 2), size=(3, 35), default_color_pair=PRIMARY)
textbox_border.add_gadget(textbox)
textbox_border.add_str("🔍", pos=(1, 1))

text_pad = BorderedOnFocusTextPad(pos=(1, 1), size=(13, 33))
text_pad.text = JABBERWOCKY
text_pad_border = Text(pos=(6, 2), size=(15, 35), default_color_pair=PRIMARY)
text_pad_border.add_gadget(text_pad)

labels = Text(
size=(22, 39),
pos_hint={"y_hint": 0.5, "x_hint": 0.5},
default_color_pair=SECONDARY,
)
border.add_border()
border.add_str("🔍", pos=(1, 1))
border.add_gadget(textbox)

self.add_gadgets(window, border)
labels.add_str("__Textbox__", pos=(1, 16), markdown=True)
labels.add_str("__Text Pad__", pos=(5, 16), markdown=True)
labels.add_gadgets(textbox_border, text_pad_border)
self.add_gadget(labels)


if __name__ == "__main__":
TextPadApp().run()
TextPadApp(title="Text Input Example", background_color_pair=PRIMARY).run()

0 comments on commit 9155692

Please sign in to comment.