v0.1.3 — Centered Teletext frame, added full footer with color band, and finalized header alignment.

This commit is contained in:
Stu Leak 2025-11-03 11:17:44 -05:00
parent 64f0e74105
commit 211ebfcd01
9 changed files with 67 additions and 63 deletions

22
main.py
View File

@ -1,13 +1,12 @@
# ============================================================
# File: /home/stu/Projects/Local REPO/telefact/main.py
# File: /telefact/main.py
# Description:
# Entry point for the Telefact Broadcaster mode.
# Initializes the Tkinter window, loads configuration,
# and renders the Teletext grid with dynamic header.
# and renders the Teletext grid with dynamic header/footer.
# ============================================================
import tkinter as tk
from src.config_manager import ConfigManager
from src.telefact_renderer import TelefactRenderer
from src.core.telefact_frame import TelefactFrame
@ -31,34 +30,33 @@ def main():
height=config["ScreenHeight"],
show_grid=config.get("ShowGrid", False),
font_path=config["Font"]["Path"],
font_size=config["Font"]["Size"],
)
# --- Prepare frame ---
frame = TelefactFrame()
# --- Initialize header ---
# --- Header ---
header = TelefactHeader(frame, config)
header.render()
header.update_time(root, renderer)
# --- Initialize footer ---
footer = TelefactFooter(frame, config)
footer.render_test_footer()
# --- Body & footer test content ---
# --- Body content ---
formatter = TelefactFormatter(frame)
formatter.add_body_line(1, "Welcome to the Telefact Broadcaster base.", align="center", color="white")
formatter.add_body_line(3, "Press Q or ESC to exit.", align="center", color="cyan")
formatter.set_footer("PAGE 100 TELEFACT", align="center", color="green")
# --- Render frame ---
# --- Footer (replaces old PAGE 100 TELEFACT) ---
footer = TelefactFooter(frame, config)
footer.set_footer("Telefact: The world at your fingertips", align="left", fg="yellow", bg="blue")
# --- Render everything ---
renderer.render(frame)
# --- Bind exit keys ---
root.bind("<Escape>", lambda e: root.quit())
root.bind("q", lambda e: root.quit())
# --- Start loop ---
root.mainloop()

Binary file not shown.

View File

@ -2,8 +2,7 @@
# File: /home/stu/Projects/Local REPO/telefact/src/core/telefact_footer.py
# Description:
# Dynamic Telefact footer renderer for broadcaster mode.
# Draws a single bottom-row text band with background color
# and per-page contextual support.
# Draws a single bottom-row text band with full background fill.
# ============================================================
from src.core.telefact_frame import TelefactFrame
@ -22,24 +21,24 @@ class TelefactFooter:
self.frame = frame
self.config = config
# default colors from global config
# Default colors
colours = config.get("Colours", {})
self.default_bg = colours.get("Footer", "blue")
self.default_fg = colours.get("TextPrimary", "white")
# reserved footer row (last visible line)
# Reserved row (bottom row = line 24)
self.row = frame.rows - 1
# --------------------------------------------------------
def clear_footer(self, bg: str | None = None):
"""Clears the footer line with background fill."""
"""Clears the footer row with solid background color."""
bg_color = bg or self.default_bg
for c in range(self.frame.cols):
self.frame.set_cell(c, self.row, " ", self.default_fg, bg_color)
# --------------------------------------------------------
def set_footer(self, text: str, align: str = "left", fg: str | None = None, bg: str | None = None):
"""Draw a footer message with color and alignment control."""
"""Draw footer message with proper background fill."""
fg_color = fg or self.default_fg
bg_color = bg or self.default_bg
self.clear_footer(bg_color)
@ -47,25 +46,26 @@ class TelefactFooter:
text = text.strip()
text_len = len(text)
# --- Alignment handling ---
# Alignment
if align == "center":
start_col = (self.frame.cols - text_len) // 2
elif align == "right":
start_col = max(self.frame.cols - text_len - 1, 0)
else:
start_col = 1
start_col = 1 # left padding
# --- Background fill ---
for c in range(self.frame.cols):
self.frame.set_cell(c, self.row, " ", fg_color, bg_color)
# --- Text overlay ---
# Draw each character with full background
for i, ch in enumerate(text):
pos = start_col + i
if 0 <= pos < self.frame.cols:
self.frame.set_cell(pos, self.row, ch, fg_color)
self.frame.set_cell(pos, self.row, ch, fg_color, bg_color)
# --------------------------------------------------------
def render_test_footer(self):
"""Temporary demo for testing footer display."""
self.set_footer("Telefact: The world at your fingertips", align="left", fg="yellow", bg="blue")
self.set_footer(
"Telefact: The world at your fingertips",
align="left",
fg="yellow",
bg="blue",
)

View File

@ -1,5 +1,5 @@
# ============================================================
# File: /home/stu/Projects/Local REPO/telefact/src/core/telefact_frame.py
# File: /telefact/src/core/telefact_frame.py
# Description:
# Telefact Frame (model)
# Defines a 40×24 grid and logical regions for Teletext layout.

View File

@ -1,5 +1,5 @@
# ============================================================
# File: /home/stu/Projects/Local REPO/telefact/src/core/telefact_header.py
# File: /telefact/src/core/telefact_header.py
# Description:
# Dynamic Telefact header renderer for broadcaster mode.
# Displays page numbers, centered service name block with

View File

@ -1,10 +1,9 @@
# ============================================================
# File: /home/stu/Projects/Local REPO/telefact/src/telefact_renderer.py
# File: /telefact/src/telefact_renderer.py
# Description:
# Telefact Renderer (Tkinter)
# Renders a 40×24 Telefact grid with full foreground/background
# colour support, aligned inside a CRT-style safe area margin.
# No header/footer bars — layout calibration only.
# colour support, perfectly centered inside the window.
# ============================================================
import os
@ -44,20 +43,33 @@ class TelefactRenderer:
self.height = height
self.show_grid = show_grid
# Teletext dimensions
# Teletext logical dimensions
self.cols, self.rows = 40, 24
# Safe area margins (simulate CRT overscan)
self.margin_x = 24
self.margin_y = 24
self.inner_w = width - self.margin_x * 2
self.inner_h = height - self.margin_y * 2
# --- Dynamic centered layout ---
# Define safe area target margins
safe_margin_x = 24
safe_margin_y = 24
# Per-cell dimensions
self.cell_w = self.inner_w // self.cols
self.cell_h = self.inner_h // self.rows
self.w = self.inner_w
self.h = self.inner_h
# Compute total drawable region
self.inner_w = width - safe_margin_x * 2
self.inner_h = height - safe_margin_y * 2
# Compute exact per-cell dimensions (float precision)
self.cell_w = self.inner_w / self.cols
self.cell_h = self.inner_h / self.rows
# Compute corrected total grid size (may differ slightly due to float math)
total_grid_w = self.cell_w * self.cols
total_grid_h = self.cell_h * self.rows
# --- Center grid on screen ---
self.margin_x = (width - total_grid_w) / 2
self.margin_y = (height - total_grid_h) / 2
# Cache total grid extents
self.w = total_grid_w
self.h = total_grid_h
# Base colours
self.colors = {
@ -101,12 +113,12 @@ class TelefactRenderer:
return ("Courier New", font_size, "bold")
# ------------------------------------------------------------------
def _gx(self, col: int) -> int:
"""Grid X coordinate."""
def _gx(self, col: int) -> float:
"""Grid X coordinate (precise, centered)."""
return self.margin_x + col * self.cell_w
def _gy(self, row: int) -> int:
"""Grid Y coordinate."""
def _gy(self, row: int) -> float:
"""Grid Y coordinate (precise, centered)."""
return self.margin_y + row * self.cell_h
# ------------------------------------------------------------------
@ -115,21 +127,18 @@ class TelefactRenderer:
x = self._gx(col)
y = self._gy(row)
# Draw background block
# Background rectangle
self.canvas.create_rectangle(
x,
y,
x + self.cell_w,
y + self.cell_h,
x, y, x + self.cell_w, y + self.cell_h,
fill=PALETTE.get(bg, bg),
outline=PALETTE.get(bg, bg),
outline=PALETTE.get(bg, bg)
)
# Draw text glyph
# Foreground glyph
if char.strip():
self.canvas.create_text(
x + 2,
y + self.cell_h // 2,
y + self.cell_h / 2,
anchor="w",
text=char,
font=self.font,
@ -138,7 +147,7 @@ class TelefactRenderer:
# ------------------------------------------------------------------
def _draw_grid(self) -> None:
"""Optional debug overlay for cell alignment."""
"""Optional grid overlay for visual debugging."""
for c in range(self.cols + 1):
x = self._gx(c)
self.canvas.create_line(
@ -152,20 +161,17 @@ class TelefactRenderer:
# ------------------------------------------------------------------
def render(self, frame: TelefactFrame) -> None:
"""Renders the full Telefact grid (foreground + background)."""
"""Renders the entire 40×24 Telefact grid."""
self.canvas.delete("all")
# Fill background
# Fill full canvas background
self.canvas.create_rectangle(
0,
0,
self.width,
self.height,
0, 0, self.width, self.height,
fill=PALETTE.get(self.colors["Background"], self.colors["Background"]),
width=0,
)
# Draw all cells (bg first, then text)
# Draw text grid (each cell: bg + fg)
for row in range(frame.rows):
for col in range(frame.cols):
ch, fg, bg = frame.get_cell(col, row)