diff --git a/projector.py b/projector.py index 537825c..b62cd35 100755 --- a/projector.py +++ b/projector.py @@ -21,6 +21,7 @@ import sqlite3 import tkinter as tk +from tkinter import font import json import os import math @@ -128,13 +129,18 @@ class SongProjector: self.right_frame.pack(side="right", fill="y") font_weight = "bold" if self.settings.get("font_bold", False) else "normal" + self.custom_font = font.Font( + family=self.settings["font_name"], + size=int(self.settings["font_size"]), + weight=font_weight + ) self.display_text = tk.Label( self.color_frame, text="", bg=self.settings["bg_color"], fg=self.settings["fg_color"], - font=(self.settings["font_name"], int(self.settings["font_size"]), font_weight), + font=self.custom_font, wraplength=color_width, justify="center" ) @@ -228,37 +234,28 @@ class SongProjector: def split_long_line(self, line): """ Vrne seznam pod-vrstic, ki skupaj tvorijo `line`, - pri čemer so (približno) enako dolge glede na število znakov. + pri čemer so dolge največ `self.color_width` pikslov. """ - avg_char_width = int(self.settings["font_size"]) * 0.57 - wraplength_px = self.color_width - # Koliko znakov približno gre v eno vrstico - approx_chars_per_line = max(1, int(wraplength_px / avg_char_width)) - - if len(line) <= approx_chars_per_line: - return [line] - - # Potrebno število pod-vrstic - n_sub = math.ceil(len(line) / approx_chars_per_line) - words = line.split() - total_chars = sum(len(w) for w in words) + len(words) - 1 # vključno s presledki - target_len = total_chars / n_sub + if not words: + return [""] sub_lines = [] current_words = [] - current_len = 0 for word in words: - added_len = len(word) + (1 if current_words else 0) # presledek pred besedo, če ni prva - if current_len + added_len > target_len and len(sub_lines) < n_sub - 1: - # Začni novo vrstico - sub_lines.append(" ".join(current_words)) - current_words = [word] - current_len = len(word) - else: + test_line = " ".join(current_words + [word]) + # Izmerimo širino v pikslih + if self.custom_font.measure(test_line) <= self.color_width: current_words.append(word) - current_len += added_len + else: + if current_words: + sub_lines.append(" ".join(current_words)) + current_words = [word] + else: + # Beseda je sama po sebi predolga (zelo redko) + sub_lines.append(word) + current_words = [] if current_words: sub_lines.append(" ".join(current_words)) @@ -330,75 +327,70 @@ class SongProjector: if result: lyrics = result[0] - max_height = self.screen_height - (self.line_height * 1.5) - avg_char_width = int(self.settings["font_size"]) * 0.57 - wraplength = self.color_width + max_height = self.screen_height - (self.line_height * 2) - # ------------------------------------------- - # 1. Razbijanje besedila na (pod-)vrstice - # ------------------------------------------- - raw_lines = lyrics.strip().splitlines() - processed_lines = [] - for raw in raw_lines: - if raw.strip() == "": - processed_lines.append("") # ohranimo prazno vrstico - else: - processed_lines.extend(self.split_long_line(raw)) + # 1. Razdelimo na kitice (stanzas) + # Kitice so ločene z eno ali več praznimi vrsticami + import re + stanzas_raw = re.split(r'\n\s*\n', lyrics.strip()) + + processed_stanzas = [] + for stanza in stanzas_raw: + lines = stanza.splitlines() + stanza_lines = [] + for line in lines: + if line.strip(): + stanza_lines.extend(self.split_long_line(line)) + if stanza_lines: + processed_stanzas.append(stanza_lines) - # ------------------------------------------- - # 2. Razdeljevanje vrstic na strani - # ------------------------------------------- + # 2. Razdeljevanje kitic na strani pages = [] current_page_lines = [] current_height = 0 - blank_line_count = 0 - for line in processed_lines: - is_blank = (line.strip() == "") - if is_blank: - blank_line_count += 1 - else: - blank_line_count = 0 - - approx_line_length = len(line) - approx_line_count = 1 if is_blank else math.ceil((approx_line_length * avg_char_width) / wraplength) - needed_height = self.line_height * approx_line_count - - # Prazna vrstica več kot 1-krat pomeni nova kitica ⇒ nova stran - if blank_line_count >= 2: + for stanza in processed_stanzas: + stanza_height = len(stanza) * self.line_height + + # Če kitica sama po sebi presega max_height, jo moramo razdeliti + if stanza_height > max_height: + # Če imamo že kaj na strani, to zaključimo if current_page_lines: - pages.append("\n".join(current_page_lines).strip()) + pages.append("\n".join(current_page_lines)) current_page_lines = [] current_height = 0 - blank_line_count = 0 - continue - - # Če čez spodnji rob strani … - if current_height + needed_height > max_height + self.line_height // 2: - # poskusimo prelomiti na prazni vrstici znotraj strani - found_split = False - for i in reversed(range(len(current_page_lines))): - if current_page_lines[i].strip() == "": - pages.append("\n".join(current_page_lines[:i]).strip()) - current_page_lines = current_page_lines[i + 1:] - current_height = sum( - self.line_height * ( - 1 if l.strip() == "" else math.ceil(len(l) * avg_char_width / wraplength) - ) - for l in current_page_lines - ) - found_split = True - break - if not found_split: - pages.append("\n".join(current_page_lines).strip()) - current_page_lines = [] - current_height = 0 - - current_page_lines.append(line) - current_height += needed_height + + # Razdelimo predolgo kitico na več strani + temp_stanza_lines = [] + temp_height = 0 + for line in stanza: + if temp_height + self.line_height > max_height: + pages.append("\n".join(temp_stanza_lines)) + temp_stanza_lines = [line] + temp_height = self.line_height + else: + temp_stanza_lines.append(line) + temp_height += self.line_height + if temp_stanza_lines: + current_page_lines = temp_stanza_lines + current_height = temp_height + + # Če kitica ne gre več na trenutno stran + elif current_height + stanza_height + (self.line_height if current_page_lines else 0) > max_height: + pages.append("\n".join(current_page_lines)) + current_page_lines = stanza + current_height = stanza_height + + # Kitica gre na trenutno stran + else: + if current_page_lines: + current_page_lines.append("") # Razmik med kiticami + current_height += self.line_height + current_page_lines.extend(stanza) + current_height += stanza_height if current_page_lines: - pages.append("\n".join(current_page_lines).strip()) + pages.append("\n".join(current_page_lines)) self.pages = pages self.current_page_index = 0