feat: implement flashing support (0x08/0x09) with 1Hz timer
This commit is contained in:
@@ -63,6 +63,12 @@ class TeletextCanvas(QWidget):
|
|||||||
self.service = None # Reference to TeletextService for DRCS/Shared data
|
self.service = None # Reference to TeletextService for DRCS/Shared data
|
||||||
self.subset_idx = 0 # Default English
|
self.subset_idx = 0 # Default English
|
||||||
|
|
||||||
|
# Flashing state
|
||||||
|
self.flash_on = True
|
||||||
|
self.flash_timer = QTimer(self)
|
||||||
|
self.flash_timer.timeout.connect(self.toggle_flash)
|
||||||
|
self.flash_timer.start(500) # 500ms toggle (1Hz flash rate)
|
||||||
|
|
||||||
# Teletext is 40 columns x 25 rows
|
# Teletext is 40 columns x 25 rows
|
||||||
# We will render to a fixed size QImage and scale it
|
# We will render to a fixed size QImage and scale it
|
||||||
self.cols = 40
|
self.cols = 40
|
||||||
@@ -87,6 +93,12 @@ class TeletextCanvas(QWidget):
|
|||||||
self.cursor_is_graphics = False # Tracked during draw
|
self.cursor_is_graphics = False # Tracked during draw
|
||||||
# Blinking cursor timer could be added, for now static inverted is fine or toggle on timer elsewhere
|
# Blinking cursor timer could be added, for now static inverted is fine or toggle on timer elsewhere
|
||||||
|
|
||||||
|
def toggle_flash(self):
|
||||||
|
self.flash_on = not self.flash_on
|
||||||
|
if self.page:
|
||||||
|
self.redraw()
|
||||||
|
self.update()
|
||||||
|
|
||||||
def get_byte_at(self, x, y):
|
def get_byte_at(self, x, y):
|
||||||
if not self.page: return 0
|
if not self.page: return 0
|
||||||
|
|
||||||
@@ -274,6 +286,7 @@ class TeletextCanvas(QWidget):
|
|||||||
hold_graphics = False
|
hold_graphics = False
|
||||||
held_char = 0x20 # Space
|
held_char = 0x20 # Space
|
||||||
double_height = False
|
double_height = False
|
||||||
|
flashing = False
|
||||||
|
|
||||||
last_visible_idx = -1
|
last_visible_idx = -1
|
||||||
bg_segments = [(0, bg)] # Track BG changes: (index, color)
|
bg_segments = [(0, bg)] # Track BG changes: (index, color)
|
||||||
@@ -364,6 +377,10 @@ class TeletextCanvas(QWidget):
|
|||||||
break
|
break
|
||||||
painter.fillRect(k * self.cell_w, y, self.cell_w, self.cell_h * 2, cell_bg)
|
painter.fillRect(k * self.cell_w, y, self.cell_w, self.cell_h * 2, cell_bg)
|
||||||
|
|
||||||
|
elif byte_val == 0x08: # Start Flashing
|
||||||
|
flashing = True
|
||||||
|
elif byte_val == 0x09: # Steady
|
||||||
|
flashing = False
|
||||||
elif byte_val == 0x19: # Contiguous Graphics
|
elif byte_val == 0x19: # Contiguous Graphics
|
||||||
contiguous = True
|
contiguous = True
|
||||||
elif byte_val == 0x1A: # Separated Graphics
|
elif byte_val == 0x1A: # Separated Graphics
|
||||||
@@ -410,45 +427,60 @@ class TeletextCanvas(QWidget):
|
|||||||
|
|
||||||
# Draw Foreground
|
# Draw Foreground
|
||||||
if draw_fg:
|
if draw_fg:
|
||||||
# Calculate height
|
# If flashing is active and flash is in 'off' state, skip drawing FG
|
||||||
# For Mosaics, we use the height param.
|
if not (flashing and not self.flash_on):
|
||||||
# For Alphanumerics, we scale the painter.
|
# Calculate height
|
||||||
|
# For Mosaics, we use the height param.
|
||||||
|
# For Alphanumerics, we scale the painter.
|
||||||
|
|
||||||
if is_control:
|
if is_control:
|
||||||
# "Set-at" spacing attribute? Teletext control codes occupy a space
|
# "Set-at" spacing attribute? Teletext control codes occupy a space
|
||||||
# unless "Hold Graphics" replaces it with previous graphic char.
|
# unless "Hold Graphics" replaces it with previous graphic char.
|
||||||
if hold_graphics and graphics_mode:
|
if hold_graphics and graphics_mode:
|
||||||
if double_height:
|
if double_height:
|
||||||
self.draw_mosaic(painter, x, y, held_char, fg, contiguous, height=self.cell_h * 2)
|
self.draw_mosaic(painter, x, y, held_char, fg, contiguous, height=self.cell_h * 2)
|
||||||
|
else:
|
||||||
|
self.draw_mosaic(painter, x, y, held_char, fg, contiguous)
|
||||||
else:
|
else:
|
||||||
self.draw_mosaic(painter, x, y, held_char, fg, contiguous)
|
# Draw space (nothing, since we filled BG)
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
# Draw space (nothing, since we filled BG)
|
# Check for DRCS
|
||||||
pass
|
drcs_char = None
|
||||||
else:
|
if self.page and hasattr(self, 'parent') and hasattr(self.parent(), 'service'):
|
||||||
# Check for DRCS
|
# Try to find drcs in service
|
||||||
drcs_char = None
|
service = self.parent().service
|
||||||
if self.page and hasattr(self, 'parent') and hasattr(self.parent(), 'service'):
|
# For now, assume Set 0 if we have drcs_data for this code
|
||||||
# Try to find drcs in service
|
drcs_char = service.drcs_data.get((0, byte_val))
|
||||||
service = self.parent().service
|
|
||||||
# For now, assume Set 0 if we have drcs_data for this code
|
|
||||||
drcs_char = service.drcs_data.get((0, byte_val))
|
|
||||||
|
|
||||||
# Alternatively, if we just want it to work in the test where we might not have parent()
|
# Alternatively, if we just want it to work in the test where we might not have parent()
|
||||||
# We can store a reference to the service in the canvas
|
# We can store a reference to the service in the canvas
|
||||||
if not drcs_char and hasattr(self, 'service') and self.service:
|
if not drcs_char and hasattr(self, 'service') and self.service:
|
||||||
drcs_char = self.service.drcs_data.get((0, byte_val))
|
drcs_char = self.service.drcs_data.get((0, byte_val))
|
||||||
|
|
||||||
if drcs_char:
|
if drcs_char:
|
||||||
self.draw_drcs(painter, x, y, drcs_char, fg, double_height)
|
self.draw_drcs(painter, x, y, drcs_char, fg, double_height)
|
||||||
elif graphics_mode:
|
elif graphics_mode:
|
||||||
# Mosaic Graphics
|
# Mosaic Graphics
|
||||||
h_mos = self.cell_h * 2 if double_height else self.cell_h
|
h_mos = self.cell_h * 2 if double_height else self.cell_h
|
||||||
if (0x20 <= byte_val <= 0x3F) or (0x60 <= byte_val <= 0x7F):
|
if (0x20 <= byte_val <= 0x3F) or (0x60 <= byte_val <= 0x7F):
|
||||||
self.draw_mosaic(painter, x, y, byte_val, fg, contiguous, height=h_mos)
|
self.draw_mosaic(painter, x, y, byte_val, fg, contiguous, height=h_mos)
|
||||||
held_char = byte_val
|
held_char = byte_val
|
||||||
|
else:
|
||||||
|
# Capital letter in graphics mode? Usually shows char?
|
||||||
|
char = get_char(byte_val, self.subset_idx)
|
||||||
|
painter.setPen(fg)
|
||||||
|
if double_height:
|
||||||
|
painter.save()
|
||||||
|
painter.translate(x, y)
|
||||||
|
painter.scale(1, 2)
|
||||||
|
painter.drawText(QRect(0, 0, self.cell_w, self.cell_h), Qt.AlignmentFlag.AlignCenter, char)
|
||||||
|
painter.restore()
|
||||||
|
else:
|
||||||
|
painter.drawText(QRect(x, y, self.cell_w, self.cell_h), Qt.AlignmentFlag.AlignCenter, char)
|
||||||
|
held_char = 0x20
|
||||||
else:
|
else:
|
||||||
# Capital letter in graphics mode? Usually shows char?
|
# Alphanumeric
|
||||||
char = get_char(byte_val, self.subset_idx)
|
char = get_char(byte_val, self.subset_idx)
|
||||||
painter.setPen(fg)
|
painter.setPen(fg)
|
||||||
if double_height:
|
if double_height:
|
||||||
@@ -459,19 +491,6 @@ class TeletextCanvas(QWidget):
|
|||||||
painter.restore()
|
painter.restore()
|
||||||
else:
|
else:
|
||||||
painter.drawText(QRect(x, y, self.cell_w, self.cell_h), Qt.AlignmentFlag.AlignCenter, char)
|
painter.drawText(QRect(x, y, self.cell_w, self.cell_h), Qt.AlignmentFlag.AlignCenter, char)
|
||||||
held_char = 0x20
|
|
||||||
else:
|
|
||||||
# Alphanumeric
|
|
||||||
char = get_char(byte_val, self.subset_idx)
|
|
||||||
painter.setPen(fg)
|
|
||||||
if double_height:
|
|
||||||
painter.save()
|
|
||||||
painter.translate(x, y)
|
|
||||||
painter.scale(1, 2)
|
|
||||||
painter.drawText(QRect(0, 0, self.cell_w, self.cell_h), Qt.AlignmentFlag.AlignCenter, char)
|
|
||||||
painter.restore()
|
|
||||||
else:
|
|
||||||
painter.drawText(QRect(x, y, self.cell_w, self.cell_h), Qt.AlignmentFlag.AlignCenter, char)
|
|
||||||
# Draw Cursor
|
# Draw Cursor
|
||||||
# Invert the cell at cursor position
|
# Invert the cell at cursor position
|
||||||
if draw_fg and self.cursor_visible and c == self.cursor_x and row == self.cursor_y:
|
if draw_fg and self.cursor_visible and c == self.cursor_x and row == self.cursor_y:
|
||||||
|
|||||||
Reference in New Issue
Block a user