diff --git a/src/teletext/renderer.py b/src/teletext/renderer.py index a173f8a..cd14c6e 100755 --- a/src/teletext/renderer.py +++ b/src/teletext/renderer.py @@ -63,6 +63,12 @@ class TeletextCanvas(QWidget): self.service = None # Reference to TeletextService for DRCS/Shared data 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 # We will render to a fixed size QImage and scale it self.cols = 40 @@ -87,6 +93,12 @@ class TeletextCanvas(QWidget): 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 + 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): if not self.page: return 0 @@ -274,6 +286,7 @@ class TeletextCanvas(QWidget): hold_graphics = False held_char = 0x20 # Space double_height = False + flashing = False last_visible_idx = -1 bg_segments = [(0, bg)] # Track BG changes: (index, color) @@ -364,6 +377,10 @@ class TeletextCanvas(QWidget): break 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 contiguous = True elif byte_val == 0x1A: # Separated Graphics @@ -410,45 +427,60 @@ class TeletextCanvas(QWidget): # Draw Foreground if draw_fg: - # Calculate height - # For Mosaics, we use the height param. - # For Alphanumerics, we scale the painter. - - if is_control: - # "Set-at" spacing attribute? Teletext control codes occupy a space - # unless "Hold Graphics" replaces it with previous graphic char. - if hold_graphics and graphics_mode: - if double_height: - 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: - # Draw space (nothing, since we filled BG) - pass - else: - # Check for DRCS - drcs_char = None - if self.page and hasattr(self, 'parent') and hasattr(self.parent(), 'service'): - # Try to find drcs in service - 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)) + # If flashing is active and flash is in 'off' state, skip drawing FG + if not (flashing and not self.flash_on): + # Calculate height + # For Mosaics, we use the height param. + # For Alphanumerics, we scale the painter. - # 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 - if not drcs_char and hasattr(self, 'service') and self.service: - drcs_char = self.service.drcs_data.get((0, byte_val)) - - if drcs_char: - self.draw_drcs(painter, x, y, drcs_char, fg, double_height) - elif graphics_mode: - # Mosaic Graphics - h_mos = self.cell_h * 2 if double_height else self.cell_h - if (0x20 <= byte_val <= 0x3F) or (0x60 <= byte_val <= 0x7F): - self.draw_mosaic(painter, x, y, byte_val, fg, contiguous, height=h_mos) - held_char = byte_val + if is_control: + # "Set-at" spacing attribute? Teletext control codes occupy a space + # unless "Hold Graphics" replaces it with previous graphic char. + if hold_graphics and graphics_mode: + if double_height: + 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: - # Capital letter in graphics mode? Usually shows char? + # Draw space (nothing, since we filled BG) + pass + else: + # Check for DRCS + drcs_char = None + if self.page and hasattr(self, 'parent') and hasattr(self.parent(), 'service'): + # Try to find drcs in service + 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() + # We can store a reference to the service in the canvas + if not drcs_char and hasattr(self, 'service') and self.service: + drcs_char = self.service.drcs_data.get((0, byte_val)) + + if drcs_char: + self.draw_drcs(painter, x, y, drcs_char, fg, double_height) + elif graphics_mode: + # Mosaic Graphics + h_mos = self.cell_h * 2 if double_height else self.cell_h + if (0x20 <= byte_val <= 0x3F) or (0x60 <= byte_val <= 0x7F): + self.draw_mosaic(painter, x, y, byte_val, fg, contiguous, height=h_mos) + 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: + # Alphanumeric char = get_char(byte_val, self.subset_idx) painter.setPen(fg) if double_height: @@ -459,19 +491,6 @@ class TeletextCanvas(QWidget): painter.restore() else: 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 # Invert the cell at cursor position if draw_fg and self.cursor_visible and c == self.cursor_x and row == self.cursor_y: