Added meter class to create percentage meters and fixed input io blocking errors when printing

pull/27/head
aristocratos 2020-07-03 04:01:31 +02:00
parent bea8bf084a
commit bd6c2ffed3
1 changed files with 321 additions and 188 deletions

509
bpytop
View File

@ -289,15 +289,20 @@ class Key:
""".list = Input queue | .new = Input threading event | .reader = Input reader thread | .start() = Start input reader | .stop() = Stop input reader""" """.list = Input queue | .new = Input threading event | .reader = Input reader thread | .start() = Start input reader | .stop() = Stop input reader"""
list: List[str] = [] list: List[str] = []
new = threading.Event() new = threading.Event()
idle = threading.Event()
idle.set()
stopping: bool = False stopping: bool = False
started: bool = False
reader: threading.Thread
@classmethod @classmethod
def start(cls): def start(cls):
cls.stopping = False cls.stopping = False
cls.reader = threading.Thread(target=get_key) cls.reader = threading.Thread(target=get_key)
cls.reader.start() cls.reader.start()
cls.started = True
@classmethod @classmethod
def stop(cls): def stop(cls):
if cls.reader.is_alive(): if cls.started and cls.reader.is_alive():
cls.stopping = True cls.stopping = True
try: try:
cls.reader.join() cls.reader.join()
@ -305,11 +310,14 @@ class Key:
pass pass
class Color: class Color:
'''self.__init__ accepts 6 digit hexadecimal: string "#RRGGBB", 2 digit hexadecimal: string "#FF" and decimal RGB "0-255 0-255 0-255" as a string.\n '''Holds representations for a 24-bit color
self.__init__ also accepts depth="fg" or "bg" | default=bool\n __init__(color, depth="fg", default=False)
self.__call__(*args) converts arguments to a string and apply color\n -- color accepts 6 digit hexadecimal: string "#RRGGBB", 2 digit hexadecimal: string "#FF" or decimal RGB "255 255 255" as a string.
self.__str__ returns escape sequence to set color. __iter__ returns iteration over red, green and blue in integer values of 0-255.\n -- depth accepts "fg" or "bg"
Values: .hex: str | .dec: Tuple[int] | .red: int | .green: int | .blue: int | .depth: str | .escape: str\n __call__(*args) converts arguments to a string and apply color
__str__ returns escape sequence to set color
__iter__ returns iteration over red, green and blue in integer values of 0-255.
* Values: .hex: str | .dec: Tuple[int, int, int] | .red: int | .green: int | .blue: int | .depth: str | .escape: str
''' '''
hex: str; dec: Tuple[int, int, int]; red: int; green: int; blue: int; depth: str; escape: str; default: bool hex: str; dec: Tuple[int, int, int]; red: int; green: int; blue: int; depth: str; escape: str; default: bool
@ -318,11 +326,10 @@ class Color:
self.default = default self.default = default
try: try:
if not color: if not color:
if depth != "bg" and not default: raise ValueError("No RGB values given") self.dec = (-1, -1, -1)
self.dec = (0, 0, 0)
self.hex = "" self.hex = ""
self.red = self.green = self.blue = 0 self.red = self.green = self.blue = -1
self.escape = "\033[49m" self.escape = "\033[49m" if depth == "bg" and default else ""
return return
elif color.startswith("#"): elif color.startswith("#"):
@ -370,44 +377,184 @@ class Color:
if len(args) == 0: return "" if len(args) == 0: return ""
return f'{self.escape}{"".join(map(str, args))}{getattr(Term, self.depth)}' return f'{self.escape}{"".join(map(str, args))}{getattr(Term, self.depth)}'
@staticmethod
def fg(h_r: Union[str, int], g: int = 0, b: int = 0) -> str:
"""Returns escape sequence to set foreground color, accepts either 6 digit hexadecimal: "#RRGGBB", 2 digit hexadecimal: "#FF" or decimal RGB: 0-255, 0-255, 0-255"""
color: str = ""
if isinstance(h_r, int): #* Check for decimal RGB
color = f'\033[38;2;{h_r};{g};{b}m'
else: #* Check for 2 or 6 digit hexadecimal RGB
if h_r[0] == "#": h_r = h_r[1:]
try:
if len(h_r) == 2:
c = int(h_r, base=16)
color = f'\033[38;2;{c};{c};{c}m'
elif len(h_r) == 6:
color = f'\033[38;2;{int(h_r[0:2], base=16)};{int(h_r[2:4], base=16)};{int(h_r[4:6], base=16)}m'
except ValueError:
pass
return color
@staticmethod
def bg(h_r: Union[str, int], g: int = 0, b: int = 0) -> str:
"""Returns escape sequence to set background color, accepts either 6 digit hexadecimal: "#RRGGBB", 2 digit hexadecimal: "#FF" or decimal RGB: 0-255, 0-255, 0-255"""
color: str = ""
if isinstance(h_r, int): #* Check for decimal RGB
color = f'\033[48;2;{h_r};{g};{b}m'
else: #* Check for 2 or 6 digit hexadecimal RGB
if h_r[0] == "#": h_r = h_r[1:]
try:
if len(h_r) == 2:
c = int(h_r, base=16)
color = f'\033[48;2;{c};{c};{c}m'
elif len(h_r) == 6:
color = f'\033[48;2;{int(h_r[0:2], base=16)};{int(h_r[2:4], base=16)};{int(h_r[4:6], base=16)}m'
except ValueError:
pass
return color
class Theme: class Theme:
'''__init__ accepts a dict containing { "color_element" : "color" } , errors defaults to default theme color''' '''__init__ accepts a dict containing { "color_element" : "color" }'''
main_bg = main_fg = title = hi_fg = selected_bg = selected_fg = inactive_fg = proc_misc = cpu_box = mem_box = net_box = proc_box = div_line = temp_start = temp_mid = temp_end = cpu_start = cpu_mid = cpu_end = free_start = free_mid = free_end = cached_start = cached_mid = cached_end = available_start = available_mid = available_end = used_start = used_mid = used_end = download_start = download_mid = download_end = upload_start = upload_mid = upload_end = NotImplemented main_bg = main_fg = title = hi_fg = selected_bg = selected_fg = inactive_fg = proc_misc = cpu_box = mem_box = net_box = proc_box = div_line = temp_start = temp_mid = temp_end = cpu_start = cpu_mid = cpu_end = free_start = free_mid = free_end = cached_start = cached_mid = cached_end = available_start = available_mid = available_end = used_start = used_mid = used_end = download_start = download_mid = download_end = upload_start = upload_mid = upload_end = NotImplemented
gradient: Dict[str, List[str]] = {
"temp" : [],
"cpu" : [],
"free" : [],
"cached" : [],
"available" : [],
"used" : [],
"download" : [],
"upload" : []
}
def __init__(self, tdict: Dict[str, str]): def __init__(self, tdict: Dict[str, str]):
for item, value in tdict.items(): #* Get key names from DEFAULT_THEME dict to not leave any color unset if missing from theme dict
if hasattr(self, item): for item, value in DEFAULT_THEME.items():
default = False if item not in ["main_fg", "main_bg"] else True default = False if item not in ["main_fg", "main_bg"] else True
depth = "fg" if item not in ["main_bg", "selected_bg"] else "bg" depth = "fg" if item not in ["main_bg", "selected_bg"] else "bg"
if item in tdict.keys():
setattr(self, item, Color(tdict[item], depth=depth, default=default))
else:
setattr(self, item, Color(value, depth=depth, default=default)) setattr(self, item, Color(value, depth=depth, default=default))
if getattr(self, item).escape == "": #* Create color gradients from one, two or three colors, 101 values
setattr(self, item, Color(DEFAULT_THEME[item], depth=depth, default=default)) rgb: Dict[str, Tuple[int, int, int]]
colors: List[Tuple[int, ...]]
rgb_check: List[int]
for name in self.gradient.keys():
rgb = { "start" : getattr(self, f'{name}_start').dec, "mid" : getattr(self, f'{name}_mid').dec, "end" : getattr(self, f'{name}_end').dec }
colors = [ getattr(self, f'{name}_start') ]
if rgb["end"][0] >= 0:
r = 50 if rgb["mid"][0] >= 0 else 100
for first, second in ["start", "mid" if r == 50 else "end"], ["mid", "end"]:
for i in range(r):
rgb_check = []
for n in range(3):
rgb_check += [rgb[first][n] + i * (rgb[second][n] - rgb[first][n]) // r]
for n, ch in enumerate(rgb_check):
if ch > 255: rgb_check[n] = 255
elif ch < 0: rgb_check[n] = 0
colors += [tuple(rgb_check)]
if r == 100:
break
for color in colors:
self.gradient[name] += [Color.fg(*color)] # pylint: disable=no-value-for-parameter
else:
c = Color.fg(*rgb["start"])
for _ in range(100):
self.gradient[name] += [c]
#* Set terminal colors
Term.fg, Term.bg = self.main_fg, self.main_bg Term.fg, Term.bg = self.main_fg, self.main_bg
print(self.main_fg, self.main_bg) #* Set terminal colors print(self.main_fg, self.main_bg)
class Banner:
'''Holds the bpytop banner, .draw(line=, [col=0], [center=False], [now=False])'''
out: List[str] = []
c_color: str = ""
length: int = 0
if not out:
for num, (color, line) in enumerate(BANNER_SRC.items()):
if len(line) > length: length = len(line)
out += [""]
line_color = Color.fg(color)
line_dark = Color.fg(f'#{80 - num * 6}')
for letter in line:
if letter == "█" and c_color != line_color:
c_color = line_color
out[num] += line_color
elif letter == " ":
letter = f'{Mv.r(1)}'
elif letter != "█" and c_color != line_dark:
c_color = line_dark
out[num] += line_dark
out[num] += letter
@classmethod
def draw(cls, line: int, col: int = 0, center: bool = False, now: bool = False):
out: str = ""
if center: col = Term.width // 2 - cls.length // 2
for n, o in enumerate(cls.out):
out += f'{Mv.to(line + n, col)}{o}'
out += f'{Term.fg}'
if now: print(out)
else: return out
class Draw: class Draw:
'''Holds the draw buffer\n '''Holds the draw buffer and manages IO blocking queue
Add to buffer: .buffer(name, *args, append=False, now=False)\n * .buffer([+]name[!], *args, append=False, now=False) : Add *args to buffer
Print buffer: .out(clear=False)\n * - Adding "+" prefix to name sets append to True and appends to name's current string
* - Adding "!" suffix to name sets now to True and print name's current string
* .out(clear=False) : Print all strings in buffer, clear=True clear all buffers after
* .now(*args) : Prints all arguments as a string
''' '''
strings: Dict[str, str] = {} strings: Dict[str, str] = {}
last_screen: str = "" last_screen: str = ""
idle = threading.Event()
idle.set()
@classmethod
def now(cls, *args):
'''Print to screen'''
Key.idle.wait()
try:
print(*args)
except BlockingIOError:
#pass
cls.idle.clear()
Key.idle.wait()
print(*args)
cls.idle.set()
print("Error!")
@classmethod @classmethod
def buffer(cls, name: str, *args, append: bool = False, now: bool = False): def buffer(cls, name: str, *args, append: bool = False, now: bool = False):
string: str = "" string: str = ""
if name.startswith("+"):
name = name.lstrip("+")
append = True
if name.endswith("!"):
name = name.rstrip("!")
now = True
if name == "": name = "_null"
if args: string = "".join(map(str, args)) if args: string = "".join(map(str, args))
if name not in cls.strings or not append: cls.strings[name] = "" if name not in cls.strings or not append: cls.strings[name] = ""
cls.strings[name] += string cls.strings[name] += string
if now: print(string) if now: cls.now(string)
@classmethod @classmethod
def out(cls, clear = False): def out(cls, clear = False):
cls.last_screen = "".join(cls.strings.values()) cls.last_screen = "".join(cls.strings.values())
if clear: cls.strings = {} if clear: cls.strings = {}
print(cls.last_screen) cls.now(cls.last_screen)
class Symbol: class Symbol:
h_line: str = "─" h_line: str = "─"
@ -434,6 +581,7 @@ class Symbol:
3.0 : "⠇", 3.1 : "⠏", 3.2 : "⠟", 3.3 : "⠿", 3.4 : "⢿", 3.0 : "⠇", 3.1 : "⠏", 3.2 : "⠟", 3.3 : "⠿", 3.4 : "⢿",
4.0 : "⡇", 4.1 : "⡏", 4.2 : "⡟", 4.3 : "⡿", 4.4 : "⣿" 4.0 : "⡇", 4.1 : "⡏", 4.2 : "⡟", 4.3 : "⡿", 4.4 : "⣿"
} }
meter: str = "■"
class Graphs: class Graphs:
'''Holds all graph objects and dicts for dynamically created graphs''' '''Holds all graph objects and dicts for dynamically created graphs'''
@ -445,17 +593,7 @@ class Graphs:
detailed_mem: object = None detailed_mem: object = None
pid_cpu: Dict[int, object] = {} pid_cpu: Dict[int, object] = {}
class Meters:
'''Holds created meters to reuse instead of recreating meters of past values'''
cpu: Dict[int, str] = {}
mem_used: Dict[int, str] = {}
mem_available: Dict[int, str] = {}
mem_cached: Dict[int, str] = {}
mem_free: Dict[int, str] = {}
swap_used: Dict[int, str] = {}
swap_free: Dict[int, str] = {}
disks_used: Dict[int, str] = {}
disks_free: Dict[int, str] = {}
class Box: class Box:
'''Box object with all needed attributes for create_box() function''' '''Box object with all needed attributes for create_box() function'''
@ -641,69 +779,45 @@ def save_config(path: str, conf: Config):
except Exception as e: except Exception as e:
errlog.exception(str(e)) errlog.exception(str(e))
def fg(h_r: Union[str, int], g: int = 0, b: int = 0) -> str:
"""Returns escape sequence to set foreground color, accepts either 6 digit hexadecimal: "#RRGGBB", 2 digit hexadecimal: "#FF" or decimal RGB: 0-255, 0-255, 0-255"""
color: str = ""
if isinstance(h_r, int): #* Check for decimal RGB
color = f'\033[38;2;{h_r};{g};{b}m'
else: #* Check for 2 or 6 digit hexadecimal RGB
if h_r[0] == "#": h_r = h_r[1:]
try:
if len(h_r) == 2:
c = int(h_r, base=16)
color = f'\033[38;2;{c};{c};{c}m'
elif len(h_r) == 6:
color = f'\033[38;2;{int(h_r[0:2], base=16)};{int(h_r[2:4], base=16)};{int(h_r[4:6], base=16)}m'
except ValueError:
pass
return color
def bg(h_r: Union[str, int], g: int = 0, b: int = 0) -> str:
"""Returns escape sequence to set background color, accepts either 6 digit hexadecimal: "#RRGGBB", 2 digit hexadecimal: "#FF" or decimal RGB: 0-255, 0-255, 0-255"""
color: str = ""
if isinstance(h_r, int): #* Check for decimal RGB
color = f'\033[48;2;{h_r};{g};{b}m'
else: #* Check for 2 or 6 digit hexadecimal RGB
if h_r[0] == "#": h_r = h_r[1:]
try:
if len(h_r) == 2:
c = int(h_r, base=16)
color = f'\033[48;2;{c};{c};{c}m'
elif len(h_r) == 6:
color = f'\033[48;2;{int(h_r[0:2], base=16)};{int(h_r[2:4], base=16)};{int(h_r[4:6], base=16)}m'
except ValueError:
pass
return color
def get_key(): def get_key():
"""Get a single key from stdin, convert to readable format and save to keys list""" """Get a single key from stdin, convert to readable format and save to keys list"""
input_key: str = "" input_key: str = ""
clean_key: str = "" clean_key: str = ""
with Raw(sys.stdin): #* Set raw mode try:
with Nonblocking(sys.stdin): #* Set nonblocking mode while not Key.stopping:
while not Key.stopping: #Draw.idle.wait()
if not select([sys.stdin], [], [], 0.1)[0]: #* Wait 100ms for input then restart loop to check for stop signal with Raw(sys.stdin): #* Set raw mode
#with Nonblocking(sys.stdin): #* Set nonblocking mode
if not select([sys.stdin], [], [], 0.1)[0]:
continue continue
Key.idle.clear()
try: try:
input_key = sys.stdin.read(1) #* Read 1 character from stdin input_key += sys.stdin.read(1)
if input_key == "\033": #* Read 3 additional characters if first is escape character if input_key == "\033":
input_key += sys.stdin.read(3) with Nonblocking(sys.stdin): #* Set nonblocking mode
except: input_key += sys.stdin.read(3)
pass except Exception as e:
if input_key == "\033": clean_key = "escape" errlog.exception(f'{e}')
elif input_key == "\n": clean_key = "enter"
elif input_key == "\x7f" or input_key == "\x08": clean_key = "backspace"
elif input_key.isprintable(): clean_key = input_key #* Return character if input key is printable if input_key == "\033": clean_key = "escape"
elif input_key.startswith("\n"): clean_key = "enter"
elif input_key.startswith("\x7f") or input_key.startswith("\x08"): clean_key = "backspace"
elif input_key.isalnum(): clean_key = input_key
else: errlog.info(f'Pressed key: {repr(input_key)}')
if clean_key: if clean_key:
Key.list.append(clean_key) #* Store keys in input queue for later processing Key.list.append(clean_key) #* Store keys in input queue for later processing
clean_key = "" clean_key = ""
Key.new.set() #* Set threading event to interrupt main thread sleep Key.new.set() #* Set threading event to interrupt main thread sleep
input_key = "" input_key = ""
sys.stdin.read(100) #* Clear stdin with Nonblocking(sys.stdin):
sys.stdin.read(10) #* Clear stdin
Key.idle.set()
except Exception as e:
errlog.exception(f'{e}')
clean_quit(1)
def now_sleeping(signum, frame): def now_sleeping(signum, frame):
"""Reset terminal settings and stop background input read before putting to sleep""" """Reset terminal settings and stop background input read before putting to sleep"""
@ -724,7 +838,8 @@ def clean_quit(errcode: int = 0):
"""Reset terminal settings, save settings to config and stop background input read before quitting""" """Reset terminal settings, save settings to config and stop background input read before quitting"""
Key.stop() Key.stop()
save_config(CONFIG_FILE, config) save_config(CONFIG_FILE, config)
print(Term.clear, Term.normal_screen, Term.show_cursor) #print(Term.clear, Term.normal_screen, Term.show_cursor)
Term.echo(True)
raise SystemExit(errcode) raise SystemExit(errcode)
def calc_sizes(): def calc_sizes():
@ -840,74 +955,85 @@ def draw_bg(now: bool = True):
#* Draw proc box #* Draw proc box
proc_box = create_box(box_object=proc, line_color=theme.proc_box, fill=True) proc_box = create_box(box_object=proc, line_color=theme.proc_box, fill=True)
Draw.buffer("bg", cpu_box, mem_box, net_box, proc_box) Draw.buffer("bg", cpu_box, mem_box, net_box, proc_box, Term.fg)
#? Function dependent classes --------------------------------------------------------------------> #? Function dependent classes -------------------------------------------------------------------->
class Banner: class Meter:
out: List[str] = [] '''Creates a percentage meter
c_color: str = "" __init__(value, width, color_gradient) to create new meter
length: int = 0 __call__(value) to set value and return meter as a string
if not out: __str__ returns last set meter as a string
for num, (color, line) in enumerate(BANNER_SRC.items()): '''
if len(line) > length: length = len(line) out: str = ""
out += [""] color_gradient: List[str]
line_color = fg(color) width: int
line_dark = fg(f'#{80 - num * 6}') saved: Dict[int, str] = {}
for letter in line:
if letter == "█" and c_color != line_color:
c_color = line_color
out[num] += line_color
elif letter == " ":
letter = f'{Mv.r(1)}'
elif letter != "█" and c_color != line_dark:
c_color = line_dark
out[num] += line_dark
out[num] += letter
@classmethod def __init__(self, value: int, width: int, color_gradient: List[str]):
def draw(cls, line: int, col: int = 0, center: bool = False, now: bool = False): self.color_gradient = color_gradient
self.width = width
self.out = self._create(value, width, color_gradient)
self.saved[value] = self.out
def __call__(self, value: int):
if value in self.saved.keys():
self.out = self.saved[value]
else:
self.out = self._create(value, self.width, self.color_gradient)
self.saved[value] = self.out
return self.out
def __str__(self):
return self.out
def __repr__(self):
return repr(self.out)
@staticmethod
def _create(value: int, width: int, color_gradient: List[str], add: bool = False):
if value > 100: value = 100
elif value < 0: value = 100
out: str = "" out: str = ""
if center: col = Term.width // 2 - cls.length // 2 for i in range(1, width + 1):
for n, o in enumerate(cls.out): if value >= round(i * 100 / width):
out += f'{Mv.to(line + n, col)}{o}' out += f'{color_gradient[round(i * 100 / width)]}{Symbol.meter}'
out += f'{Term.fg}' else:
if now: print(out) out += theme.inactive_fg(Symbol.meter * (width + 1 - i))
else: return out break
else:
out += f'{Term.fg}'
return out
class Meters:
cpu: Meter
mem_used: Meter
mem_available: Meter
mem_cached: Meter
mem_free: Meter
swap_used: Meter
swap_free: Meter
disks_used: Meter
disks_free: Meter
#? Main function ---------------------------------------------------------------------------------> #? Main function --------------------------------------------------------------------------------->
def main(): def main():
line: str = "" pass
this_key: str = ""
count: int = 0
while True:
count += 1
print(f'{Mv.to(1,1)}{Fx.b}{blue("Count:")} {count} {lime("Time:")} {time.strftime("%H:%M:%S", time.localtime())}')
print(f'{fg("#ff")} Width: {Term.width} Height: {Term.height} Resized: {Term.resized}')
while Key.list:
Key.new.clear()
this_key = Key.list.pop()
print(f'{Mv.to(2,1)}{fg("#ff9050")}{Fx.b}Last key= {Term.fg}{Fx.ub}{repr(this_key)}{" " * 40}')
if this_key == "backspace":
line = line[:-1]
elif this_key == "enter":
line += "\n"
else:
line += this_key
print(f'{Mv.to(3,1)}{fg("#90ff50")}{Fx.b}Full line= {Term.fg}{Fx.ub}{line}{Fx.bl}| {Fx.ubl}')
if this_key == "q":
clean_quit()
if this_key == "R":
raise Exception("Test ERROR")
if not Key.reader.is_alive():
clean_quit(1)
Key.new.wait(1.0)
#? Init ------------------------------------------------------------------------------------------> #? Init ------------------------------------------------------------------------------------------>
#Key.start() print(Term.alt_screen, Term.clear, Term.hide_cursor)
Term.echo(False)
signal.signal(signal.SIGINT, quit_sigint) #* Ctrl-C
Key.start()
CPU_NAME: str = get_cpu_name() CPU_NAME: str = get_cpu_name()
@ -915,6 +1041,8 @@ config: Config = Config(load_config(CONFIG_FILE))
config.proc_per_core = True config.proc_per_core = True
#config.color_theme = "solarized_dark"
theme: Theme = Theme(load_theme(config.color_theme)) theme: Theme = Theme(load_theme(config.color_theme))
cpu = Box("cpu", height_p=32, width_p=100) cpu = Box("cpu", height_p=32, width_p=100)
@ -930,77 +1058,82 @@ orange = theme.available_end
green = theme.cpu_start green = theme.cpu_start
dfg = theme.main_fg dfg = theme.main_fg
def testing_colors(): def testing_colors():
for item, _ in DEFAULT_THEME.items(): for item, _ in DEFAULT_THEME.items():
Draw.buffer("testing", Fx.b, getattr(theme, item)(f'{item:<20}'), Fx.ub, f'{"hex=" + getattr(theme, item).hex:<20} dec={getattr(theme, item).dec}\n') Draw.buffer("+testing", Fx.b, getattr(theme, item)(f'{item:<20}'), Fx.ub, f'{"hex=" + getattr(theme, item).hex:<20} dec={getattr(theme, item).dec}\n')
Draw.out() Draw.out()
print()
print(theme.temp_start, "Hej!\n")
print(Term.fg, "\nHEJ\n")
print(repr(Term.fg), repr(Term.bg))
quit() def testing_boxes():
calc_sizes()
draw_bg()
Draw.out()
print(Mv.to(35, 1))
def testing_banner(): def testing_banner():
print(Term.normal_screen, Term.alt_screen) Draw.buffer("banner", Banner.draw(18, center=True))
#Key.start()
calc_sizes()
draw_bg()
Draw.buffer("banner", Banner.draw(18, 45))
Draw.out() Draw.out()
print(Mv.to(35, 1)) print(Mv.to(35, 1))
def testing_meter():
Draw.buffer("meters")
for _ in range(10):
Draw.buffer("+meters", "1234567890")
Draw.buffer("+meters", "\n")
korv = Meter(0, Term.width, theme.gradient["cpu"])
quit() for i in range(0,101, 2):
Draw.buffer("+meters", korv(i), "\n")
Draw.out()
# quit() def testing_keyinput():
line: str = ""
# global theme this_key: str = ""
count: int = 0
# path = "/home/gnm/.config/bashtop/themes/" while True:
# for file in os.listdir(path): count += 1
# if file.endswith(".theme"): Draw.buffer("!", f'{Mv.to(1,1)}{Fx.b}{blue("Count:")} {count} {lime("Time:")} {time.strftime("%H:%M:%S", time.localtime())}',
# theme = Theme(load_theme(path + file)) f'{Color.fg("#ff")} Width: {Term.width} Height: {Term.height} Resized: {Term.resized}')
# draw_bg() while Key.list:
# Draw.out() Key.new.clear()
# time.sleep(1) this_key = Key.list.pop()
Draw.buffer("!", f'{Mv.to(2,1)}{Color.fg("#ff9050")}{Fx.b}Last key= {Term.fg}{Fx.ub}{repr(this_key)}{" " * 40}')
#draw_bg() if this_key == "backspace":
#Draw.buffer("banner", Banner.draw(5, center=True)) line = line[:-1]
elif this_key == "enter":
#Draw.out() line += "\n"
else:
# print(f'\n{Fx.b}Terminal Height={Term.height} Width={Term.width}') line += this_key
# total_h = total_w = 0 Draw.buffer("!", f'{Mv.to(3,1)}{Color.fg("#90ff50")}{Fx.b}Full line= {Term.fg}{Fx.ub}{line}{Fx.bl}| {Fx.ubl}')
# for box in boxes: if this_key == "q":
# print(f'\n{getattr(box, "name")} Height={getattr(box, "height")} Width={getattr(box, "width")}') clean_quit()
# total_h += getattr(box, "height") if this_key == "R":
# total_w += getattr(box, "width") raise Exception("Test ERROR")
# print(f'\nTotal Height={cpu.height + net.height + mem.height} Width={net.width + proc.width}') if not Key.reader.is_alive():
#Key.stop() clean_quit(1)
quit() Key.new.wait(1.0)
#testing_colors()
#error_log("/home/gnm/bashtop/misc/error.log")
try: try:
testing_banner() #testing_keyinput()
#testing_banner()
#testing_colors() #testing_colors()
#testing_boxes()
testing_meter()
# Draw.idle.clear()
# Key.idle.wait()
# input(f'{Mv.to(Term.height - 5, 1)}Enter to exit')
# Draw.idle.set()
#time.sleep(2)
except Exception as e: except Exception as e:
errlog.exception(f'{e}') errlog.exception(f'{e}')
clean_quit(1) clean_quit(1)
quit() clean_quit()
if __name__ == "__main__": if __name__ == "__main__":