[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Аналог на GDK_INVERT при cairo/GTK 3
From: |
Yavor Doganov |
Subject: |
Re: Аналог на GDK_INVERT при cairo/GTK 3 |
Date: |
Mon, 11 Nov 2019 01:40:32 +0200 |
User-agent: |
Wanderlust/2.15.9 (Almost Unreal) SEMI-EPG/1.14.7 (Harue) FLIM/1.14.9 (Gojō) APEL/10.8 EasyPG/1.0.0 Emacs/26 (x86_64-pc-linux-gnu) MULE/6.0 (HANACHIRUSATO) |
Kaloian Doganov wrote:
> Малко е неудобно да се чете функция без изрично упоменати входящи
> параметри. :-)
Извинявам се, реших да ги спестя, защото не съм ги променял
и вече дадох връзка към оригиналната функция. Ето ги:
static void
draw_selection (GtkPlotCanvas *canvas, GtkPlotCanvasChild *child,
GtkAllocation area)
GtkPlotCanvas е подклас на GtkWidget (в оригиналния код е на
GtkObject, но в GTK 3 този тип обект го няма), аргумента child може да
го игнорираш напълно, а area е структура (реално GdkRectangle, което
пък е cairo_rectangle_t) с 4 члена: x, y, width и height.
> Правилното изпълнение на тази стратегия (с прерисуване на всичко), е
> движението на мишката да тригерира прерисуване на графиката, а веднага
> след прерисуването на графиката да се рисува селекцията отгоре. Не
> знам как това се прави с GTK и Cairo, но нещо такова трябва да се
> организира. Представям си, че би могъл да се закачиш за ::draw и, ако
> имаш активна селекция, да си рисуваш селекцията веднага след като
> стандартния ::draw се изпълни, но това са хвърчащи фантазии.
Проблемът е, че при движението на мишката правоъгълника се променя и
нещо трябва да „трие“ следите. Точно това прави dovtk-lasso, което ми
изглежа доста сложно, за моя мозък поне. Състоянието се записва в
серия правоъгълници, които се опресняват при движението,
възстановявайки основата. Това GDK_INVERT го прави автоматично и то
"under the hood", както се казва.
> Не ми става ясно в какво се изразява премигването -- премигва само
> селекцията или цялата графика? Ако е само селекцията, този ефект
> сигурно ще изчезне ако рисуваш селекцията веднага след ::draw на
> графиката.
Трепти само селекцията и това е съвсем естествено, понеже след всяко
изпълнение на draw_selection (което е много пъти в рамките на този
motion event), се задейства ::draw, който рисува цялата графика
наново, изтривайки правогълника, очертаващ селекцията.
> При всички положения, обаче, ми се струва добра идея да се закачиш за
> ::draw и да рисуваш селекцията веднага след "стандартния" ::draw на
> графиката (по възможност синхронно, в същия пас на main queue-то).
Това прави dovtk-lasso. Обектът се закача на собствен ::draw, свързан
с g_signal_connect_after и чрез сложен (за мен) механизъм се грижи за
обновяването и възстановяването на териториите, които засягаш при
чертането на селекцията. Естествено, трябва да възбуждаш обновяването
чрез dovtk_lasso_update на съответните места в event handler-ите.
> Едва сега попрегледах кода в gtkplotcanvas.c и, честно казано, ми се
> струва, че логиката около рисуването на widget-а поначало е некоректна.
> Авторът има имплементация на draw, която не рисува пълният state на
> widget-а. Вместо това изглежда, че draw рисува базовата графика, а
> после авторът рисува допълнително в резултат от някакви събития (напр.
> движение на мишката). Това е доста кофти, защото ако draw бъде извикан
> по друг повод, нарисуваното на екрана ще излезе от синхрон с
> потребителския state.
Да, това е типична практика при много програми, писани за GTK 2 (и
1.2, BTW), работи си без проблем. Понеже събитието „провлачване с
мишка“ се инвалидира при почти всяко друго събитие, това не е голям
кахър.
> Ето един пример, който е малко измислен, но е първото което се сетих
> докато преглеждах кода: Ако натиснем левия бутон на мишката върху
> графиката, преместим курсора за да се появи селекция, и -- без да
> пускаме левия бутон -- натиснем клавишната комбинация за Maximize на
> текущия прозорец, селекцията се одрисква.
Пробва ли го? Аз съм на Window Maker и нямам клавишна комбинация за
максимизиране, но пробвах с Alt-Tab да положа друг прозорец върху
графиката -- това незабавано инвалидира селекцията и не се случва
нищо, просто пунктирания правоъгълник изчезва.
> Този ефект е пряко следствие от липсата на читав draw, който да
> отразява текущия модел върху екрана. Изображението на екрана се
> получава от основния draw, плюс още нафлякани неща върху него които се
> рисуват не по време на draw -- при движение на мишката се трие старата
> селекция, рисува се нова, т.н.
Дори и да се чертае само от ::draw, това няма как да промени нещата и
няма как да ме улесни по никакъв начин. На практика
gdk_window_begin_draw_frame чертае в offscreen буфер, който след
gdk_window_end_draw_frame се рисува ефективно на екрана. Ако чертая
само от ::draw и изпълнявам draw_selection оттам на базата на някаква
глобална булева променлива, която се контролира от event handler-ите,
това несъмнено е по-добре, но няма как да реши проблема с
възстановяването на основната графика при движението на мишката.
> Най-простият начин да се организират тези неща е събитията да водят до
> смяна на някакъв невидим state в widget-а (т.нар. модел), а draw да
> рисува на базата на този невидим state. Напр. event handler-а за
> движение на мишката трябва само да сменя някакви числови координати в
> модела на текущата селекция и да тригерира draw (независимо дали
> синхронно с draw или асинхронно с queue_draw), който да ги нарисува.
> Това е най-простият начин да се осигури кохерентност.
Това прави dovtk-lasso, хвърли едно око на кода. Искаше ми се точно
тази сложност да избегна.
> Вярно е, че понякога тригерирането на пълен redraw при всяко събитие
> може да води до големи разходи на ресурси.
Дизайнът на GTK 3 е изцяло подчинен на пестене на ресурси. Резултатът
е много повече код (като обем, а и понякога като сложност) за
разработчиците на приложения, но за сметка на повече ресурси. Както
се казваше навремето: казармата е тежка, но за сметка на това
продължителна.
Няма страшно, идва GTK 4, което ще е супер-юбер-хипер версия на
библиотеката. Толкова гот, че планират да чупят ABI регулярно.
> Струва ми се, че проблемите които срещаш с портването на селекцията
> са следствие от това, че авторът поначало е организирал рисуването
> нехигиенично.
Не, това е генерален проблем при GTK и cairo, който не съществува при
GDK 2. Както е писал потребителя във връзката, която дадох.