Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 1337bce10e
Fetching contributors…

Cannot retrieve contributors at this time

184 lines (163 sloc) 4.666 kb
/*
* 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);
}
Jump to Line
Something went wrong with that request. Please try again.