mirror of https://github.com/aristocratos/bpytop
Added load_config(), save_config(), get_themes() and changed DEFAULT_CONF to a string template
parent
e2de8e7401
commit
bea8bf084a
421
bpytop
421
bpytop
|
@ -19,6 +19,7 @@ import os, sys, time, threading, signal, re, subprocess, logging, logging.handle
|
||||||
from select import select
|
from select import select
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from distutils.util import strtobool
|
from distutils.util import strtobool
|
||||||
|
from string import Template
|
||||||
from typing import List, Set, Dict, Tuple, Optional, Union, Any, Callable, ContextManager, Iterable
|
from typing import List, Set, Dict, Tuple, Optional, Union, Any, Callable, ContextManager, Iterable
|
||||||
|
|
||||||
errors: List[str] = []
|
errors: List[str] = []
|
||||||
|
@ -49,7 +50,7 @@ from functools import partial
|
||||||
|
|
||||||
print: partial = partial(print, sep="", end="", flush=True) #* Setup print function to default to empty seperator and no new line
|
print: partial = partial(print, sep="", end="", flush=True) #* Setup print function to default to empty seperator and no new line
|
||||||
|
|
||||||
#? Variables ------------------------------------------------------------------------------------->
|
#? Constants ------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
BANNER_SRC: Dict[str, str] = {
|
BANNER_SRC: Dict[str, str] = {
|
||||||
"#E62525" : "██████╗ ██████╗ ██╗ ██╗████████╗ ██████╗ ██████╗",
|
"#E62525" : "██████╗ ██████╗ ██╗ ██╗████████╗ ██████╗ ██████╗",
|
||||||
|
@ -62,63 +63,65 @@ BANNER_SRC: Dict[str, str] = {
|
||||||
|
|
||||||
VERSION: str = "0.0.1"
|
VERSION: str = "0.0.1"
|
||||||
|
|
||||||
DEFAULT_CONF: str = f'#? Config file for bpytop v. {VERSION}\n'
|
#* This is the template used to create a new config file
|
||||||
DEFAULT_CONF += '''
|
DEFAULT_CONF: Template = Template(f'#? Config file for bpytop v. {VERSION}' + '''
|
||||||
|
|
||||||
#* Color theme, looks for a .theme file in "~/.config/bpytop/themes" and "~/.config/bpytop/user_themes", "Default" for builtin default theme
|
#* Color theme, looks for a .theme file in "~/.config/bpytop/themes" and "~/.config/bpytop/user_themes", "Default" for builtin default theme
|
||||||
color_theme = "Default"
|
color_theme="$color_theme"
|
||||||
|
|
||||||
#* Update time in milliseconds, increases automatically if set below internal loops processing time, recommended 2000 ms or above for better sample times for graphs
|
#* Update time in milliseconds, increases automatically if set below internal loops processing time, recommended 2000 ms or above for better sample times for graphs
|
||||||
update_ms = 2500
|
update_ms=$update_ms
|
||||||
|
|
||||||
#* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu responsive"
|
#* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu responsive"
|
||||||
#* "cpu lazy" updates sorting over time, "cpu responsive" updates sorting directly
|
#* "cpu lazy" updates sorting over time, "cpu responsive" updates sorting directly
|
||||||
proc_sorting = "cpu lazy"
|
proc_sorting="$proc_sorting"
|
||||||
|
|
||||||
#* Reverse sorting order, True or False
|
#* Reverse sorting order, True or False
|
||||||
proc_reversed = False
|
proc_reversed=$proc_reversed
|
||||||
|
|
||||||
#* Show processes as a tree
|
#* Show processes as a tree
|
||||||
proc_tree = False
|
proc_tree=$proc_tree
|
||||||
|
|
||||||
#* Check cpu temperature, only works if "sensors", "vcgencmd" or "osx-cpu-temp" commands is available
|
#* Check cpu temperature, only works if "sensors", "vcgencmd" or "osx-cpu-temp" commands is available
|
||||||
check_temp = True
|
check_temp=$check_temp
|
||||||
|
|
||||||
#* Draw a clock at top of screen, formatting according to strftime, empty string to disable
|
#* Draw a clock at top of screen, formatting according to strftime, empty string to disable
|
||||||
draw_clock = "%X"
|
draw_clock="$draw_clock"
|
||||||
|
|
||||||
#* Update main ui when menus are showing, set this to false if the menus is flickering too much for comfort
|
#* Update main ui when menus are showing, set this to false if the menus is flickering too much for comfort
|
||||||
background_update = True
|
background_update=$background_update
|
||||||
|
|
||||||
#* Custom cpu model name, empty string to disable
|
#* Custom cpu model name, empty string to disable
|
||||||
custom_cpu_name = ""
|
custom_cpu_name="$custom_cpu_name"
|
||||||
|
|
||||||
#* Show color gradient in process list, True or False
|
#* Show color gradient in process list, True or False
|
||||||
proc_gradient = True
|
proc_gradient=$proc_gradient
|
||||||
|
|
||||||
#* If process cpu usage should be of the core it's running on or usage of the total available cpu power
|
#* If process cpu usage should be of the core it's running on or usage of the total available cpu power
|
||||||
proc_per_core = False
|
proc_per_core=$proc_per_core
|
||||||
|
|
||||||
#* Optional filter for shown disks, should be names of mountpoints, "root" replaces "/", separate multiple values with space
|
#* Optional filter for shown disks, should be names of mountpoints, "root" replaces "/", separate multiple values with space
|
||||||
disks_filter = ""
|
disks_filter="$disks_filter"
|
||||||
|
|
||||||
#* Enable check for new version from github.com/aristocratos/bpytop at start
|
#* Enable check for new version from github.com/aristocratos/bpytop at start
|
||||||
update_check = True
|
update_check=$update_check
|
||||||
|
|
||||||
#* Enable graphs with double the horizontal resolution, increases cpu usage
|
#* Enable graphs with double the horizontal resolution, increases cpu usage
|
||||||
hires_graphs = False
|
hires_graphs=$hires_graphs
|
||||||
|
''')
|
||||||
|
|
||||||
'''
|
CONFIG_DIR: str = f'{Path.home()}/.config/bpytop'
|
||||||
|
if not os.path.isdir(CONFIG_DIR):
|
||||||
conf: Path = Path(f'{Path.home()}/.config/bpytop')
|
|
||||||
if not conf.is_dir():
|
|
||||||
try:
|
try:
|
||||||
conf.mkdir(mode=0o777, parents=True)
|
os.makedirs(CONFIG_DIR)
|
||||||
|
os.mkdir(f'{CONFIG_DIR}/themes')
|
||||||
|
os.mkdir(f'{CONFIG_DIR}/user_themes')
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
print(f'ERROR!\nNo permission to write to "{conf}" directory!')
|
print(f'ERROR!\nNo permission to write to "{CONFIG_DIR}" directory!')
|
||||||
quit(1)
|
quit(1)
|
||||||
|
CONFIG_FILE: str = f'{CONFIG_DIR}/bpytop.conf'
|
||||||
CONFIG_DIR: str = str(conf)
|
THEME_DIR: str = f'{CONFIG_DIR}/themes'
|
||||||
del conf
|
USER_THEME_DIR: str = f'{CONFIG_DIR}/user_themes'
|
||||||
|
|
||||||
CORES: int = psutil.cpu_count(logical=False) or 1
|
CORES: int = psutil.cpu_count(logical=False) or 1
|
||||||
THREADS: int = psutil.cpu_count(logical=True) or 1
|
THREADS: int = psutil.cpu_count(logical=True) or 1
|
||||||
|
@ -386,24 +389,24 @@ class Theme:
|
||||||
|
|
||||||
class Draw:
|
class Draw:
|
||||||
'''Holds the draw buffer\n
|
'''Holds the draw buffer\n
|
||||||
Add to buffer: .buffer(name, *args, now=False, clear=False)\n
|
Add to buffer: .buffer(name, *args, append=False, now=False)\n
|
||||||
Print buffer: .out()\n
|
Print buffer: .out(clear=False)\n
|
||||||
'''
|
'''
|
||||||
strings: Dict[str, str] = {}
|
strings: Dict[str, str] = {}
|
||||||
last_screen: str = ""
|
last_screen: str = ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def buffer(cls, name: str, *args, now: bool = False, clear: bool = False):
|
def buffer(cls, name: str, *args, append: bool = False, now: bool = False):
|
||||||
string: str = ""
|
string: str = ""
|
||||||
if args: string = "".join(map(str, args))
|
if args: string = "".join(map(str, args))
|
||||||
if name not in cls.strings or clear: 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: print(string)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def out(cls):
|
def out(cls, clear = False):
|
||||||
cls.last_screen = "".join(cls.strings.values())
|
cls.last_screen = "".join(cls.strings.values())
|
||||||
#cls.strings = {}
|
if clear: cls.strings = {}
|
||||||
print(cls.last_screen)
|
print(cls.last_screen)
|
||||||
|
|
||||||
class Symbol:
|
class Symbol:
|
||||||
|
@ -432,6 +435,101 @@ class Symbol:
|
||||||
4.0 : "⡇", 4.1 : "⡏", 4.2 : "⡟", 4.3 : "⡿", 4.4 : "⣿"
|
4.0 : "⡇", 4.1 : "⡏", 4.2 : "⡟", 4.3 : "⡿", 4.4 : "⣿"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Graphs:
|
||||||
|
'''Holds all graph objects and dicts for dynamically created graphs'''
|
||||||
|
cpu: object = None
|
||||||
|
cores: Dict[int, object] = {}
|
||||||
|
temps: Dict[int, object] = {}
|
||||||
|
net: object = None
|
||||||
|
detailed_cpu: object = None
|
||||||
|
detailed_mem: object = None
|
||||||
|
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:
|
||||||
|
'''Box object with all needed attributes for create_box() function'''
|
||||||
|
def __init__(self, name: str, height_p: int, width_p: int):
|
||||||
|
self.name: str = name
|
||||||
|
self.height_p: int = height_p
|
||||||
|
self.width_p: int = width_p
|
||||||
|
self.x: int = 0
|
||||||
|
self.y: int = 0
|
||||||
|
self.width: int = 0
|
||||||
|
self.height: int = 0
|
||||||
|
self.out: str = ""
|
||||||
|
if name == "proc":
|
||||||
|
self.detailed: bool = False
|
||||||
|
self.detailed_x: int = 0
|
||||||
|
self.detailed_y: int = 0
|
||||||
|
self.detailed_width: int = 0
|
||||||
|
self.detailed_height: int = 8
|
||||||
|
if name == "mem":
|
||||||
|
self.divider: int = 0
|
||||||
|
self.mem_width: int = 0
|
||||||
|
self.disks_width: int = 0
|
||||||
|
if name in ("cpu", "net"):
|
||||||
|
self.box_x: int = 0
|
||||||
|
self.box_y: int = 0
|
||||||
|
self.box_width: int = 0
|
||||||
|
self.box_height: int = 0
|
||||||
|
self.box_columns: int = 0
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
'''Holds all config variables'''
|
||||||
|
keys: List[str] = ["color_theme", "update_ms", "proc_sorting", "proc_reversed", "proc_tree", "check_temp", "draw_clock", "background_update", "custom_cpu_name", "proc_gradient", "proc_per_core", "disks_filter", "update_check", "hires_graphs"]
|
||||||
|
conf_dict: Dict[str, Union[str, int, bool]] = {}
|
||||||
|
color_theme: str = "Default"
|
||||||
|
update_ms: int = 2500
|
||||||
|
proc_sorting: str = "cpu lazy"
|
||||||
|
proc_reversed: bool = False
|
||||||
|
proc_tree: bool = False
|
||||||
|
check_temp: bool = True
|
||||||
|
draw_clock: str = "%X"
|
||||||
|
background_update: bool = True
|
||||||
|
custom_cpu_name: str = ""
|
||||||
|
proc_gradient: bool = True
|
||||||
|
proc_per_core: bool = False
|
||||||
|
disks_filter: str = ""
|
||||||
|
update_check: bool = True
|
||||||
|
hires_graphs: bool = False
|
||||||
|
|
||||||
|
changed: bool = False
|
||||||
|
recreate: bool = False
|
||||||
|
|
||||||
|
__initialized: bool = False
|
||||||
|
|
||||||
|
def __init__(self, conf: Dict[str, Union[str, int, bool]]):
|
||||||
|
if not isinstance(conf, dict):
|
||||||
|
conf = {}
|
||||||
|
if not "version" in conf.keys() or conf["version"] != VERSION:
|
||||||
|
self.recreate = True
|
||||||
|
for key in self.keys:
|
||||||
|
if key in conf.keys():
|
||||||
|
setattr(self, key, conf[key])
|
||||||
|
else:
|
||||||
|
self.recreate = True
|
||||||
|
self.conf_dict[key] = getattr(self, key)
|
||||||
|
self.__initialized = True
|
||||||
|
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
if self.__initialized:
|
||||||
|
object.__setattr__(self, "changed", True)
|
||||||
|
object.__setattr__(self, name, value)
|
||||||
|
if name not in ["_Config__initialized", "recreate", "changed"]:
|
||||||
|
self.conf_dict[name] = value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#? Functions ------------------------------------------------------------------------------------->
|
#? Functions ------------------------------------------------------------------------------------->
|
||||||
|
@ -469,9 +567,24 @@ def get_cpu_name():
|
||||||
|
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def load_theme(path: str) -> Dict[str, str]:
|
def get_themes() -> Dict[str, str]:
|
||||||
'''Load a bashtop formatted theme file'''
|
'''Returns a dict with names and paths to all found themes'''
|
||||||
|
found: Dict[str, str] = { "Default" : "Default" }
|
||||||
|
try:
|
||||||
|
for d in (THEME_DIR, USER_THEME_DIR):
|
||||||
|
for f in os.listdir(d):
|
||||||
|
if f.endswith(".theme"):
|
||||||
|
found[f'{f[:-6] if d == THEME_DIR else f[:-6] + "*"}'] = f'{d}/{f}'
|
||||||
|
except Exception as e:
|
||||||
|
errlog.exception(str(e))
|
||||||
|
return found
|
||||||
|
|
||||||
|
def load_theme(name: str) -> Dict[str, str]:
|
||||||
|
'''Load a bashtop formatted theme file and return a dict'''
|
||||||
new_theme: Dict[str, str] = {}
|
new_theme: Dict[str, str] = {}
|
||||||
|
all_themes: Dict[str, str] = get_themes()
|
||||||
|
if name == "Default" or name not in all_themes.keys(): return DEFAULT_THEME
|
||||||
|
path: str = all_themes[name]
|
||||||
try:
|
try:
|
||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
|
@ -485,6 +598,49 @@ def load_theme(path: str) -> Dict[str, str]:
|
||||||
|
|
||||||
return new_theme
|
return new_theme
|
||||||
|
|
||||||
|
def load_config(path: str) -> Dict[str, Union[str, int, bool]]:
|
||||||
|
'''Load config from file, set correct types for values and return a dict'''
|
||||||
|
new_config: Dict[str,Union[str, int, bool]] = {}
|
||||||
|
if not os.path.isfile(path): return new_config
|
||||||
|
try:
|
||||||
|
with open(path, "r") as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.rstrip()
|
||||||
|
if line.startswith("#? Config"):
|
||||||
|
new_config["version"] = line[line.find("v. ") + 3:]
|
||||||
|
for key in Config.keys:
|
||||||
|
if line.startswith(key):
|
||||||
|
l = line.lstrip(key + "=")
|
||||||
|
if l.startswith('"'):
|
||||||
|
l = l.lstrip('"').rstrip('"')
|
||||||
|
if type(getattr(Config, key)) == type(int()):
|
||||||
|
try:
|
||||||
|
new_config[key] = int(l)
|
||||||
|
except Exception as e:
|
||||||
|
errlog.exception(str(e))
|
||||||
|
new_config[key] = ""
|
||||||
|
if type(getattr(Config, key)) == type(bool()):
|
||||||
|
try:
|
||||||
|
new_config[key] = bool(strtobool(l))
|
||||||
|
except Exception as e:
|
||||||
|
errlog.exception(str(e))
|
||||||
|
new_config[key] = ""
|
||||||
|
if type(getattr(Config, key)) == type(str()):
|
||||||
|
new_config[key] = str(l)
|
||||||
|
except Exception as e:
|
||||||
|
errlog.exception(str(e))
|
||||||
|
|
||||||
|
return new_config
|
||||||
|
|
||||||
|
def save_config(path: str, conf: Config):
|
||||||
|
'''Save current config to config file if difference in values or version, creates a new file if not found'''
|
||||||
|
if not conf.changed and not conf.recreate: return
|
||||||
|
try:
|
||||||
|
with open(path, "w" if os.path.isfile(path) else "x") as f:
|
||||||
|
f.write(DEFAULT_CONF.substitute(conf.conf_dict))
|
||||||
|
except Exception as e:
|
||||||
|
errlog.exception(str(e))
|
||||||
|
|
||||||
def fg(h_r: Union[str, int], g: int = 0, b: int = 0) -> str:
|
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"""
|
"""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 = ""
|
color: str = ""
|
||||||
|
@ -567,6 +723,7 @@ def quit_sigint(signum, frame):
|
||||||
def clean_quit(errcode: int = 0):
|
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)
|
||||||
print(Term.clear, Term.normal_screen, Term.show_cursor)
|
print(Term.clear, Term.normal_screen, Term.show_cursor)
|
||||||
raise SystemExit(errcode)
|
raise SystemExit(errcode)
|
||||||
|
|
||||||
|
@ -597,7 +754,7 @@ def calc_sizes():
|
||||||
elif THREADS > cpu.height - 5 and cpu.width > 100: cpu.box_width = 24 * 2; cpu.box_height = round(THREADS / 2) + 4; cpu.box_columns = 2
|
elif THREADS > cpu.height - 5 and cpu.width > 100: cpu.box_width = 24 * 2; cpu.box_height = round(THREADS / 2) + 4; cpu.box_columns = 2
|
||||||
else: cpu.box_width = 24; cpu.box_height = THREADS + 4; cpu.box_columns = 1
|
else: cpu.box_width = 24; cpu.box_height = THREADS + 4; cpu.box_columns = 1
|
||||||
|
|
||||||
if Config.check_temp: cpu.box_width += 13 * cpu.box_columns
|
if config.check_temp: cpu.box_width += 13 * cpu.box_columns
|
||||||
if cpu.box_height > cpu.height - 3: cpu.box_height = cpu.height - 3
|
if cpu.box_height > cpu.height - 3: cpu.box_height = cpu.height - 3
|
||||||
cpu.box_x = (cpu.width - 2) - cpu.box_width
|
cpu.box_x = (cpu.width - 2) - cpu.box_width
|
||||||
cpu.box_y = cpu.y + ((cpu.height - 2) // 2) - round(cpu.box_height / 2) + 2
|
cpu.box_y = cpu.y + ((cpu.height - 2) // 2) - round(cpu.box_height / 2) + 2
|
||||||
|
@ -659,37 +816,33 @@ def create_box(x: int = 0, y: int = 0, width: int = 0, height: int = 0, title: s
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
#? Main function --------------------------------------------------------------------------------->
|
def draw_bg(now: bool = True):
|
||||||
|
'''Draw all boxes to buffer and print to screen if now=True'''
|
||||||
|
|
||||||
def main():
|
#* Draw cpu box and cpu sub box
|
||||||
line: str = ""
|
cpu_box = f'{create_box(box_object=cpu, line_color=theme.cpu_box, fill=True)}\
|
||||||
this_key: str = ""
|
{Mv.to(cpu.y, cpu.x + 10)}{theme.cpu_box(Symbol.title_left)}{Fx.b}{theme.hi_fg("m")}{theme.title("enu")}{Fx.ub}{theme.cpu_box(Symbol.title_right)}\
|
||||||
count: int = 0
|
{create_box(x=cpu.box_x, y=cpu.box_y, width=cpu.box_width, height=cpu.box_height, line_color=theme.div_line, title=CPU_NAME[:18 if config.check_temp else 9])}'
|
||||||
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)
|
|
||||||
|
|
||||||
|
#* Draw mem/disk box and divider
|
||||||
|
mem_box = f'{create_box(box_object=mem, line_color=theme.mem_box, fill=True)}\
|
||||||
|
{Mv.to(mem.y, mem.divider + 2)}{theme.mem_box(Symbol.title_left)}{Fx.b}{theme.title("disks")}{Fx.ub}{theme.mem_box(Symbol.title_right)}\
|
||||||
|
{Mv.to(mem.y, mem.divider)}{theme.mem_box(Symbol.div_up)}\
|
||||||
|
{Mv.to(mem.y + mem.height, mem.divider)}{theme.mem_box(Symbol.div_down)}{theme.div_line}'
|
||||||
|
for i in range(1, mem.height):
|
||||||
|
mem_box += f'{Mv.to(mem.y + i, mem.divider)}{Symbol.v_line}'
|
||||||
|
|
||||||
#? Init Classes ---------------------------------------------------------------------------------->
|
#* Draw net box and net sub box
|
||||||
|
net_box = f'{create_box(box_object=net, line_color=theme.net_box, fill=True)}\
|
||||||
|
{create_box(x=net.box_x, y=net.box_y, width=net.box_width, height=net.box_height, line_color=theme.div_line, title="Download")}\
|
||||||
|
{Mv.to(net.box_y + net.box_height, net.box_x + 1)}{theme.div_line(Symbol.title_left)}{Fx.b}{theme.title("Upload")}{Fx.ub}{theme.div_line(Symbol.title_right)}'
|
||||||
|
|
||||||
|
#* Draw proc box
|
||||||
|
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)
|
||||||
|
|
||||||
|
#? Function dependent classes -------------------------------------------------------------------->
|
||||||
|
|
||||||
class Banner:
|
class Banner:
|
||||||
out: List[str] = []
|
out: List[str] = []
|
||||||
|
@ -722,68 +875,47 @@ class Banner:
|
||||||
if now: print(out)
|
if now: print(out)
|
||||||
else: return out
|
else: return out
|
||||||
|
|
||||||
class Config:
|
#? Main function --------------------------------------------------------------------------------->
|
||||||
'''Holds all config variables'''
|
|
||||||
check_temp: bool = True
|
|
||||||
|
|
||||||
class Graphs:
|
def main():
|
||||||
'''Holds all graph objects and dicts for dynamically created graphs'''
|
line: str = ""
|
||||||
cpu: object = None
|
this_key: str = ""
|
||||||
cores: Dict[int, object] = {}
|
count: int = 0
|
||||||
temps: Dict[int, object] = {}
|
while True:
|
||||||
net: object = None
|
count += 1
|
||||||
detailed_cpu: object = None
|
print(f'{Mv.to(1,1)}{Fx.b}{blue("Count:")} {count} {lime("Time:")} {time.strftime("%H:%M:%S", time.localtime())}')
|
||||||
detailed_mem: object = None
|
print(f'{fg("#ff")} Width: {Term.width} Height: {Term.height} Resized: {Term.resized}')
|
||||||
pid_cpu: Dict[int, object] = {}
|
while Key.list:
|
||||||
|
Key.new.clear()
|
||||||
class Meters:
|
this_key = Key.list.pop()
|
||||||
'''Holds created meters to reuse instead of recreating meters of past values'''
|
print(f'{Mv.to(2,1)}{fg("#ff9050")}{Fx.b}Last key= {Term.fg}{Fx.ub}{repr(this_key)}{" " * 40}')
|
||||||
cpu: Dict[int, str] = {}
|
if this_key == "backspace":
|
||||||
mem_used: Dict[int, str] = {}
|
line = line[:-1]
|
||||||
mem_available: Dict[int, str] = {}
|
elif this_key == "enter":
|
||||||
mem_cached: Dict[int, str] = {}
|
line += "\n"
|
||||||
mem_free: Dict[int, str] = {}
|
else:
|
||||||
swap_used: Dict[int, str] = {}
|
line += this_key
|
||||||
swap_free: Dict[int, str] = {}
|
print(f'{Mv.to(3,1)}{fg("#90ff50")}{Fx.b}Full line= {Term.fg}{Fx.ub}{line}{Fx.bl}| {Fx.ubl}')
|
||||||
disks_used: Dict[int, str] = {}
|
if this_key == "q":
|
||||||
disks_free: Dict[int, str] = {}
|
clean_quit()
|
||||||
|
if this_key == "R":
|
||||||
class Box:
|
raise Exception("Test ERROR")
|
||||||
'''Box object with all needed attributes for create_box() function'''
|
if not Key.reader.is_alive():
|
||||||
def __init__(self, name: str, height_p: int, width_p: int):
|
clean_quit(1)
|
||||||
self.name: str = name
|
Key.new.wait(1.0)
|
||||||
self.height_p: int = height_p
|
|
||||||
self.width_p: int = width_p
|
|
||||||
self.x: int = 0
|
|
||||||
self.y: int = 0
|
|
||||||
self.width: int = 0
|
|
||||||
self.height: int = 0
|
|
||||||
self.out: str = ""
|
|
||||||
if name == "proc":
|
|
||||||
self.detailed: bool = False
|
|
||||||
self.detailed_x: int = 0
|
|
||||||
self.detailed_y: int = 0
|
|
||||||
self.detailed_width: int = 0
|
|
||||||
self.detailed_height: int = 8
|
|
||||||
if name == "mem":
|
|
||||||
self.divider: int = 0
|
|
||||||
self.mem_width: int = 0
|
|
||||||
self.disks_width: int = 0
|
|
||||||
if name in ("cpu", "net"):
|
|
||||||
self.box_x: int = 0
|
|
||||||
self.box_y: int = 0
|
|
||||||
self.box_width: int = 0
|
|
||||||
self.box_height: int = 0
|
|
||||||
self.box_columns: int = 0
|
|
||||||
|
|
||||||
|
|
||||||
#? Init variables -------------------------------------------------------------------------------->
|
#? Init ------------------------------------------------------------------------------------------>
|
||||||
|
|
||||||
|
#Key.start()
|
||||||
|
|
||||||
CPU_NAME: str = get_cpu_name()
|
CPU_NAME: str = get_cpu_name()
|
||||||
|
|
||||||
|
config: Config = Config(load_config(CONFIG_FILE))
|
||||||
|
|
||||||
#theme = Theme(load_theme("/home/gnm/.config/bashtop/themes/monokai.theme"))
|
config.proc_per_core = True
|
||||||
theme = Theme(DEFAULT_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)
|
||||||
mem = Box("mem", height_p=40, width_p=45)
|
mem = Box("mem", height_p=40, width_p=45)
|
||||||
|
@ -798,39 +930,11 @@ orange = theme.available_end
|
||||||
green = theme.cpu_start
|
green = theme.cpu_start
|
||||||
dfg = theme.main_fg
|
dfg = theme.main_fg
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def draw_bg(now: bool = True):
|
|
||||||
'''Draw all boxes to buffer and print to screen if now=True'''
|
|
||||||
Draw.buffer("bg", clear=True)
|
|
||||||
|
|
||||||
#* Draw cpu box and cpu sub box
|
|
||||||
cpu_box = f'{create_box(box_object=cpu, line_color=theme.cpu_box, fill=True)}\
|
|
||||||
{Mv.to(cpu.y, cpu.x + 10)}{theme.cpu_box(Symbol.title_left)}{Fx.b}{theme.hi_fg("m")}{theme.title("enu")}{Fx.ub}{theme.cpu_box(Symbol.title_right)}\
|
|
||||||
{create_box(x=cpu.box_x, y=cpu.box_y, width=cpu.box_width, height=cpu.box_height, line_color=theme.div_line, title=CPU_NAME[:18 if Config.check_temp else 9])}'
|
|
||||||
|
|
||||||
#* Draw mem/disk box and divider
|
|
||||||
mem_box = f'{create_box(box_object=mem, line_color=theme.mem_box, fill=True)}\
|
|
||||||
{Mv.to(mem.y, mem.divider + 2)}{theme.mem_box(Symbol.title_left)}{Fx.b}{theme.title("disks")}{Fx.ub}{theme.mem_box(Symbol.title_right)}\
|
|
||||||
{Mv.to(mem.y, mem.divider)}{theme.mem_box(Symbol.div_up)}\
|
|
||||||
{Mv.to(mem.y + mem.height, mem.divider)}{theme.mem_box(Symbol.div_down)}{theme.div_line}'
|
|
||||||
for i in range(1, mem.height):
|
|
||||||
mem_box += f'{Mv.to(mem.y + i, mem.divider)}{Symbol.v_line}'
|
|
||||||
|
|
||||||
#* Draw net box and net sub box
|
|
||||||
net_box = f'{create_box(box_object=net, line_color=theme.net_box, fill=True)}\
|
|
||||||
{create_box(x=net.box_x, y=net.box_y, width=net.box_width, height=net.box_height, line_color=theme.div_line, title="Download")}\
|
|
||||||
{Mv.to(net.box_y + net.box_height, net.box_x + 1)}{theme.div_line(Symbol.title_left)}{Fx.b}{theme.title("Upload")}{Fx.ub}{theme.div_line(Symbol.title_right)}'
|
|
||||||
|
|
||||||
#* Draw proc box
|
|
||||||
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)
|
|
||||||
|
|
||||||
def testing_colors():
|
def testing_colors():
|
||||||
for item, _ in DEFAULT_THEME.items():
|
for item, _ in DEFAULT_THEME.items():
|
||||||
print(Fx.b, getattr(theme, item)(f'{item:<20}'), Fx.ub, f'{"hex=" + getattr(theme, item).hex:<20} dec={getattr(theme, item).dec}', end="\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()
|
||||||
print()
|
print()
|
||||||
print(theme.temp_start, "Hej!\n")
|
print(theme.temp_start, "Hej!\n")
|
||||||
print(Term.fg, "\nHEJ\n")
|
print(Term.fg, "\nHEJ\n")
|
||||||
|
@ -840,23 +944,21 @@ def testing_colors():
|
||||||
|
|
||||||
def testing_banner():
|
def testing_banner():
|
||||||
print(Term.normal_screen, Term.alt_screen)
|
print(Term.normal_screen, Term.alt_screen)
|
||||||
Key.start()
|
#Key.start()
|
||||||
#try:
|
|
||||||
#sad
|
|
||||||
#except Exception as e:
|
|
||||||
# errlog.exception(f'{e}')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#eprint("Test")
|
|
||||||
calc_sizes()
|
calc_sizes()
|
||||||
|
|
||||||
draw_bg()
|
draw_bg()
|
||||||
|
|
||||||
Draw.buffer("banner", Banner.draw(18, 45), clear=True)
|
Draw.buffer("banner", Banner.draw(18, 45))
|
||||||
Draw.out()
|
Draw.out()
|
||||||
|
|
||||||
print(Mv.to(35, 1), repr(Term.fg), " ", repr(Term.bg), "\n")
|
print(Mv.to(35, 1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
quit()
|
||||||
|
|
||||||
|
|
||||||
# quit()
|
# quit()
|
||||||
|
|
||||||
|
@ -882,7 +984,7 @@ def testing_banner():
|
||||||
# total_h += getattr(box, "height")
|
# total_h += getattr(box, "height")
|
||||||
# total_w += getattr(box, "width")
|
# total_w += getattr(box, "width")
|
||||||
# print(f'\nTotal Height={cpu.height + net.height + mem.height} Width={net.width + proc.width}')
|
# print(f'\nTotal Height={cpu.height + net.height + mem.height} Width={net.width + proc.width}')
|
||||||
Key.stop()
|
#Key.stop()
|
||||||
quit()
|
quit()
|
||||||
|
|
||||||
|
|
||||||
|
@ -892,6 +994,7 @@ def testing_banner():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
testing_banner()
|
testing_banner()
|
||||||
|
#testing_colors()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
errlog.exception(f'{e}')
|
errlog.exception(f'{e}')
|
||||||
clean_quit(1)
|
clean_quit(1)
|
||||||
|
|
Loading…
Reference in New Issue