Skip to content

Commit f5f5609

Browse files
committed
Lyrics editor improvements (Taiko2k#2256)
* visible indicator for which column is active + new rect_abs function * fixup! visible indicator for which column is active + new rect_abs function * optimization * getting tired. starting 2 work on save box * exhausting myself * part 1 of save box done. switching gears * column labels basics * minor optimization * starting to work on better text cursor behavior * continued improvements * new edit handling is complete i think * time button refinements * replace all humiliation * icon changes, hacky workaround for text display bug, text edit fix for small window mode * (mostly) fix time display desync bug * beginnings of multiline text box * major progress on multiline text box * mlt * no idea what i'm doing * progress * text highlighting basics * multiline text box is alpha ready * starting to move back towards the editor * major highlight progress * yeah * don't remenbver what i did employers don't read these please * we are starting our final descent into pr airport * further refinements * ctrl text editing with line breax * abject misery back 2 drawing board. cool new ddt function * i think i've saved it i think all the text editing and highlighting is actually working again * regular typing and deleting fixed. found bug where you can't edit the very first character * possibly actually fixed but i dont believe it * Sloptimization™ * my brain is leaking out my ears * cleanup * one final nut to crack before i'm done * slop appeasement * fixed a severe and perplexing buggit add .git add .git add .! i think i'm genuinely ready now * final cleanup * styles and types * tiny spacing change * chaunge logge * final
1 parent a11d212 commit f5f5609

6 files changed

Lines changed: 1442 additions & 247 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
Changelog
33
---------
44

5+
### v11.1.2
6+
7+
- Revamps & refinements to both synced and static lyrics editors
8+
- Fixed bug that caused GNOME to occasionally crash when Tauon did
9+
10+
511
### v11.1.1
612

713
- Fixed seek and volume bars ignoring theme transparency (Carbon, Neon Love, Sunken)
@@ -11,6 +17,7 @@ Changelog
1117
### v11.1.0
1218

1319
- Added new Frost UI backround mode
20+
- Improved touch support
1421
- Combined visualiser and top panel menu
1522
- Fixed columns auto resize
1623
- Fixed synced lyrics not showing in lyrics widget

src/tauon/__main__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,3 +662,4 @@ def polyline(points: list[tuple[float, float]]) -> None:
662662
open_crash_log(crash_log_path)
663663
elif buttonid.value == BUTTON_ID_QUIT:
664664
pass
665+
sdl3.SDL_Quit()

src/tauon/t_modules/t_draw.py

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ def __init__(self, renderer: sdl3.LP_SDL_Renderer) -> None:
175175

176176
self.was_truncated = False
177177

178+
self._locate_cache: dict[tuple[str, int], Pango.Layout] = {}
179+
178180
def load_image(self, g: BytesIO) -> sdl3.LP_SDL_Surface:
179181
size = g.getbuffer().nbytes
180182
pointer = ctypes.c_void_p(ctypes.addressof(ctypes.c_char.from_buffer(g.getbuffer())))
@@ -259,6 +261,24 @@ def rect(self, rectangle: tuple[int, int, int, int], colour: ColourRGBA) -> None
259261
# else:
260262
# sdl3.SDL_RenderDrawRect(self.renderer, self.sdlrect)
261263

264+
def rect_abs(self, rectangle: tuple[int, int, int, int], colour: ColourRGBA) -> None:
265+
"""x1, y1, x2, y2"""
266+
sdl3.SDL_SetRenderDrawColor(self.renderer, colour.r, colour.g, colour.b, colour.a)
267+
268+
x1 = min(rectangle[0], rectangle[2])
269+
y1 = min(rectangle[1], rectangle[3])
270+
x2 = max(rectangle[0], rectangle[2])
271+
y2 = max(rectangle[1], rectangle[3])
272+
self.sdlrect.x = float(x1)
273+
self.sdlrect.y = float(y1)
274+
self.sdlrect.w = float(x2-x1)
275+
self.sdlrect.h = float(y2-y1)
276+
277+
# if fill:
278+
sdl3.SDL_RenderFillRect(self.renderer, self.sdlrect)
279+
# else:
280+
# sdl3.SDL_RenderDrawRect(self.renderer, self.sdlrect)
281+
262282
def bordered_rect(
263283
self, rectangle: tuple[int, int, int, int], fill_colour: ColourRGBA, outer_colour: ColourRGBA, border_size: int
264284
) -> None:
@@ -618,7 +638,7 @@ def __draw_text_cairo(
618638
layout.set_text(text, -1)
619639
except Exception:
620640
logging.exception(f"Text error on text: {text}")
621-
layout.set_text(text.encode("utf-8", "replace").decode("utf-8"), -1)
641+
layout.set_text(text.encode("utf-8", "replace").decode(), -1)
622642

623643
# logging.info(layout.get_direction(0))
624644

@@ -759,3 +779,78 @@ def text(
759779
)
760780

761781
return self.__draw_text_cairo(location, text, colour, font, max_w, bg, align, real_bg=real_bg, key=key)
782+
783+
def get_wrapped_lines(self, text: str, font: int, max_x: int) -> list[str]:
784+
"""this function is 95% Genuine Slop™
785+
imagines a beautiful world where the input text is wrapped and returns the separated lines as they would appear"""
786+
if not text:
787+
return []
788+
789+
if font not in self.f_dict:
790+
logging.info(f"Font not loaded: {font!s}")
791+
return [text]
792+
793+
max_x += 12
794+
max_x = round(max_x)
795+
796+
layout = self.layout
797+
layout.set_auto_dir(False)
798+
layout.set_font_description(self._font_description(font))
799+
layout.set_wrap(Pango.WrapMode.WORD_CHAR)
800+
layout.set_ellipsize(Pango.EllipsizeMode.NONE)
801+
layout.set_width(max_x * 1000)
802+
layout.set_height(-1)
803+
804+
all_lines: list[str] = []
805+
806+
# Split on real newlines ourselves so Pango only ever wraps a single
807+
# paragraph at a time — that way every line it returns is a soft wrap,
808+
# and every boundary between paragraphs is unambiguously a real \n.
809+
for paragraph in text.split("\n"):
810+
if paragraph == "":
811+
all_lines.append("\n")
812+
continue
813+
814+
try:
815+
layout.set_text(paragraph, -1)
816+
except Exception:
817+
logging.exception(f"Text error on text: {paragraph}")
818+
paragraph = paragraph.encode(encoding="replace").decode()
819+
layout.set_text(paragraph, -1)
820+
821+
encoded = paragraph.encode()
822+
for i, line in enumerate(layout.get_lines_readonly()):
823+
start = line.start_index
824+
end = start + line.length
825+
if i == 0 and all_lines:
826+
all_lines.append('\n' + encoded[start:end].decode())
827+
else:
828+
all_lines.append(encoded[start:end].decode())
829+
830+
return all_lines
831+
832+
def measure_and_locate(self, text: str, font: int, x_pixels: float, y_pixels: float = 0) -> tuple[float, int, bool]:
833+
"""this function is 100% Genuine Slop™
834+
provides a faster way of setting your cursor position based on mouse position"""
835+
key = (text, font)
836+
layout = self._locate_cache.get(key)
837+
if layout is None:
838+
layout = PangoCairo.create_layout(self.context)
839+
layout.set_font_description(self._font_description(font))
840+
layout.set_width(-1)
841+
layout.set_text(text, -1)
842+
self._locate_cache[key] = layout
843+
# simple bound so this doesn't grow forever
844+
if len(self._locate_cache) > 64:
845+
self._locate_cache.pop(next(iter(self._locate_cache)))
846+
847+
full_w_pango, _ = layout.get_size()
848+
full_w_px = full_w_pango / Pango.SCALE
849+
850+
inside, index, trailing = layout.xy_to_index(
851+
round(x_pixels * Pango.SCALE),
852+
round(y_pixels * Pango.SCALE),
853+
)
854+
char_index = len(text.encode()[:index].decode())
855+
856+
return full_w_px, char_index, bool(trailing)

0 commit comments

Comments
 (0)