Refactor colors Class for Curses UI

pull/2884/head
nicolargo 2024-07-21 19:16:33 +02:00
parent e086625f1a
commit 6b036ec0ac
3 changed files with 167 additions and 126 deletions

View File

@ -720,6 +720,10 @@ Examples of use:
args.time = 1
args.disable_history = True
# Unicode => No separator
if args.disable_unicode:
args.enable_separator = False
def parse_args(self):
"""Parse command line arguments."""
args = self.init_args().parse_args()

View File

@ -0,0 +1,161 @@
#
# This file is part of Glances.
#
# SPDX-FileCopyrightText: 2024 Nicolas Hennion <nicolas@nicolargo.com>
#
# SPDX-License-Identifier: LGPL-3.0-only
#
"""Glances colors."""
import sys
from glances.logger import logger
try:
import curses
except ImportError:
logger.critical("Curses module not found. Glances cannot start in standalone mode.")
sys.exit(1)
class GlancesColors:
"""Class to manage colors in Glances UI
For the moment limited to Curses interface.
But will be used in the WebUI through the issue #2048"""
def __init__(self, args) -> None:
self.args = args
# Define "home made" bold
self.A_BOLD = 0 if args.disable_bold else curses.A_BOLD
# Set defaults curses colors
try:
if hasattr(curses, 'start_color'):
curses.start_color()
logger.debug(f'Curses interface compatible with {curses.COLORS} colors')
if hasattr(curses, 'use_default_colors'):
# Use -1 to use the default foregound/background color
curses.use_default_colors()
if hasattr(curses, 'assume_default_colors'):
# Define the color index 0 with -1 and -1 for foregound/background
# = curses.init_pair(0, -1, -1)
curses.assume_default_colors(-1, -1)
except Exception as e:
logger.warning(f'Error initializing terminal color ({e})')
if curses.has_colors():
# The screen is compatible with a colored design
# ex: export TERM=xterm-256color
# export TERM=xterm-color
self.__define_colors()
else:
# The screen is NOT compatible with a colored design
# switch to B&W text styles
# ex: export TERM=xterm-mono
self.__define_bw()
def __repr__(self) -> dict:
return self.get()
def __define_colors(self) -> None:
curses.init_pair(1, -1, -1)
if self.args.disable_bg:
curses.init_pair(2, curses.COLOR_RED, -1)
curses.init_pair(3, curses.COLOR_GREEN, -1)
curses.init_pair(5, curses.COLOR_MAGENTA, -1)
else:
curses.init_pair(2, -1, curses.COLOR_RED)
curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_GREEN)
curses.init_pair(5, -1, curses.COLOR_MAGENTA)
curses.init_pair(4, curses.COLOR_BLUE, -1)
curses.init_pair(6, curses.COLOR_RED, -1)
curses.init_pair(7, curses.COLOR_GREEN, -1)
curses.init_pair(8, curses.COLOR_MAGENTA, -1)
# Colors text styles
self.DEFAULT = curses.color_pair(1)
self.OK_LOG = curses.color_pair(3) | self.A_BOLD
self.NICE = curses.color_pair(8)
self.CPU_TIME = curses.color_pair(8)
self.CAREFUL_LOG = curses.color_pair(4) | self.A_BOLD
self.WARNING_LOG = curses.color_pair(5) | self.A_BOLD
self.CRITICAL_LOG = curses.color_pair(2) | self.A_BOLD
self.OK = curses.color_pair(7)
self.CAREFUL = curses.color_pair(4)
self.WARNING = curses.color_pair(8) | self.A_BOLD
self.CRITICAL = curses.color_pair(6) | self.A_BOLD
self.INFO = curses.color_pair(4)
self.FILTER = self.A_BOLD
self.SELECTED = self.A_BOLD
self.SEPARATOR = curses.color_pair(1)
if curses.COLORS > 8:
# ex: export TERM=xterm-256color
try:
curses.init_pair(9, curses.COLOR_CYAN, -1)
curses.init_pair(10, curses.COLOR_YELLOW, -1)
except Exception:
curses.init_pair(9, -1, -1)
curses.init_pair(10, -1, -1)
self.FILTER = curses.color_pair(9) | self.A_BOLD
self.SELECTED = curses.color_pair(10) | self.A_BOLD
# Define separator line style
try:
curses.init_color(11, 500, 500, 500)
curses.init_pair(11, curses.COLOR_BLACK, -1)
self.SEPARATOR = curses.color_pair(11)
except Exception:
# Catch exception in TMUX
pass
def __define_bw(self) -> None:
# The screen is NOT compatible with a colored design
# switch to B&W text styles
# ex: export TERM=xterm-mono
self.DEFAULT = -1
self.OK_LOG = -1
self.NICE = self.A_BOLD
self.CPU_TIME = self.A_BOLD
self.CAREFUL_LOG = self.A_BOLD
self.WARNING_LOG = curses.A_UNDERLINE
self.CRITICAL_LOG = curses.A_REVERSE
self.OK = -1
self.CAREFUL = self.A_BOLD
self.WARNING = curses.A_UNDERLINE
self.CRITICAL = curses.A_REVERSE
self.INFO = self.A_BOLD
self.FILTER = self.A_BOLD
self.SELECTED = self.A_BOLD
self.SEPARATOR = -1
def get(self) -> dict:
return {
'DEFAULT': self.DEFAULT,
'UNDERLINE': curses.A_UNDERLINE,
'BOLD': self.A_BOLD,
'SORT': curses.A_UNDERLINE | self.A_BOLD,
'OK': self.OK,
'MAX': self.OK | self.A_BOLD,
'FILTER': self.FILTER,
'TITLE': self.A_BOLD,
'PROCESS': self.OK,
'PROCESS_SELECTED': self.OK | curses.A_UNDERLINE,
'STATUS': self.OK,
'NICE': self.NICE,
'CPU_TIME': self.CPU_TIME,
'CAREFUL': self.CAREFUL,
'WARNING': self.WARNING,
'CRITICAL': self.CRITICAL,
'OK_LOG': self.OK_LOG,
'CAREFUL_LOG': self.CAREFUL_LOG,
'WARNING_LOG': self.WARNING_LOG,
'CRITICAL_LOG': self.CRITICAL_LOG,
'PASSWORD': curses.A_PROTECT,
'SELECTED': self.SELECTED,
'INFO': self.INFO,
'ERROR': self.SELECTED,
'SEPARATOR': self.SEPARATOR,
}

View File

@ -14,6 +14,7 @@ import sys
from glances.events_list import glances_events
from glances.globals import MACOS, WINDOWS, disable, enable, itervalues, nativestr, u
from glances.logger import logger
from glances.outputs.glances_colors import GlancesColors
from glances.outputs.glances_unicode import unicode_message
from glances.processes import glances_processes, sort_processes_key_list
from glances.timer import Timer
@ -162,7 +163,7 @@ class _GlancesCurses:
self._init_cursor()
# Init the colors
self.colors_list = build_colors_list(args)
self.colors_list = GlancesColors(args).get()
# Init main window
self.term_window = self.screen.subwin(0, 0)
@ -1179,128 +1180,3 @@ class GlancesTextboxYesNo(Textbox):
def do_command(self, ch):
return super().do_command(ch)
def build_colors_list(args):
"""Init the Curses color layout."""
# Set curses options
try:
if hasattr(curses, 'start_color'):
curses.start_color()
logger.debug(f'Curses interface compatible with {curses.COLORS} colors')
if hasattr(curses, 'use_default_colors'):
curses.use_default_colors()
except Exception as e:
logger.warning(f'Error initializing terminal color ({e})')
# Init colors
if args.disable_bold:
A_BOLD = 0
args.disable_bg = True
else:
A_BOLD = curses.A_BOLD
title_color = A_BOLD
if curses.has_colors():
# The screen is compatible with a colored design
# ex: export TERM=xterm-256color
# export TERM=xterm-color
curses.init_pair(1, -1, -1)
if args.disable_bg:
curses.init_pair(2, curses.COLOR_RED, -1)
curses.init_pair(3, curses.COLOR_GREEN, -1)
curses.init_pair(5, curses.COLOR_MAGENTA, -1)
else:
curses.init_pair(2, -1, curses.COLOR_RED)
curses.init_pair(3, 0, curses.COLOR_GREEN)
curses.init_pair(5, -1, curses.COLOR_MAGENTA)
curses.init_pair(4, curses.COLOR_BLUE, -1)
curses.init_pair(6, curses.COLOR_RED, -1)
curses.init_pair(7, curses.COLOR_GREEN, -1)
curses.init_pair(8, curses.COLOR_MAGENTA, -1)
# Colors text styles
no_color = curses.color_pair(1)
default_color = curses.color_pair(3) | A_BOLD
nice_color = curses.color_pair(8)
cpu_time_color = curses.color_pair(8)
ifCAREFUL_color = curses.color_pair(4) | A_BOLD
ifWARNING_color = curses.color_pair(5) | A_BOLD
ifCRITICAL_color = curses.color_pair(2) | A_BOLD
default_color2 = curses.color_pair(7)
ifCAREFUL_color2 = curses.color_pair(4)
ifWARNING_color2 = curses.color_pair(8) | A_BOLD
ifCRITICAL_color2 = curses.color_pair(6) | A_BOLD
ifINFO_color = curses.color_pair(4)
filter_color = A_BOLD
selected_color = A_BOLD
separator = curses.color_pair(1)
if curses.COLORS > 8:
# ex: export TERM=xterm-256color
colors_list = [curses.COLOR_CYAN, curses.COLOR_YELLOW]
for i in range(0, 3):
try:
curses.init_pair(i + 9, colors_list[i], -1)
except Exception:
curses.init_pair(i + 9, -1, -1)
filter_color = curses.color_pair(9) | A_BOLD
selected_color = curses.color_pair(10) | A_BOLD
# Define separator line style
try:
curses.init_color(11, 500, 500, 500)
curses.init_pair(11, curses.COLOR_BLACK, -1)
separator = curses.color_pair(11)
except Exception:
# Catch exception in TMUX
pass
else:
# The screen is NOT compatible with a colored design
# switch to B&W text styles
# ex: export TERM=xterm-mono
no_color = -1
default_color = -1
nice_color = A_BOLD
cpu_time_color = A_BOLD
ifCAREFUL_color = A_BOLD
ifWARNING_color = curses.A_UNDERLINE
ifCRITICAL_color = curses.A_REVERSE
default_color2 = -1
ifCAREFUL_color2 = A_BOLD
ifWARNING_color2 = curses.A_UNDERLINE
ifCRITICAL_color2 = curses.A_REVERSE
ifINFO_color = A_BOLD
filter_color = A_BOLD
selected_color = A_BOLD
separator = -1
# Define the colors list (hash table) for stats
return {
'DEFAULT': no_color,
'UNDERLINE': curses.A_UNDERLINE,
'BOLD': A_BOLD,
'SORT': curses.A_UNDERLINE | A_BOLD,
'OK': default_color2,
'MAX': default_color2 | A_BOLD,
'FILTER': filter_color,
'TITLE': title_color,
'PROCESS': default_color2,
'PROCESS_SELECTED': default_color2 | curses.A_UNDERLINE,
'STATUS': default_color2,
'NICE': nice_color,
'CPU_TIME': cpu_time_color,
'CAREFUL': ifCAREFUL_color2,
'WARNING': ifWARNING_color2,
'CRITICAL': ifCRITICAL_color2,
'OK_LOG': default_color,
'CAREFUL_LOG': ifCAREFUL_color,
'WARNING_LOG': ifWARNING_color,
'CRITICAL_LOG': ifCRITICAL_color,
'PASSWORD': curses.A_PROTECT,
'SELECTED': selected_color,
'INFO': ifINFO_color,
'ERROR': selected_color,
'SEPARATOR': separator,
}