mirror of
https://github.com/pdxlocations/contact.git
synced 2026-08-05 00:13:49 +02:00
Color Customization (#64)
* init * customize colors * fix splash frame * cleanup
This commit is contained in:
+20
-1
@@ -24,4 +24,23 @@ notification_symbol = "*"
|
||||
ack_implicit_str = "[◌]"
|
||||
ack_str = "[✓]"
|
||||
nak_str = "[x]"
|
||||
ack_unknown_str = "[…]"
|
||||
ack_unknown_str = "[…]"
|
||||
|
||||
# (forground, background) white, black, red, green, yellow, blue, magenta, cyan
|
||||
COLOR_CONFIG = {
|
||||
"default": ("white", "black"),
|
||||
"splash_logo": ("green", "black"),
|
||||
"splash_text": ("white", "black"),
|
||||
"input": ("white", "black"),
|
||||
"node_list": ("white", "black"),
|
||||
"channel_list": ("white", "black"),
|
||||
"channel_selected": ("green", "black"),
|
||||
"rx_messages": ("cyan", "black"),
|
||||
"tx_messages": ("green", "black"),
|
||||
"timestamps": ("white", "black"),
|
||||
"commands": ("white", "black"),
|
||||
"window_frame": ("white", "black"),
|
||||
"window_frame_selected": ("green", "black"),
|
||||
"log_header": ("blue", "black"),
|
||||
"log": ("green", "black")
|
||||
}
|
||||
+34
-5
@@ -1,9 +1,38 @@
|
||||
import curses
|
||||
import globals
|
||||
|
||||
COLOR_MAP = {
|
||||
"black": curses.COLOR_BLACK,
|
||||
"red": curses.COLOR_RED,
|
||||
"green": curses.COLOR_GREEN,
|
||||
"yellow": curses.COLOR_YELLOW,
|
||||
"blue": curses.COLOR_BLUE,
|
||||
"magenta": curses.COLOR_MAGENTA,
|
||||
"cyan": curses.COLOR_CYAN,
|
||||
"white": curses.COLOR_WHITE
|
||||
}
|
||||
|
||||
def setup_colors():
|
||||
"""
|
||||
Initialize curses color pairs based on the COLOR_CONFIG.
|
||||
"""
|
||||
curses.start_color()
|
||||
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK)
|
||||
curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK)
|
||||
curses.init_pair(3, curses.COLOR_CYAN, curses.COLOR_BLACK)
|
||||
curses.init_pair(4, curses.COLOR_YELLOW, curses.COLOR_BLACK)
|
||||
curses.init_pair(5, curses.COLOR_RED, curses.COLOR_BLACK)
|
||||
for idx, (category, (fg_name, bg_name)) in enumerate(globals.COLOR_CONFIG.items(), start=1):
|
||||
fg = COLOR_MAP.get(fg_name.lower(), curses.COLOR_WHITE)
|
||||
bg = COLOR_MAP.get(bg_name.lower(), curses.COLOR_BLACK)
|
||||
curses.init_pair(idx, fg, bg)
|
||||
globals.COLOR_CONFIG[category] = idx
|
||||
|
||||
|
||||
def get_color(category, bold=False, reverse=False, underline=False):
|
||||
"""
|
||||
Retrieve a curses color pair with optional attributes.
|
||||
"""
|
||||
color = curses.color_pair(globals.COLOR_CONFIG[category])
|
||||
if bold:
|
||||
color |= curses.A_BOLD
|
||||
if reverse:
|
||||
color |= curses.A_REVERSE
|
||||
if underline:
|
||||
color |= curses.A_UNDERLINE
|
||||
return color
|
||||
+60
-40
@@ -5,7 +5,7 @@ from utilities.utils import get_name_from_number, get_channels
|
||||
from settings import settings_menu
|
||||
from message_handlers.tx_handler import send_message, send_traceroute
|
||||
import ui.dialog
|
||||
from ui.colors import setup_colors
|
||||
from ui.colors import setup_colors, get_color
|
||||
|
||||
def get_msg_window_lines():
|
||||
packetlog_height = packetlog_win.getmaxyx()[0] if globals.display_log else 0
|
||||
@@ -42,12 +42,15 @@ def refresh_pad(window):
|
||||
def highlight_line(highlight, window, line):
|
||||
pad = channel_pad
|
||||
select_len = 0
|
||||
color = curses.color_pair(1)
|
||||
ch_color = get_color("channel_list")
|
||||
nd_color = get_color("node_list")
|
||||
|
||||
if(window == 2):
|
||||
pad = nodes_pad
|
||||
select_len = len(get_name_from_number(globals.node_list[line], "long"))
|
||||
|
||||
pad.chgat(line, 1, select_len, nd_color | curses.A_REVERSE if highlight else nd_color)
|
||||
|
||||
if(window == 0):
|
||||
channel = list(globals.all_messages.keys())[line]
|
||||
win_width = channel_box.getmaxyx()[1]
|
||||
@@ -57,9 +60,9 @@ def highlight_line(highlight, window, line):
|
||||
select_len = min(len(channel), win_width - 4)
|
||||
|
||||
if line == globals.selected_channel and highlight == False:
|
||||
color = curses.color_pair(2)
|
||||
ch_color = get_color("channel_selected")
|
||||
|
||||
pad.chgat(line, 1, select_len, color | curses.A_REVERSE if highlight else color)
|
||||
pad.chgat(line, 1, select_len, ch_color | curses.A_REVERSE if highlight else ch_color)
|
||||
|
||||
def add_notification(channel_number):
|
||||
globals.notifications.add(channel_number)
|
||||
@@ -67,15 +70,15 @@ def add_notification(channel_number):
|
||||
def remove_notification(channel_number):
|
||||
globals.notifications.discard(channel_number)
|
||||
|
||||
def draw_text_field(win, text):
|
||||
def draw_text_field(win, text, color):
|
||||
win.border()
|
||||
win.addstr(1, 1, text)
|
||||
win.addstr(1, 1, text, color)
|
||||
|
||||
def draw_centered_text_field(win, text, y_offset = 0):
|
||||
def draw_centered_text_field(win, text, y_offset, color):
|
||||
height, width = win.getmaxyx()
|
||||
x = (width - len(text)) // 2
|
||||
y = (height // 2) + y_offset
|
||||
win.addstr(y, x, text)
|
||||
win.addstr(y, x, text, color)
|
||||
win.refresh()
|
||||
|
||||
def draw_debug(value):
|
||||
@@ -96,10 +99,11 @@ def draw_splash(stdscr):
|
||||
start_x = width // 2 - len(message_1) // 2
|
||||
start_x2 = width // 2 - len(message_4) // 2
|
||||
start_y = height // 2 - 1
|
||||
stdscr.addstr(start_y, start_x, message_1, curses.color_pair(2) | curses.A_BOLD)
|
||||
stdscr.addstr(start_y+1, start_x-1, message_2, curses.color_pair(2) | curses.A_BOLD)
|
||||
stdscr.addstr(start_y+2, start_x-2, message_3, curses.color_pair(2) | curses.A_BOLD)
|
||||
stdscr.addstr(start_y+4, start_x2, message_4)
|
||||
stdscr.addstr(start_y, start_x, message_1, get_color("splash_logo", bold=True))
|
||||
stdscr.addstr(start_y+1, start_x-1, message_2, get_color("splash_logo", bold=True))
|
||||
stdscr.addstr(start_y+2, start_x-2, message_3, get_color("splash_logo", bold=True))
|
||||
stdscr.addstr(start_y+4, start_x2, message_4, get_color("splash_text"))
|
||||
stdscr.attrset(get_color("window_frame"))
|
||||
stdscr.box()
|
||||
stdscr.refresh()
|
||||
curses.napms(500)
|
||||
@@ -124,16 +128,16 @@ def draw_channel_list():
|
||||
truncated_channel = channel[:win_width - 5] + '-' if len(channel) > win_width - 5 else channel
|
||||
if i == globals.selected_channel:
|
||||
if globals.current_window == 0:
|
||||
channel_pad.addstr(i, 1, truncated_channel + notification, curses.color_pair(1) | curses.A_REVERSE)
|
||||
channel_pad.addstr(i, 1, truncated_channel + notification, get_color("channel_list", reverse=True))
|
||||
remove_notification(globals.selected_channel)
|
||||
else:
|
||||
channel_pad.addstr(i, 1, truncated_channel + notification, curses.color_pair(2))
|
||||
channel_pad.addstr(i, 1, truncated_channel + notification, get_color("channel_selected"))
|
||||
else:
|
||||
channel_pad.addstr(i, 1, truncated_channel + notification, curses.color_pair(1))
|
||||
channel_pad.addstr(i, 1, truncated_channel + notification, get_color("channel_list"))
|
||||
|
||||
channel_box.attrset(curses.color_pair(2) if globals.current_window == 0 else curses.color_pair(0))
|
||||
channel_box.attrset(get_color("window_frame_selected") if globals.current_window == 0 else get_color("window_frame"))
|
||||
channel_box.box()
|
||||
channel_box.attrset(curses.color_pair(0))
|
||||
channel_box.attrset((get_color("window_frame")))
|
||||
channel_box.refresh()
|
||||
|
||||
refresh_pad(0)
|
||||
@@ -157,13 +161,19 @@ def draw_messages_window(scroll_to_bottom = False):
|
||||
messages_pad.resize(msg_line_count, messages_box.getmaxyx()[1])
|
||||
|
||||
for line in wrapped_lines:
|
||||
color = curses.color_pair(1) if prefix.startswith("--") else (curses.color_pair(3) if prefix.startswith(globals.sent_message_prefix) else curses.color_pair(2))
|
||||
if prefix.startswith("--"):
|
||||
color = get_color("timestamps")
|
||||
elif prefix.startswith(globals.sent_message_prefix):
|
||||
color = get_color("tx_messages")
|
||||
else:
|
||||
color = get_color("rx_messages")
|
||||
|
||||
messages_pad.addstr(row, 1, line, color)
|
||||
row += 1
|
||||
|
||||
messages_box.attrset(curses.color_pair(2) if globals.current_window == 1 else curses.color_pair(0))
|
||||
messages_box.attrset(get_color("window_frame_selected") if globals.current_window == 1 else get_color("window_frame"))
|
||||
messages_box.box()
|
||||
messages_box.attrset(curses.color_pair(0))
|
||||
messages_box.attrset(get_color("window_frame"))
|
||||
messages_box.refresh()
|
||||
|
||||
if(scroll_to_bottom):
|
||||
@@ -184,13 +194,13 @@ def draw_node_list():
|
||||
|
||||
for i, node in enumerate(globals.node_list):
|
||||
if globals.selected_node == i and globals.current_window == 2:
|
||||
nodes_pad.addstr(i, 1, get_name_from_number(node, "long"), curses.color_pair(1) | curses.A_REVERSE)
|
||||
nodes_pad.addstr(i, 1, get_name_from_number(node, "long"), get_color("node_list", reverse=True))
|
||||
else:
|
||||
nodes_pad.addstr(i, 1, get_name_from_number(node, "long"), curses.color_pair(1))
|
||||
nodes_pad.addstr(i, 1, get_name_from_number(node, "long"), get_color("node_list"))
|
||||
|
||||
nodes_box.attrset(curses.color_pair(2) if globals.current_window == 2 else curses.color_pair(0))
|
||||
nodes_box.attrset(get_color("window_frame_selected") if globals.current_window == 2 else get_color("window_frame"))
|
||||
nodes_box.box()
|
||||
nodes_box.attrset(curses.color_pair(0))
|
||||
nodes_box.attrset(get_color("window_frame"))
|
||||
nodes_box.refresh()
|
||||
|
||||
refresh_pad(2)
|
||||
@@ -259,7 +269,7 @@ def draw_packetlog_win():
|
||||
|
||||
# Add headers
|
||||
headers = f"{'From':<{columns[0]}} {'To':<{columns[1]}} {'Port':<{columns[2]}} {'Payload':<{width-span}}"
|
||||
packetlog_win.addstr(1, 1, headers[:width - 2],curses.A_UNDERLINE) # Truncate headers if they exceed window width
|
||||
packetlog_win.addstr(1, 1, headers[:width - 2],get_color("log_header", underline=True)) # Truncate headers if they exceed window width
|
||||
|
||||
for i, packet in enumerate(reversed(globals.packet_buffer)):
|
||||
if i >= height - 3: # Skip if exceeds the window height
|
||||
@@ -283,7 +293,7 @@ def draw_packetlog_win():
|
||||
logString = logString[:width - 3]
|
||||
|
||||
# Add to the window
|
||||
packetlog_win.addstr(i + 2, 1, logString)
|
||||
packetlog_win.addstr(i + 2, 1, logString, get_color("log"))
|
||||
|
||||
packetlog_win.box()
|
||||
packetlog_win.refresh()
|
||||
@@ -315,16 +325,26 @@ def main_ui(stdscr):
|
||||
function_win = curses.newwin(3, width, height - 3, 0)
|
||||
packetlog_win = curses.newwin(int(height / 3), messages_width, height - int(height / 3) - 3, channel_width)
|
||||
|
||||
draw_centered_text_field(function_win, f"↑→↓← = Select ENTER = Send ` = Settings ^P = Packet Log ESC = Quit")
|
||||
draw_centered_text_field(function_win, f"↑→↓← = Select ENTER = Send ` = Settings ^P = Packet Log ESC = Quit",0 ,get_color("commands"))
|
||||
|
||||
# Draw boxes around windows
|
||||
channel_box.attrset(curses.color_pair(2))
|
||||
|
||||
# Set the normal frame color for the channel box
|
||||
channel_box.attrset(get_color("window_frame"))
|
||||
channel_box.box()
|
||||
channel_box.attrset(curses.color_pair(0))
|
||||
|
||||
# Draw boxes for other windows
|
||||
entry_win.attrset(get_color("window_frame"))
|
||||
entry_win.box()
|
||||
|
||||
nodes_box.attrset(get_color("window_frame"))
|
||||
nodes_box.box()
|
||||
|
||||
messages_box.attrset(get_color("window_frame"))
|
||||
messages_box.box()
|
||||
function_win.box()
|
||||
|
||||
function_win.attrset(get_color("window_frame"))
|
||||
function_win.box()
|
||||
|
||||
# Refresh all windows
|
||||
entry_win.refresh()
|
||||
@@ -343,7 +363,7 @@ def main_ui(stdscr):
|
||||
draw_messages_window(True)
|
||||
|
||||
while True:
|
||||
draw_text_field(entry_win, f"Input: {input_text[-(width - 10):]}")
|
||||
draw_text_field(entry_win, f"Input: {input_text[-(width - 10):]}", get_color("input"))
|
||||
|
||||
# Get user input from entry window
|
||||
char = entry_win.get_wch()
|
||||
@@ -411,40 +431,40 @@ def main_ui(stdscr):
|
||||
globals.current_window = (globals.current_window + delta) % 3
|
||||
|
||||
if old_window == 0:
|
||||
channel_box.attrset(curses.color_pair(0))
|
||||
channel_box.attrset(get_color("window_frame"))
|
||||
channel_box.box()
|
||||
channel_box.refresh()
|
||||
highlight_line(False, 0, globals.selected_channel)
|
||||
refresh_pad(0)
|
||||
if old_window == 1:
|
||||
messages_box.attrset(curses.color_pair(0))
|
||||
messages_box.attrset(get_color("window_frame"))
|
||||
messages_box.box()
|
||||
messages_box.refresh()
|
||||
refresh_pad(1)
|
||||
elif old_window == 2:
|
||||
nodes_box.attrset(curses.color_pair(0))
|
||||
nodes_box.attrset(get_color("window_frame"))
|
||||
nodes_box.box()
|
||||
nodes_box.refresh()
|
||||
highlight_line(False, 2, globals.selected_node)
|
||||
refresh_pad(2)
|
||||
|
||||
if globals.current_window == 0:
|
||||
channel_box.attrset(curses.color_pair(2))
|
||||
channel_box.attrset(get_color("window_frame_selected"))
|
||||
channel_box.box()
|
||||
channel_box.attrset(curses.color_pair(0))
|
||||
channel_box.attrset(get_color("window_frame"))
|
||||
channel_box.refresh()
|
||||
highlight_line(True, 0, globals.selected_channel)
|
||||
refresh_pad(0)
|
||||
elif globals.current_window == 1:
|
||||
messages_box.attrset(curses.color_pair(2))
|
||||
messages_box.attrset(get_color("window_frame_selected"))
|
||||
messages_box.box()
|
||||
messages_box.attrset(curses.color_pair(0))
|
||||
messages_box.attrset(get_color("window_frame"))
|
||||
messages_box.refresh()
|
||||
refresh_pad(1)
|
||||
elif globals.current_window == 2:
|
||||
nodes_box.attrset(curses.color_pair(2))
|
||||
nodes_box.attrset(get_color("window_frame_selected"))
|
||||
nodes_box.box()
|
||||
nodes_box.attrset(curses.color_pair(0))
|
||||
nodes_box.attrset(get_color("window_frame"))
|
||||
nodes_box.refresh()
|
||||
highlight_line(True, 2, globals.selected_node)
|
||||
refresh_pad(2)
|
||||
|
||||
Reference in New Issue
Block a user