Вопсчем, у меня что-то получилось. Не знаю, насколько это правильно, но по крайней мере, используются штатные средства ББ.
Суть вот какая (жалко, ДРАКОНом не владею - нарисовал бы схему! Ничего, вот устаканятся дела - возьмём на вооружение).
На форме лежит кнопка (отображение-контейнер).
Код:
CONST
hoverDelay = 40;
TYPE
ActionHover = POINTER TO RECORD (Services.Action)
b: Button;
END;
Button = POINTER TO RECORD (Views.View)
control: ButtonContext;
bitmap: ButtonContext;
selected: BOOLEAN;
ident: Identity; (* temporary dummy model *)
focus: ButtonContext; (* current focus; either top or bottom *)
path: Path;
picw, pich: INTEGER; (* пользовательские габариты картинки *)
flat: BOOLEAN;
hover: BOOLEAN; (* признак "зависания" курсора над контролом *)
ahover: ActionHover;
END;
В обработчике сообщений контроллера, при получении сообщения
Controllers.CursorMessage взводится флаг "ховер", отображение обновляется и запускается отложенное действие:
Код:
| msg: Controllers.CursorMessage DO
IF ~b.hover THEN
b.hover := TRUE; b.Update; (* первоначальное включение ховера *)
IF b.ahover = NIL THEN (* запустить периодическую проверку ховера *)
NEW(b.ahover); b.ahover.b := b; Services.DoLater(b.ahover, Services.Ticks() + hoverDelay);
END
END
Процедура этого самого отложенного действия, периодически отсылает отображению сообщение HoverMsg. Ну и проверяет режим "ховера" - если таковой включён, то регистрируется заново, обеспечивая периодичность. А если "ховер" выключен, то процедура делает обновление отображения и вырубается.
Код:
(* Периодическая проверка ховера. Если курсор вне контрола, то ховер вырубается. Если нет, проверка запускается вновь.*)
PROCEDURE (a: ActionHover) Do;
VAR hoverMsg: HoverMsg;
BEGIN
Views.Broadcast(a.b, hoverMsg);
IF a.b.hover THEN Services.DoLater(a, Services.Ticks() + hoverDelay) ELSE Views.Update(a.b, Views.keepFrames) END
END Do;
Ну а в обработчике сообщений отображения, ловится сообщение HoverMsg, и запускается проверка координат курсора. То есть, в случае вылета курсора за пределы рамки отображения, отложенное действие отработает минимум два раза. Один раз отошлёт сообщение (при обработке которого выяснится, что курсор вне рамки), а второй раз - обнаружит выключение ховера и вырубится.
Код:
PROCEDURE (b: Button) HandleViewMsg (f: Views.Frame; VAR msg: Views.Message);
BEGIN
WITH msg: HoverMsg DO
CheckHover(f, b);
ELSE
END
END HandleViewMsg;
Ну и вот сама проверка координат курсора:
Код:
PROCEDURE CheckHover(f: Views.Frame; b: Button);
VAR w, h, x, y: INTEGER; modifiers: SET; isDown: BOOLEAN;
BEGIN
b.context.GetSize(w, h); f.Input(x, y, modifiers, isDown);
IF ((x > 0) & (x < w)) & ((y > 0) & (y <h)) THEN
IF ~b.hover THEN
b.hover := TRUE;
END
ELSE
IF b.hover THEN b.hover := FALSE; b.ahover := NIL END
END;
END CheckHover;