Warto oddzielić to, co jest na ekranie, GUI (czyli ten bounding box) od samej logiki danego narzędzia do rysowania linii.
No bo takie narzędzie do generowania linii może być bardzo proste:
- przyjmij pozycję x,y i zapamiętaj ją jako punkt startowy
- w pętli: nasłuchuj pozycji x,y i emituj ją jako punkt końcowy (z możliwością update'u)
- poczekaj na zatwierdzenie pozycji x,y i emituj ją jako punkt końcowy
czyli w pseudokodzie:
Kopiuj
start = null
end = null
event = await mouseDown
start = event.position
while event = await mouseUp or mouseMove:
end = event.position
match event:
mouseMove:
emit {start, end, done=false}
mouseUp:
emit {start, end, done=true}
return
Natomiast to nie ma wiele wspólnego z tym czy coś jest resizable. Równie dobrze takie narzędzie może działać headless. Np. mógłbyś mieć system wtyczek i odpalać narzędzie z poziomu wtyczki.
Czyli ja bym trzymał oddzielnie ResizableTool (jako coś, co odpowiada za bounding boxy) od samego narzędzia rozumianego jako logiczny sposób interakcji/generowania konkretnej geometrii.
Wtedy też decyzja jak to będzie w GUI nie będzie żadną ważną decyzję architektoniczną, a po prostu tym, czy podepniesz ResizableTool pod logikę narzędzia, czy nie podepniesz. Opieranie się na dziedziczeniu w tym momencie wydaje się hakiem implementacyjnym, a nie czymś, co ma sens na poziomie architektury.