Skip to content

Instantly share code, notes, and snippets.

@jerlendds
Last active January 28, 2022 19:08
Show Gist options
  • Select an option

  • Save jerlendds/bf786d3f5b460f75f3b0b8faa2e6538f to your computer and use it in GitHub Desktop.

Select an option

Save jerlendds/bf786d3f5b460f75f3b0b8faa2e6538f to your computer and use it in GitHub Desktop.
#!/usr/bin/python
# -*- coding: utf-8 -*-
# tuic - textual user interface controller
# Experiments With Curses | 2021, July 17
# I'm currently working on writing a simple TUI for a web crawler
# that supports scraping and analyzing anything you want to write a plugin for.
# This file creates two windows and draws boxes around the created windows
# The windows respond to the terminal resizing and the terminal display will be redrawn to reflect the new size
# KNOWN ISSUES: When terminal size becomes too small the program crashes
import curses as c
VERSION_STRING = "0.1.6"
def draw_win_border(win: c.newwin, height: int, width: int,
title: str = 'Active scrapers', b_color: int = 4,
t_color: int = 1):
hort = '━'
vert = '┃'
tr = '┓'
br = '┛'
tl = '┏'
bl = '┗'
win.clear()
win.scrollok(0)
border_color_pair = b_color
win.addstr(0, 2, title, c.color_pair(t_color))
try:
win.addstr(height - 3, 2, "Height:", c.color_pair(t_color))
win.addstr(height - 3, 10, f"{height}", c.color_pair(5))
win.addstr(height - 4, 2, "Width:", c.color_pair(t_color))
win.addstr(height - 4, 9, f"{width}", c.color_pair(5))
except c.error:
pass
for pnt in range(0, width):
try:
if pnt == win.getmaxyx()[1] - 1:
pass
elif pnt not in range(0, len(title) + 3):
win.addch(0, pnt, hort, c.color_pair(border_color_pair))
if pnt == 0:
pass
elif pnt == width:
pass
else:
win.addch(height - 1, pnt, hort, c.color_pair(border_color_pair))
except c.error:
pass
for pnt in range(0, height):
try:
if pnt == 0:
win.addch(pnt, 0, tl, c.color_pair(border_color_pair))
win.addch(pnt, win.getmaxyx()[1] - 1, tr, c.color_pair(border_color_pair))
elif pnt == height - 1:
win.addch(pnt, 0, bl, c.color_pair(border_color_pair))
win.addch(pnt, win.getmaxyx()[1] - 1, br, c.color_pair(border_color_pair))
else:
win.addch(pnt, 0, vert, c.color_pair(border_color_pair))
win.addch(pnt, win.getmaxyx()[1] - 1, vert, c.color_pair(border_color_pair))
except c.error:
pass
win.refresh()
def create_win(**kwargs) -> c.newwin:
"""Create new curses window from dict
Parameters
----------
kwargs
dict containing keys: height (or nlines), width (or ncols), begin_y (or start_y), begin_x (or start_x)
Returns
-------
_CursesWindow object
"""
win_conf = {}
for key, value in kwargs.items():
if key == "height" or key == "nlines":
win_conf["nlines"] = value
elif key == "width" or key == "ncols":
win_conf["ncols"] = value
elif key == "begin_y" or key == "start_y":
win_conf["begin_y"] = value
elif key == "begin_x" or key == "start_x":
win_conf["begin_x"] = value
elif key == "parent_win":
win_conf['parent_win'] = value
else:
raise KeyError
nlines = win_conf.get('nlines')
ncols = win_conf.get('ncols')
begin_y = win_conf.get('begin_y')
begin_x = win_conf.get('begin_x')
win = c.newwin(nlines, ncols, begin_y, begin_x)
if win_conf.get('parent_win'):
win1 = c.newwin(nlines - 2, ncols - 2, begin_y, begin_x + 1)
win.refresh()
win1.refresh()
return [win, win1]
win.refresh()
return win
def constrain_win_size(win: c.newwin, min_value: int = 11, constrain_type: str = 'height'):
"""Print an error when the terminal does not meet the requested dimensions
Parameters
----------
win
expects a _CursesWindow object, typically the stdscr
min_value
constraint value
constrain_type
constraint axis can be either 'height' or 'width'
Returns
-------
None
"""
try:
g['height'], g['width'] = win.getmaxyx()
if g.get(constrain_type) <= min_value:
while True:
win.addstr(0, 0, 'Error: 12 is minimum terminal height\t')
win.addstr(1, 0, f'Current height: {g.get("height")}\t')
if c.KEY_RESIZE:
win.refresh()
g['height'], g['width'] = win.getmaxyx()
if g.get(constrain_type) > min_value:
break
except c.error:
pass
g = {}
def main(stdscr: c.newwin): # noqa
c.curs_set(0)
c.init_pair(1, c.COLOR_CYAN, c.COLOR_BLACK)
c.init_pair(2, c.COLOR_GREEN, c.COLOR_BLACK)
c.init_pair(3, c.COLOR_BLUE, c.COLOR_BLACK)
c.init_pair(4, c.COLOR_WHITE, c.COLOR_BLACK)
c.init_pair(5, c.COLOR_MAGENTA, c.COLOR_BLACK)
c.init_pair(6, 255, 2)
c.init_pair(7, c.COLOR_BLACK, c.COLOR_WHITE)
c.init_pair(9, c.COLOR_BLACK, c.COLOR_GREEN)
while True:
constrain_win_size(stdscr)
shell_conf = {
"height": g.get('height'),
"width": int(g.get('width') / 3 * 2),
"begin_y": 0,
"begin_x": 0,
"parent_win": True
}
sess_conf = {
"height": g.get('height'),
"width": int(g.get('width') / 3),
"begin_y": 0,
"begin_x": int(g.get('width') / 3 * 2),
"parent_win": False
}
shell_win_set = create_win(**shell_conf)
shell_win_b = shell_win_set[0]
shell_win = shell_win_set[1]
sess_win = create_win(**sess_conf)
draw_win_border(win=shell_win_b, height=g.get('height') - 6, width=g.get('width'),
title=f"running u-serp {VERSION_STRING}", t_color=2)
draw_win_border(win=sess_win, height=g.get('height'), width=g.get('width'))
shell_win.addstr(1, 1, "[STATUS]", c.color_pair(5))
shell_win.addstr(1, 10, "welcome to an experiment with curses", c.color_pair(2))
shell_win.addstr(3, 10, "- github/jerlendds", c.color_pair(2))
shell_win.getch()
sess_win.getch()
if __name__ == "__main__":
c.wrapper(main)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment