summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXScrlbr.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/tkMacOSXScrlbr.c')
-rw-r--r--macosx/tkMacOSXScrlbr.c1047
1 files changed, 307 insertions, 740 deletions
diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c
index 1a071f3..411e18d 100644
--- a/macosx/tkMacOSXScrlbr.c
+++ b/macosx/tkMacOSXScrlbr.c
@@ -2,71 +2,46 @@
* tkMacOSXScrollbar.c --
*
* This file implements the Macintosh specific portion of the scrollbar
- * widget. The Macintosh scrollbar may also draw a windows grow region
- * under certain cases.
+ * widget.
*
* Copyright (c) 1996 by Sun Microsystems, Inc.
- * Copyright 2001, Apple Computer, Inc.
- * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2001-2009, Apple Inc.
+ * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
*
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkMacOSXScrlbr.c,v 1.29 2008/12/07 16:36:26 das Exp $
+ * RCS: @(#) $Id: tkMacOSXScrlbr.c,v 1.30 2009/06/29 14:35:01 das Exp $
*/
#include "tkMacOSXPrivate.h"
#include "tkScrollbar.h"
-#include "tkMacOSXDebug.h"
-#define MIN_SCROLLBAR_VALUE 0
-#define SCROLLBAR_SCALING_VALUE ((double)(LONG_MAX>>1))
+/*
+#ifdef TK_MAC_DEBUG
+#define TK_MAC_DEBUG_SCROLLBAR
+#endif
+*/
/*
* Declaration of Mac specific scrollbar structure.
*/
typedef struct MacScrollbar {
- TkScrollbar info; /* Generic scrollbar info */
- ControlRef sbHandle; /* Scrollbar control */
- int macFlags; /* Various flags; see below */
- Rect eraseRect; /* Rect to erase before drawing control */
+ TkScrollbar info;
+ NSScroller *scroller;
+ int variant;
} MacScrollbar;
-/*
- * Flag bits for scrollbars on the Mac:
- *
- * ALREADY_DEAD: Non-zero means this scrollbar has been
- * destroyed, but has not been cleaned up.
- * IN_MODAL_LOOP: Non-zero means this scrollbar is in the middle
- * of a modal loop.
- * ACTIVE: Non-zero means this window is currently
- * active (in the foreground).
- */
-
-#define ALREADY_DEAD 1
-#define IN_MODAL_LOOP 2
-#define ACTIVE 4
-
-/*
- * Globals uses locally in this file.
- */
-static ControlActionUPP scrollActionProc = NULL; /* Pointer to func. */
-static ControlActionUPP thumbActionProc = NULL; /* Pointer to func. */
-static Point mouseDownPoint; /* Used to store the coordinates where the
- * mouse was first pressed to begin dragging
- * the thumb, because ThumbActionProc can't
- * take any args. */
-
typedef struct ScrollbarMetrics {
- SInt32 width, minHeight, minThumbHeight;
- short topArrowHeight, bottomArrowHeight;
- ControlSize size;
+ SInt32 width, minThumbHeight;
+ int minHeight, topArrowHeight, bottomArrowHeight;
+ NSControlSize controlSize;
} ScrollbarMetrics;
static ScrollbarMetrics metrics[2] = {
- {15, 54, 26, 14, 14, kControlSizeNormal}, /* kThemeScrollBarMedium */
- {11, 40, 20, 10, 10, kControlSizeSmall}, /* kThemeScrollBarSmall */
+ {15, 54, 26, 14, 14, NSRegularControlSize}, /* kThemeScrollBarMedium */
+ {11, 40, 20, 10, 10, NSSmallControlSize}, /* kThemeScrollBarSmall */
};
/*
@@ -77,36 +52,109 @@ static ScrollbarMetrics metrics[2] = {
static char defWidth[TCL_INTEGER_SPACE];
/*
- * Forward declarations for procedures defined later in this file:
+ * Declarations for functions defined in this file.
*/
-static pascal void ScrollbarActionProc(ControlRef theControl,
- ControlPartCode partCode);
-static pascal void ThumbActionProc(ControlRef theControl,
- ControlPartCode partCode);
-static int ScrollbarBindProc(ClientData clientData,
- Tcl_Interp *interp, XEvent *eventPtr,
- Tk_Window tkwin, KeySym keySym);
+static void UpdateScrollbarMetrics(void);
static void ScrollbarEventProc(ClientData clientData,
XEvent *eventPtr);
-static void UpdateControlValues(MacScrollbar *macScrollPtr);
/*
- * The class procedure table for the scrollbar widget. Leave the proc fields
- * initialized to NULL, which should happen automatically because of the scope
- * at which the variable is declared.
+ * The class procedure table for the scrollbar widget.
*/
Tk_ClassProcs tkpScrollbarProcs = {
sizeof(Tk_ClassProcs) /* size */
};
+
+#pragma mark TKApplication(TKScrlbr)
+
+#define NSAppleAquaScrollBarVariantChanged @"AppleAquaScrollBarVariantChanged"
+
+@implementation TKApplication(TKScrlbr)
+- (void)tkScroller:(NSScroller *)scroller {
+ NSScrollerPart hitPart = [scroller hitPart];
+ TkScrollbar *scrollPtr = (TkScrollbar *)[scroller tag];
+ Tcl_DString cmdString;
+ Tcl_Interp *interp;
+ int result;
+
+ if (!scrollPtr || !scrollPtr->command || !scrollPtr->commandSize ||
+ hitPart == NSScrollerNoPart) {
+ return;
+ }
+
+ Tcl_DStringInit(&cmdString);
+ Tcl_DStringAppend(&cmdString, scrollPtr->command,
+ scrollPtr->commandSize);
+ switch (hitPart) {
+ case NSScrollerKnob:
+ case NSScrollerKnobSlot: {
+ char valueString[TCL_DOUBLE_SPACE];
+
+ Tcl_PrintDouble(NULL, [scroller doubleValue] *
+ (1.0 - [scroller knobProportion]), valueString);
+ Tcl_DStringAppendElement(&cmdString, "moveto");
+ Tcl_DStringAppendElement(&cmdString, valueString);
+ break;
+ }
+ case NSScrollerDecrementLine:
+ case NSScrollerIncrementLine:
+ Tcl_DStringAppendElement(&cmdString, "scroll");
+ Tcl_DStringAppendElement(&cmdString,
+ (hitPart == NSScrollerDecrementLine) ? "-1" : "1");
+ Tcl_DStringAppendElement(&cmdString, "unit");
+ break;
+ case NSScrollerDecrementPage:
+ case NSScrollerIncrementPage:
+ Tcl_DStringAppendElement(&cmdString, "scroll");
+ Tcl_DStringAppendElement(&cmdString,
+ (hitPart == NSScrollerDecrementPage) ? "-1" : "1");
+ Tcl_DStringAppendElement(&cmdString, "page");
+ break;
+ }
+ interp = scrollPtr->interp;
+ Tcl_Preserve(interp);
+ Tcl_Preserve(scrollPtr);
+ result = Tcl_EvalEx(interp, Tcl_DStringValue(&cmdString),
+ Tcl_DStringLength(&cmdString), TCL_EVAL_GLOBAL);
+ if (result != TCL_OK && result != TCL_CONTINUE && result != TCL_BREAK) {
+ Tcl_AddErrorInfo(interp, "\n (scrollbar command)");
+ Tcl_BackgroundException(interp, result);
+ }
+ Tcl_Release(scrollPtr);
+ Tcl_Release(interp);
+ Tcl_DStringFree(&cmdString);
+#ifdef TK_MAC_DEBUG_SCROLLBAR
+ TKLog(@"scroller %s value %f knobProportion %f",
+ ((TkWindow *)scrollPtr->tkwin)->pathName, [scroller doubleValue],
+ [scroller knobProportion]);
+#endif
+}
+- (void)scrollBarVariantChanged:(NSNotification *)notification {
+#ifdef TK_MAC_DEBUG_NOTIFICATIONS
+ TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
+#endif
+ UpdateScrollbarMetrics();
+}
+- (void)_setupScrollBarNotifications {
+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+#define observe(n, s) [nc addObserver:self selector:@selector(s) name:(n) object:nil]
+ observe(NSAppleAquaScrollBarVariantChanged, scrollBarVariantChanged:);
+#undef observe
+
+ UpdateScrollbarMetrics();
+}
+@end
+
+#pragma mark -
/*
*----------------------------------------------------------------------
*
- * TkMacOSXInitScrollbarMetrics --
+ * UpdateScrollbarMetrics --
*
- * This function initializes the current system metrics for a scrollbar.
+ * This function retrieves the current system metrics for a scrollbar.
*
* Results:
* None.
@@ -117,35 +165,45 @@ Tk_ClassProcs tkpScrollbarProcs = {
*----------------------------------------------------------------------
*/
-void
-TkMacOSXInitScrollbarMetrics(void)
+static void
+UpdateScrollbarMetrics(void)
{
const short height = 100, width = 50;
- ThemeTrackDrawInfo info = {0, {0, 0, height, width}, 0, 1, 0, 0,
- kThemeTrackShowThumb, kThemeTrackActive, 0, {{1, 0}}};
- Rect bounds;
+ HIThemeTrackDrawInfo info = {
+ .version = 0,
+ .bounds = {{0, 0}, {width, height}},
+ .min = 0,
+ .max = 1,
+ .value = 0,
+ .attributes = kThemeTrackShowThumb,
+ .enableState = kThemeTrackActive,
+ .trackInfo.scrollbar = {.viewsize = 1, .pressState = 0},
+ };
+ CGRect bounds;
Tk_ConfigSpec *specPtr;
ChkErr(GetThemeMetric, kThemeMetricScrollBarWidth, &metrics[0].width);
ChkErr(GetThemeMetric, kThemeMetricScrollBarMinThumbHeight,
&metrics[0].minThumbHeight);
info.kind = kThemeScrollBarMedium;
- ChkErr(GetThemeTrackDragRect, &info, &bounds);
- metrics[0].topArrowHeight = bounds.top;
- metrics[0].bottomArrowHeight = height - bounds.bottom;
+ ChkErr(HIThemeGetTrackDragRect, &info, &bounds);
+ metrics[0].topArrowHeight = bounds.origin.y;
+ metrics[0].bottomArrowHeight = height - (bounds.origin.y +
+ bounds.size.height);
metrics[0].minHeight = metrics[0].minThumbHeight +
metrics[0].topArrowHeight + metrics[0].bottomArrowHeight;
ChkErr(GetThemeMetric, kThemeMetricSmallScrollBarWidth, &metrics[1].width);
ChkErr(GetThemeMetric, kThemeMetricSmallScrollBarMinThumbHeight,
&metrics[1].minThumbHeight);
info.kind = kThemeScrollBarSmall;
- ChkErr(GetThemeTrackDragRect, &info, &bounds);
- metrics[1].topArrowHeight = bounds.top;
- metrics[1].bottomArrowHeight = height - bounds.bottom;
+ ChkErr(HIThemeGetTrackDragRect, &info, &bounds);
+ metrics[1].topArrowHeight = bounds.origin.y;
+ metrics[1].bottomArrowHeight = height - (bounds.origin.y +
+ bounds.size.height);
metrics[1].minHeight = metrics[1].minThumbHeight +
metrics[1].topArrowHeight + metrics[1].bottomArrowHeight;
- sprintf(defWidth, "%ld", metrics[0].width);
+ sprintf(defWidth, "%d", (int)(metrics[0].width));
for (specPtr = tkpScrollbarConfigSpecs; specPtr->type != TK_CONFIG_END;
specPtr++) {
if (specPtr->offset == Tk_Offset(TkScrollbar, width)) {
@@ -165,45 +223,49 @@ TkMacOSXInitScrollbarMetrics(void)
* Returns a newly allocated TkScrollbar structure.
*
* Side effects:
- * None.
+ * Registers an event handler for the widget.
*
*----------------------------------------------------------------------
*/
TkScrollbar *
TkpCreateScrollbar(
- Tk_Window tkwin) /* New Tk Window. */
+ Tk_Window tkwin)
{
- static int initialized = 0;
- MacScrollbar * macScrollPtr;
- TkWindow *winPtr = (TkWindow *)tkwin;
+ MacScrollbar *scrollPtr = (MacScrollbar *) ckalloc(sizeof(MacScrollbar));
- if (scrollActionProc == NULL) {
- scrollActionProc = NewControlActionUPP(ScrollbarActionProc);
- thumbActionProc = NewControlActionUPP(ThumbActionProc);
- }
- if (!initialized) {
- TkMacOSXInitScrollbarMetrics();
- initialized = 1;
- }
- macScrollPtr = (MacScrollbar *) ckalloc(sizeof(MacScrollbar));
- macScrollPtr->sbHandle = NULL;
- macScrollPtr->macFlags = 0;
- SetRect(&macScrollPtr->eraseRect, 0, 0, 0, 0);
+ scrollPtr->scroller = nil;
Tk_CreateEventHandler(tkwin, ActivateMask|ExposureMask|
- StructureNotifyMask|FocusChangeMask,
- ScrollbarEventProc, (ClientData) macScrollPtr);
+ StructureNotifyMask|FocusChangeMask,
+ ScrollbarEventProc, (ClientData) scrollPtr);
- if (!Tcl_GetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL)) {
- Tcl_SetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL,
- (ClientData)1);
- TkCreateBindingProcedure(winPtr->mainPtr->interp,
- winPtr->mainPtr->bindingTable,
- (ClientData)Tk_GetUid("Scrollbar"), "<ButtonPress>",
- ScrollbarBindProc, NULL, NULL);
- }
- return (TkScrollbar *) macScrollPtr;
+ return (TkScrollbar *) scrollPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpDestroyScrollbar --
+ *
+ * Free data structures associated with the scrollbar control.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpDestroyScrollbar(
+ TkScrollbar *scrollPtr)
+{
+ MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
+
+ TkMacOSXMakeCollectableAndRelease(macScrollPtr->scroller);
}
/*
@@ -230,109 +292,81 @@ TkpDisplayScrollbar(
{
TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
MacScrollbar *macScrollPtr = (MacScrollbar *) clientData;
+ NSScroller *scroller = macScrollPtr->scroller;
Tk_Window tkwin = scrollPtr->tkwin;
- CGrafPtr destPort, savePort;
- Boolean portChanged;
- WindowRef windowRef;
+ TkWindow *winPtr = (TkWindow *) tkwin;
+ MacDrawable *macWin = (MacDrawable *) winPtr->window;
+ TkMacOSXDrawingContext dc;
+ NSView *view = TkMacOSXDrawableView(macWin);
+ CGFloat viewHeight = [view bounds].size.height;
+ CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
+ .ty = viewHeight};
+ NSRect frame;
+ double knobProportion = scrollPtr->lastFraction - scrollPtr->firstFraction;
- if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
- goto done;
+ scrollPtr->flags &= ~REDRAW_PENDING;
+ if (!scrollPtr->tkwin || !Tk_IsMapped(tkwin) || !view ||
+ !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
+ return;
}
-
- /*
- * Draw the focus or any 3D relief we may have.
- */
+ CGContextConcatCTM(dc.context, t);
if (scrollPtr->highlightWidth != 0) {
GC fgGC, bgGC;
- bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr,
- Tk_WindowId(tkwin));
-
+ bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin);
if (scrollPtr->flags & GOT_FOCUS) {
- fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr,
- Tk_WindowId(tkwin));
- TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth,
- Tk_WindowId(tkwin));
+ fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin);
} else {
- TkpDrawHighlightBorder(tkwin, bgGC, bgGC, scrollPtr->highlightWidth,
- Tk_WindowId(tkwin));
+ fgGC = bgGC;
}
- }
- Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), scrollPtr->bgBorder,
- scrollPtr->highlightWidth, scrollPtr->highlightWidth,
- Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
- Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
- scrollPtr->borderWidth, scrollPtr->relief);
-
- if (macScrollPtr->sbHandle == NULL) {
- Rect r = {0, 0, 1, 1};
-
- windowRef = TkMacOSXDrawableWindow(Tk_WindowId(tkwin));
- CreateScrollBarControl(windowRef, &r, 0, 0, 0, 0, true, NULL,
- &(macScrollPtr->sbHandle));
- SetControlReference(macScrollPtr->sbHandle, (SInt32) scrollPtr);
-
- if (IsWindowActive(windowRef)) {
- macScrollPtr->macFlags |= ACTIVE;
+ TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth,
+ (Pixmap) macWin);
+ }
+ Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder,
+ scrollPtr->highlightWidth, scrollPtr->highlightWidth,
+ Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
+ Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
+ scrollPtr->borderWidth, scrollPtr->relief);
+ Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder,
+ scrollPtr->inset, scrollPtr->inset,
+ Tk_Width(tkwin) - 2*scrollPtr->inset,
+ Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT);
+ if ([scroller superview] != view) {
+ [view addSubview:scroller];
+ }
+ frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin),
+ Tk_Height(tkwin));
+ frame = NSInsetRect(frame, scrollPtr->inset, scrollPtr->inset);
+ frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
+ NSWindow *w = [view window];
+ if ([w showsResizeIndicator]) {
+ NSRect growBox = [view convertRect:[w _growBoxRect] fromView:nil];
+ if (NSIntersectsRect(growBox, frame)) {
+ if (scrollPtr->vertical) {
+ CGFloat y = frame.origin.y;
+ frame.origin.y = growBox.origin.y + growBox.size.height;
+ frame.size.height -= frame.origin.y - y;
+ } else {
+ frame.size.width = growBox.origin.x - frame.origin.x;
+ }
+ TkMacOSXSetScrollbarGrow(winPtr, true);
}
}
-
- /*
- * Update the control values before we draw.
- */
-
- UpdateControlValues(macScrollPtr);
-
- /*
- * Set up port for drawing Macintosh control.
- */
- destPort = TkMacOSXGetDrawablePort(Tk_WindowId(tkwin));
- portChanged = QDSwapPort(destPort, &savePort);
- TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin));
-
- /*
- * Scrollbars do not erase the complete control bounds if they are wider
- * than the standard width, so manually erase the extra space.
- */
-
- if (!EmptyRect(&macScrollPtr->eraseRect)) {
- EraseRect(&macScrollPtr->eraseRect);
- }
-
- Draw1Control(macScrollPtr->sbHandle);
-
- if (portChanged) {
- QDSwapPort(savePort, NULL);
- }
-
- done:
- scrollPtr->flags &= ~REDRAW_PENDING;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkpConfigureScrollbar --
- *
- * This procedure is called after the generic code has finished
- * processing configuration options, in order to configure platform
- * specific options.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkpConfigureScrollbar(
- register TkScrollbar *scrollPtr)
- /* Information about widget; may or may not
- * already have values for some fields. */
-{
+ if (!NSEqualRects(frame, [scroller frame])) {
+ [scroller setFrame:frame];
+ }
+ [scroller setEnabled:(knobProportion < 1.0 &&
+ (scrollPtr->vertical ? frame.size.height : frame.size.width) >
+ metrics[macScrollPtr->variant].minHeight)];
+ [scroller setDoubleValue:scrollPtr->firstFraction / (1.0 - knobProportion)];
+ [scroller setKnobProportion:knobProportion];
+ [scroller displayRectIgnoringOpacity:[scroller bounds]];
+ TkMacOSXRestoreDrawingContext(&dc);
+#ifdef TK_MAC_DEBUG_SCROLLBAR
+ TKLog(@"scroller %s frame %@ width %d height %d",
+ ((TkWindow *)scrollPtr->tkwin)->pathName, NSStringFromRect(frame),
+ Tk_Width(tkwin), Tk_Height(tkwin));
+#endif
}
/*
@@ -355,18 +389,55 @@ TkpConfigureScrollbar(
void
TkpComputeScrollbarGeometry(
- register TkScrollbar *scrollPtr) /* Scrollbar whose geometry may
- * have changed. */
+ register TkScrollbar *scrollPtr)
+ /* Scrollbar whose geometry may have
+ * changed. */
{
- int variant, fieldLength;
+ MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
+ NSScroller *scroller = macScrollPtr->scroller;
+ int width, height, variant, fieldLength;
if (scrollPtr->highlightWidth < 0) {
scrollPtr->highlightWidth = 0;
}
scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
- variant = ((scrollPtr->vertical ? Tk_Width(scrollPtr->tkwin) :
- Tk_Height(scrollPtr->tkwin)) - 2 * scrollPtr->inset
- < metrics[0].width) ? 1 : 0;
+ width = Tk_Width(scrollPtr->tkwin) - 2 * scrollPtr->inset;
+ height = Tk_Height(scrollPtr->tkwin) - 2 * scrollPtr->inset;
+ variant = ((scrollPtr->vertical ? width : height) < metrics[0].width) ?
+ 1 : 0;
+ macScrollPtr->variant = variant;
+ if (scroller) {
+ NSSize size = [scroller frame].size;
+ if ((size.width > size.height) ^ !scrollPtr->vertical) {
+ /* Orientation changed, need new scroller */
+ if ([scroller superview]) {
+ [scroller removeFromSuperviewWithoutNeedingDisplay];
+ }
+ TkMacOSXMakeCollectableAndRelease(scroller);
+ }
+ }
+ if (!scroller) {
+ if ((width > height) ^ !scrollPtr->vertical) {
+ /* -[NSScroller initWithFrame:] determines horizonalness for the
+ * lifetime of the scroller via isHoriz = (width > height) */
+ if (scrollPtr->vertical) {
+ width = height;
+ } else if (width > 1) {
+ height = width - 1;
+ } else {
+ height = 1;
+ width = 2;
+ }
+ }
+ scroller = [[NSScroller alloc] initWithFrame:
+ NSMakeRect(0, 0, width, height)];
+ macScrollPtr->scroller = TkMacOSXMakeUncollectable(scroller);
+ [scroller setAction:@selector(tkScroller:)];
+ [scroller setTarget:NSApp];
+ [scroller setTag:(NSInteger)scrollPtr];
+ }
+ [[scroller cell] setControlSize:metrics[variant].controlSize];
+
scrollPtr->arrowLength = (metrics[variant].topArrowHeight +
metrics[variant].bottomArrowHeight) / 2;
fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
@@ -421,14 +492,22 @@ TkpComputeScrollbarGeometry(
2 * scrollPtr->inset);
}
Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset);
+#ifdef TK_MAC_DEBUG_SCROLLBAR
+ TKLog(@"scroller %s bounds %@ width %d height %d inset %d borderWidth %d",
+ ((TkWindow *)scrollPtr->tkwin)->pathName,
+ NSStringFromRect([scroller bounds]),
+ width, height, scrollPtr->inset, scrollPtr->borderWidth);
+#endif
}
/*
*----------------------------------------------------------------------
*
- * TkpDestroyScrollbar --
+ * TkpConfigureScrollbar --
*
- * Free data structures associated with the scrollbar control.
+ * This procedure is called after the generic code has finished
+ * processing configuration options, in order to configure platform
+ * specific options.
*
* Results:
* None.
@@ -440,18 +519,11 @@ TkpComputeScrollbarGeometry(
*/
void
-TkpDestroyScrollbar(
- TkScrollbar *scrollPtr) /* Scrollbar to destroy. */
+TkpConfigureScrollbar(
+ register TkScrollbar *scrollPtr)
+ /* Information about widget; may or may not
+ * already have values for some fields. */
{
- MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr;
-
- if (macScrollPtr->sbHandle != NULL) {
- if (!(macScrollPtr->macFlags & IN_MODAL_LOOP)) {
- DisposeControl(macScrollPtr->sbHandle);
- macScrollPtr->sbHandle = NULL;
- }
- }
- macScrollPtr->macFlags |= ALREADY_DEAD;
}
/*
@@ -474,59 +546,29 @@ TkpDestroyScrollbar(
int
TkpScrollbarPosition(
- TkScrollbar *scrollPtr, /* Scrollbar widget record. */
- int x, int y) /* Coordinates within scrollPtr's
- * window. */
+ register TkScrollbar *scrollPtr,
+ /* Scrollbar widget record. */
+ int x, int y) /* Coordinates within scrollPtr's window. */
{
- MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
- CGrafPtr destPort, savePort;
- Boolean portChanged;
- int inactive = 0;
- ControlPartCode part;
- Point where = {y, x};
- Rect bounds;
-
- if ((x < scrollPtr->inset) || (x >= (Tk_Width(scrollPtr->tkwin) -
- scrollPtr->inset)) || (y < scrollPtr->inset) ||
- (y >= (Tk_Height(scrollPtr->tkwin) - scrollPtr->inset))) {
- return OUTSIDE;
- }
-
- /*
- * All of the calculations in this procedure mirror those in
- * DisplayScrollbar. Be sure to keep the two consistent. On the Macintosh
- * we use the OS call TestControl to do this mapping. For TestControl to
- * work, the scrollbar must be active and must be in the current port.
- */
-
- destPort = TkMacOSXGetDrawablePort(Tk_WindowId(scrollPtr->tkwin));
- portChanged = QDSwapPort(destPort, &savePort);
- UpdateControlValues(macScrollPtr);
- if (!IsControlActive(macScrollPtr->sbHandle)) {
- inactive = true;
- ActivateControl(macScrollPtr->sbHandle);
- }
- TkMacOSXWinBounds((TkWindow *) scrollPtr->tkwin, &bounds);
- where.h += bounds.left;
- where.v += bounds.top;
- part = TestControl(((MacScrollbar *) scrollPtr)->sbHandle, where);
- if (inactive) {
- DeactivateControl(macScrollPtr->sbHandle);
- }
- if (portChanged) {
- QDSwapPort(savePort, NULL);
- }
- switch (part) {
- case kAppearancePartUpButton:
+ NSScroller *scroller = ((MacScrollbar *) scrollPtr)->scroller;
+ MacDrawable *macWin = (MacDrawable *)
+ ((TkWindow *) scrollPtr->tkwin)->window;
+ NSView *view = TkMacOSXDrawableView(macWin);
+
+ switch ([scroller testPart:NSMakePoint(macWin->xOff + x,
+ [view bounds].size.height - (macWin->yOff + y))]) {
+ case NSScrollerDecrementLine:
return TOP_ARROW;
- case kAppearancePartPageUpArea:
+ case NSScrollerDecrementPage:
return TOP_GAP;
- case kAppearancePartIndicator:
+ case NSScrollerKnob:
return SLIDER;
- case kAppearancePartPageDownArea:
+ case NSScrollerIncrementPage:
return BOTTOM_GAP;
- case kAppearancePartDownButton:
+ case NSScrollerIncrementLine:
return BOTTOM_ARROW;
+ case NSScrollerKnobSlot:
+ case NSScrollerNoPart:
default:
return OUTSIDE;
}
@@ -535,344 +577,6 @@ TkpScrollbarPosition(
/*
*--------------------------------------------------------------
*
- * ThumbActionProc --
- *
- * Callback procedure used by the Macintosh toolbox call
- * HandleControlClick. This call is used to track the thumb of the
- * scrollbar. Unlike the ScrollbarActionProc function this function is
- * called once and basically takes over tracking the scrollbar from the
- * control. This is done to avoid conflicts with what the control plans
- * to draw.
- *
- * Results:
- * None.
- *
- * Side effects:
- * May change the display.
- *
- *--------------------------------------------------------------
- */
-
-static pascal void
-ThumbActionProc(
- ControlRef theControl,
- ControlPartCode partCode)
-{
- TkScrollbar *scrollPtr = (TkScrollbar *)(intptr_t)
- GetControlReference(theControl);
- MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
- Tcl_DString cmdString;
- /*int origValue;*/ /* dead code */
- int variant;
- short trackBarSize;
- double oldFirstFraction, newFirstFraction;
- char valueString[40];
- Point currentPoint = { 0, 0 };
- Rect trackRect;
- Tcl_Interp *interp;
- MouseTrackingResult trackingResult;
- OSStatus err;
-
- if (scrollPtr == NULL) {
- return;
- }
-
- Tcl_DStringInit(&cmdString);
- /*origValue = GetControl32BitValue(macScrollPtr->sbHandle);*/ /* dead code */
- GetControlBounds(macScrollPtr->sbHandle, &trackRect);
-
- if (scrollPtr->vertical) {
- variant = (trackRect.right - trackRect.left) < metrics[0].width ? 1 : 0;
- trackBarSize = trackRect.bottom - trackRect.top -
- metrics[variant].topArrowHeight -
- metrics[variant].bottomArrowHeight;
- InsetRect(&trackRect, -25, -113);
- } else {
- variant = (trackRect.bottom - trackRect.top) < metrics[0].width ? 1 : 0;
- trackBarSize = trackRect.right - trackRect.left -
- metrics[variant].topArrowHeight -
- metrics[variant].bottomArrowHeight;
- InsetRect(&trackRect, -113, -25);
- }
-
- /*
- * Track the mouse while the button is held down. If the mouse is moved,
- * we calculate the value that should be passed to the "command" part of
- * the scrollbar. Since the mouse may move a distance too small to cause a
- * change to the first fraction, each calculation must be done versus what
- * the first fraction was when the mouse button was initially pressed.
- * Otherwise, moving the mouse too slowly will cause the calculated
- * fraction delta to be zero and the scrollbar won't respond.
- */
-
- oldFirstFraction = scrollPtr->firstFraction;
-
- TkMacOSXTrackingLoop(1);
- do {
- err = ChkErr(TrackMouseLocationWithOptions, NULL,
- kTrackMouseLocationOptionDontConsumeMouseUp,
- kEventDurationForever, &currentPoint, NULL, &trackingResult);
- if ((err == noErr) && ((trackingResult == kMouseTrackingMouseDragged)
- || (trackingResult == kMouseTrackingMouseMoved))) {
- /*
- * Calculate where the scrollbar should move to, based on where the
- * mouse button was pressed and where the scrollbar initially was
- * at that time. Note that PtInRect() will return false if
- * currentPoint or trackRect are not in is not in current graphics
- * port, which may happen if any of the waiting idle events change
- * the port (e.g. with SetPort()) but fail to restore it before
- * returning and the scrollbar will lock in place.
- */
-
- newFirstFraction = oldFirstFraction;
- if (PtInRect(currentPoint, &trackRect)) {
- short pixDiff;
-
- if (scrollPtr->vertical) {
- pixDiff = currentPoint.v - mouseDownPoint.v;
- } else {
- pixDiff = currentPoint.h - mouseDownPoint.h;
- }
- newFirstFraction += (double)pixDiff / trackBarSize;
- if (newFirstFraction > 1.0) {
- newFirstFraction = 1.0;
- } else if (newFirstFraction < 0.0) {
- newFirstFraction = 0.0;
- }
- }
-
- /*
- * Move the scrollbar thumb to the new first fraction given its
- * position when initially pressed and how far the mouse has
- * moved. Process waiting idle tasks afterward to allow for the
- * display to update.
- */
-
- Tcl_PrintDouble(NULL, newFirstFraction, valueString);
- Tcl_DStringSetLength(&cmdString, 0);
- Tcl_DStringAppend(&cmdString, scrollPtr->command,
- scrollPtr->commandSize);
- Tcl_DStringAppendElement(&cmdString, "moveto");
- Tcl_DStringAppendElement(&cmdString, valueString);
- interp = scrollPtr->interp;
- Tcl_Preserve(interp);
- Tcl_EvalEx(interp, Tcl_DStringValue(&cmdString),
- Tcl_DStringLength(&cmdString), TCL_EVAL_GLOBAL);
- Tcl_Release(interp);
- TkMacOSXRunTclEventLoop();
- }
- } while ((err == noErr) && trackingResult != kMouseTrackingMouseReleased);
- TkMacOSXTrackingLoop(0);
- Tcl_DStringFree(&cmdString);
- return;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * ScrollbarActionProc --
- *
- * Callback procedure used by the Macintosh toolbox call
- * HandleControlClick. This call will update the display while the
- * scrollbar is being manipulated by the user.
- *
- * Results:
- * None.
- *
- * Side effects:
- * May change the display.
- *
- *--------------------------------------------------------------
- */
-
-static pascal void
-ScrollbarActionProc(
- ControlRef theControl, /* Handle to scrollbat control */
- ControlPartCode partCode) /* Part of scrollbar that was "hit" */
-{
- TkScrollbar *scrollPtr = (TkScrollbar *)(intptr_t)
- GetControlReference(theControl);
- MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
- Tcl_DString cmdString;
-
- Tcl_DStringInit(&cmdString);
- Tcl_DStringAppend(&cmdString, scrollPtr->command,
- scrollPtr->commandSize);
-
- if ( partCode == kAppearancePartUpButton ||
- partCode == kAppearancePartDownButton ) {
- Tcl_DStringAppendElement(&cmdString, "scroll");
- Tcl_DStringAppendElement(&cmdString,
- (partCode == kAppearancePartUpButton) ? "-1" : "1");
- Tcl_DStringAppendElement(&cmdString, "unit");
- } else if (partCode == kAppearancePartPageUpArea ||
- partCode == kAppearancePartPageDownArea ) {
- Tcl_DStringAppendElement(&cmdString, "scroll");
- Tcl_DStringAppendElement(&cmdString,
- (partCode == kAppearancePartPageUpArea) ? "-1" : "1");
- Tcl_DStringAppendElement(&cmdString, "page");
- } else if (partCode == kAppearancePartIndicator) {
- char valueString[TCL_DOUBLE_SPACE];
-
- Tcl_PrintDouble(NULL, (GetControl32BitValue(macScrollPtr->sbHandle) -
- MIN_SCROLLBAR_VALUE) / SCROLLBAR_SCALING_VALUE, valueString);
- Tcl_DStringAppendElement(&cmdString, "moveto");
- Tcl_DStringAppendElement(&cmdString, valueString);
- }
- Tcl_Preserve(scrollPtr->interp);
- Tcl_EvalEx(scrollPtr->interp, Tcl_DStringValue(&cmdString),
- Tcl_DStringLength(&cmdString), TCL_EVAL_GLOBAL);
- Tcl_Release(scrollPtr->interp);
- Tcl_DStringFree(&cmdString);
- TkMacOSXRunTclEventLoop();
-}
-
-/*
- *--------------------------------------------------------------
- *
- * ScrollbarBindProc --
- *
- * This procedure is invoked when the default <ButtonPress> binding on
- * the Scrollbar bind tag fires.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The event enters a modal loop.
- *
- *--------------------------------------------------------------
- */
-
-static int
-ScrollbarBindProc(
- ClientData clientData, /* Not used. */
- Tcl_Interp *interp, /* Interp with binding. */
- XEvent *eventPtr, /* X event that triggered binding. */
- Tk_Window tkwin, /* Target window for event. */
- KeySym keySym) /* The KeySym if a key event. */
-{
- TkWindow *winPtr = (TkWindow *) tkwin;
- TkScrollbar *scrollPtr = (TkScrollbar *) winPtr->instanceData;
- MacScrollbar *macScrollPtr = (MacScrollbar *) winPtr->instanceData;
-
- Tcl_Preserve(scrollPtr);
- macScrollPtr->macFlags |= IN_MODAL_LOOP;
-
- if (eventPtr->type == ButtonPress) {
- Point where;
- Rect bounds;
- ControlPartCode part;
- CGrafPtr destPort, savePort;
- Boolean portChanged;
- Window window;
-
- /*
- * To call Macintosh control routines we must have the port set to the
- * window containing the control. We will then test which part of the
- * control was hit and act accordingly.
- */
-
- destPort = TkMacOSXGetDrawablePort(Tk_WindowId(scrollPtr->tkwin));
- portChanged = QDSwapPort(destPort, &savePort);
- TkMacOSXSetUpClippingRgn(Tk_WindowId(scrollPtr->tkwin));
-
- TkMacOSXWinBounds((TkWindow *) scrollPtr->tkwin, &bounds);
- where.h = eventPtr->xbutton.x + bounds.left;
- where.v = eventPtr->xbutton.y + bounds.top;
- part = TestControl(macScrollPtr->sbHandle, where);
- TkMacOSXTrackingLoop(1);
- if (part == kAppearancePartIndicator && scrollPtr->jump == false) {
- /*
- * Case 1: In thumb, no jump scrolling. Call track control with
- * the thumb action proc which will do most of the work.
- */
-
- mouseDownPoint.h = where.h;
- mouseDownPoint.v = where.v;
- HandleControlClick(macScrollPtr->sbHandle, where,
- TkMacOSXModifierState(), thumbActionProc);
- } else if (part == kAppearancePartIndicator) {
- /*
- * Case 2: in thumb with jump scrolling. Call HandleControlClick
- * with a NULL action proc. Use the new value of the control to
- * set update the control.
- */
-
- part = HandleControlClick(macScrollPtr->sbHandle, where,
- TkMacOSXModifierState(), NULL);
- if (part == kAppearancePartIndicator) {
- Tcl_DString cmdString;
- char valueString[TCL_DOUBLE_SPACE];
-
- Tcl_PrintDouble(NULL,
- (GetControl32BitValue(macScrollPtr->sbHandle) -
- MIN_SCROLLBAR_VALUE) / SCROLLBAR_SCALING_VALUE,
- valueString);
- Tcl_DStringInit(&cmdString);
- Tcl_DStringAppend(&cmdString, scrollPtr->command,
- strlen(scrollPtr->command));
- Tcl_DStringAppendElement(&cmdString, "moveto");
- Tcl_DStringAppendElement(&cmdString, valueString);
-
- interp = scrollPtr->interp;
- Tcl_Preserve(interp);
- Tcl_EvalEx(interp, Tcl_DStringValue(&cmdString),
- Tcl_DStringLength(&cmdString), TCL_EVAL_GLOBAL);
- Tcl_Release(interp);
- Tcl_DStringFree(&cmdString);
- TkMacOSXRunTclEventLoop();
- }
- } else if (part != 0) {
- /*
- * Case 3: in any other part of the scrollbar. We call
- * HandleControlClick with the scrollActionProc which will do most
- * all the work.
- */
-
- HandleControlClick(macScrollPtr->sbHandle, where,
- TkMacOSXModifierState(), scrollActionProc);
-
- /*
- * Workaround for Carbon bug where the scrollbar down arrow
- * sometimes gets "stuck" after the mousebutton has been released.
- */
-
- if (scrollPtr->tkwin) {
- TkMacOSXSetUpClippingRgn(Tk_WindowId(scrollPtr->tkwin));
- }
- Draw1Control(macScrollPtr->sbHandle);
- }
- TkMacOSXTrackingLoop(0);
-
- /*
- * The HandleControlClick call will "eat" the ButtonUp event. We now
- * generate a ButtonUp event so Tk will unset implicit grabs etc.
- */
-
- if (scrollPtr->tkwin) {
- window = Tk_WindowId(scrollPtr->tkwin);
- TkGenerateButtonEventForXPointer(window);
- }
-
- if (portChanged) {
- QDSwapPort(savePort, NULL);
- }
- }
-
- if (macScrollPtr->sbHandle && (macScrollPtr->macFlags & ALREADY_DEAD)) {
- DisposeControl(macScrollPtr->sbHandle);
- macScrollPtr->sbHandle = NULL;
- }
- macScrollPtr->macFlags &= ~IN_MODAL_LOOP;
- Tcl_Release(scrollPtr);
-
- return TCL_OK;
-}
-
-/*
- *--------------------------------------------------------------
- *
* ScrollbarEventProc --
*
* This procedure is invoked by the Tk dispatcher for various events on
@@ -894,162 +598,25 @@ ScrollbarEventProc(
XEvent *eventPtr) /* Information about event. */
{
TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
- MacScrollbar *macScrollPtr = (MacScrollbar *) clientData;
- if (eventPtr->type == UnmapNotify) {
+ switch (eventPtr->type) {
+ case UnmapNotify:
TkMacOSXSetScrollbarGrow((TkWindow *) scrollPtr->tkwin, false);
- } else if (eventPtr->type == ActivateNotify) {
- macScrollPtr->macFlags |= ACTIVE;
+ break;
+ case ActivateNotify:
+ case DeactivateNotify:
TkScrollbarEventuallyRedraw((ClientData) scrollPtr);
- } else if (eventPtr->type == DeactivateNotify) {
- macScrollPtr->macFlags &= ~ACTIVE;
- TkScrollbarEventuallyRedraw((ClientData) scrollPtr);
- } else {
+ break;
+ default:
TkScrollbarEventProc(clientData, eventPtr);
}
}
/*
- *--------------------------------------------------------------
- *
- * UpdateControlValues --
- *
- * This procedure updates the Macintosh scrollbar control to display the
- * values defined by the Tk scrollbar.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The Macintosh control is updated.
- *
- *--------------------------------------------------------------
- */
-
-static void
-UpdateControlValues(
- MacScrollbar *macScrollPtr) /* Scrollbar data struct. */
-{
- TkScrollbar *scrollPtr = (TkScrollbar *) macScrollPtr;
- Tk_Window tkwin = scrollPtr->tkwin;
- MacDrawable *macDraw = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin);
- double dViewSize;
- Rect contrlRect, portRect;
- int variant, active;
- short width, height;
-
- contrlRect.left = macDraw->xOff + scrollPtr->inset;
- contrlRect.top = macDraw->yOff + scrollPtr->inset;
- contrlRect.right = macDraw->xOff + Tk_Width(tkwin) - scrollPtr->inset;
- contrlRect.bottom = macDraw->yOff + Tk_Height(tkwin) - scrollPtr->inset;
-
- GetPortBounds(GetWindowPort(GetControlOwner(macScrollPtr->sbHandle)),
- &portRect);
-
- /*
- * If the scrollbar is flush against the bottom right hand corner then we
- * leave space to draw the grow region for the window.
- */
-
- if (portRect.bottom == contrlRect.bottom &&
- portRect.right == contrlRect.right) {
- TkMacOSXSetScrollbarGrow((TkWindow *) tkwin, true);
- if (macDraw->toplevel &&
- TkMacOSXResizable(macDraw->toplevel->winPtr)) {
- int growSize;
-
- switch (TkMacOSXWindowClass(macDraw->toplevel->winPtr)) {
- case kFloatingWindowClass:
- case kUtilityWindowClass:
- growSize = metrics[1].width - 1;
- break;
- case kDocumentWindowClass:
- case kMovableAlertWindowClass:
- case kMovableModalWindowClass:
- default:
- growSize = metrics[0].width - 1;
- break;
- }
- if (scrollPtr->vertical) {
- contrlRect.bottom -= growSize;
- } else {
- contrlRect.right -= growSize;
- }
- }
- } else {
- TkMacOSXSetScrollbarGrow((TkWindow *) tkwin, false);
- }
-
- if (IsControlVisible (macScrollPtr->sbHandle)) {
- SetControlVisibility(macScrollPtr->sbHandle, false, false);
- }
-
- if (scrollPtr->vertical) {
- width = contrlRect.right - contrlRect.left;
- height = contrlRect.bottom - contrlRect.top;
- } else {
- width = contrlRect.bottom - contrlRect.top;
- height = contrlRect.right - contrlRect.left;
- }
- variant = width < metrics[0].width ? 1 : 0;
- SetControlData(macScrollPtr->sbHandle, kControlEntireControl,
- kControlSizeTag, sizeof(ControlSize),
- &(metrics[variant].size));
-
- macScrollPtr->eraseRect = contrlRect;
- if (scrollPtr->vertical) {
- macScrollPtr->eraseRect.left += metrics[variant].width;
- } else {
- macScrollPtr->eraseRect.top += metrics[variant].width;
- }
-
- /*
- * Ensure we set scrollbar control bounds only once all size adjustments
- * have been computed.
- */
-
- SetControlBounds(macScrollPtr->sbHandle, &contrlRect);
-
- /*
- * Given the Tk parameters for the fractions of the start and end of the
- * thumb, the following calculation determines the location for the
- * Macintosh thumb. The Aqua scroll control works as follows. The
- * scrollbar's value is the position of the left (or top) side of the view
- * area in the content area being scrolled. The maximum value of the
- * control is therefore the dimension of the content area less the size of
- * the view area. Since these values are all integers, and Tk gives the
- * thumb position as fractions, we have introduced a scaling factor.
- */
-
- dViewSize = (scrollPtr->lastFraction - scrollPtr->firstFraction)
- * SCROLLBAR_SCALING_VALUE;
- SetControl32BitMinimum(macScrollPtr->sbHandle, MIN_SCROLLBAR_VALUE);
- SetControl32BitMaximum(macScrollPtr->sbHandle, MIN_SCROLLBAR_VALUE +
- SCROLLBAR_SCALING_VALUE - dViewSize);
- SetControlViewSize(macScrollPtr->sbHandle, dViewSize);
- SetControl32BitValue(macScrollPtr->sbHandle, MIN_SCROLLBAR_VALUE +
- SCROLLBAR_SCALING_VALUE * scrollPtr->firstFraction);
-
- if((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0)
- || height <= metrics[variant].minHeight) {
- /* Disable scrollbar */
- SetControl32BitMaximum(macScrollPtr->sbHandle, MIN_SCROLLBAR_VALUE);
- }
- active = ((macScrollPtr->macFlags & ACTIVE) != 0);
- if (active != IsControlActive(macScrollPtr->sbHandle)) {
- if (active) {
- ActivateControl(macScrollPtr->sbHandle);
- } else {
- DeactivateControl(macScrollPtr->sbHandle);
- }
- }
- SetControlVisibility(macScrollPtr->sbHandle, true, false);
-}
-
-/*
* Local Variables:
* mode: c
* c-basic-offset: 4
- * fill-column: 78
+ * fill-column: 79
+ * coding: utf-8
* End:
*/