Import Tk 8.6.6 (as of svn r86089)
This commit is contained in:
183
generic/ttk/ttkTrack.c
Normal file
183
generic/ttk/ttkTrack.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Joe English
|
||||
*
|
||||
* TtkTrackElementState() -- helper routine for widgets
|
||||
* like scrollbars in which individual elements may
|
||||
* be active or pressed instead of the widget as a whole.
|
||||
*
|
||||
* Usage:
|
||||
* TtkTrackElementState(&recordPtr->core);
|
||||
*
|
||||
* Registers an event handler on the widget that tracks pointer
|
||||
* events and updates the state of the element under the
|
||||
* mouse cursor.
|
||||
*
|
||||
* The "active" element is the one under the mouse cursor,
|
||||
* and is normally set to the ACTIVE state unless another element
|
||||
* is currently being pressed.
|
||||
*
|
||||
* The active element becomes "pressed" on <ButtonPress> events,
|
||||
* and remains "active" and "pressed" until the corresponding
|
||||
* <ButtonRelease> event.
|
||||
*
|
||||
* TODO: Handle "chords" properly (e.g., <B1-ButtonPress-2>)
|
||||
*/
|
||||
|
||||
#include <tk.h>
|
||||
#include "ttkTheme.h"
|
||||
#include "ttkWidget.h"
|
||||
|
||||
typedef struct {
|
||||
WidgetCore *corePtr; /* widget to track */
|
||||
Ttk_Layout tracking; /* current layout being tracked */
|
||||
Ttk_Element activeElement; /* element under the mouse cursor */
|
||||
Ttk_Element pressedElement; /* currently pressed element */
|
||||
} ElementStateTracker;
|
||||
|
||||
/*
|
||||
* ActivateElement(es, node) --
|
||||
* Make 'node' the active element if non-NULL.
|
||||
* Deactivates the currently active element if different.
|
||||
*
|
||||
* The active element has TTK_STATE_ACTIVE set _unless_
|
||||
* another element is 'pressed'
|
||||
*/
|
||||
static void ActivateElement(ElementStateTracker *es, Ttk_Element element)
|
||||
{
|
||||
if (es->activeElement == element) {
|
||||
/* No change */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!es->pressedElement) {
|
||||
if (es->activeElement) {
|
||||
/* Deactivate old element */
|
||||
Ttk_ChangeElementState(es->activeElement, 0,TTK_STATE_ACTIVE);
|
||||
}
|
||||
if (element) {
|
||||
/* Activate new element */
|
||||
Ttk_ChangeElementState(element, TTK_STATE_ACTIVE,0);
|
||||
}
|
||||
TtkRedisplayWidget(es->corePtr);
|
||||
}
|
||||
|
||||
es->activeElement = element;
|
||||
}
|
||||
|
||||
/* ReleaseElement --
|
||||
* Releases the currently pressed element, if any.
|
||||
*/
|
||||
static void ReleaseElement(ElementStateTracker *es)
|
||||
{
|
||||
if (!es->pressedElement)
|
||||
return;
|
||||
|
||||
Ttk_ChangeElementState(
|
||||
es->pressedElement, 0,TTK_STATE_PRESSED|TTK_STATE_ACTIVE);
|
||||
es->pressedElement = 0;
|
||||
|
||||
/* Reactivate element under the mouse cursor:
|
||||
*/
|
||||
if (es->activeElement)
|
||||
Ttk_ChangeElementState(es->activeElement, TTK_STATE_ACTIVE,0);
|
||||
|
||||
TtkRedisplayWidget(es->corePtr);
|
||||
}
|
||||
|
||||
/* PressElement --
|
||||
* Presses the specified element.
|
||||
*/
|
||||
static void PressElement(ElementStateTracker *es, Ttk_Element element)
|
||||
{
|
||||
if (es->pressedElement) {
|
||||
ReleaseElement(es);
|
||||
}
|
||||
|
||||
if (element) {
|
||||
Ttk_ChangeElementState(
|
||||
element, TTK_STATE_PRESSED|TTK_STATE_ACTIVE, 0);
|
||||
}
|
||||
|
||||
es->pressedElement = element;
|
||||
TtkRedisplayWidget(es->corePtr);
|
||||
}
|
||||
|
||||
/* ElementStateEventProc --
|
||||
* Event handler for tracking element states.
|
||||
*/
|
||||
|
||||
static const unsigned ElementStateMask =
|
||||
ButtonPressMask
|
||||
| ButtonReleaseMask
|
||||
| PointerMotionMask
|
||||
| LeaveWindowMask
|
||||
| EnterWindowMask
|
||||
| StructureNotifyMask
|
||||
;
|
||||
|
||||
static void
|
||||
ElementStateEventProc(ClientData clientData, XEvent *ev)
|
||||
{
|
||||
ElementStateTracker *es = clientData;
|
||||
Ttk_Layout layout = es->corePtr->layout;
|
||||
Ttk_Element element;
|
||||
|
||||
/* Guard against dangling pointers [#2431428]
|
||||
*/
|
||||
if (es->tracking != layout) {
|
||||
es->pressedElement = es->activeElement = 0;
|
||||
es->tracking = layout;
|
||||
}
|
||||
|
||||
switch (ev->type)
|
||||
{
|
||||
case MotionNotify :
|
||||
element = Ttk_IdentifyElement(
|
||||
layout, ev->xmotion.x, ev->xmotion.y);
|
||||
ActivateElement(es, element);
|
||||
break;
|
||||
case LeaveNotify:
|
||||
ActivateElement(es, 0);
|
||||
if (ev->xcrossing.mode == NotifyGrab)
|
||||
PressElement(es, 0);
|
||||
break;
|
||||
case EnterNotify:
|
||||
element = Ttk_IdentifyElement(
|
||||
layout, ev->xcrossing.x, ev->xcrossing.y);
|
||||
ActivateElement(es, element);
|
||||
break;
|
||||
case ButtonPress:
|
||||
element = Ttk_IdentifyElement(
|
||||
layout, ev->xbutton.x, ev->xbutton.y);
|
||||
if (element)
|
||||
PressElement(es, element);
|
||||
break;
|
||||
case ButtonRelease:
|
||||
ReleaseElement(es);
|
||||
break;
|
||||
case DestroyNotify:
|
||||
/* Unregister this event handler and free client data.
|
||||
*/
|
||||
Tk_DeleteEventHandler(es->corePtr->tkwin,
|
||||
ElementStateMask, ElementStateEventProc, es);
|
||||
ckfree(clientData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TtkTrackElementState --
|
||||
* Register an event handler to manage the 'pressed'
|
||||
* and 'active' states of individual widget elements.
|
||||
*/
|
||||
|
||||
void TtkTrackElementState(WidgetCore *corePtr)
|
||||
{
|
||||
ElementStateTracker *es = ckalloc(sizeof(*es));
|
||||
es->corePtr = corePtr;
|
||||
es->tracking = 0;
|
||||
es->activeElement = es->pressedElement = 0;
|
||||
Tk_CreateEventHandler(corePtr->tkwin,
|
||||
ElementStateMask,ElementStateEventProc,es);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user