2 * Copyright (c) 2004, Joe English
4 * TtkTrackElementState() -- helper routine for widgets
5 * like scrollbars in which individual elements may
6 * be active or pressed instead of the widget as a whole.
9 * TtkTrackElementState(&recordPtr->core);
11 * Registers an event handler on the widget that tracks pointer
12 * events and updates the state of the element under the
15 * The "active" element is the one under the mouse cursor,
16 * and is normally set to the ACTIVE state unless another element
17 * is currently being pressed.
19 * The active element becomes "pressed" on <ButtonPress> events,
20 * and remains "active" and "pressed" until the corresponding
21 * <ButtonRelease> event.
23 * TODO: Handle "chords" properly (e.g., <B1-ButtonPress-2>)
28 #include "ttkWidget.h"
31 WidgetCore *corePtr; /* widget to track */
32 Ttk_Layout tracking; /* current layout being tracked */
33 Ttk_Element activeElement; /* element under the mouse cursor */
34 Ttk_Element pressedElement; /* currently pressed element */
35 } ElementStateTracker;
38 * ActivateElement(es, node) --
39 * Make 'node' the active element if non-NULL.
40 * Deactivates the currently active element if different.
42 * The active element has TTK_STATE_ACTIVE set _unless_
43 * another element is 'pressed'
45 static void ActivateElement(ElementStateTracker *es, Ttk_Element element)
47 if (es->activeElement == element) {
52 if (!es->pressedElement) {
53 if (es->activeElement) {
54 /* Deactivate old element */
55 Ttk_ChangeElementState(es->activeElement, 0,TTK_STATE_ACTIVE);
58 /* Activate new element */
59 Ttk_ChangeElementState(element, TTK_STATE_ACTIVE,0);
61 TtkRedisplayWidget(es->corePtr);
64 es->activeElement = element;
68 * Releases the currently pressed element, if any.
70 static void ReleaseElement(ElementStateTracker *es)
72 if (!es->pressedElement)
75 Ttk_ChangeElementState(
76 es->pressedElement, 0,TTK_STATE_PRESSED|TTK_STATE_ACTIVE);
77 es->pressedElement = 0;
79 /* Reactivate element under the mouse cursor:
81 if (es->activeElement)
82 Ttk_ChangeElementState(es->activeElement, TTK_STATE_ACTIVE,0);
84 TtkRedisplayWidget(es->corePtr);
88 * Presses the specified element.
90 static void PressElement(ElementStateTracker *es, Ttk_Element element)
92 if (es->pressedElement) {
97 Ttk_ChangeElementState(
98 element, TTK_STATE_PRESSED|TTK_STATE_ACTIVE, 0);
101 es->pressedElement = element;
102 TtkRedisplayWidget(es->corePtr);
105 /* ElementStateEventProc --
106 * Event handler for tracking element states.
109 static const unsigned ElementStateMask =
115 | StructureNotifyMask
119 ElementStateEventProc(ClientData clientData, XEvent *ev)
121 ElementStateTracker *es = clientData;
122 Ttk_Layout layout = es->corePtr->layout;
125 /* Guard against dangling pointers [#2431428]
127 if (es->tracking != layout) {
128 es->pressedElement = es->activeElement = 0;
129 es->tracking = layout;
135 element = Ttk_IdentifyElement(
136 layout, ev->xmotion.x, ev->xmotion.y);
137 ActivateElement(es, element);
140 ActivateElement(es, 0);
141 if (ev->xcrossing.mode == NotifyGrab)
145 element = Ttk_IdentifyElement(
146 layout, ev->xcrossing.x, ev->xcrossing.y);
147 ActivateElement(es, element);
150 element = Ttk_IdentifyElement(
151 layout, ev->xbutton.x, ev->xbutton.y);
153 PressElement(es, element);
159 /* Unregister this event handler and free client data.
161 Tk_DeleteEventHandler(es->corePtr->tkwin,
162 ElementStateMask, ElementStateEventProc, es);
169 * TtkTrackElementState --
170 * Register an event handler to manage the 'pressed'
171 * and 'active' states of individual widget elements.
174 void TtkTrackElementState(WidgetCore *corePtr)
176 ElementStateTracker *es = ckalloc(sizeof(*es));
177 es->corePtr = corePtr;
179 es->activeElement = es->pressedElement = 0;
180 Tk_CreateEventHandler(corePtr->tkwin,
181 ElementStateMask,ElementStateEventProc,es);