diff --git a/.gitignore b/.gitignore index 6cd35f5..47d4bab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ __pycache__/ venv3/ -.gitignore *.log diff --git a/README.md b/README.md index caae500..4aeac12 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # QLPyCon - Quake Live Python Console -A modular, refactored terminal-based client for monitoring Quake Live servers via ZMQ. - -## Version 0.8.0 - Modular Architecture +A modular, refactored terminal-based client for monitoring and remote controlling Quake Live servers via ZMQ. ### Features @@ -93,15 +91,6 @@ python main.py --unknown-log my_unknown.log - Threaded input queue for non-blocking commands - Color rendering with curses -### Key Improvements Over v0.7.0 - -1. **Modular Design** - Separated concerns into focused modules -2. **Clean Classes** - OOP design for state and connections -3. **Better Maintainability** - Each module has a single responsibility -4. **Easier Testing** - Components can be tested independently -5. **Clear Interfaces** - Well-defined APIs between modules -6. **Improved Comments** - Every module, class, and function documented - ### Event Types Supported - `PLAYER_SWITCHTEAM` - Team changes @@ -125,20 +114,6 @@ Quake Live uses `^N` color codes where N is 0-7: - `^6` - Magenta - `^7` - White (default) -### Development - -To extend QLPyCon: - -1. **Add new event types** - Edit `parser.py`, add handler method -2. **Change UI layout** - Edit `ui.py`, modify window creation -3. **Add new commands** - Edit `main.py`, handle in main loop -4. **Modify formatting** - Edit `formatter.py`, adjust color/timestamp logic -5. **Add configuration** - Edit `config.py`, add constants - ### License -MIT License - See original qlpycon.py for details - -### Credits - -Refactored from qlpycon.py v0.7.0 +WTFPL diff --git a/ui.py b/ui.py index bfed193..94e1c85 100644 --- a/ui.py +++ b/ui.py @@ -36,38 +36,40 @@ class CursesHandler(logging.Handler): except: self.handleError(record) - def print_colored(window, message, attributes=0): """ Print message with Quake color codes (^N) - ^0 = black, ^1 = red, ^2 = green, ^3 = yellow, ^4 = blue, ^5 = cyan, ^6 = magenta, ^7 = white + ^0 = bold, ^1 = red, ^2 = green, ^3 = yellow, ^4 = blue, ^5 = cyan, ^6 = magenta, ^7 = white/reset """ if not curses.has_colors: window.addstr(message) return color = 0 + bold = False parse_color = False for ch in message: val = ord(ch) if parse_color: - if ord('0') <= val <= ord('7'): + if ch == '0': + bold = True + elif ch == '7': + color = 0 + bold = False + elif ord('1') <= val <= ord('6'): color = val - ord('0') - if color == 7: - color = 0 else: - window.addch('^', curses.color_pair(color) | attributes) - window.addch(ch, curses.color_pair(color) | attributes) + window.addch('^', curses.color_pair(color) | (curses.A_BOLD if bold else 0) | attributes) + window.addch(ch, curses.color_pair(color) | (curses.A_BOLD if bold else 0) | attributes) parse_color = False elif ch == '^': parse_color = True else: - window.addch(ch, curses.color_pair(color) | attributes) + window.addch(ch, curses.color_pair(color) | (curses.A_BOLD if bold else 0) | attributes) window.refresh() - class UIManager: """Manages curses windows and display""" @@ -196,7 +198,7 @@ class UIManager: # Line 1: Hostname hostname = server_info.hostname - print_colored(self.info_window, f"^6═══ {hostname} ^6═══^7\n", 0) + print_colored(self.info_window, f"^6═══^0 {hostname} ^7^6═══^7\n", 0) # Line 2: Game info gametype = server_info.gametype @@ -209,14 +211,14 @@ class UIManager: maxclients = server_info.maxclients print_colored(self.info_window, - f"^3Type:^7 {gametype} ^3Map:^7 {mapname} ^3Players:^7 {curclients}/{maxclients} " - f"^3Limits (T/F/R/C):^7 {timelimit}/{fraglimit}/{roundlimit}/{caplimit}\n", 0) + f"^3Type:^7^0 {gametype} ^7^3Map:^7^0 {mapname} ^7^3Players:^7^0 {curclients}/{maxclients} " + f"^7^3Limits (T/F/R/C):^7 {timelimit}/{fraglimit}/{roundlimit}/{caplimit}\n", 0) # Line 3: Team headers and player lists teams = game_state.player_tracker.get_players_by_team() if server_info.gametype in TEAM_MODES: - print_colored(self.info_window, f"^1(RED) ^4(BLUE) ^3(SPEC)\n", 0) + print_colored(self.info_window, f"^0^1(RED) ^4(BLUE) ^3(SPEC)\n", 0) red_players = teams['RED'][:4] blue_players = teams['BLUE'][:4] @@ -240,7 +242,7 @@ class UIManager: line = f"{red}{' ' * red_pad}{blue}{' ' * blue_pad}{spec}\n" print_colored(self.info_window, line, 0) else: - print_colored(self.info_window, f"^3(FREE)\n", 0) + print_colored(self.info_window, f"^0^3(FREE)\n", 0) free_players = teams['FREE'][:4] for player in free_players: print_colored(self.info_window, f"{player}\n", 0)