summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/text.n2
-rw-r--r--generic/tkEntry.c4
-rw-r--r--generic/tkFont.c2
-rw-r--r--generic/tkGrid.c4
-rw-r--r--generic/tkText.c53
-rw-r--r--generic/tkText.h3
-rw-r--r--generic/tkTextBTree.c3
-rw-r--r--generic/tkTextDisp.c611
-rw-r--r--generic/tkTextIndex.c91
-rw-r--r--library/scrlbar.tcl2
-rw-r--r--macosx/tkMacOSXButton.c2042
-rw-r--r--macosx/tkMacOSXDraw.c31
-rw-r--r--macosx/tkMacOSXEmbed.c48
-rw-r--r--macosx/tkMacOSXInit.c7
-rw-r--r--macosx/tkMacOSXMenubutton.c994
-rw-r--r--macosx/tkMacOSXPort.h10
-rw-r--r--macosx/tkMacOSXPrivate.h3
-rw-r--r--macosx/tkMacOSXScrlbr.c781
-rw-r--r--macosx/tkMacOSXWindowEvent.c83
-rw-r--r--tests/canvText.test4
-rw-r--r--tests/text.test54
-rw-r--r--tests/textDisp.test320
-rw-r--r--tests/ttk/spinbox.test2
23 files changed, 3025 insertions, 2129 deletions
diff --git a/doc/text.n b/doc/text.n
index b0fd514..a7eeffc 100644
--- a/doc/text.n
+++ b/doc/text.n
@@ -1870,7 +1870,7 @@ This command returns an empty string.
\fIpathName \fBwindow \fIoption \fR?\fIarg arg ...\fR?
This command is used to manipulate embedded windows.
The behavior of the command depends on the \fIoption\fR argument
-that follows the \fBtag\fR argument.
+that follows the \fBwindow\fR argument.
The following forms of the command are currently supported:
.RS
.TP
diff --git a/generic/tkEntry.c b/generic/tkEntry.c
index 816b7fa..6683cdc 100644
--- a/generic/tkEntry.c
+++ b/generic/tkEntry.c
@@ -1330,7 +1330,7 @@ ConfigureEntry(
double dvalue;
- if (sscanf(entryPtr->string, "%lf", &dvalue) == 0) {
+ if (sscanf(entryPtr->string, "%lf", &dvalue) <= 0) {
/* Scan failure */
dvalue = sbPtr->fromValue;
} else {
@@ -4231,7 +4231,7 @@ SpinboxInvoke(
} else if (!DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue)) {
double dvalue;
- if (sscanf(entryPtr->string, "%lf", &dvalue) == 0) {
+ if (sscanf(entryPtr->string, "%lf", &dvalue) <= 0) {
/*
* If the string doesn't scan as a double value, just
* use the -from value
diff --git a/generic/tkFont.c b/generic/tkFont.c
index 9eaaf94..5d2ad43 100644
--- a/generic/tkFont.c
+++ b/generic/tkFont.c
@@ -3015,7 +3015,6 @@ ConfigAttributesObj(
for (i = 0; i < objc; i += 2) {
optionPtr = objv[i];
- valuePtr = objv[i + 1];
if (Tcl_GetIndexFromObj(interp, optionPtr, fontOpt, "option", 1,
&index) != TCL_OK) {
@@ -3034,6 +3033,7 @@ ConfigAttributesObj(
}
return TCL_ERROR;
}
+ valuePtr = objv[i + 1];
switch (index) {
case FONT_FAMILY:
diff --git a/generic/tkGrid.c b/generic/tkGrid.c
index c6a00d5..ccdde19 100644
--- a/generic/tkGrid.c
+++ b/generic/tkGrid.c
@@ -1991,7 +1991,7 @@ ResolveConstraints(
if (slavePtr->numCols > 1) {
slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
layoutPtr[rightEdge].binNextPtr = slavePtr;
- } else {
+ } else if (rightEdge >= 0) {
int size = slavePtr->size + layoutPtr[rightEdge].pad;
if (size > layoutPtr[rightEdge].minSize) {
@@ -2010,7 +2010,7 @@ ResolveConstraints(
if (slavePtr->numRows > 1) {
slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
layoutPtr[rightEdge].binNextPtr = slavePtr;
- } else {
+ } else if (rightEdge >= 0) {
int size = slavePtr->size + layoutPtr[rightEdge].pad;
if (size > layoutPtr[rightEdge].minSize) {
diff --git a/generic/tkText.c b/generic/tkText.c
index f3e1c26..139e71d 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -871,7 +871,7 @@ TextWidgetObjCmd(
} else if (c == 'd' && (length > 8)
&& !strncmp("-displaylines", option, (unsigned) length)) {
TkTextLine *fromPtr, *lastPtr;
- TkTextIndex index;
+ TkTextIndex index, index2;
int compare = TkTextIndexCmp(indexFromPtr, indexToPtr);
value = 0;
@@ -906,35 +906,44 @@ TextWidgetObjCmd(
/*
* We're going to count up all display lines in the logical
* line of 'indexFromPtr' up to, but not including the logical
- * line of 'indexToPtr', and then subtract off what we didn't
- * want from 'from' and add on what we didn't count from 'to.
+ * line of 'indexToPtr' (except if this line is elided), and
+ * then subtract off what came in too much from elided lines,
+ * also subtract off what we didn't want from 'from' and add
+ * on what we didn't count from 'to'.
*/
- while (index.linePtr != indexToPtr->linePtr) {
- value += TkTextUpdateOneLine(textPtr, fromPtr,0,&index,0);
-
- /*
- * We might have skipped past indexToPtr, if we have
- * multiple logical lines in a single display line.
- */
- if (TkTextIndexCmp(&index,indexToPtr) > 0) {
- break;
- }
+ while (TkTextIndexCmp(&index,indexToPtr) < 0) {
+ value += TkTextUpdateOneLine(textPtr, index.linePtr,
+ 0, &index, 0);
}
- /*
- * Now we need to adjust the count to add on the number of
- * display lines in the last logical line, and subtract off
- * the number of display lines overcounted in the first
- * logical line. This logic is still ok if both indices are in
- * the same logical line.
- */
+ index2 = index;
+
+ /*
+ * Now we need to adjust the count to:
+ * - subtract off the number of display lines between
+ * indexToPtr and index2, since we might have skipped past
+ * indexToPtr, if we have several logical lines in a
+ * single display line
+ * - subtract off the number of display lines overcounted
+ * in the first logical line
+ * - add on the number of display lines in the last logical
+ * line
+ * This logic is still ok if both indexFromPtr and indexToPtr
+ * are in the same logical line.
+ */
+ index = *indexToPtr;
+ index.byteIndex = 0;
+ while (TkTextIndexCmp(&index,&index2) < 0) {
+ value -= TkTextUpdateOneLine(textPtr, index.linePtr,
+ 0, &index, 0);
+ }
index.linePtr = indexFromPtr->linePtr;
index.byteIndex = 0;
while (1) {
TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL);
- if (index.byteIndex >= indexFromPtr->byteIndex) {
+ if (TkTextIndexCmp(&index,indexFromPtr) >= 0) {
break;
}
TkTextIndexForwBytes(textPtr, &index, 1, &index);
@@ -946,7 +955,7 @@ TextWidgetObjCmd(
index.byteIndex = 0;
while (1) {
TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL);
- if (index.byteIndex >= indexToPtr->byteIndex) {
+ if (TkTextIndexCmp(&index,indexToPtr) >= 0) {
break;
}
TkTextIndexForwBytes(textPtr, &index, 1, &index);
diff --git a/generic/tkText.h b/generic/tkText.h
index 4ffdc8a..6f5f153 100644
--- a/generic/tkText.h
+++ b/generic/tkText.h
@@ -1071,6 +1071,9 @@ MODULE_SCOPE void TkTextIndexBackChars(const TkText *textPtr,
TkTextIndex *dstPtr, TkTextCountType type);
MODULE_SCOPE int TkTextIndexCmp(const TkTextIndex *index1Ptr,
const TkTextIndex *index2Ptr);
+MODULE_SCOPE int TkTextIndexCountBytes(const TkText *textPtr,
+ const TkTextIndex *index1Ptr,
+ const TkTextIndex *index2Ptr);
MODULE_SCOPE int TkTextIndexCount(const TkText *textPtr,
const TkTextIndex *index1Ptr,
const TkTextIndex *index2Ptr,
diff --git a/generic/tkTextBTree.c b/generic/tkTextBTree.c
index 67ff79d..92164fc 100644
--- a/generic/tkTextBTree.c
+++ b/generic/tkTextBTree.c
@@ -1882,8 +1882,7 @@ TkBTreePreviousLine(
* number of pixels in the widget.
*
* Results:
- * The result is the index of linePtr within the tree, where 0
- * corresponds to the first line in the tree.
+ * The result is the pixel height of the top of the given line.
*
* Side effects:
* None.
diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c
index bb026af..49a35f5 100644
--- a/generic/tkTextDisp.c
+++ b/generic/tkTextDisp.c
@@ -243,7 +243,8 @@ typedef struct DLine {
* top to bottom. Note: the next DLine doesn't
* always correspond to the next line of text:
* (a) can have multiple DLines for one text
- * line, and (b) can have gaps where DLine's
+ * line (wrapping), (b) can have elided newlines,
+ * and (c) can have gaps where DLine's
* have been deleted because they're out of
* date. */
int flags; /* Various flag bits: see below for values. */
@@ -542,7 +543,8 @@ static void DisplayDLine(TkText *textPtr, DLine *dlPtr,
static void DisplayLineBackground(TkText *textPtr, DLine *dlPtr,
DLine *prevPtr, Pixmap pixmap);
static void DisplayText(ClientData clientData);
-static DLine * FindDLine(DLine *dlPtr, CONST TkTextIndex *indexPtr);
+static DLine * FindDLine(TkText *textPtr, DLine *dlPtr,
+ CONST TkTextIndex *indexPtr);
static void FreeDLines(TkText *textPtr, DLine *firstPtr,
DLine *lastPtr, int action);
static void FreeStyle(TkText *textPtr, TextStyle *stylePtr);
@@ -589,6 +591,8 @@ static int TextGetScrollInfoObj(Tcl_Interp *interp,
int *intPtr);
static void AsyncUpdateLineMetrics(ClientData clientData);
static void AsyncUpdateYScrollbar(ClientData clientData);
+static int IsStartOfNotMergedLine(TkText *textPtr,
+ CONST TkTextIndex *indexPtr);
/*
* Result values returned by TextGetScrollInfoObj:
@@ -1758,7 +1762,7 @@ UpdateDisplayInfo(
*/
index = textPtr->topIndex;
- dlPtr = FindDLine(dInfoPtr->dLinePtr, &index);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &index);
if ((dlPtr != NULL) && (dlPtr != dInfoPtr->dLinePtr)) {
FreeDLines(textPtr, dInfoPtr->dLinePtr, dlPtr, DLINE_UNLINK);
}
@@ -3381,7 +3385,7 @@ TkTextFindDisplayLineEnd(
* of the original index within its display
* line. */
{
- if (!end && indexPtr->byteIndex == 0) {
+ if (!end && IsStartOfNotMergedLine(textPtr, indexPtr)) {
/*
* Nothing to do.
*/
@@ -3460,8 +3464,9 @@ TkTextFindDisplayLineEnd(
* this now.
*/
- *xOffset = DlineXOfIndex(textPtr, dlPtr,
- indexPtr->byteIndex - dlPtr->index.byteIndex);
+ *xOffset = DlineXOfIndex(textPtr, dlPtr,
+ TkTextIndexCountBytes(textPtr, &dlPtr->index,
+ indexPtr));
}
if (end) {
/*
@@ -3531,6 +3536,27 @@ CalculateDisplayLineHeight(
DLine *dlPtr;
int pixelHeight;
+ if (tkTextDebug) {
+ int oldtkTextDebug = tkTextDebug;
+ /*
+ * Check that the indexPtr we are given really is at the start of a
+ * display line. The gymnastics with tkTextDebug is to prevent
+ * failure of a test suite test, that checks that lines are rendered
+ * exactly once. TkTextFindDisplayLineEnd is used here for checking
+ * indexPtr but it calls LayoutDLine/FreeDLine which makes the
+ * counting wrong. The debug mode shall therefore be switched off
+ * when calling TkTextFindDisplayLineEnd.
+ */
+
+ TkTextIndex indexPtr2 = *indexPtr;
+ tkTextDebug = 0;
+ TkTextFindDisplayLineEnd(textPtr, &indexPtr2, 0, NULL);
+ tkTextDebug = oldtkTextDebug;
+ if (TkTextIndexCmp(&indexPtr2,indexPtr) != 0) {
+ Tcl_Panic("CalculateDisplayLineHeight called with bad indexPtr");
+ }
+ }
+
/*
* Special case for artificial last line. May be better to move this
* inside LayoutDLine.
@@ -3597,26 +3623,44 @@ TkTextIndexYPixels(
{
int pixelHeight;
TkTextIndex index;
+ int alreadyStartOfLine = 1;
+
+ /*
+ * Find the index denoting the closest position being at the same time
+ * the start of a logical line above indexPtr and the start of a display
+ * line.
+ */
- pixelHeight = TkBTreePixelsTo(textPtr, indexPtr->linePtr);
+ index = *indexPtr;
+ while (1) {
+ TkTextFindDisplayLineEnd(textPtr, &index, 0, NULL);
+ if (index.byteIndex == 0) {
+ break;
+ }
+ TkTextIndexBackBytes(textPtr, &index, 1, &index);
+ alreadyStartOfLine = 0;
+ }
+
+ pixelHeight = TkBTreePixelsTo(textPtr, index.linePtr);
/*
- * Iterate through all display-lines corresponding to the single logical
- * line belonging to indexPtr, adding up the pixel height of each such
- * display line as we go along, until we go past 'indexPtr'.
+ * Shortcut to avoid layout of a superfluous display line. We know there
+ * is nothing more to add up to the height if the index we were given was
+ * already on the first display line of a logical line.
*/
- if (indexPtr->byteIndex == 0) {
- return pixelHeight;
+ if (alreadyStartOfLine) {
+ return pixelHeight;
}
- index.tree = textPtr->sharedTextPtr->tree;
- index.linePtr = indexPtr->linePtr;
- index.byteIndex = 0;
- index.textPtr = NULL;
+ /*
+ * Iterate through display lines, starting at the logical line belonging
+ * to index, adding up the pixel height of each such display line as we
+ * go along, until we go past 'indexPtr'.
+ */
while (1) {
- int bytes, height;
+ int bytes, height, compare;
/*
* Currently this call doesn't have many side-effects. However, if in
@@ -3628,9 +3672,10 @@ TkTextIndexYPixels(
height = CalculateDisplayLineHeight(textPtr, &index, &bytes, NULL);
- index.byteIndex += bytes;
+ TkTextIndexForwBytes(textPtr, &index, bytes, &index);
- if (index.byteIndex > indexPtr->byteIndex) {
+ compare = TkTextIndexCmp(&index,indexPtr);
+ if (compare > 0) {
return pixelHeight;
}
@@ -3638,7 +3683,7 @@ TkTextIndexYPixels(
pixelHeight += height;
}
- if (index.byteIndex == indexPtr->byteIndex) {
+ if (compare == 0) {
return pixelHeight;
}
}
@@ -3702,10 +3747,26 @@ TkTextUpdateOneLine(
}
/*
+ * CalculateDisplayLineHeight _must_ be called (below) with an index at
+ * the beginning of a display line. Force this to happen. This is needed
+ * when TkTextUpdateOneLine is called with a line that is merged with its
+ * previous line: the number of merged logical lines in a display line is
+ * calculated correctly only when CalculateDisplayLineHeight receives
+ * an index at the beginning of a display line. In turn this causes the
+ * merged lines to receive their correct zero pixel height in
+ * TkBTreeAdjustPixelHeight.
+ */
+
+ TkTextFindDisplayLineEnd(textPtr, indexPtr, 0, NULL);
+ linePtr = indexPtr->linePtr;
+
+ /*
* Iterate through all display-lines corresponding to the single logical
- * line 'linePtr', adding up the pixel height of each such display line as
- * we go along. The final total is, therefore, the height of the logical
- * line.
+ * line 'linePtr' (and lines merged into this line due to eol elision),
+ * adding up the pixel height of each such display line as we go along.
+ * The final total is, therefore, the total height of all display lines
+ * made up by the logical line 'linePtr' and subsequent logical lines
+ * merged into this line.
*/
displayLines = 0;
@@ -3722,7 +3783,7 @@ TkTextUpdateOneLine(
* test below this while loop.
*/
- height = CalculateDisplayLineHeight(textPtr, indexPtr, &bytes,
+ height = CalculateDisplayLineHeight(textPtr, indexPtr, &bytes,
&logicalLines);
if (height > 0) {
@@ -3736,44 +3797,31 @@ TkTextUpdateOneLine(
break;
}
- if (logicalLines == 0) {
- if (indexPtr->linePtr != linePtr) {
- /*
- * If we reached the end of the logical line, then either way
- * we don't have a partial calculation.
- */
-
- partialCalc = 0;
- break;
- }
- } else if (indexPtr->byteIndex != 0) {
- /*
- * We must still be on the same wrapped line.
- */
- } else {
- /*
- * Must check if indexPtr is really a new logical line which is
- * not merged with the previous line. The only code that would
- * really know this is LayoutDLine, which doesn't pass the
- * information on, so we have to check manually here.
- */
+ if (mergedLines == 0) {
+ if (indexPtr->linePtr != linePtr) {
+ /*
+ * If we reached the end of the logical line, then either way
+ * we don't have a partial calculation.
+ */
- TkTextIndex idx;
-
- TkTextIndexBackChars(textPtr, indexPtr, 1, &idx, COUNT_INDICES);
- if (!TkTextIsElided(textPtr, &idx, NULL)) {
- /*
- * We've ended a logical line.
- */
-
- partialCalc = 0;
- break;
- }
+ partialCalc = 0;
+ break;
+ }
+ } else {
+ if (IsStartOfNotMergedLine(textPtr, indexPtr)) {
+ /*
+ * We've ended a logical line.
+ */
+
+ partialCalc = 0;
+ break;
+ }
- /*
- * We must still be on the same wrapped line.
- */
- }
+ /*
+ * We must still be on the same wrapped line, on a new logical
+ * line merged with the logical line 'linePtr'.
+ */
+ }
if (partialCalc && displayLines > 50 && mergedLines == 0) {
/*
* Only calculate 50 display lines at a time, to avoid huge
@@ -3883,6 +3931,21 @@ TkTextUpdateOneLine(
*
*----------------------------------------------------------------------
*/
+#ifdef MAC_OSX_TK
+static void
+RedisplayText(
+ ClientData clientData )
+{
+ register TkText *textPtr = (TkText *) clientData;
+ TextDInfo *dInfoPtr = textPtr->dInfoPtr;
+ TkRegion damageRegion = TkCreateRegion();
+ XRectangle rectangle = {0, 0, dInfoPtr->maxX, dInfoPtr->maxY};
+ TkUnionRectWithRegion(&rectangle, damageRegion, damageRegion);
+
+ TextInvalidateRegion(textPtr, damageRegion);
+ DisplayText(clientData);
+}
+#endif
static void
DisplayText(
@@ -3897,6 +3960,9 @@ DisplayText(
int bottomY = 0; /* Initialization needed only to stop compiler
* warnings. */
Tcl_Interp *interp;
+#ifdef MAC_OSX_TK
+ Tcl_TimerToken macRefreshTimer = NULL;
+#endif
if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
/*
@@ -3968,16 +4034,6 @@ DisplayText(
UpdateDisplayInfo(textPtr);
dInfoPtr->dLinesInvalidated = 0;
-#ifdef MAC_OSX_TK
- /*
- * Make sure that unmapped subwindows really have been unmapped.
- * If the unmap request is pending as an idle request, the window
- * can get redrawn on top of the widget.
- */
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
-#endif
-
-
/*
* See if it's possible to bring some parts of the screen up-to-date by
* scrolling (copying from other parts of the screen). We have to be
@@ -4099,6 +4155,22 @@ DisplayText(
oldY, dInfoPtr->maxX-dInfoPtr->x, height, 0, y-oldY,
damageRgn)) {
TextInvalidateRegion(textPtr, damageRgn);
+
+#ifdef MAC_OSX_TK
+
+ /*
+ * On OS X large scrolls sometimes leave garbage on the screen.
+ * This attempts to clean it up by redisplaying the Text window
+ * after 200 milliseconds.
+ */
+ if ( abs(y-oldY) > 14 ) {
+ Tcl_DeleteTimerHandler(macRefreshTimer);
+ macRefreshTimer = Tcl_CreateTimerHandler(200,
+ RedisplayText,
+ clientData);
+ }
+#endif
+
}
numCopies++;
TkDestroyRegion(damageRgn);
@@ -4547,6 +4619,8 @@ TextChanged(
TextDInfo *dInfoPtr = textPtr->dInfoPtr;
DLine *firstPtr, *lastPtr;
TkTextIndex rounded;
+ TkTextLine *linePtr;
+ int notBegin;
/*
* Schedule both a redisplay and a recomputation of display information.
@@ -4572,23 +4646,78 @@ TextChanged(
/*
* Find the DLines corresponding to index1Ptr and index2Ptr. There is one
* tricky thing here, which is that we have to relayout in units of whole
- * text lines: round index1Ptr back to the beginning of its text line, and
- * include all the display lines after index2, up to the end of its text
- * line. This is necessary because the indices stored in the display lines
- * will no longer be valid. It's also needed because any edit could change
- * the way lines wrap.
+ * text lines: This is necessary because the indices stored in the display
+ * lines will no longer be valid. It's also needed because any edit could
+ * change the way lines wrap.
+ * To relayout in units of whole text (logical) lines, round index1Ptr
+ * back to the beginning of its text line (or, if this line start is
+ * elided, to the beginning of the text line that starts the display line
+ * it is included in), and include all the display lines after index2Ptr,
+ * up to the end of its text line (or, if this line end is elided, up to
+ * the end of the first non elided text line after this line end).
*/
rounded = *index1Ptr;
rounded.byteIndex = 0;
- firstPtr = FindDLine(dInfoPtr->dLinePtr, &rounded);
+ notBegin = 0;
+ while (!IsStartOfNotMergedLine(textPtr, &rounded) && notBegin) {
+ notBegin = !TkTextIndexBackBytes(textPtr, &rounded, 1, &rounded);
+ rounded.byteIndex = 0;
+ }
+
+ /*
+ * 'rounded' now points to the start of a display line as well as the
+ * real (non elided) start of a logical line, and this index is the
+ * closest before index1Ptr.
+ */
+
+ firstPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &rounded);
+
if (firstPtr == NULL) {
+ /*
+ * index1Ptr pertains to no display line, i.e this index is after
+ * the last display line. Since index2Ptr is after index1Ptr, there
+ * is no display line to free/redisplay and we can return early.
+ */
+
return;
}
- lastPtr = FindDLine(dInfoPtr->dLinePtr, index2Ptr);
- while ((lastPtr != NULL)
- && (lastPtr->index.linePtr == index2Ptr->linePtr)) {
- lastPtr = lastPtr->nextPtr;
+
+ rounded = *index2Ptr;
+ linePtr = index2Ptr->linePtr;
+ do {
+ linePtr = TkBTreeNextLine(textPtr, linePtr);
+ if (linePtr == NULL) {
+ break;
+ }
+ rounded.linePtr = linePtr;
+ rounded.byteIndex = 0;
+ } while (!IsStartOfNotMergedLine(textPtr, &rounded));
+
+ if (linePtr == NULL) {
+ lastPtr = NULL;
+ } else {
+ /*
+ * 'rounded' now points to the start of a display line as well as the
+ * start of a logical line not merged with its previous line, and
+ * this index is the closest after index2Ptr.
+ */
+
+ lastPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &rounded);
+
+ /*
+ * At least one display line is supposed to change. This makes the
+ * redisplay OK in case the display line we expect to get here was
+ * unlinked by a previous call to TkTextChanged and the text widget
+ * did not update before reaching this point. This happens for
+ * instance when moving the cursor up one line.
+ * Note that lastPtr != NULL here, otherwise we would have returned
+ * earlier when we tested for firstPtr being NULL.
+ */
+
+ if (lastPtr == firstPtr) {
+ lastPtr = lastPtr->nextPtr;
+ }
}
/*
@@ -4768,14 +4897,13 @@ TextRedrawTag(
* the line containing the previous character.
*/
- if (curIndexPtr->byteIndex == 0) {
- dlPtr = FindDLine(dlPtr, curIndexPtr);
+ if (IsStartOfNotMergedLine(textPtr, curIndexPtr)) {
+ dlPtr = FindDLine(textPtr, dlPtr, curIndexPtr);
} else {
- TkTextIndex tmp;
+ TkTextIndex tmp = *curIndexPtr;
- tmp = *curIndexPtr;
- tmp.byteIndex -= 1;
- dlPtr = FindDLine(dlPtr, &tmp);
+ TkTextIndexBackBytes(textPtr, &tmp, 1, &tmp);
+ dlPtr = FindDLine(textPtr, dlPtr, &tmp);
}
if (dlPtr == NULL) {
break;
@@ -4791,9 +4919,9 @@ TextRedrawTag(
curIndexPtr = &search.curIndex;
endIndexPtr = curIndexPtr;
}
- endPtr = FindDLine(dlPtr, endIndexPtr);
- if ((endPtr != NULL) && (endPtr->index.linePtr == endIndexPtr->linePtr)
- && (endPtr->index.byteIndex < endIndexPtr->byteIndex)) {
+ endPtr = FindDLine(textPtr, dlPtr, endIndexPtr);
+ if ((endPtr != NULL)
+ && (TkTextIndexCmp(&endPtr->index,endIndexPtr) < 0)) {
endPtr = endPtr->nextPtr;
}
@@ -4911,7 +5039,7 @@ TkTextRelayoutWindow(
* could change the way lines wrap.
*/
- if (textPtr->topIndex.byteIndex != 0) {
+ if (!IsStartOfNotMergedLine(textPtr, &textPtr->topIndex)) {
TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
}
@@ -5024,9 +5152,9 @@ TkTextSetYView(
*/
textPtr->topIndex = *indexPtr;
- if (indexPtr->byteIndex != 0) {
- TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
- }
+ if (!IsStartOfNotMergedLine(textPtr, indexPtr)) {
+ TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
+ }
dInfoPtr->newTopPixelOffset = pickPlace;
goto scheduleUpdate;
}
@@ -5040,7 +5168,7 @@ TkTextSetYView(
if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
UpdateDisplayInfo(textPtr);
}
- dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
if (dlPtr != NULL) {
if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) {
/*
@@ -5049,19 +5177,20 @@ TkTextSetYView(
*/
dlPtr = NULL;
- } else if ((dlPtr->index.linePtr == indexPtr->linePtr)
- && (dlPtr->index.byteIndex <= indexPtr->byteIndex)) {
- if (dInfoPtr->dLinePtr == dlPtr && dInfoPtr->topPixelOffset != 0) {
- /*
- * It is on the top line, but that line is hanging off the top
- * of the screen. Change the top overlap to zero and update.
- */
-
- dInfoPtr->newTopPixelOffset = 0;
- goto scheduleUpdate;
- }
- return;
- }
+ } else {
+ if (TkTextIndexCmp(&dlPtr->index, indexPtr) <= 0) {
+ if (dInfoPtr->dLinePtr == dlPtr && dInfoPtr->topPixelOffset != 0) {
+ /*
+ * It is on the top line, but that line is hanging off the top
+ * of the screen. Change the top overlap to zero and update.
+ */
+
+ dInfoPtr->newTopPixelOffset = 0;
+ goto scheduleUpdate;
+ }
+ return;
+ }
+ }
}
/*
@@ -5072,7 +5201,9 @@ TkTextSetYView(
* If the line is not close, place it in the center of the window.
*/
- lineHeight = CalculateDisplayLineHeight(textPtr, indexPtr, NULL, NULL);
+ tmpIndex = *indexPtr;
+ TkTextFindDisplayLineEnd(textPtr, &tmpIndex, 0, NULL);
+ lineHeight = CalculateDisplayLineHeight(textPtr, &tmpIndex, NULL, NULL);
/*
* It would be better if 'bottomY' were calculated using the actual height
@@ -5113,7 +5244,7 @@ TkTextSetYView(
MeasureUp(textPtr, indexPtr, close + lineHeight
- textPtr->charHeight/2, &tmpIndex, &overlap);
- if (FindDLine(dInfoPtr->dLinePtr, &tmpIndex) != NULL) {
+ if (FindDLine(textPtr, dInfoPtr->dLinePtr, &tmpIndex) != NULL) {
bottomY = dInfoPtr->maxY - dInfoPtr->y;
}
}
@@ -5251,6 +5382,8 @@ MeasureUp(
index.linePtr = TkBTreeFindLine(srcPtr->tree, textPtr, lineNum);
index.byteIndex = 0;
+ TkTextFindDisplayLineEnd(textPtr, &index, 0, NULL);
+ lineNum = TkBTreeLinesTo(textPtr, index.linePtr);
lowestPtr = NULL;
do {
dlPtr = LayoutDLine(textPtr, &index);
@@ -5271,8 +5404,21 @@ MeasureUp(
for (dlPtr = lowestPtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) {
distance -= dlPtr->height;
if (distance <= 0) {
- *dstPtr = dlPtr->index;
- if (overlap != NULL) {
+ *dstPtr = dlPtr->index;
+
+ /*
+ * dstPtr is the start of a display line that is or is not
+ * the start of a logical line. If it is the start of a
+ * logical line, we must check whether this line is merged
+ * with the previous logical line, and if so we must adjust
+ * dstPtr to the start of the display line since a display
+ * line start needs to be returned.
+ */
+ if (!IsStartOfNotMergedLine(textPtr, dstPtr)) {
+ TkTextFindDisplayLineEnd(textPtr, dstPtr, 0, NULL);
+ }
+
+ if (overlap != NULL) {
*overlap = -distance;
}
break;
@@ -5372,16 +5518,24 @@ TkTextSeeCmd(
}
/*
- * Find the chunk that contains the desired index. dlPtr may be NULL if
- * the widget is not mapped. [Bug #641778]
+ * Find the display line containing the desired index. dlPtr may be NULL
+ * if the widget is not mapped. [Bug #641778]
*/
- dlPtr = FindDLine(dInfoPtr->dLinePtr, &index);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &index);
if (dlPtr == NULL) {
return TCL_OK;
}
- byteCount = index.byteIndex - dlPtr->index.byteIndex;
+ /*
+ * Find the chunk within the display line that contains the desired
+ * index. The chunks making the display line are skipped up to but not
+ * including the one crossing index. Skipping is done based on a
+ * byteCount offset possibly spanning several logical lines in case
+ * they are elided.
+ */
+
+ byteCount = TkTextIndexCountBytes(textPtr, &dlPtr->index, &index);
for (chunkPtr = dlPtr->chunkPtr; chunkPtr != NULL ;
chunkPtr = chunkPtr->nextPtr) {
if (byteCount < chunkPtr->numBytes) {
@@ -5392,36 +5546,33 @@ TkTextSeeCmd(
/*
* Call a chunk-specific function to find the horizontal range of the
- * character within the chunk. chunkPtr is NULL if trying to see in elided
- * region.
+ * character within the chunk.
*/
- if (chunkPtr != NULL) {
- (*chunkPtr->bboxProc)(textPtr, chunkPtr, byteCount,
- dlPtr->y + dlPtr->spaceAbove,
- dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
- dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width,
- &height);
- delta = x - dInfoPtr->curXPixelOffset;
- oneThird = lineWidth/3;
- if (delta < 0) {
- if (delta < -oneThird) {
- dInfoPtr->newXPixelOffset = (x - lineWidth/2);
- } else {
- dInfoPtr->newXPixelOffset -= ((-delta) );
- }
- } else {
- delta -= (lineWidth - width);
- if (delta > 0) {
- if (delta > oneThird) {
- dInfoPtr->newXPixelOffset = (x - lineWidth/2);
- } else {
- dInfoPtr->newXPixelOffset += (delta );
- }
- } else {
- return TCL_OK;
- }
- }
+ (*chunkPtr->bboxProc)(textPtr, chunkPtr, byteCount,
+ dlPtr->y + dlPtr->spaceAbove,
+ dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
+ dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width,
+ &height);
+ delta = x - dInfoPtr->curXPixelOffset;
+ oneThird = lineWidth/3;
+ if (delta < 0) {
+ if (delta < -oneThird) {
+ dInfoPtr->newXPixelOffset = (x - lineWidth/2);
+ } else {
+ dInfoPtr->newXPixelOffset -= ((-delta) );
+ }
+ } else {
+ delta -= (lineWidth - width);
+ if (delta > 0) {
+ if (delta > oneThird) {
+ dInfoPtr->newXPixelOffset = (x - lineWidth/2);
+ } else {
+ dInfoPtr->newXPixelOffset += (delta );
+ }
+ } else {
+ return TCL_OK;
+ }
}
dInfoPtr->flags |= DINFO_OUT_OF_DATE;
if (!(dInfoPtr->flags & REDRAW_PENDING)) {
@@ -5658,7 +5809,25 @@ YScrollByLines(
offset++;
if (offset == 0) {
textPtr->topIndex = dlPtr->index;
- break;
+
+ /*
+ * topIndex is the start of a logical line. However, if
+ * the eol of the previous logical line is elided, then
+ * topIndex may be elsewhere than the first character of
+ * a display line, which is unwanted. Adjust to the start
+ * of the display line, if needed.
+ * topIndex is the start of a display line that is or is
+ * not the start of a logical line. If it is the start of
+ * a logical line, we must check whether this line is
+ * merged with the previous logical line, and if so we
+ * must adjust topIndex to the start of the display line.
+ */
+ if (!IsStartOfNotMergedLine(textPtr, &textPtr->topIndex)) {
+ TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex,
+ 0, NULL);
+ }
+
+ break;
}
}
@@ -6136,13 +6305,10 @@ GetYPixelCount(
/*
* For the common case where this dlPtr is also the start of the logical
- * line, we can return right away. Note the implicit assumption here that
- * the start of a logical line is always the start of a display line (if
- * the 'elide won't elide first newline' bug is fixed, this will no longer
- * necessarily be true).
+ * line, we can return right away.
*/
- if (dlPtr->index.byteIndex == 0) {
+ if (IsStartOfNotMergedLine(textPtr, &dlPtr->index)) {
return count;
}
@@ -6424,11 +6590,12 @@ AsyncUpdateYScrollbar(
static DLine *
FindDLine(
+ TkText *textPtr, /* Widget record for text widget. */
register DLine *dlPtr, /* Pointer to first in list of DLines to
* search. */
CONST TkTextIndex *indexPtr)/* Index of desired character. */
{
- TkTextLine *linePtr;
+ DLine *dlPtrPrev;
if (dlPtr == NULL) {
return NULL;
@@ -6443,43 +6610,89 @@ FindDLine(
}
/*
- * Find the first display line that covers the desired text line.
+ * The display line containing the desired index is such that the index
+ * of the first character of this display line is at or before the
+ * desired index, and the index of the first character of the next
+ * display line is after the desired index.
*/
- linePtr = dlPtr->index.linePtr;
- while (linePtr != indexPtr->linePtr) {
- while (dlPtr->index.linePtr == linePtr) {
- dlPtr = dlPtr->nextPtr;
- if (dlPtr == NULL) {
- return NULL;
- }
- }
+ while (TkTextIndexCmp(&dlPtr->index,indexPtr) < 0) {
+ dlPtrPrev = dlPtr;
+ dlPtr = dlPtr->nextPtr;
+ if (dlPtr == NULL) {
+ TkTextIndex indexPtr2;
+ /*
+ * We're past the last display line, either because the desired
+ * index lies past the visible text, or because the desired index
+ * is on the last display line showing the last logical line.
+ */
+ indexPtr2 = dlPtrPrev->index;
+ TkTextIndexForwBytes(textPtr, &indexPtr2, dlPtrPrev->byteCount,
+ &indexPtr2);
+ if (TkTextIndexCmp(&indexPtr2,indexPtr) > 0) {
+ dlPtr = dlPtrPrev;
+ break;
+ } else {
+ return NULL;
+ }
+ }
+ if (TkTextIndexCmp(&dlPtr->index,indexPtr) > 0) {
+ dlPtr = dlPtrPrev;
+ break;
+ }
+ }
- /*
- * VMD: some concern here as to whether this logic, or the caller's
- * logic will work well with partial peer widgets.
- */
+ return dlPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * IsStartOfNotMergedLine --
+ *
+ * This function checks whether the given index is the start of a
+ * logical line that is not merged with the previous logical line
+ * (due to elision of the eol of the previous line).
+ *
+ * Results:
+ * Returns whether the given index denotes the first index of a
+* logical line not merged with its previous line.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
- linePtr = TkBTreeNextLine(NULL, linePtr);
- if (linePtr == NULL) {
- Tcl_Panic("FindDLine reached end of text");
- }
- }
- if (indexPtr->linePtr != dlPtr->index.linePtr) {
- return dlPtr;
+static int
+IsStartOfNotMergedLine(
+ TkText *textPtr, /* Widget record for text widget. */
+ CONST TkTextIndex *indexPtr) /* Index to check. */
+{
+ TkTextIndex indexPtr2;
+
+ if (indexPtr->byteIndex != 0) {
+ /*
+ * Not the start of a logical line.
+ */
+ return 0;
}
- /*
- * Now get to the right position within the text line.
- */
+ if (TkTextIndexBackBytes(textPtr, indexPtr, 1, &indexPtr2)) {
+ /*
+ * indexPtr is the first index of the text widget.
+ */
+ return 1;
+ }
- while (indexPtr->byteIndex >= (dlPtr->index.byteIndex+dlPtr->byteCount)) {
- dlPtr = dlPtr->nextPtr;
- if ((dlPtr == NULL) || (dlPtr->index.linePtr != indexPtr->linePtr)) {
- break;
- }
+ if (!TkTextIsElided(textPtr, &indexPtr2, NULL)) {
+ /*
+ * The eol of the line just before indexPtr is elided.
+ */
+ return 1;
}
- return dlPtr;
+
+ return 0;
}
/*
@@ -6814,7 +7027,7 @@ TkTextIndexBbox(
TextDInfo *dInfoPtr = textPtr->dInfoPtr;
DLine *dlPtr;
register TkTextDispChunk *chunkPtr;
- int byteIndex;
+ int byteCount;
/*
* Make sure that all of the screen layout information is up to date.
@@ -6828,24 +7041,37 @@ TkTextIndexBbox(
* Find the display line containing the desired index.
*/
- dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
+
+ /*
+ * Two cases shall be trapped here because the logic later really
+ * needs dlPtr to be the display line containing indexPtr:
+ * 1. if no display line contains the desired index (NULL dlPtr)
+ * 2. if indexPtr is before the first display line, in which case
+ * dlPtr currently points to the first display line
+ */
+
if ((dlPtr == NULL) || (TkTextIndexCmp(&dlPtr->index, indexPtr) > 0)) {
return -1;
}
/*
- * Find the chunk within the line that contains the desired index.
+ * Find the chunk within the display line that contains the desired
+ * index. The chunks making the display line are skipped up to but not
+ * including the one crossing indexPtr. Skipping is done based on
+ * a byteCount offset possibly spanning several logical lines in case
+ * they are elided.
*/
- byteIndex = indexPtr->byteIndex - dlPtr->index.byteIndex;
+ byteCount = TkTextIndexCountBytes(textPtr, &dlPtr->index, indexPtr);
for (chunkPtr = dlPtr->chunkPtr; ; chunkPtr = chunkPtr->nextPtr) {
if (chunkPtr == NULL) {
return -1;
}
- if (byteIndex < chunkPtr->numBytes) {
+ if (byteCount < chunkPtr->numBytes) {
break;
}
- byteIndex -= chunkPtr->numBytes;
+ byteCount -= chunkPtr->numBytes;
}
/*
@@ -6855,13 +7081,13 @@ TkTextIndexBbox(
* coordinate on the screen. Translate it to reflect horizontal scrolling.
*/
- (*chunkPtr->bboxProc)(textPtr, chunkPtr, byteIndex,
+ (*chunkPtr->bboxProc)(textPtr, chunkPtr, byteCount,
dlPtr->y + dlPtr->spaceAbove,
dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
dlPtr->baseline - dlPtr->spaceAbove, xPtr, yPtr, widthPtr,
heightPtr);
*xPtr = *xPtr + dInfoPtr->x - dInfoPtr->curXPixelOffset;
- if ((byteIndex == chunkPtr->numBytes-1) && (chunkPtr->nextPtr == NULL)) {
+ if ((byteCount == chunkPtr->numBytes-1) && (chunkPtr->nextPtr == NULL)) {
/*
* Last character in display line. Give it all the space up to the
* line.
@@ -6959,7 +7185,16 @@ TkTextDLineInfo(
* Find the display line containing the desired index.
*/
- dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
+
+ /*
+ * Two cases shall be trapped here because the logic later really
+ * needs dlPtr to be the display line containing indexPtr:
+ * 1. if no display line contains the desired index (NULL dlPtr)
+ * 2. if indexPtr is before the first display line, in which case
+ * dlPtr currently points to the first display line
+ */
+
if ((dlPtr == NULL) || (TkTextIndexCmp(&dlPtr->index, indexPtr) > 0)) {
return -1;
}
diff --git a/generic/tkTextIndex.c b/generic/tkTextIndex.c
index 70c94db..13f3957 100644
--- a/generic/tkTextIndex.c
+++ b/generic/tkTextIndex.c
@@ -40,6 +40,9 @@ static CONST char * StartEnd(TkText *textPtr, CONST char *string,
static int GetIndex(Tcl_Interp *interp, TkSharedText *sharedPtr,
TkText *textPtr, CONST char *string,
TkTextIndex *indexPtr, int *canCachePtr);
+static int IndexCountBytesOrdered(CONST TkText *textPtr,
+ CONST TkTextIndex *indexPtr1,
+ CONST TkTextIndex *indexPtr2);
/*
* The "textindex" Tcl_Obj definition:
@@ -771,11 +774,11 @@ GetIndex(
}
if (TkTextWindowIndex(textPtr, string, indexPtr) != 0) {
- return TCL_OK;
+ goto done;
}
if (TkTextImageIndex(textPtr, string, indexPtr) != 0) {
- return TCL_OK;
+ goto done;
}
/*
@@ -1628,6 +1631,90 @@ TkTextIndexForwChars(
/*
*---------------------------------------------------------------------------
*
+ * TkTextIndexCountBytes --
+ *
+ * Given a pair of indices in a text widget, this function counts how
+ * many bytes are between the two indices. The two indices do not need
+ * to be ordered.
+ *
+ * Results:
+ * The number of bytes in the given range.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+TkTextIndexCountBytes(
+ CONST TkText *textPtr,
+ CONST TkTextIndex *indexPtr1, /* Index describing one location. */
+ CONST TkTextIndex *indexPtr2) /* Index describing second location. */
+{
+ int compare = TkTextIndexCmp(indexPtr1, indexPtr2);
+
+ if (compare == 0) {
+ return 0;
+ } else if (compare > 0) {
+ return IndexCountBytesOrdered(textPtr, indexPtr2, indexPtr1);
+ } else {
+ return IndexCountBytesOrdered(textPtr, indexPtr1, indexPtr2);
+ }
+}
+
+static int
+IndexCountBytesOrdered(
+ CONST TkText *textPtr,
+ CONST TkTextIndex *indexPtr1,
+ /* Index describing location of character from
+ * which to count. */
+ CONST TkTextIndex *indexPtr2)
+ /* Index describing location of last character
+ * at which to stop the count. */
+{
+ int byteCount, offset;
+ TkTextSegment *segPtr, *segPtr1;
+ TkTextLine *linePtr;
+
+ if (indexPtr1->linePtr == indexPtr2->linePtr) {
+ return indexPtr2->byteIndex - indexPtr1->byteIndex;
+ }
+
+ /*
+ * indexPtr2 is on a line strictly after the line containing indexPtr1.
+ * Add up:
+ * bytes between indexPtr1 and end of its line
+ * bytes in lines strictly between indexPtr1 and indexPtr2
+ * bytes between start of the indexPtr2 line and indexPtr2
+ */
+
+ segPtr1 = TkTextIndexToSeg(indexPtr1, &offset);
+ byteCount = -offset;
+ for (segPtr = segPtr1; segPtr != NULL; segPtr = segPtr->nextPtr) {
+ byteCount += segPtr->size;
+ }
+
+ linePtr = indexPtr1->linePtr->nextPtr;
+ while (linePtr != indexPtr2->linePtr) {
+ for (segPtr = linePtr->segPtr; segPtr != NULL;
+ segPtr = segPtr->nextPtr) {
+ byteCount += segPtr->size;
+ }
+ linePtr = TkBTreeNextLine(textPtr, linePtr);
+ if (linePtr == NULL) {
+ Tcl_Panic("TextIndexCountBytesOrdered ran out of lines");
+ }
+ }
+
+ byteCount += indexPtr2->byteIndex;
+
+ return byteCount;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
* TkTextIndexCount --
*
* Given an ordered pair of indices in a text widget, this function
diff --git a/library/scrlbar.tcl b/library/scrlbar.tcl
index 4cb95bd..4b25325 100644
--- a/library/scrlbar.tcl
+++ b/library/scrlbar.tcl
@@ -15,7 +15,7 @@
#-------------------------------------------------------------------------
# Standard Motif bindings:
-if {[tk windowingsystem] eq "x11"} {
+if {[tk windowingsystem] eq "x11" || [tk windowingsystem] eq "aqua"} {
bind Scrollbar <Enter> {
if {$tk_strictMotif} {
diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c
index b9ee7a3..fbad20d 100644
--- a/macosx/tkMacOSXButton.c
+++ b/macosx/tkMacOSXButton.c
@@ -5,12 +5,14 @@
* button widgets.
*
* Copyright (c) 1996-1997 by Sun Microsystems, Inc.
- * Copyright 2001-2009, Apple Inc.
- * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
- * Copyright 2014 Marc Culler.
+ * Copyright 2001, Apple Computer, Inc.
+ * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2007 Revar Desmera.
+ * Copyright 2015 Kevin Walzer/WordTech Communications LLC.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
*/
#include "tkMacOSXPrivate.h"
@@ -18,119 +20,82 @@
#include "tkMacOSXFont.h"
#include "tkMacOSXDebug.h"
-/*
-#ifdef TK_MAC_DEBUG
-#define TK_MAC_DEBUG_BUTTON
-#endif
-*/
-static NSRect TkMacOSXGetButtonFrame(TkButton *butPtr);
+#define FIRST_DRAW 2
+#define ACTIVE 4
+
/*
- * A subclass of NSButton with sanity checking:
- * NSButtons created by Tk will have their tag set to a pointer to the TkButton
- * which manages the NSButton. This allows a TkNSButton to be aware of the
- * state of its Tk parent. This subclass overrides the drawRect method
- * so that it will not draw itself unless the NSButton frame matches
- * the frame which was installed by DisplayButton, and the TkButton is
- * mapped. Also, it will not draw anything if the widget is completely
- * outside of its container.
+ * Default insets for controls
*/
-@interface TkNSButton: NSButton
-
-@end
-
-@implementation TkNSButton
-
- - (void)drawRect:(NSRect)dirtyRect
- {
- NSInteger tag = [self tag];
- if ( tag != -1) {
- TkButton *butPtr = (TkButton *)tag;
- MacDrawable* macWin = (MacDrawable *)butPtr;
- NSRect Tkframe = TkMacOSXGetButtonFrame(butPtr);
- Tk_Window tkwin = butPtr->tkwin;
- /* Do not draw if the widget is misplaced or unmapped. */
- if ( NSIsEmptyRect(Tkframe) ||
- ! macWin->winPtr->flags & TK_MAPPED ||
- ! NSEqualRects(Tkframe, [self frame])
- ) {
- return;
- }
- /* Do not draw if the widget is completely outside of its parent, or within 20 pixels of the lower border; this prevents buttons from being drawn on peer widgets as scrolling occurs. */
- if (tkwin) {
- int parent_height = Tk_Height(Tk_Parent(tkwin));
- int widget_height = Tk_Height(tkwin);
- int y = Tk_Y(tkwin);
- if ( y > parent_height - 20 || y + widget_height < 0 ) {
- return;
- }
+#define DEF_INSET_LEFT 2
+#define DEF_INSET_RIGHT 2
+#define DEF_INSET_TOP 2
+#define DEF_INSET_BOTTOM 4
- /* Do not draw if the widget is completely outside of its parent, or within 50 pixels of the right border; this prevents buttons from being drawn on peer widgets as scrolling occurs. */
- int parent_width = Tk_Width(Tk_Parent(tkwin));
- int widget_width = Tk_Width(tkwin);
- int x = Tk_X(tkwin);
- if (x > parent_width - 50 || x < 0) {
- return;
- }
+/*
+ * Some defines used to control what type of control is drawn.
+ */
- }
- }
- [super drawRect:dirtyRect];
- }
+#define DRAW_LABEL 0 /* Labels are treated genericly. */
+#define DRAW_CONTROL 1 /* Draw using the Native control. */
+#define DRAW_CUSTOM 2 /* Make our own button drawing. */
+#define DRAW_BEVEL 3
-@end
+/*
+ * The delay in milliseconds between pulsing default button redraws.
+ */
+#define PULSE_TIMER_MSECS 62 /* Largest value that didn't look stuttery */
+/*
+ * Declaration of Mac specific button structure.
+ */
-typedef struct MacButton {
- TkButton info;
- TkNSButton *button;
- NSImage *image, *selectImage, *tristateImage;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- int fix;
-#endif
-} MacButton;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+typedef struct {
+ int drawType;
+ Tk_3DBorder border;
+ int relief;
+ int offset; /* 0 means this is a normal widget. 1 means
+ * it is an image button, so we offset the
+ * image to make the button appear to move
+ * up and down as the relief changes. */
+ GC gc;
+ int hasImageOrBitmap;
+} DrawParams;
-int tkMacOSXUseCompatibilityMetrics = 1;
+typedef struct {
+ TkButton info; /* Generic button info */
+ int id;
+ int usingControl;
+ int useTkText;
+ int flags; /* Initialisation status */
+ ThemeButtonKind btnkind;
+ HIThemeButtonDrawInfo drawinfo;
+ HIThemeButtonDrawInfo lastdrawinfo;
+ DrawParams drawParams;
+ Tcl_TimerToken defaultPulseHandler;
+} MacButton;
/*
- * Use the following heuristic conversion constants to make NSButton-based
- * widget metrics match up with the old Carbon control buttons (for the
- * default Lucida Grande 13 font).
+ * Forward declarations for procedures defined later in this file:
*/
-#define NATIVE_BUTTON_INSET 2
-#define NATIVE_BUTTON_EXTRA_H 2
-
-typedef struct {
- int trimW, trimH, inset, shrinkH, offsetX, offsetY;
-} BoundsFix;
-
-#define fixForTypeStyle(type, style) ( \
- type == NSSwitchButton ? 0 : \
- type == NSRadioButton ? 1 : \
- style == NSRoundedBezelStyle ? 2 : \
- style == NSRegularSquareBezelStyle ? 3 : \
- style == NSShadowlessSquareBezelStyle ? 4 : \
- INT_MIN)
-
-static const BoundsFix boundsFixes[] = {
- [fixForTypeStyle(NSSwitchButton,0)] = { 2, 2, -1, 0, 2, 1 },
- [fixForTypeStyle(NSRadioButton,0)] = { 0, 2, -1, 0, 1, 1 },
- [fixForTypeStyle(0,NSRoundedBezelStyle)] = { 28, 16, -6, 0, 0, 3 },
- [fixForTypeStyle(0,NSRegularSquareBezelStyle)] = { 28, 15, -2, -1 },
- [fixForTypeStyle(0,NSShadowlessSquareBezelStyle)] = { 2, 2 },
-};
-#endif
+static void ButtonBackgroundDrawCB (const HIRect *btnbounds, MacButton *ptr,
+ SInt16 depth, Boolean isColorDev);
+static void ButtonContentDrawCB (const HIRect *bounds, ThemeButtonKind kind,
+ const HIThemeButtonDrawInfo *info, MacButton *ptr, SInt16 depth,
+ Boolean isColorDev);
+static void ButtonEventProc(ClientData clientData, XEvent *eventPtr);
+static void TkMacOSXComputeButtonParams (TkButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo* drawinfo);
+static int TkMacOSXComputeButtonDrawParams (TkButton * butPtr, DrawParams * dpPtr);
+static void TkMacOSXDrawButton (MacButton *butPtr,
+ GC gc, Pixmap pixmap);
+static void DrawButtonImageAndText(TkButton* butPtr);
+static void PulseDefaultButtonProc(ClientData clientData);
-static void DisplayNativeButton(TkButton *butPtr);
-static void ComputeNativeButtonGeometry(TkButton *butPtr);
-static void DisplayUnixButton(TkButton *butPtr);
-static void ComputeUnixButtonGeometry(TkButton *butPtr);
/*
* The class procedure table for the button widgets.
@@ -139,68 +104,67 @@ static void ComputeUnixButtonGeometry(TkButton *butPtr);
Tk_ClassProcs tkpButtonProcs = {
sizeof(Tk_ClassProcs), /* size */
TkButtonWorldChanged, /* worldChangedProc */
- NULL, /* createProc */
- NULL /* modalProc */
};
-
+static int bCount;
+
/*
*----------------------------------------------------------------------
*
- * TkpCreateButton --
+ * TkpButtonSetDefaults --
*
- * Allocate a new TkButton structure.
+ * This procedure is invoked before option tables are created for
+ * buttons. It modifies some of the default values to match the current
+ * values defined for this platform.
*
* Results:
- * Returns a newly allocated TkButton structure.
+ * Some of the default values in *specPtr are modified.
*
* Side effects:
- * Registers an event handler for the widget.
+ * Updates some of.
*
*----------------------------------------------------------------------
*/
-TkButton *
-TkpCreateButton(
- Tk_Window tkwin)
+void
+TkpButtonSetDefaults()
{
- MacButton *macButtonPtr = (MacButton *) ckalloc(sizeof(MacButton));
-
- macButtonPtr->button = nil;
- macButtonPtr->image = nil;
- macButtonPtr->selectImage = nil;
- macButtonPtr->tristateImage = nil;
-
- return (TkButton *) macButtonPtr;
+/*No-op.*/
}
+
/*
*----------------------------------------------------------------------
*
- * TkpDestroyButton --
+ * TkpCreateButton --
*
- * Free data structures associated with the button control.
+ * Allocate a new TkButton structure.
*
* Results:
- * None.
+ * Returns a newly allocated TkButton structure.
*
* Side effects:
- * Restores the default control state.
+ * Registers an event handler for the widget.
*
*----------------------------------------------------------------------
*/
-void
-TkpDestroyButton(
- TkButton *butPtr)
+TkButton *
+TkpCreateButton(
+ Tk_Window tkwin)
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
- [macButtonPtr->button setTag:(NSInteger)-1];
+ MacButton *macButtonPtr = (MacButton *) ckalloc(sizeof(MacButton));
+
+ Tk_CreateEventHandler(tkwin, ActivateMask,
+ ButtonEventProc, (ClientData) macButtonPtr);
+ macButtonPtr->id = bCount++;
+ macButtonPtr->flags = FIRST_DRAW;
+ macButtonPtr->btnkind = kThemePushButton;
+ macButtonPtr->defaultPulseHandler = NULL;
+ bzero(&macButtonPtr->drawinfo, sizeof(macButtonPtr->drawinfo));
+ bzero(&macButtonPtr->lastdrawinfo, sizeof(macButtonPtr->lastdrawinfo));
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->button);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->image);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->selectImage);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->tristateImage);
+ return (TkButton *)macButtonPtr;
}
/*
@@ -225,63 +189,63 @@ void
TkpDisplayButton(
ClientData clientData) /* Information about widget. */
{
+ MacButton *macButtonPtr = (MacButton *) clientData;
TkButton *butPtr = (TkButton *) clientData;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ DrawParams* dpPtr = &macButtonPtr->drawParams;
+ int needhighlight = 0;
butPtr->flags &= ~REDRAW_PENDING;
- if (!butPtr->tkwin || !Tk_IsMapped(butPtr->tkwin)) {
+ if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
return;
}
+ pixmap = (Pixmap) Tk_WindowId(tkwin);
+ TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin));
- switch (butPtr->type) {
- case TYPE_LABEL:
- DisplayUnixButton(butPtr);
- break;
- case TYPE_BUTTON:
- case TYPE_CHECK_BUTTON:
- case TYPE_RADIO_BUTTON:
- DisplayNativeButton(butPtr);
- break;
+ if (TkMacOSXComputeButtonDrawParams(butPtr, dpPtr) ) {
+ macButtonPtr->useTkText = 0;
+ } else {
+ macButtonPtr->useTkText = 1;
}
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkpShiftButton --
- *
- * Moves the frame of an NSButton (or TkNSButton) and in case the tag is
- * set, also adjusts the xOff and yOff of the controlling TkButton's
- * MacDrawable. This is used to avoid jitter when scrolling.
- *
- * Results:
- * None
- *
- * Side effects:
- * Moves the NSbutton after adjusting the associated MacDrawable.
- *
- *----------------------------------------------------------------------
- */
-void
-TkpShiftButton(
- NSButton *button,
- NSPoint delta )
- {
- NSPoint origin = [button frame].origin;
- NSInteger tag = [button tag];
- if ( tag != -1) {
- TkButton* butPtr = (TkButton *)tag;
- TkWindow *winPtr = (TkWindow *) (butPtr->tkwin);
- if (winPtr) {
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
- macWin->xOff += delta.x;
- macWin->yOff += delta.y;
- }
+
+
+ /*
+ * Set up clipping region. Make sure the we are using the port
+ * for this button, or we will set the wrong window's clip.
+ */
+
+ if (macButtonPtr->useTkText) {
+ if (butPtr->type == TYPE_BUTTON) {
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+ } else {
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
}
- origin.x += delta.x;
- origin.y -= delta.y;
- [button setFrameOrigin:origin];
+
+ /* Display image or bitmap or text for labels or custom controls. */
+ DrawButtonImageAndText(butPtr);
+ needhighlight = 1;
+ } else {
+ /* Draw the native portion of the buttons. */
+ TkMacOSXDrawButton(macButtonPtr, dpPtr->gc, pixmap);
+
+ /* Draw highlight border, if needed. */
+ if (butPtr->highlightWidth < 3) {
+ needhighlight = 1;
+ }
}
+ /* Draw highlight border, if needed. */
+ if (needhighlight) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ Tk_Draw3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin),
+ butPtr->highlightWidth, TK_RELIEF_SOLID);
+ }
+ }
+}
/*
*----------------------------------------------------------------------
@@ -300,1015 +264,1017 @@ TkpShiftButton(
*
*----------------------------------------------------------------------
*/
-
+
void
TkpComputeButtonGeometry(
- register TkButton *butPtr) /* Button whose geometry may have changed. */
+ TkButton *butPtr) /* Button whose geometry may have changed. */
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
+ int width, height, avgWidth, haveImage = 0, haveText = 0;
+ int txtWidth, txtHeight;
+ MacButton *mbPtr = (MacButton*)butPtr;
+ Tk_FontMetrics fm;
+ DrawParams drawParams;
- switch (butPtr->type) {
- case TYPE_LABEL:
- if (macButtonPtr->button && [macButtonPtr->button superview]) {
- [macButtonPtr->button removeFromSuperviewWithoutNeedingDisplay];
- }
- ComputeUnixButtonGeometry(butPtr);
+ /*
+ * First figure out the size of the contents of the button.
+ */
+
+ width = 0;
+ height = 0;
+ txtWidth = 0;
+ txtHeight = 0;
+ avgWidth = 0;
+
+ TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
+
+ butPtr->indicatorSpace = 0;
+ if (butPtr->image != NULL) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
+ }
+
+ /*Tk Aqua can't handle metrics for radiobuttons and checkbuttons with images unless they are set first. These are derived from experimentation.*/
+ if (haveImage && !haveText) {
+ switch (butPtr->type) {
+ case TYPE_RADIO_BUTTON:
+ width = butPtr->width;
+ width +=50;
break;
- case TYPE_BUTTON:
- case TYPE_CHECK_BUTTON:
+ case TYPE_CHECK_BUTTON:
+ width = butPtr->width;
+ width += 50;
+ break;
+ case TYPE_BUTTON:
+ width = butPtr->width;
+ width += 0;
+ break;
+ }
+ }
+
+ if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
+ Tk_FreeTextLayout(butPtr->textLayout);
+ butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
+ Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength,
+ butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
+
+ txtWidth = butPtr->textWidth;
+ txtHeight = butPtr->textHeight;
+ avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
+ Tk_GetFontMetrics(butPtr->tkfont, &fm);
+ haveText = (txtWidth != 0 && txtHeight != 0);
+ }
+
+ /*
+ * If the button is compound (ie, it shows both an image and text),
+ * the new geometry is a combination of the image and text geometry.
+ * We only honor the compound bit if the button has both text and an
+ * image, because otherwise it is not really a compound button.
+ */
+
+ if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM:
+ /*
+ * Image is above or below text.
+ */
+
+ height += txtHeight + butPtr->padY;
+ width = (width > txtWidth ? width : txtWidth);
+ break;
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT:
+ /*
+ * Image is left or right of text.
+ */
+
+ width += txtWidth + butPtr->padX;
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ case COMPOUND_CENTER:
+ /*
+ * Image and text are superimposed.
+ */
+
+ width = (width > txtWidth ? width : txtWidth);
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ case COMPOUND_NONE:
+ break;
+ }
+ if (butPtr->width > 0) {
+ width = butPtr->width;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height;
+ }
+
+ } else if (haveImage) {
+
+ if (butPtr->width > 0) {
+ width = butPtr->width;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height;
+ }
+
+ } else {
+ width = txtWidth;
+ height = txtHeight;
+
+ if (butPtr->width > 0) {
+ width = butPtr->width * avgWidth;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height * fm.linespace;
+ }
+ }
+
+ width += 2 * butPtr->padX;
+ height += 2 * butPtr->padY;
+
+
+ /* Need special handling for radiobuttons and checkbuttons: the text is drawn right on top of the button unless we expand the width. This is not perfect; some radiobuttons may render on top anyway. Need to find a better solution to calculate average text width.*/
+ switch (butPtr->type) {
case TYPE_RADIO_BUTTON:
- if (!macButtonPtr->button) {
- TkNSButton *button = [[TkNSButton alloc] initWithFrame:NSZeroRect];
- [button setTag:(NSInteger)butPtr];
- macButtonPtr->button = TkMacOSXMakeUncollectable(button);
+ width += 50;
+ break;
+ case TYPE_CHECK_BUTTON:
+ width += 50;
+ break;
+ }
+
+ /*
+ * Now figure out the size of the border decorations for the button.
+ */
+
+ if (butPtr->highlightWidth < 0) {
+ butPtr->highlightWidth = 0;
+ }
+
+ butPtr->inset = 0;
+ butPtr->inset += butPtr->highlightWidth;
+
+ if (TkMacOSXComputeButtonDrawParams(butPtr,&drawParams)) {
+
+
+ HIRect tmpRect;
+ HIRect contBounds;
+ int paddingx = 0;
+ int paddingy = 0;
+
+ tmpRect = CGRectMake(0, 0, width, height);
+
+
+ HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds);
+
+
+ /* If the content region has a minimum height, match it. */
+ if (height < contBounds.size.height) {
+ height = contBounds.size.height;
+ }
+
+ /* If the content region has a minimum width, match it. */
+ if (width < contBounds.size.width) {
+ width = contBounds.size.width;
+ }
+
+ /* Pad to fill difference between content bounds and button bounds. */
+ paddingx = tmpRect.origin.x - contBounds.origin.x;
+ paddingy = tmpRect.origin.y - contBounds.origin.y;
+ if (paddingx > 0) {
+ width += paddingx;
+ }
+ if (paddingy > 0) {
+ height += paddingy;
+ }
+
+ if (height < paddingx - 4) {
+ /* can't have buttons much shorter than button side diameter. */
+ height = paddingx - 4;
}
- ComputeNativeButtonGeometry(butPtr);
- break;
+
+ } else {
+ height += butPtr->borderWidth*2;
+ width += butPtr->borderWidth*2;
}
+
+ width += butPtr->inset*2;
+ height += butPtr->inset*2;
+
+ Tk_GeometryRequest(butPtr->tkwin, width, height);
+ Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
+
}
-
+
+/*
/*
*----------------------------------------------------------------------
*
- * TkpButtonSetDefaults --
+ * DrawButtonImageAndText --
*
- * This procedure is invoked before option tables are created for
- * buttons. It modifies some of the default values to match the current
- * values defined for this platform.
+ * Draws the image and text associated with a button or label.
*
* Results:
- * Some of the default values in *specPtr are modified.
+ * None.
*
* Side effects:
- * Updates some of.
+ * The image and text are drawn.
*
*----------------------------------------------------------------------
*/
-
-void
-TkpButtonSetDefaults()
+static void
+DrawButtonImageAndText(
+ TkButton* butPtr)
{
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (!tkMacOSXUseCompatibilityMetrics) {
- strcpy(tkDefButtonHighlightWidth, DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM);
- strcpy(tkDefLabelHighlightWidth, DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM);
- strcpy(tkDefButtonPadx, DEF_BUTTON_PADX_NOCM);
- strcpy(tkDefLabelPadx, DEF_BUTTON_PADX_NOCM);
- strcpy(tkDefButtonPady, DEF_BUTTON_PADY_NOCM);
- strcpy(tkDefLabelPady, DEF_BUTTON_PADY_NOCM);
+
+ MacButton *mbPtr = (MacButton*)butPtr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ int haveImage = 0;
+ int haveText = 0;
+ int imageWidth = 0;
+ int imageHeight = 0;
+ int imageXOffset = 0;
+ int imageYOffset = 0;
+ int textXOffset = 0;
+ int textYOffset = 0;
+ int width = 0;
+ int height = 0;
+ int fullWidth = 0;
+ int fullHeight = 0;
+ int pressed = 0;
+
+
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
-#endif
-}
-#pragma mark -
-#pragma mark Native Buttons:
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+ if (butPtr->image != None) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
+ }
+
+ imageWidth = width;
+ imageHeight = height;
+
+ if (mbPtr->drawinfo.state == kThemeStatePressed) {
+ /* Offset bitmaps by a bit when the button is pressed. */
+ pressed = 1;
+ }
+
+ haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
+ if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
+ int x;
+ int y;
+ textXOffset = 0;
+ textYOffset = 0;
+ fullWidth = 0;
+ fullHeight = 0;
+
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM: {
+ /* Image is above or below text */
+ if (butPtr->compound == COMPOUND_TOP) {
+ textYOffset = height + butPtr->padY;
+ } else {
+ imageYOffset = butPtr->textHeight + butPtr->padY;
+ }
+ fullHeight = height + butPtr->textHeight + butPtr->padY;
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ break;
+ }
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT: {
+ /*
+ * Image is left or right of text
+ */
+
+ if (butPtr->compound == COMPOUND_LEFT) {
+ textXOffset = width + butPtr->padX;
+ } else {
+ imageXOffset = butPtr->textWidth + butPtr->padX;
+ }
+ fullWidth = butPtr->textWidth + butPtr->padX + width;
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
+ }
+ case COMPOUND_CENTER: {
+ /*
+ * Image and text are superimposed
+ */
+
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
+ }
+ case COMPOUND_NONE: {break;}
+ }
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ fullWidth, fullHeight, &x, &y);
+ if (dpPtr->relief == TK_RELIEF_SUNKEN) {
+ x += dpPtr->offset;
+ y += dpPtr->offset;
+ } else if (dpPtr->relief == TK_RELIEF_RAISED) {
+ x -= dpPtr->offset;
+ y -= dpPtr->offset;
+ }
+ if (pressed) {
+ x += dpPtr->offset;
+ y += dpPtr->offset;
+ }
+ imageXOffset += x;
+ imageYOffset += y;
+ textYOffset -= 1;
+
+ if (butPtr->image != NULL) {
+ if ((butPtr->selectImage != NULL) &&
+ (butPtr->flags & SELECTED)) {
+ Tk_RedrawImage(butPtr->selectImage, 0, 0,
+ width, height, pixmap, imageXOffset, imageYOffset);
+ } else if ((butPtr->tristateImage != NULL) &&
+ (butPtr->flags & TRISTATED)) {
+ Tk_RedrawImage(butPtr->tristateImage, 0, 0,
+ width, height, pixmap, imageXOffset, imageYOffset);
+ } else {
+ Tk_RedrawImage(butPtr->image, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ }
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc,
+ imageXOffset, imageYOffset);
+ XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width, (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+
+ Tk_DrawTextLayout(butPtr->display, pixmap,
+ dpPtr->gc, butPtr->textLayout,
+ x + textXOffset, y + textYOffset, 0, -1);
+ Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout,
+ x + textXOffset, y + textYOffset,
+ butPtr->underline);
+ } else {
+ if (haveImage) {
+ int x = 0;
+ int y;
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ width, height, &x, &y);
+ if (dpPtr->relief == TK_RELIEF_SUNKEN) {
+ x += dpPtr->offset;
+ y += dpPtr->offset;
+ } else if (dpPtr->relief == TK_RELIEF_RAISED) {
+ x -= dpPtr->offset;
+ y -= dpPtr->offset;
+ }
+ if (pressed) {
+ x += dpPtr->offset;
+ y += dpPtr->offset;
+ }
+ imageXOffset += x;
+ imageYOffset += y;
+
+ if (butPtr->image != NULL) {
+
+ if ((butPtr->selectImage != NULL) &&
+ (butPtr->flags & SELECTED)) {
+ Tk_RedrawImage(butPtr->selectImage, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ } else if ((butPtr->tristateImage != NULL) &&
+ (butPtr->flags & TRISTATED)) {
+ Tk_RedrawImage(butPtr->tristateImage, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ } else {
+ Tk_RedrawImage(butPtr->image, 0, 0, width, height,
+ pixmap, imageXOffset, imageYOffset);
+ }
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc, x, y);
+ XCopyPlane(butPtr->display, butPtr->bitmap,
+ pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width,
+ (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+ } else {
+ /*Adequate padding / offset for text in various buttons.*/
+ int x = 0;
+ int y;
+ switch (butPtr->type) {
+ case TYPE_RADIO_BUTTON:
+ case TYPE_CHECK_BUTTON:
+ if (butPtr->indicatorOn) {
+ TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
+ butPtr->textWidth, butPtr->textHeight, &x, &y);
+ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout, x + 20, y, 0, -1);
+ } else {
+ TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
+ butPtr->textWidth, butPtr->textHeight, &x, &y);
+ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout, x, y, 0, -1);
+ }
+ break;
+ case TYPE_BUTTON:
+ case TYPE_LABEL:
+ TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
+ butPtr->textWidth, butPtr->textHeight, &x, &y);
+ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout, x, y, 0, -1);
+ y += butPtr->textHeight/2;
+ break;
+ }
+ }
+ }
+
+
+ /*
+ * If the button is disabled with a stipple rather than a special
+ * foreground color, generate the stippled effect. If the widget
+ * is selected and we use a different background color when selected,
+ * must temporarily modify the GC so the stippling is the right color.
+ */
+
+ if (mbPtr->useTkText) {
+ if ((butPtr->state == STATE_DISABLED)
+ && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) {
+ if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
+ && (butPtr->selectBorder != NULL)) {
+ XSetForeground(butPtr->display, butPtr->stippleGC,
+ Tk_3DBorderColor(butPtr->selectBorder)->pixel);
+ }
+ /*
+ * Stipple the whole button if no disabledFg was specified,
+ * otherwise restrict stippling only to displayed image
+ */
+ if (butPtr->disabledFg == NULL) {
+ XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
+ 0, 0, (unsigned) Tk_Width(tkwin),
+ (unsigned) Tk_Height(tkwin));
+ } else {
+ XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
+ imageXOffset, imageYOffset,
+ (unsigned) imageWidth, (unsigned) imageHeight);
+ }
+ if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
+ && (butPtr->selectBorder != NULL)
+ ) {
+ XSetForeground(butPtr->display, butPtr->stippleGC,
+ Tk_3DBorderColor(butPtr->normalBorder)->pixel);
+ }
+ }
+
+ /*
+ * Draw the border and traversal highlight last. This way, if the
+ * button's contents overflow they'll be covered up by the border.
+ */
+
+ if (dpPtr->relief != TK_RELIEF_FLAT) {
+ int inset = butPtr->highlightWidth;
+ Tk_Draw3DRectangle(tkwin, pixmap, dpPtr->border, inset, inset,
+ Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset,
+ butPtr->borderWidth, dpPtr->relief);
+ }
+ }
+
+ }
+
+
+
-
/*
*----------------------------------------------------------------------
*
- * TkMacOSXGetButtonFrame --
+ * TkpDestroyButton --
*
- * Computes a frame for an NSButton that will correspond to where
- * Tk thinks the button is located.
+ * Free data structures associated with the button control.
*
* Results:
- * Returns an NSRect describing a frame for an NSButton.
+ * None.
*
* Side effects:
- * None
+ * Restores the default control state.
*
*----------------------------------------------------------------------
*/
-NSRect TkMacOSXGetButtonFrame(
- TkButton *butPtr)
-{
- MacButton *macButtonPtr = (MacButton *) butPtr;
- Tk_Window tkwin = butPtr->tkwin;
- TkWindow *winPtr = (TkWindow *) tkwin;
- if (tkwin) {
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
- NSView *view = TkMacOSXDrawableView(macWin);
- CGFloat viewHeight = [view bounds].size.height;
- NSRect frame = NSMakeRect(macWin->xOff, macWin->yOff,
- Tk_Width(tkwin), Tk_Height(tkwin));
-
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- BoundsFix boundsFix = boundsFixes[macButtonPtr->fix];
- frame = NSOffsetRect(frame, boundsFix.offsetX, boundsFix.offsetY);
- frame.size.height -= boundsFix.shrinkH + NATIVE_BUTTON_EXTRA_H;
- frame = NSInsetRect(frame, boundsFix.inset + NATIVE_BUTTON_INSET,
- boundsFix.inset + NATIVE_BUTTON_INSET);
- }
-#endif
- frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
- return frame;
- } else {
- return NSZeroRect;
+void
+TkpDestroyButton(
+ TkButton *butPtr)
+{
+ MacButton *mbPtr = (MacButton *) butPtr; /* Mac button. */
+ if (mbPtr->defaultPulseHandler) {
+ Tcl_DeleteTimerHandler(mbPtr->defaultPulseHandler);
}
}
/*
- *----------------------------------------------------------------------
+ *--------------------------------------------------------------
*
- * DisplayNativeButton --
+ * TkMacOSXDrawButton --
*
- * This procedure is invoked to display a button widget. It is
- * normally invoked as an idle handler.
+ * This function draws the tk button using Mac controls
+ * In addition, this code may apply custom colors passed
+ * in the TkButton.
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * Commands are output to X to display the button in its
- * current mode. The REDRAW_PENDING flag is cleared.
+ * The control is created, or reinitialised as needed
*
- *----------------------------------------------------------------------
+ *--------------------------------------------------------------
*/
static void
-DisplayNativeButton(
- TkButton *butPtr)
+TkMacOSXDrawButton(
+ MacButton *mbPtr, /* Mac button. */
+ GC gc, /* The GC we are drawing into - needed for
+ * the bevel button */
+ Pixmap pixmap) /* The pixmap we are drawing into - needed
+ * for the bevel button */
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
- TkNSButton *button = macButtonPtr->button;
- Tk_Window tkwin = butPtr->tkwin;
- TkWindow *winPtr = (TkWindow *) tkwin;
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
+ TkButton * butPtr = ( TkButton *)mbPtr;
+ TkWindow * winPtr;
+ HIRect cntrRect;
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;
- int enabled;
- NSCellStateValue state;
-
- if (!view ||
- !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
- return;
- }
- CGContextConcatCTM(dc.context, t);
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ int useNewerHITools = 1;
+
+ winPtr = (TkWindow *)butPtr->tkwin;
- /*
- * We cannot change the background color of the button itself, only the
- * color of the background of its container.
- * This will be the color that peeks around the rounded corners of the
- * button. We make this the highlightbackground rather than the background,
- * because if you color the background of a frame containing a
- * button, you usually also color the highlightbackground as well,
- * or you will get a thin grey ring around the button.
- */
+ TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
+
+ cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin),Tk_Height(butPtr->tkwin));
+
+ cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset);
+
+ if (useNewerHITools == 1) {
+ HIRect contHIRec;
+ static HIThemeButtonDrawInfo hiinfo;
+
+ ButtonBackgroundDrawCB(&cntrRect, mbPtr, 32, true);
+
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
+ }
+
+
+ if (mbPtr->btnkind == kThemePushButton) {
+ /*
+ * For some reason, pushbuttons get drawn a bit
+ * too low, normally. Correct for this.
+ */
+ if (cntrRect.size.height < 22) {
+ cntrRect.origin.y -= 1;
+ } else if (cntrRect.size.height < 23) {
+ cntrRect.origin.y -= 2;
+ }
+ }
+
+ hiinfo.version = 0;
+ hiinfo.state = mbPtr->drawinfo.state;
+ hiinfo.kind = mbPtr->btnkind;
+ hiinfo.value = mbPtr->drawinfo.value;
+ hiinfo.adornment = mbPtr->drawinfo.adornment;
+ hiinfo.animation.time.current = CFAbsoluteTimeGetCurrent();
+ if (hiinfo.animation.time.start == 0) {
+ hiinfo.animation.time.start = hiinfo.animation.time.current;
+ }
+
+ HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec);
+
+ TkMacOSXRestoreDrawingContext(&dc);
+
+ ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, (MacButton *)mbPtr, 32, true);
- Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, butPtr->type == TYPE_BUTTON ?
- butPtr->highlightBorder : butPtr->normalBorder, 0, 0,
- Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
- if ([button superview] != view) {
- [view addSubview:button];
- }
- if (macButtonPtr->tristateImage) {
- NSImage *selectImage = macButtonPtr->selectImage ?
- macButtonPtr->selectImage : macButtonPtr->image;
- [button setImage:(butPtr->flags & TRISTATED ?
- selectImage : macButtonPtr->image)];
- [button setAlternateImage:(butPtr->flags & TRISTATED ?
- macButtonPtr->tristateImage : selectImage)];
- }
- if (butPtr->flags & SELECTED) {
- state = NSOnState;
- } else if (butPtr->flags & TRISTATED) {
- state = NSMixedState;
- } else {
- state = NSOffState;
- }
- [button setState:state];
- enabled = !(butPtr->state == STATE_DISABLED);
- [button setEnabled:enabled];
- if (enabled) {
- //[button highlight:(butPtr->state == STATE_ACTIVE)];
- //[cell setHighlighted:(butPtr->state == STATE_ACTIVE)];
- }
- if (butPtr->type == TYPE_BUTTON && butPtr->defaultState == STATE_ACTIVE) {
- //[[view window] setDefaultButtonCell:cell];
- [button setKeyEquivalent:@"\r"];
} else {
- [button setKeyEquivalent:@""];
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
+ }
+
+ TkMacOSXRestoreDrawingContext(&dc);
}
- frame = TkMacOSXGetButtonFrame(butPtr);
- [button setFrame:frame];
- [button displayRectIgnoringOpacity:[button bounds]];
- TkMacOSXRestoreDrawingContext(&dc);
-#ifdef TK_MAC_DEBUG_BUTTON
- TKLog(@"button %s frame %@ width %d height %d",
- ((TkWindow *)butPtr->tkwin)->pathName, NSStringFromRect(frame),
- Tk_Width(tkwin), Tk_Height(tkwin));
-#endif
+ mbPtr->lastdrawinfo = mbPtr->drawinfo;
}
/*
- *----------------------------------------------------------------------
+ *--------------------------------------------------------------
*
- * ComputeNativeButtonGeometry --
+ * ButtonBackgroundDrawCB --
*
- * After changes in a button's text or bitmap, this procedure
- * recomputes the button's geometry and passes this information
- * along to the geometry manager for the window.
+ * This function draws the background that
+ * lies under checkboxes and radiobuttons.
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * The button's window may change size.
+ * The background gets updated to the current color.
*
- *----------------------------------------------------------------------
+ *--------------------------------------------------------------
*/
-
static void
-ComputeNativeButtonGeometry(
- TkButton *butPtr) /* Button whose geometry may have changed. */
+ButtonBackgroundDrawCB (
+ const HIRect * btnbounds,
+ MacButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
- TkNSButton *button = macButtonPtr->button;
- NSButtonCell *cell = [button cell];
- NSButtonType type = -1;
- NSBezelStyle style = 0;
- NSInteger highlightsBy = 0, showsStateBy = 0;
- NSFont *font;
- NSRect bounds = NSZeroRect, titleRect = NSZeroRect;
- int haveImage = (butPtr->image || butPtr->bitmap != None), haveText = 0;
- int haveCompound = (butPtr->compound != COMPOUND_NONE);
- int width, height, border = 0;
+ MacButton* mbPtr = (MacButton*)ptr;
+ TkButton* butPtr = (TkButton*)mbPtr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ int usehlborder = 0;
- butPtr->indicatorSpace = 0;
- butPtr->inset = 0;
- if (butPtr->highlightWidth < 0) {
- butPtr->highlightWidth = 0;
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- switch (butPtr->type) {
- case TYPE_BUTTON:
- type = NSMomentaryPushInButton;
- if (!haveImage) {
- style = NSRoundedBezelStyle;
- butPtr->inset = butPtr->defaultState != STATE_DISABLED ?
- butPtr->highlightWidth : 0;
- [button setImage:nil];
- [button setImagePosition:NSNoImage];
- } else {
- style = NSShadowlessSquareBezelStyle;
- highlightsBy = butPtr->selectImage || butPtr->bitmap ?
- NSContentsCellMask : 0;
- border = butPtr->borderWidth;
- }
- break;
- case TYPE_RADIO_BUTTON:
- case TYPE_CHECK_BUTTON:
- if (!haveImage /*|| butPtr->indicatorOn*/) { // TODO: indicatorOn
- type = butPtr->type == TYPE_RADIO_BUTTON ?
- NSRadioButton : NSSwitchButton;
- butPtr->inset = /*butPtr->indicatorOn ? 0 :*/ butPtr->borderWidth;
- } else {
- type = NSPushOnPushOffButton;
- style = NSShadowlessSquareBezelStyle;
- highlightsBy = butPtr->selectImage || butPtr->bitmap ?
- NSContentsCellMask : 0;
- showsStateBy = butPtr->selectImage || butPtr->tristateImage ?
- NSContentsCellMask : 0;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- border = butPtr->borderWidth > 1 ? butPtr->borderWidth - 1 : 1;
- } else
-#endif
- {
- border = butPtr->borderWidth;
- }
- }
- break;
- }
- [button setButtonType:type];
- if (style) {
- [button setBezelStyle:style];
- }
- if (highlightsBy) {
- [cell setHighlightsBy:highlightsBy|[cell highlightsBy]];
- }
- if (showsStateBy) {
- [cell setShowsStateBy:showsStateBy|[cell showsStateBy]];
- }
-#if 0
- if (style == NSShadowlessSquareBezelStyle) {
- NSControlSize controlSize = NSRegularControlSize;
-
- if (butPtr->borderWidth <= 2) {
- controlSize = NSMiniControlSize;
- } else if (butPtr->borderWidth == 3) {
- controlSize = NSSmallControlSize;
- }
- [cell setControlSize:controlSize];
- }
-#endif
- [button setAllowsMixedState:YES];
-
- if (!haveImage || haveCompound) {
- int len;
- char *text = Tcl_GetStringFromObj(butPtr->textPtr, &len);
-
- if (len) {
- NSString *title = [[NSString alloc] initWithBytes:text length:len
- encoding:NSUTF8StringEncoding];
- [button setTitle:title];
- [title release];
- haveText = 1;
- }
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+ if (butPtr->type != TYPE_LABEL) {
+ switch (mbPtr->btnkind) {
+ case kThemeSmallBevelButton:
+ case kThemeBevelButton:
+ case kThemeRoundedBevelButton:
+ case kThemePushButton:
+ usehlborder = 1;
+ break;
+ }
}
- haveCompound = (haveCompound && haveImage && haveText);
- if (haveText) {
- NSTextAlignment alignment = NSNaturalTextAlignment;
-
- switch (butPtr->justify) {
- case TK_JUSTIFY_LEFT:
- alignment = NSLeftTextAlignment;
- break;
- case TK_JUSTIFY_RIGHT:
- alignment = NSRightTextAlignment;
- break;
- case TK_JUSTIFY_CENTER:
- alignment = NSCenterTextAlignment;
- break;
- }
- [button setAlignment:alignment];
+ if (usehlborder) {
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
} else {
- [button setTitle:@""];
- }
- font = TkMacOSXNSFontForFont(butPtr->tkfont);
- if (font) {
- [button setFont:font];
- }
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->image);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->selectImage);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->tristateImage);
- if (haveImage) {
- int width, height;
- NSImage *image, *selectImage = nil, *tristateImage = nil;
- NSCellImagePosition pos = NSImageOnly;
-
- if (butPtr->image) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- image = TkMacOSXGetNSImageWithTkImage(butPtr->display,
- butPtr->image, width, height);
- if (butPtr->selectImage) {
- selectImage = TkMacOSXGetNSImageWithTkImage(butPtr->display,
- butPtr->selectImage, width, height);
- }
- if (butPtr->tristateImage) {
- tristateImage = TkMacOSXGetNSImageWithTkImage(butPtr->display,
- butPtr->tristateImage, width, height);
- }
- } else {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- image = TkMacOSXGetNSImageWithBitmap(butPtr->display,
- butPtr->bitmap, butPtr->normalTextGC, width, height);
- selectImage = TkMacOSXGetNSImageWithBitmap(butPtr->display,
- butPtr->bitmap, butPtr->activeTextGC, width, height);
- }
- [button setImage:image];
- if (selectImage) {
- [button setAlternateImage:selectImage];
- }
- if (tristateImage) {
- macButtonPtr->image = TkMacOSXMakeUncollectableAndRetain(image);
- if (selectImage) {
- macButtonPtr->selectImage =
- TkMacOSXMakeUncollectableAndRetain(selectImage);
- }
- macButtonPtr->tristateImage =
- TkMacOSXMakeUncollectableAndRetain(tristateImage);
- }
- if (haveCompound) {
- switch ((enum compound) butPtr->compound) {
- case COMPOUND_TOP:
- pos = NSImageAbove;
- break;
- case COMPOUND_BOTTOM:
- pos = NSImageBelow;
- break;
- case COMPOUND_LEFT:
- pos = NSImageLeft;
- break;
- case COMPOUND_RIGHT:
- pos = NSImageRight;
- break;
- case COMPOUND_CENTER:
- pos = NSImageOverlaps;
- break;
- case COMPOUND_NONE:
- pos = NSImageOnly;
- break;
- }
- }
- [button setImagePosition:pos];
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
}
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ButtonContentDrawCB --
+ *
+ * This function draws the label and image for the button.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The content of the button gets updated.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+ButtonContentDrawCB (
+ const HIRect * btnbounds,
+ ThemeButtonKind kind,
+ const HIThemeButtonDrawInfo *drawinfo,
+ MacButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
+{
+ TkButton *butPtr = (TkButton *)ptr;
+ Tk_Window tkwin = butPtr->tkwin;
+ HIRect * bounds;
- // if font is too tall, we can't use the fixed-height rounded bezel
- if (!haveImage && haveText && style == NSRoundedBezelStyle) {
- Tk_FontMetrics fm;
- Tk_GetFontMetrics(butPtr->tkfont, &fm);
- if (fm.linespace > 18) {
- [button setBezelStyle:(style = NSRegularSquareBezelStyle)];
- }
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
+ MacDrawable *macWin = (MacDrawable *) Tk_WindowId(tkwin);
- bounds.size = [cell cellSize];
- if (haveText) {
- titleRect = [cell titleRectForBounds:bounds];
- if (butPtr->wrapLength > 0 &&
- titleRect.size.width > butPtr->wrapLength) {
- if (style == NSRoundedBezelStyle) {
- [button setBezelStyle:(style = NSRegularSquareBezelStyle)];
- bounds.size = [cell cellSize];
- titleRect = [cell titleRectForBounds:bounds];
- }
- bounds.size.width -= titleRect.size.width - butPtr->wrapLength;
- bounds.size.height = 40000.0;
- [cell setWraps:YES];
- bounds.size = [cell cellSizeForBounds:bounds];
-#ifdef TK_MAC_DEBUG_BUTTON
- titleRect = [cell titleRectForBounds:bounds];
-#endif
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- bounds.size.height += 3;
- }
-#endif
- }
- }
- width = lround(bounds.size.width);
- height = lround(bounds.size.height);
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- macButtonPtr->fix = fixForTypeStyle(type, style);
- width -= boundsFixes[macButtonPtr->fix].trimW;
- height -= boundsFixes[macButtonPtr->fix].trimH;
- }
-#endif
+ /*Overlay Tk elements over button native region: drawing elements within button boundaries/native region causes unpredictable metrics.*/
+ DrawButtonImageAndText( butPtr);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ButtonEventProc --
+ *
+ * This procedure is invoked by the Tk dispatcher for various
+ * events on buttons.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * When it gets exposed, it is redisplayed.
+ *
+ *--------------------------------------------------------------
+ */
- if (haveImage || haveCompound) {
- if (butPtr->width > 0) {
- width = butPtr->width;
- }
- if (butPtr->height > 0) {
- height = butPtr->height;
+static void
+ButtonEventProc(
+ ClientData clientData, /* Information about window. */
+ XEvent *eventPtr) /* Information about event. */
+{
+ TkButton *buttonPtr = (TkButton *) clientData;
+ MacButton *mbPtr = (MacButton *) clientData;
+
+ if (eventPtr->type == ActivateNotify
+ || eventPtr->type == DeactivateNotify) {
+ if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) {
+ return;
}
- } else {
- if (butPtr->width > 0) {
- int avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
- width = butPtr->width * avgWidth;
+ if (eventPtr->type == ActivateNotify) {
+ mbPtr->flags |= ACTIVE;
+ } else {
+ mbPtr->flags &= ~ACTIVE;
}
- if (butPtr->height > 0) {
- Tk_FontMetrics fm;
-
- Tk_GetFontMetrics(butPtr->tkfont, &fm);
- height = butPtr->height * fm.linespace;
+ if ((buttonPtr->flags & REDRAW_PENDING) == 0) {
+ Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) buttonPtr);
+ buttonPtr->flags |= REDRAW_PENDING;
}
}
- if (!haveImage || haveCompound) {
- width += 2*butPtr->padX;
- height += 2*butPtr->padY;
- }
- if (haveImage) {
- width += 2*border;
- height += 2*border;
- }
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- width += 2*NATIVE_BUTTON_INSET;
- height += 2*NATIVE_BUTTON_INSET + NATIVE_BUTTON_EXTRA_H;
- }
-#endif
- Tk_GeometryRequest(butPtr->tkwin, width, height);
- Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
-#ifdef TK_MAC_DEBUG_BUTTON
- TKLog(@"button %s bounds %@ titleRect %@ width %d height %d inset %d borderWidth %d",
- ((TkWindow *)butPtr->tkwin)->pathName, NSStringFromRect(bounds),
- NSStringFromRect(titleRect), width, height, butPtr->inset,
- butPtr->borderWidth);
-#endif
}
-
-#pragma mark -
-#pragma mark Unix Buttons:
-
/*
*----------------------------------------------------------------------
*
- * DisplayUnixButton --
+ * TkMacOSXComputeButtonParams --
*
- * This procedure is invoked to display a button widget. It is
- * normally invoked as an idle handler.
+ * This procedure computes the various parameters used
+ * when creating a Carbon Appearance control.
+ * These are determined by the various tk button parameters
*
* Results:
* None.
*
* Side effects:
- * Commands are output to X to display the button in its
- * current mode. The REDRAW_PENDING flag is cleared.
+ * Sets the btnkind and drawinfo parameters
*
*----------------------------------------------------------------------
*/
-void
-DisplayUnixButton(
- TkButton *butPtr)
+static void
+TkMacOSXComputeButtonParams(
+ TkButton * butPtr,
+ ThemeButtonKind* btnkind,
+ HIThemeButtonDrawInfo *drawinfo)
{
- GC gc;
- Tk_3DBorder border;
- Pixmap pixmap;
- int x = 0; /* Initialization only needed to stop compiler
- * warning. */
- int y, relief;
- Tk_Window tkwin = butPtr->tkwin;
- int width = 0, height = 0, fullWidth, fullHeight;
- int textXOffset, textYOffset;
- int haveImage = 0, haveText = 0;
- int imageWidth, imageHeight;
- int imageXOffset = 0, imageYOffset = 0;
- /* image information that will be used to
- * restrict disabled pixmap as well */
-
- border = butPtr->normalBorder;
- if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
- gc = butPtr->disabledGC;
- } else if ((butPtr->state == STATE_ACTIVE)
- && !Tk_StrictMotif(butPtr->tkwin)) {
- gc = butPtr->activeTextGC;
- border = butPtr->activeBorder;
+ MacButton *mbPtr = (MacButton *)butPtr;
+
+ if (butPtr->borderWidth <= 2) {
+ *btnkind = kThemeSmallBevelButton;
+ } else if (butPtr->borderWidth == 3) {
+ *btnkind = kThemeBevelButton;
+ } else if (butPtr->borderWidth == 4) {
+ *btnkind = kThemeRoundedBevelButton;
} else {
- gc = butPtr->normalTextGC;
+ *btnkind = kThemePushButton;
}
- if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE)
- && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) {
- border = butPtr->selectBorder;
- }
-
- relief = butPtr->relief;
-
- pixmap = (Pixmap) Tk_WindowId(tkwin);
- Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
- Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
-
- /*
- * Display image or bitmap or text for button.
- */
-
- if (butPtr->image != NULL) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- haveImage = 1;
- } else if (butPtr->bitmap != None) {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- haveImage = 1;
- }
- imageWidth = width;
- imageHeight = height;
-
- haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
-
- if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
- textXOffset = 0;
- textYOffset = 0;
- fullWidth = 0;
- fullHeight = 0;
-
- switch ((enum compound) butPtr->compound) {
- case COMPOUND_TOP:
- case COMPOUND_BOTTOM:
- /*
- * Image is above or below text.
- */
-
- if (butPtr->compound == COMPOUND_TOP) {
- textYOffset = height + butPtr->padY;
- } else {
- imageYOffset = butPtr->textHeight + butPtr->padY;
- }
- fullHeight = height + butPtr->textHeight + butPtr->padY;
- fullWidth = (width > butPtr->textWidth ? width :
- butPtr->textWidth);
- textXOffset = (fullWidth - butPtr->textWidth)/2;
- imageXOffset = (fullWidth - width)/2;
- break;
- case COMPOUND_LEFT:
- case COMPOUND_RIGHT:
- /*
- * Image is left or right of text.
- */
-
- if (butPtr->compound == COMPOUND_LEFT) {
- textXOffset = width + butPtr->padX;
- } else {
- imageXOffset = butPtr->textWidth + butPtr->padX;
- }
- fullWidth = butPtr->textWidth + butPtr->padX + width;
- fullHeight = (height > butPtr->textHeight ? height :
- butPtr->textHeight);
- textYOffset = (fullHeight - butPtr->textHeight)/2;
- imageYOffset = (fullHeight - height)/2;
- break;
- case COMPOUND_CENTER:
- /*
- * Image and text are superimposed.
- */
-
- fullWidth = (width > butPtr->textWidth ? width :
- butPtr->textWidth);
- fullHeight = (height > butPtr->textHeight ? height :
- butPtr->textHeight);
- textXOffset = (fullWidth - butPtr->textWidth)/2;
- imageXOffset = (fullWidth - width)/2;
- textYOffset = (fullHeight - butPtr->textHeight)/2;
- imageYOffset = (fullHeight - height)/2;
- break;
- case COMPOUND_NONE:
- break;
- }
-
- TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
- fullWidth, fullHeight, &x, &y);
-
- imageXOffset += x;
- imageYOffset += y;
-
- if (butPtr->image != NULL) {
- /*
- * Do boundary clipping, so that Tk_RedrawImage is passed valid
- * coordinates. [Bug 979239]
- */
-
- if (imageXOffset < 0) {
- imageXOffset = 0;
- }
- if (imageYOffset < 0) {
- imageYOffset = 0;
- }
- if (width > Tk_Width(tkwin)) {
- width = Tk_Width(tkwin);
- }
- if (height > Tk_Height(tkwin)) {
- height = Tk_Height(tkwin);
- }
- if ((width + imageXOffset) > Tk_Width(tkwin)) {
- imageXOffset = Tk_Width(tkwin) - width;
- }
- if ((height + imageYOffset) > Tk_Height(tkwin)) {
- imageYOffset = Tk_Height(tkwin) - height;
- }
-
- if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) {
- Tk_RedrawImage(butPtr->selectImage, 0, 0,
- width, height, pixmap, imageXOffset, imageYOffset);
- } else if ((butPtr->tristateImage != NULL) && (butPtr->flags & TRISTATED)) {
- Tk_RedrawImage(butPtr->tristateImage, 0, 0,
- width, height, pixmap, imageXOffset, imageYOffset);
- } else {
- Tk_RedrawImage(butPtr->image, 0, 0, width,
- height, pixmap, imageXOffset, imageYOffset);
- }
- } else {
- XSetClipOrigin(butPtr->display, gc, imageXOffset, imageYOffset);
- XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc,
- 0, 0, (unsigned int) width, (unsigned int) height,
- imageXOffset, imageYOffset, 1);
- XSetClipOrigin(butPtr->display, gc, 0, 0);
- }
- Tk_DrawTextLayout(butPtr->display, pixmap, gc,
- butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1);
- Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
- butPtr->textLayout, x + textXOffset, y + textYOffset,
- butPtr->underline);
- y += fullHeight/2;
- } else {
- if (haveImage) {
- TkComputeAnchor(butPtr->anchor, tkwin, 0, 0,
- width, height, &x, &y);
- imageXOffset += x;
- imageYOffset += y;
- if (butPtr->image != NULL) {
- /*
- * Do boundary clipping, so that Tk_RedrawImage is passed
- * valid coordinates. [Bug 979239]
- */
-
- if (imageXOffset < 0) {
- imageXOffset = 0;
- }
- if (imageYOffset < 0) {
- imageYOffset = 0;
- }
- if (width > Tk_Width(tkwin)) {
- width = Tk_Width(tkwin);
- }
- if (height > Tk_Height(tkwin)) {
- height = Tk_Height(tkwin);
- }
- if ((width + imageXOffset) > Tk_Width(tkwin)) {
- imageXOffset = Tk_Width(tkwin) - width;
- }
- if ((height + imageYOffset) > Tk_Height(tkwin)) {
- imageYOffset = Tk_Height(tkwin) - height;
- }
-
- if ((butPtr->selectImage != NULL) &&
- (butPtr->flags & SELECTED)) {
- Tk_RedrawImage(butPtr->selectImage, 0, 0, width,
- height, pixmap, imageXOffset, imageYOffset);
- } else if ((butPtr->tristateImage != NULL) &&
- (butPtr->flags & TRISTATED)) {
- Tk_RedrawImage(butPtr->tristateImage, 0, 0, width,
- height, pixmap, imageXOffset, imageYOffset);
+ if ((butPtr->image == None) && (butPtr->bitmap == None)) {
+ switch (butPtr->type) {
+ case TYPE_BUTTON:
+ *btnkind = kThemePushButton;
+ break;
+ case TYPE_RADIO_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallRadioButton;
} else {
- Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap,
- imageXOffset, imageYOffset);
+ *btnkind = kThemeRadioButton;
}
- } else {
- XSetClipOrigin(butPtr->display, gc, x, y);
- XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0,
- (unsigned int) width, (unsigned int) height, x, y, 1);
- XSetClipOrigin(butPtr->display, gc, 0, 0);
- }
- y += height/2;
- } else {
- TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
- butPtr->textWidth, butPtr->textHeight, &x, &y);
-
- Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout,
- x, y, 0, -1);
- Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
- butPtr->textLayout, x, y, butPtr->underline);
- y += butPtr->textHeight/2;
+ break;
+ case TYPE_CHECK_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallCheckBox;
+ } else {
+ *btnkind = kThemeCheckBox;
+ }
+ break;
}
}
- /*
- * If the button is disabled with a stipple rather than a special
- * foreground color, generate the stippled effect. If the widget is
- * selected and we use a different background color when selected, must
- * temporarily modify the GC so the stippling is the right color.
- */
-
- if ((butPtr->state == STATE_DISABLED)
- && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) {
- if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
- && (butPtr->selectBorder != NULL)) {
- XSetForeground(butPtr->display, butPtr->stippleGC,
- Tk_3DBorderColor(butPtr->selectBorder)->pixel);
- }
-
- /*
- * Stipple the whole button if no disabledFg was specified, otherwise
- * restrict stippling only to displayed image
- */
-
- if (butPtr->disabledFg == NULL) {
- XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC, 0, 0,
- (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin));
- } else {
- XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
- imageXOffset, imageYOffset,
- (unsigned) imageWidth, (unsigned) imageHeight);
- }
- if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
- && (butPtr->selectBorder != NULL)) {
- XSetForeground(butPtr->display, butPtr->stippleGC,
- Tk_3DBorderColor(butPtr->normalBorder)->pixel);
- }
+ if (butPtr->indicatorOn) {
+ switch (butPtr->type) {
+ case TYPE_RADIO_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallRadioButton;
+ } else {
+ *btnkind = kThemeRadioButton;
+ }
+ break;
+ case TYPE_CHECK_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallCheckBox;
+ } else {
+ *btnkind = kThemeCheckBox;
+ }
+ break;
+ }
+ } else {
+ if (butPtr->type == TYPE_RADIO_BUTTON ||
+ butPtr->type == TYPE_CHECK_BUTTON
+ ) {
+ if (*btnkind == kThemePushButton) {
+ *btnkind = kThemeBevelButton;
+ }
+ }
}
- /*
- * Draw the border and traversal highlight last. This way, if the button's
- * contents overflow they'll be covered up by the border. This code is
- * complicated by the possible combinations of focus highlight and default
- * rings. We draw the focus and highlight rings using the highlight border
- * and highlight foreground color.
- */
-
- if (relief != TK_RELIEF_FLAT) {
- int inset = butPtr->highlightWidth;
-
- if (butPtr->defaultState == DEFAULT_ACTIVE) {
- /*
- * Draw the default ring with 2 pixels of space between the
- * default ring and the button and the default ring and the focus
- * ring. Note that we need to explicitly draw the space in the
- * highlightBorder color to ensure that we overwrite any overflow
- * text and/or a different button background color.
- */
-
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
- inset, Tk_Width(tkwin) - 2*inset,
- Tk_Height(tkwin) - 2*inset, 2, TK_RELIEF_FLAT);
- inset += 2;
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
- inset, Tk_Width(tkwin) - 2*inset,
- Tk_Height(tkwin) - 2*inset, 1, TK_RELIEF_SUNKEN);
- inset++;
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
- inset, Tk_Width(tkwin) - 2*inset,
- Tk_Height(tkwin) - 2*inset, 2, TK_RELIEF_FLAT);
-
- inset += 2;
- } else if (butPtr->defaultState == DEFAULT_NORMAL) {
- /*
- * Leave room for the default ring and write over any text or
- * background color.
- */
-
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0,
- 0, Tk_Width(tkwin), Tk_Height(tkwin), 5, TK_RELIEF_FLAT);
- inset += 5;
- }
-
- /*
- * Draw the button border.
- */
-
- Tk_Draw3DRectangle(tkwin, pixmap, border, inset, inset,
- Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset,
- butPtr->borderWidth, relief);
+ if (butPtr->flags & SELECTED) {
+ drawinfo->value = kThemeButtonOn;
+ } else if (butPtr->flags & TRISTATED) {
+ drawinfo->value = kThemeButtonMixed;
+ } else {
+ drawinfo->value = kThemeButtonOff;
}
- if (butPtr->highlightWidth > 0) {
- GC gc;
-
- if (butPtr->flags & GOT_FOCUS) {
- gc = Tk_GCForColor(butPtr->highlightColorPtr, pixmap);
- } else {
- gc = Tk_GCForColor(Tk_3DBorderColor(butPtr->highlightBorder),
- pixmap);
+
+ if ((mbPtr->flags & FIRST_DRAW) != 0) {
+ mbPtr->flags &= ~FIRST_DRAW;
+ if (Tk_MacOSXIsAppInFront()) {
+ mbPtr->flags |= ACTIVE;
}
+ }
- /*
- * Make sure the focus ring shrink-wraps the actual button, not the
- * padding space left for a default ring.
- */
+ drawinfo->state = kThemeStateInactive;
+ if ((mbPtr->flags & ACTIVE) == 0) {
+ if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailableInactive;
+ } else {
+ drawinfo->state = kThemeStateInactive;
+ }
+ } else if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailable;
+ } else if (butPtr->state == STATE_ACTIVE) {
+ drawinfo->state = kThemeStatePressed;
+ } else {
+ drawinfo->state = kThemeStateActive;
+ }
- if (butPtr->defaultState == DEFAULT_NORMAL) {
- TkDrawInsetFocusHighlight(tkwin, gc, butPtr->highlightWidth,
- pixmap, 5);
- } else {
- Tk_DrawFocusHighlight(tkwin, gc, butPtr->highlightWidth, pixmap);
- }
+ drawinfo->adornment = kThemeAdornmentNone;
+ if (butPtr->defaultState == DEFAULT_ACTIVE) {
+ drawinfo->adornment |= kThemeAdornmentDefault;
+ if (!mbPtr->defaultPulseHandler) {
+ mbPtr->defaultPulseHandler = Tcl_CreateTimerHandler(
+ PULSE_TIMER_MSECS, PulseDefaultButtonProc,
+ (ClientData) butPtr);
+ }
+ } else if (mbPtr->defaultPulseHandler) {
+ Tcl_DeleteTimerHandler(mbPtr->defaultPulseHandler);
+ }
+ if (butPtr->highlightWidth >= 3) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ drawinfo->adornment |= kThemeAdornmentFocus;
+ }
}
}
/*
*----------------------------------------------------------------------
*
- * ComputeUnixButtonGeometry --
+ * TkMacOSXComputeButtonDrawParams --
*
- * After changes in a button's text or bitmap, this procedure
- * recomputes the button's geometry and passes this information
- * along to the geometry manager for the window.
+ * This procedure computes the various parameters used
+ * when drawing a button
+ * These are determined by the various tk button parameters
*
* Results:
- * None.
+ * 1 if control will be used, 0 otherwise.
*
* Side effects:
- * The button's window may change size.
+ * Sets the button draw parameters
*
*----------------------------------------------------------------------
*/
-void
-ComputeUnixButtonGeometry(
- register TkButton *butPtr) /* Button whose geometry may have changed. */
+static int
+TkMacOSXComputeButtonDrawParams(
+ TkButton *butPtr,
+ DrawParams *dpPtr)
{
- int width, height, avgWidth, txtWidth, txtHeight;
- int haveImage = 0, haveText = 0;
- Tk_FontMetrics fm;
-
- butPtr->inset = butPtr->highlightWidth + butPtr->borderWidth;
-
- /*
- * Leave room for the default ring if needed.
- */
-
- if (butPtr->defaultState != DEFAULT_DISABLED) {
- butPtr->inset += 5;
+ MacButton *mbPtr = (MacButton *)butPtr;
+
+ dpPtr->hasImageOrBitmap = ((butPtr->image != NULL)
+ || (butPtr->bitmap != None));
+
+ if (butPtr->type != TYPE_LABEL) {
+ dpPtr->offset = 0;
+ if (dpPtr->hasImageOrBitmap) {
+ switch (mbPtr->btnkind) {
+ case kThemeSmallBevelButton:
+ case kThemeBevelButton:
+ case kThemeRoundedBevelButton:
+ case kThemePushButton:
+ dpPtr->offset = 1;
+ break;
+ }
+ }
}
- butPtr->indicatorSpace = 0;
- width = 0;
- height = 0;
- txtWidth = 0;
- txtHeight = 0;
- avgWidth = 0;
- if (butPtr->image != NULL) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- haveImage = 1;
- } else if (butPtr->bitmap != None) {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- haveImage = 1;
+ dpPtr->border = butPtr->normalBorder;
+ if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
+ dpPtr->gc = butPtr->disabledGC;
+ } else if (butPtr->type == TYPE_BUTTON && butPtr->state == STATE_ACTIVE) {
+ dpPtr->gc = butPtr->activeTextGC;
+ dpPtr->border = butPtr->activeBorder;
+ } else {
+ dpPtr->gc = butPtr->normalTextGC;
}
- if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
- Tk_FreeTextLayout(butPtr->textLayout);
-
- butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
- Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength,
- butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
-
- txtWidth = butPtr->textWidth;
- txtHeight = butPtr->textHeight;
- avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
- Tk_GetFontMetrics(butPtr->tkfont, &fm);
- haveText = (txtWidth != 0 && txtHeight != 0);
+ if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE)
+ && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) {
+ dpPtr->border = butPtr->selectBorder;
}
/*
- * If the button is compound (i.e., it shows both an image and text), the
- * new geometry is a combination of the image and text geometry. We only
- * honor the compound bit if the button has both text and an image,
- * because otherwise it is not really a compound button.
+ * Override the relief specified for the button if this is a
+ * checkbutton or radiobutton and there's no indicator.
+ * However, don't do this in the presence of Appearance, since
+ * then the bevel button will take care of the relief.
*/
- if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
- switch ((enum compound) butPtr->compound) {
- case COMPOUND_TOP:
- case COMPOUND_BOTTOM:
- /*
- * Image is above or below text.
- */
+ dpPtr->relief = butPtr->relief;
- height += txtHeight + butPtr->padY;
- width = (width > txtWidth ? width : txtWidth);
- break;
- case COMPOUND_LEFT:
- case COMPOUND_RIGHT:
- /*
- * Image is left or right of text.
- */
-
- width += txtWidth + butPtr->padX;
- height = (height > txtHeight ? height : txtHeight);
- break;
- case COMPOUND_CENTER:
- /*
- * Image and text are superimposed.
- */
-
- width = (width > txtWidth ? width : txtWidth);
- height = (height > txtHeight ? height : txtHeight);
- break;
- case COMPOUND_NONE:
- break;
- }
- if (butPtr->width > 0) {
- width = butPtr->width;
- }
- if (butPtr->height > 0) {
- height = butPtr->height;
+ if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) {
+ if (!dpPtr->hasImageOrBitmap) {
+ dpPtr->relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN
+ : TK_RELIEF_RAISED;
}
+ }
- width += 2*butPtr->padX;
- height += 2*butPtr->padY;
- } else {
- if (haveImage) {
- if (butPtr->width > 0) {
- width = butPtr->width;
- }
- if (butPtr->height > 0) {
- height = butPtr->height;
- }
- } else {
- width = txtWidth;
- height = txtHeight;
+ /*
+ * Determine the draw type
+ */
- if (butPtr->width > 0) {
- width = butPtr->width * avgWidth;
- }
- if (butPtr->height > 0) {
- height = butPtr->height * fm.linespace;
- }
+ if (butPtr->type == TYPE_LABEL) {
+ dpPtr->drawType = DRAW_LABEL;
+ } else if (butPtr->type == TYPE_BUTTON) {
+ if (!dpPtr->hasImageOrBitmap) {
+ dpPtr->drawType = DRAW_CONTROL;
+ } else {
+ dpPtr->drawType = DRAW_BEVEL;
}
+ } else if (butPtr->indicatorOn) {
+ dpPtr->drawType = DRAW_CONTROL;
+ } else if (dpPtr->hasImageOrBitmap) {
+ dpPtr->drawType = DRAW_BEVEL;
+ } else {
+ dpPtr->drawType = DRAW_CUSTOM;
}
- if (!haveImage) {
- width += 2*butPtr->padX;
- height += 2*butPtr->padY;
+ if ((dpPtr->drawType == DRAW_CONTROL) || (dpPtr->drawType == DRAW_BEVEL)) {
+ return 1;
+ } else {
+ return 0;
}
- Tk_GeometryRequest(butPtr->tkwin, (int) (width
- + 2*butPtr->inset), (int) (height + 2*butPtr->inset));
- Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
}
-
/*
- * Local Variables:
- * mode: objc
- * c-basic-offset: 4
- * fill-column: 79
- * coding: utf-8
- * End:
+ *--------------------------------------------------------------
+ *
+ * PulseDefaultButtonProc --
+ *
+ * This function redraws the button on a timer, to pulse
+ * default buttons.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Sets a timer to run itself again.
+ *
+ *--------------------------------------------------------------
*/
+static void
+PulseDefaultButtonProc(ClientData clientData)
+{
+ MacButton *mbPtr = (MacButton *)clientData;
+ TkpDisplayButton(clientData);
+ mbPtr->defaultPulseHandler = Tcl_CreateTimerHandler(
+ PULSE_TIMER_MSECS, PulseDefaultButtonProc, clientData);
+}
+
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c
index d4b2c85..8fe9a95 100644
--- a/macosx/tkMacOSXDraw.c
+++ b/macosx/tkMacOSXDraw.c
@@ -101,13 +101,6 @@ TkMacOSXInitCGDrawing(
(char *) &useThemedFrame, TCL_LINK_BOOLEAN) != TCL_OK) {
Tcl_ResetResult(interp);
}
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (Tcl_LinkVar(interp, "::tk::mac::useCompatibilityMetrics",
- (char *) &tkMacOSXUseCompatibilityMetrics, TCL_LINK_BOOLEAN)
- != TCL_OK) {
- Tcl_ResetResult(interp);
- }
-#endif
}
return TCL_OK;
}
@@ -1516,25 +1509,11 @@ TkScrollWindow(
/* Scroll the rectangle. */
[view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)];
-
- /*
- * Adjust the positions of the button subwindows that meet the scroll
- * area.
- */
-
- for (NSView *subview in [view subviews] ) {
- if ( [subview isKindOfClass:[NSButton class]] == YES ) {
- NSRect subframe = [subview frame];
- if ( NSIntersectsRect(scrollSrc, subframe) ||
- NSIntersectsRect(scrollDst, subframe) ) {
- TkpShiftButton((NSButton *)subview, delta );
- }
- }
- }
-
- /* Redisplay the scrolled area. */
- [view displayRect:scrollDst];
-
+
+ /* Redisplay the scrolled area; hide to reduce flicker after removal of private API calls. */
+ [view setHidden:YES];
+ [view displayRect:scrollDst];
+ [view setHidden:NO];
}
}
diff --git a/macosx/tkMacOSXEmbed.c b/macosx/tkMacOSXEmbed.c
index 17832c6..ef83276 100644
--- a/macosx/tkMacOSXEmbed.c
+++ b/macosx/tkMacOSXEmbed.c
@@ -174,6 +174,50 @@ TkpMakeWindow(
/*
*----------------------------------------------------------------------
*
+ * TkpScanWindowId --
+ *
+ * Given a string, produce the corresponding Window Id.
+ *
+ * Results:
+ * The return value is normally TCL_OK; in this case *idPtr will be set
+ * to the Window value equivalent to string. If string is improperly
+ * formed then TCL_ERROR is returned and an error message will be left in
+ * the interp's result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkpScanWindowId(
+ Tcl_Interp *interp,
+ CONST char * string,
+ Window *idPtr)
+{
+ int code;
+ Tcl_Obj obj;
+
+ obj.refCount = 1;
+ obj.bytes = string;
+ obj.length = strlen(string);
+ obj.typePtr = NULL;
+
+ code = Tcl_GetLongFromObj(interp, &obj, (long *)idPtr);
+
+ if (obj.refCount > 1) {
+ Tcl_Panic("invalid sharing of Tcl_Obj on C stack");
+ }
+ if (obj.typePtr && obj.typePtr->freeIntRepProc) {
+ obj.typePtr->freeIntRepProc(&obj);
+ }
+ return code;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TkpUseWindow --
*
* This procedure causes a Tk window to use a given X window as its
@@ -214,7 +258,7 @@ TkpUseWindow(
}
/*
- * Decode the container pointer, and look for it among the list of
+ * Decode the container window ID, and look for it among the list of
* available containers.
*
* N.B. For now, we are limiting the containers to be in the same Tk
@@ -222,7 +266,7 @@ TkpUseWindow(
* containers.
*/
- if (Tcl_GetInt(interp, string, (int*) &parent) != TCL_OK) {
+ if (TkpScanWindowId(interp, string, (Window *)&parent) != TCL_OK) {
return TCL_ERROR;
}
diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c
index b9514b4..752ec48 100644
--- a/macosx/tkMacOSXInit.c
+++ b/macosx/tkMacOSXInit.c
@@ -33,7 +33,7 @@ static char scriptPath[PATH_MAX + 1] = "";
int tkMacOSXGCEnabled = 0;
long tkMacOSXMacOSXVersion = 0;
-#pragma mark TKApplication(TKInit)
+#pragma mark TKApplication(TKInit)
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#define NSTextInputContextKeyboardSelectionDidChangeNotification @"NSTextInputContextKeyboardSelectionDidChangeNotification"
@@ -55,10 +55,6 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
- (void)_setupWindowNotifications;
@end
-@interface TKApplication(TKScrlbr)
-- (void)_setupScrollBarNotifications;
-@end
-
@interface TKApplication(TKMenus)
- (void)_setupMenus;
@end
@@ -102,7 +98,6 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
selector:@selector(_postedNotification:) name:nil object:nil];
#endif
[self _setupWindowNotifications];
- [self _setupScrollBarNotifications];
[self _setupApplicationNotifications];
}
- (NSString *)tkFrameworkImagePath:(NSString*)image {
diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c
index abb2c6e..a1c3138 100644
--- a/macosx/tkMacOSXMenubutton.c
+++ b/macosx/tkMacOSXMenubutton.c
@@ -5,76 +5,71 @@
* menubutton widget.
*
* Copyright (c) 1996 by Sun Microsystems, Inc.
- * Copyright 2001-2009, Apple Inc.
- * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2001, Apple Computer, Inc.
+ * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2007 Revar Desmera.
+ * Copyright 2015 Kevin Walzer/WordTech Communications LLC.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
*/
#include "tkMacOSXPrivate.h"
+#include "tkMenu.h"
#include "tkMenubutton.h"
#include "tkMacOSXFont.h"
#include "tkMacOSXDebug.h"
-/*
-#ifdef TK_MAC_DEBUG
-#define TK_MAC_DEBUG_MENUBUTTON
-#endif
-*/
+#define FIRST_DRAW 2
+#define ACTIVE 4
-typedef struct MacMenuButton {
- TkMenuButton info;
- NSPopUpButton *button;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- int fix;
-#endif
-} MacMenuButton;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+typedef struct {
+ Tk_3DBorder border;
+ int relief;
+ GC gc;
+ int hasImageOrBitmap;
+} DrawParams;
+
/*
- * Use the following heuristic conversion constants to make NSButton-based
- * widget metrics match up with the old Carbon control buttons (for the
- * default Lucida Grande 13 font).
- * TODO: provide a scriptable way to turn this off and use the raw NSButton
- * metrics (will also need dynamic adjustment of the default padding,
- * c.f. tkMacOSXDefault.h).
+ * Declaration of Mac specific button structure.
*/
-typedef struct {
- int trimW, trimH, inset, shrinkW, offsetX, offsetY;
-} BoundsFix;
-
-#define fixForStyle(style) ( \
- style == NSRoundedBezelStyle ? 1 : \
- style == NSRegularSquareBezelStyle ? 2 : \
- style == NSShadowlessSquareBezelStyle ? 3 : \
- INT_MIN)
-
-static const BoundsFix boundsFixes[] = {
- [fixForStyle(NSRoundedBezelStyle)] = { 14, 10, -2, -1},
- [fixForStyle(NSRegularSquareBezelStyle)] = { 6, 13, -2, 1, 1},
- [fixForStyle(NSShadowlessSquareBezelStyle)] = { 15, 0, 2 },
-};
-
-#endif
+typedef struct MacMenuButton {
+ TkMenuButton info; /* Generic button info. */
+ int flags;
+ ThemeButtonKind btnkind;
+ HIThemeButtonDrawInfo drawinfo;
+ HIThemeButtonDrawInfo lastdrawinfo;
+ DrawParams drawParams;
+} MacMenuButton;
/*
* Forward declarations for procedures defined later in this file:
*/
static void MenuButtonEventProc(ClientData clientData, XEvent *eventPtr);
+static void MenuButtonBackgroundDrawCB ( MacMenuButton *ptr, SInt16 depth, Boolean isColorDev);
+static void MenuButtonContentDrawCB ( ThemeButtonKind kind, const HIThemeButtonDrawInfo * info, MacMenuButton *ptr, SInt16 depth, Boolean isColorDev);
+static void MenuButtonEventProc ( ClientData clientData, XEvent *eventPtr);
+static void TkMacOSXComputeMenuButtonParams (TkMenuButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo* drawinfo);
+static int TkMacOSXComputeMenuButtonDrawParams (TkMenuButton * butPtr, DrawParams * dpPtr);
+static void TkMacOSXDrawMenuButton (MacMenuButton *butPtr,
+ GC gc, Pixmap pixmap);
+static void DrawMenuButtonImageAndText(TkMenuButton* butPtr);
/*
- * The structure below defines menubutton class behavior by means of functions
- * that can be invoked from generic window code.
+ * The structure below defines menubutton class behavior by means of
+ * procedures that can be invoked from generic window code.
*/
Tk_ClassProcs tkpMenubuttonClass = {
sizeof(Tk_ClassProcs), /* size */
TkMenuButtonWorldChanged, /* worldChangedProc */
};
+
/*
*----------------------------------------------------------------------
@@ -96,115 +91,94 @@ TkMenuButton *
TkpCreateMenuButton(
Tk_Window tkwin)
{
- MacMenuButton *macButtonPtr =
- (MacMenuButton *) ckalloc(sizeof(MacMenuButton));
-
- macButtonPtr->button = nil;
+ MacMenuButton *mbPtr = (MacMenuButton *) ckalloc(sizeof(MacMenuButton));
Tk_CreateEventHandler(tkwin, ActivateMask,
- MenuButtonEventProc, (ClientData) macButtonPtr);
- return (TkMenuButton *) macButtonPtr;
+ MenuButtonEventProc, (ClientData) mbPtr);
+ mbPtr->flags = FIRST_DRAW;
+ mbPtr->btnkind = kThemePopupButton;
+ bzero(&mbPtr->drawinfo, sizeof(mbPtr->drawinfo));
+ bzero(&mbPtr->lastdrawinfo, sizeof(mbPtr->lastdrawinfo));
+
+ return (TkMenuButton *) mbPtr;
}
/*
*----------------------------------------------------------------------
*
- * TkpDestroyMenuButton --
+ * TkpDisplayMenuButton --
*
- * Free data structures associated with the menubutton control.
+ * This procedure is invoked to display a menubutton widget.
*
* Results:
* None.
*
* Side effects:
- * Restores the default control state.
+ * Commands are output to X to display the menubutton in its
+ * current mode.
*
*----------------------------------------------------------------------
*/
void
-TkpDestroyMenuButton(
- TkMenuButton *mbPtr)
+TkpDisplayMenuButton(
+ ClientData clientData) /* Information about widget. */
{
- MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr;
- [macButtonPtr->button setTag:(NSInteger)-1];
+ MacMenuButton *mbPtr = (MacMenuButton *)clientData;
+ TkMenuButton *butPtr = (TkMenuButton *) clientData;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ DrawParams* dpPtr = &mbPtr->drawParams;
+
+ butPtr->flags &= ~REDRAW_PENDING;
+ if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
+ return;
+ }
+
+ pixmap = (Pixmap) Tk_WindowId(tkwin);
+
+ TkMacOSXComputeMenuButtonDrawParams(butPtr, dpPtr);
+
+ /*
+ * set up clipping region. Make sure the we are using the port
+ * for this button, or we will set the wrong window's clip.
+ */
+
+ TkMacOSXSetUpClippingRgn(pixmap);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->button);
+ /* Draw the native portion of the buttons. */
+ TkMacOSXDrawMenuButton(mbPtr, dpPtr->gc, pixmap);
+
+ /* Draw highlight border, if needed. */
+ if (butPtr->highlightWidth < 3) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ Tk_Draw3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin),
+ butPtr->highlightWidth, TK_RELIEF_SOLID);
+ }
+ }
}
/*
*----------------------------------------------------------------------
*
- * TkpDisplayMenuButton --
+ * TkpDestroyMenuButton --
*
- * This function is invoked to display a menubutton widget.
+ * Free data structures associated with the menubutton control.
*
* Results:
* None.
*
* Side effects:
- * Commands are output to X to display the menubutton in its current
- * mode.
+ * Restores the default control state.
*
*----------------------------------------------------------------------
*/
void
-TkpDisplayMenuButton(
- ClientData clientData) /* Information about widget. */
+TkpDestroyMenuButton(
+ TkMenuButton *mbPtr)
{
- TkMenuButton *mbPtr = (TkMenuButton *) clientData;
- MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr;
- NSPopUpButton *button = macButtonPtr->button;
- Tk_Window tkwin = mbPtr->tkwin;
- 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;
- int enabled;
-
- mbPtr->flags &= ~REDRAW_PENDING;
- if (!tkwin || !Tk_IsMapped(tkwin) || !view ||
- !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
- return;
- }
- CGContextConcatCTM(dc.context, t);
- Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, mbPtr->normalBorder, 0, 0,
- Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
- if ([button superview] != view) {
- [view addSubview:button];
- }
- enabled = !(mbPtr->state == STATE_DISABLED);
- [button setEnabled:enabled];
- if (enabled) {
- [[button cell] setHighlighted:(mbPtr->state == STATE_ACTIVE)];
- }
- frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin),
- Tk_Height(tkwin));
- frame = NSInsetRect(frame, mbPtr->inset, mbPtr->inset);
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- BoundsFix boundsFix = boundsFixes[macButtonPtr->fix];
- frame = NSOffsetRect(frame, boundsFix.offsetX, boundsFix.offsetY);
- frame.size.width -= boundsFix.shrinkW;
- frame = NSInsetRect(frame, boundsFix.inset, boundsFix.inset);
- }
-#endif
- frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
- if (!NSEqualRects(frame, [button frame])) {
- [button setFrame:frame];
- }
- [button displayRectIgnoringOpacity:[button bounds]];
- TkMacOSXRestoreDrawingContext(&dc);
-#ifdef TK_MAC_DEBUG_MENUBUTTON
- TKLog(@"menubutton %s frame %@ width %d height %d",
- ((TkWindow *)mbPtr->tkwin)->pathName, NSStringFromRect(frame),
- Tk_Width(tkwin), Tk_Height(tkwin));
-#endif
}
/*
@@ -212,7 +186,7 @@ TkpDisplayMenuButton(
*
* TkpComputeMenuButtonGeometry --
*
- * After changes in a menu button's text or bitmap, this function
+ * After changes in a menu button's text or bitmap, this procedure
* recomputes the menu button's geometry and passes this information
* along to the geometry manager for the window.
*
@@ -226,205 +200,508 @@ TkpDisplayMenuButton(
*/
void
-TkpComputeMenuButtonGeometry(
- TkMenuButton *mbPtr) /* Widget record for menu button. */
+TkpComputeMenuButtonGeometry(butPtr)
+ register TkMenuButton *butPtr; /* Widget record for menu button. */
{
- MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr;
- NSPopUpButton *button = macButtonPtr->button;
- NSPopUpButtonCell *cell;
- NSMenuItem *menuItem;
- NSBezelStyle style = NSRoundedBezelStyle;
- NSFont *font;
- NSRect bounds = NSZeroRect, titleRect = NSZeroRect;
- int haveImage = (mbPtr->image || mbPtr->bitmap != None), haveText = 0;
- int haveCompound = (mbPtr->compound != COMPOUND_NONE);
- int width, height;
-
- if (!button) {
- button = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:YES];
- macButtonPtr->button = TkMacOSXMakeUncollectable(button);
- cell = [button cell];
- [cell setUsesItemFromMenu:NO];
- menuItem = [[[NSMenuItem alloc] initWithTitle:@""
- action:NULL keyEquivalent:@""] autorelease];
- [cell setMenuItem:menuItem];
- } else {
- cell = [button cell];
- menuItem = [cell menuItem];
+ int width, height, avgWidth, haveImage = 0, haveText = 0;
+ MacMenuButton *mbPtr = (MacMenuButton*)butPtr;
+ int txtWidth, txtHeight;
+ Tk_FontMetrics fm;
+ DrawParams drawParams;
+ int paddingx = 0;
+ int paddingy = 0;
+
+ /*
+ * First figure out the size of the contents of the button.
+ */
+
+ width = 0;
+ height = 0;
+ txtWidth = 0;
+ txtHeight = 0;
+ avgWidth = 0;
+
+ TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
+
+ if (butPtr->image != NULL) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
}
- if (haveImage) {
- style = NSShadowlessSquareBezelStyle;
- } else if (!mbPtr->indicatorOn) {
- style = NSRegularSquareBezelStyle;
+
+ if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
+ Tk_FreeTextLayout(butPtr->textLayout);
+ butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
+ butPtr->text, -1, butPtr->wrapLength,
+ butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
+
+ txtWidth = butPtr->textWidth;
+ txtHeight = butPtr->textHeight;
+ avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
+ Tk_GetFontMetrics(butPtr->tkfont, &fm);
+ haveText = (txtWidth != 0 && txtHeight != 0);
}
- [button setBezelStyle:style];
- [cell setArrowPosition:(mbPtr->indicatorOn ? NSPopUpArrowAtBottom :
- NSPopUpNoArrow)];
-#if 0
- NSControlSize controlSize = NSRegularControlSize;
-
- if (mbPtr->borderWidth <= 2) {
- controlSize = NSMiniControlSize;
- } else if (mbPtr->borderWidth == 3) {
- controlSize = NSSmallControlSize;
+
+ /*
+ * If the button is compound (ie, it shows both an image and text),
+ * the new geometry is a combination of the image and text geometry.
+ * We only honor the compound bit if the button has both text and an
+ * image, because otherwise it is not really a compound button.
+ */
+
+ if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM: {
+ /*
+ * Image is above or below text
+ */
+
+ height += txtHeight + butPtr->padY;
+ width = (width > txtWidth ? width : txtWidth);
+ break;
+ }
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT: {
+ /*
+ * Image is left or right of text
+ */
+
+ width += txtWidth + butPtr->padX;
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ }
+ case COMPOUND_CENTER: {
+ /*
+ * Image and text are superimposed
+ */
+
+ width = (width > txtWidth ? width : txtWidth);
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ }
+ case COMPOUND_NONE: {break;}
+ }
+
+ if (butPtr->width > 0) {
+ width = butPtr->width;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height;
+ }
+
+ } else {
+ if (haveImage) {
+ if (butPtr->width > 0) {
+ width = butPtr->width;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height;
+ }
+ } else {
+ width = txtWidth;
+ height = txtHeight;
+ if (butPtr->width > 0) {
+ width = butPtr->width * avgWidth;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height * fm.linespace;
+ }
+ }
}
- [cell setControlSize:controlSize];
-#endif
-
- if (mbPtr->text && *(mbPtr->text) && (!haveImage || haveCompound)) {
- NSString *title = [[NSString alloc] initWithUTF8String:mbPtr->text];
- [button setTitle:title];
- [title release];
- haveText = 1;
+ width += 2 * butPtr->padX - 2;
+ height += 2 * butPtr->padY - 2;
+
+ /*Add padding for button arrows.*/
+ width += 22;
+
+ /*
+ * Now figure out the size of the border decorations for the button.
+ */
+
+ if (butPtr->highlightWidth < 0) {
+ butPtr->highlightWidth = 0;
}
- haveCompound = (haveCompound && haveImage && haveText);
- if (haveText) {
- NSTextAlignment alignment = NSNaturalTextAlignment;
-
- switch (mbPtr->justify) {
- case TK_JUSTIFY_LEFT:
- alignment = NSLeftTextAlignment;
- break;
- case TK_JUSTIFY_RIGHT:
- alignment = NSRightTextAlignment;
- break;
- case TK_JUSTIFY_CENTER:
- alignment = NSCenterTextAlignment;
- break;
- }
- [button setAlignment:alignment];
- } else {
- [button setTitle:@""];
+ butPtr->inset = 0;
+ butPtr->inset += butPtr->highlightWidth;
+
+ TkMacOSXComputeMenuButtonDrawParams(butPtr,&drawParams);
+
+ HIRect tmpRect;
+ HIRect contBounds;
+
+ tmpRect = CGRectMake(0, 0, width, height);
+
+ HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds);
+
+
+
+ /* If the content region has a minimum height, match it. */
+ if (height < contBounds.size.height) {
+ height = contBounds.size.height;
+ }
+
+ /* If the content region has a minimum width, match it. */
+ if (width < contBounds.size.width) {
+ width = contBounds.size.width;
+ }
+
+ /* Pad to fill difference between content bounds and button bounds. */
+ paddingx = tmpRect.origin.x - contBounds.origin.x;
+ paddingy = tmpRect.origin.y - contBounds.origin.y;
+
+ if (paddingx > 0) {
+ width += paddingx;
}
- font = TkMacOSXNSFontForFont(mbPtr->tkfont);
- if (font) {
- [button setFont:font];
+ if (paddingy > 0) {
+ height += paddingy;
}
- if (haveImage) {
- int width, height;
- NSImage *image;
- NSCellImagePosition pos = NSImageOnly;
-
- if (mbPtr->image) {
- Tk_SizeOfImage(mbPtr->image, &width, &height);
- image = TkMacOSXGetNSImageWithTkImage(mbPtr->display,
- mbPtr->image, width, height);
- } else {
- Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
- image = TkMacOSXGetNSImageWithBitmap(mbPtr->display,
- mbPtr->bitmap, mbPtr->normalTextGC, width, height);
- }
- if (haveCompound) {
- switch ((enum compound) mbPtr->compound) {
- case COMPOUND_TOP:
- pos = NSImageAbove;
- break;
- case COMPOUND_BOTTOM:
- pos = NSImageBelow;
- break;
- case COMPOUND_LEFT:
- pos = NSImageLeft;
- break;
- case COMPOUND_RIGHT:
- pos = NSImageRight;
- break;
- case COMPOUND_CENTER:
- pos = NSImageOverlaps;
- break;
- case COMPOUND_NONE:
- pos = NSImageOnly;
- break;
- }
- }
- [button setImagePosition:pos];
- [menuItem setImage:image];
- bounds.size = cell ? [cell cellSize] : NSZeroSize;
- if (bounds.size.height < height + 8) { /* workaround AppKit sizing bug */
- bounds.size.height = height + 8;
- }
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (!mbPtr->indicatorOn && tkMacOSXUseCompatibilityMetrics) {
- bounds.size.width -= 16;
- }
-#endif
- } else {
- bounds.size = cell ? [cell cellSize] : NSZeroSize;
+
+ width += butPtr->inset*2;
+ height += butPtr->inset*2;
+
+
+ Tk_GeometryRequest(butPtr->tkwin, width, height);
+ Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawMenuButtonImageAndText --
+ *
+ * Draws the image and text associated witha button or label.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The image and text are drawn.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+DrawMenuButtonImageAndText(
+ TkMenuButton* butPtr)
+{
+ MacMenuButton *mbPtr = (MacMenuButton*)butPtr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ int haveImage = 0;
+ int haveText = 0;
+ int imageWidth = 0;
+ int imageHeight = 0;
+ int imageXOffset = 0;
+ int imageYOffset = 0;
+ int textXOffset = 0;
+ int textYOffset = 0;
+ int width = 0;
+ int height = 0;
+ int fullWidth = 0;
+ int fullHeight = 0;
+ int pressed;
+
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- if (haveText) {
- titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect;
- if (mbPtr->wrapLength > 0 &&
- titleRect.size.width > mbPtr->wrapLength) {
- if (style == NSRoundedBezelStyle) {
- [button setBezelStyle:(style = NSRegularSquareBezelStyle)];
- bounds.size = cell ? [cell cellSize] : NSZeroSize;
- titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect;
- }
- bounds.size.width -= titleRect.size.width - mbPtr->wrapLength;
- bounds.size.height = 40000.0;
- [cell setWraps:YES];
- bounds.size = cell ? [cell cellSizeForBounds:bounds] : NSZeroSize;
-#ifdef TK_MAC_DEBUG_MENUBUTTON
- titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect;
-#endif
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- bounds.size.height += 3;
- }
-#endif
- }
+
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+
+ if (butPtr->image != None) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
}
- width = lround(bounds.size.width);
- height = lround(bounds.size.height);
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- macButtonPtr->fix = fixForStyle(style);
- width -= boundsFixes[macButtonPtr->fix].trimW;
- height -= boundsFixes[macButtonPtr->fix].trimH;
+
+ imageWidth = width;
+ imageHeight = height;
+
+ if (mbPtr->drawinfo.state == kThemeStatePressed) {
+ /* Offset bitmaps by a bit when the button is pressed. */
+ pressed = 1;
}
-#endif
+
+ haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
+ if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
+ int x = 0;
+ int y = 0;
+ textXOffset = 0;
+ textYOffset = 0;
+ fullWidth = 0;
+ fullHeight = 0;
- if (haveImage || haveCompound) {
- if (mbPtr->width > 0) {
- width = mbPtr->width;
- }
- if (mbPtr->height > 0) {
- height = mbPtr->height;
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM: {
+ /* Image is above or below text */
+ if (butPtr->compound == COMPOUND_TOP) {
+ textYOffset = height + butPtr->padY;
+ } else {
+ imageYOffset = butPtr->textHeight + butPtr->padY;
+ }
+ fullHeight = height + butPtr->textHeight + butPtr->padY;
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ break;
+ }
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT: {
+ /*
+ * Image is left or right of text
+ */
+
+ if (butPtr->compound == COMPOUND_LEFT) {
+ textXOffset = width + butPtr->padX - 2;
+ } else {
+ imageXOffset = butPtr->textWidth + butPtr->padX;
+ }
+ fullWidth = butPtr->textWidth + butPtr->padX + width;
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
+ }
+ case COMPOUND_CENTER: {
+ /*
+ * Image and text are superimposed
+ */
+
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
+ }
+ case COMPOUND_NONE: {break;}
}
+
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ fullWidth, fullHeight, &x, &y);
+ imageXOffset += x;
+ imageYOffset += y;
+ textYOffset -= 1;
+
+ if (butPtr->image != NULL) {
+ Tk_RedrawImage(butPtr->image, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc,
+ imageXOffset, imageYOffset);
+ XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width, (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+
+ Tk_DrawTextLayout(butPtr->display, pixmap,
+ dpPtr->gc, butPtr->textLayout,
+ x + textXOffset, y + textYOffset, 0, -1);
+ Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout,
+ x + textXOffset, y + textYOffset,
+ butPtr->underline);
} else {
- if (mbPtr->width > 0) {
- int avgWidth = Tk_TextWidth(mbPtr->tkfont, "0", 1);
- width = mbPtr->width * avgWidth;
+ if (haveImage) {
+ int x = 0;
+ int y;
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ width, height, &x, &y);
+ imageXOffset += x;
+ imageYOffset += y;
+
+ if (butPtr->image != NULL) {
+ Tk_RedrawImage(butPtr->image, 0, 0, width, height,
+ pixmap, imageXOffset, imageYOffset);
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc, x, y);
+ XCopyPlane(butPtr->display, butPtr->bitmap,
+ pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width,
+ (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+ } else {
+ /*Move x back by six pixels to give the menubutton arrows room.*/
+ int x = 0;
+ int y;
+ textXOffset = 6;
+ TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
+ butPtr->textWidth, butPtr->textHeight, &x, &y);
+ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout, x - textXOffset, y, 0, -1);
+ y += butPtr->textHeight/2;
+ }
+ }
+}
+
+
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TkMacOSXDrawMenuButton --
+ *
+ * This function draws the tk menubutton using Mac controls
+ * In addition, this code may apply custom colors passed
+ * in the TkMenubutton.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+TkMacOSXDrawMenuButton(
+ MacMenuButton *mbPtr, /* Mac menubutton. */
+ GC gc, /* The GC we are drawing into - needed for
+ * the bevel button */
+ Pixmap pixmap) /* The pixmap we are drawing into - needed
+ * for the bevel button */
+
+{
+ TkMenuButton * butPtr = ( TkMenuButton *)mbPtr;
+ TkWindow * winPtr;
+ HIRect cntrRect;
+ TkMacOSXDrawingContext dc;
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ int useNewerHITools = 1;
+
+ winPtr = (TkWindow *)butPtr->tkwin;
+
+ TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
+
+ cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin),Tk_Height(butPtr->tkwin));
+
+ cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset);
+
+
+ if (useNewerHITools == 1) {
+ HIRect hirec;
+ HIRect contHIRec;
+ static HIThemeButtonDrawInfo hiinfo;
+ Rect contRect;
+
+ MenuButtonBackgroundDrawCB((MacMenuButton*) mbPtr, 32, true);
+
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
}
- if (mbPtr->height > 0) {
- Tk_FontMetrics fm;
- Tk_GetFontMetrics(mbPtr->tkfont, &fm);
- height = mbPtr->height * fm.linespace;
+
+ hiinfo.version = 0;
+ hiinfo.state = mbPtr->drawinfo.state;
+ hiinfo.kind = mbPtr->btnkind;
+ hiinfo.value = mbPtr->drawinfo.value;
+ hiinfo.adornment = mbPtr->drawinfo.adornment;
+ hiinfo.animation.time.current = CFAbsoluteTimeGetCurrent();
+ if (hiinfo.animation.time.start == 0) {
+ hiinfo.animation.time.start = hiinfo.animation.time.current;
+ }
+
+ HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec);
+
+ TkMacOSXRestoreDrawingContext(&dc);
+
+ MenuButtonContentDrawCB( mbPtr->btnkind, &mbPtr->drawinfo, (MacMenuButton *)mbPtr, 32, true);
+ } else {
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
}
+
+
+ TkMacOSXRestoreDrawingContext(&dc);
}
- if (!haveImage || haveCompound) {
- width += 2*mbPtr->padX;
- height += 2*mbPtr->padY;
- }
- if (mbPtr->highlightWidth < 0) {
- mbPtr->highlightWidth = 0;
+ mbPtr->lastdrawinfo = mbPtr->drawinfo;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * MenuButtonBackgroundDrawCB --
+ *
+ * This function draws the background that
+ * lies under checkboxes and radiobuttons.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The background gets updated to the current color.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+MenuButtonBackgroundDrawCB (
+ MacMenuButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
+{
+ TkMenuButton* butPtr = (TkMenuButton*)ptr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- if (haveImage) {
- mbPtr->inset = mbPtr->highlightWidth;
- width += 2*mbPtr->borderWidth;
- height += 2*mbPtr->borderWidth;
- } else {
- mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth;
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * MenuButtonContentDrawCB --
+ *
+ * This function draws the label and image for the button.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The content of the button gets updated.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+MenuButtonContentDrawCB (
+ ThemeButtonKind kind,
+ const HIThemeButtonDrawInfo *drawinfo,
+ MacMenuButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
+{
+ TkMenuButton *butPtr = (TkMenuButton *)ptr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Rect bounds;
+
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- Tk_GeometryRequest(mbPtr->tkwin, width + 2 * mbPtr->inset,
- height + 2 * mbPtr->inset);
- Tk_SetInternalBorder(mbPtr->tkwin, mbPtr->inset);
-#ifdef TK_MAC_DEBUG_MENUBUTTON
- TKLog(@"menubutton %s bounds %@ titleRect %@ width %d height %d inset %d borderWidth %d",
- ((TkWindow *)mbPtr->tkwin)->pathName, NSStringFromRect(bounds),
- NSStringFromRect(titleRect), width, height, mbPtr->inset,
- mbPtr->borderWidth);
-#endif
+ MacDrawable *macWin = (MacDrawable *) Tk_WindowId(tkwin);
+
+ DrawMenuButtonImageAndText( butPtr);
}
/*
@@ -439,7 +716,7 @@ TkpComputeMenuButtonGeometry(
* None.
*
* Side effects:
- * When activation state changes, it is redisplayed.
+ * When it gets exposed, it is redisplayed.
*
*--------------------------------------------------------------
*/
@@ -449,27 +726,124 @@ MenuButtonEventProc(
ClientData clientData, /* Information about window. */
XEvent *eventPtr) /* Information about event. */
{
- TkMenuButton *mbPtr = (TkMenuButton *) clientData;
+ TkMenuButton *buttonPtr = (TkMenuButton *) clientData;
+ MacMenuButton *mbPtr = (MacMenuButton *) clientData;
- if (!mbPtr->tkwin || !Tk_IsMapped(mbPtr->tkwin)) {
- return;
+ if (eventPtr->type == ActivateNotify
+ || eventPtr->type == DeactivateNotify) {
+ if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) {
+ return;
+ }
+ if (eventPtr->type == ActivateNotify) {
+ mbPtr->flags |= ACTIVE;
+ } else {
+ mbPtr->flags &= ~ACTIVE;
+ }
+ if ((buttonPtr->flags & REDRAW_PENDING) == 0) {
+ Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) buttonPtr);
+ buttonPtr->flags |= REDRAW_PENDING;
+ }
}
- switch (eventPtr->type) {
- case ActivateNotify:
- case DeactivateNotify:
- if (!(mbPtr->flags & REDRAW_PENDING)) {
- Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr);
- mbPtr->flags |= REDRAW_PENDING;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXComputeMenuButtonParams --
+ *
+ * This procedure computes the various parameters used
+ * when creating a Carbon Appearance control.
+ * These are determined by the various tk button parameters
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Sets the btnkind and drawinfo parameters
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+TkMacOSXComputeMenuButtonParams(TkMenuButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo *drawinfo)
+{
+ MacMenuButton *mbPtr = (MacMenuButton *)butPtr;
+
+ if (butPtr->image || butPtr->bitmap) {
+ /* TODO: allow for Small and Mini menubuttons. */
+ *btnkind = kThemePopupButton;
+ } else {
+ if (!butPtr->text || !*butPtr->text) {
+ *btnkind = kThemeArrowButton;
+ } else {
+ *btnkind = kThemePopupButton;
+ }
+ }
+
+ drawinfo->value = kThemeButtonOff;
+
+ if ((mbPtr->flags & FIRST_DRAW) != 0) {
+ mbPtr->flags &= ~FIRST_DRAW;
+ if (Tk_MacOSXIsAppInFront()) {
+ mbPtr->flags |= ACTIVE;
}
- break;
}
+
+ drawinfo->state = kThemeStateInactive;
+ if ((mbPtr->flags & ACTIVE) == 0) {
+ if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailableInactive;
+ } else {
+ drawinfo->state = kThemeStateInactive;
+ }
+ } else if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailable;
+ } else {
+ drawinfo->state = kThemeStateActive;
+ }
+
+ drawinfo->adornment = kThemeAdornmentNone;
+ if (butPtr->highlightWidth >= 3) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ drawinfo->adornment |= kThemeAdornmentFocus;
+ }
+ }
+ drawinfo->adornment |= kThemeAdornmentArrowDoubleArrow;
}
/*
- * Local Variables:
- * mode: objc
- * c-basic-offset: 4
- * fill-column: 79
- * coding: utf-8
- * End:
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXComputeMenuButtonDrawParams --
+ *
+ * This procedure computes the various parameters used
+ * when drawing a button
+ * These are determined by the various tk button parameters
+ *
+ * Results:
+ * 1 if control will be used, 0 otherwise.
+ *
+ * Side effects:
+ * Sets the button draw parameters
+ *
+ *----------------------------------------------------------------------
*/
+
+static int
+TkMacOSXComputeMenuButtonDrawParams(TkMenuButton * butPtr, DrawParams * dpPtr)
+{
+ dpPtr->hasImageOrBitmap = ((butPtr->image != NULL)
+ || (butPtr->bitmap != None));
+ dpPtr->border = butPtr->normalBorder;
+ if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
+ dpPtr->gc = butPtr->disabledGC;
+ } else if (butPtr->state == STATE_ACTIVE) {
+ dpPtr->gc = butPtr->activeTextGC;
+ dpPtr->border = butPtr->activeBorder;
+ } else {
+ dpPtr->gc = butPtr->normalTextGC;
+ }
+
+ return 1;
+}
+
diff --git a/macosx/tkMacOSXPort.h b/macosx/tkMacOSXPort.h
index 0a60cf6..2ccbac3 100644
--- a/macosx/tkMacOSXPort.h
+++ b/macosx/tkMacOSXPort.h
@@ -158,18 +158,10 @@
/*
* This macro stores a representation of the window handle in a string.
- * This should perhaps use the real size of an XID.
*/
#define TkpPrintWindowId(buf,w) \
- sprintf((buf), "0x%x", (unsigned int) (w))
-
-/*
- * TkpScanWindowId is just an alias for Tcl_GetInt on Unix.
- */
-
-#define TkpScanWindowId(i,s,wp) \
- Tcl_GetInt((i),(s),(int *) (wp))
+ sprintf((buf), "0x%lx", (unsigned long) (w))
/*
* Turn off Tk double-buffering as Aqua windows are already double-buffered.
diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h
index 4978611..18af42f 100644
--- a/macosx/tkMacOSXPrivate.h
+++ b/macosx/tkMacOSXPrivate.h
@@ -178,9 +178,6 @@ MODULE_SCOPE CGFloat tkMacOSXZeroScreenHeight;
MODULE_SCOPE CGFloat tkMacOSXZeroScreenTop;
MODULE_SCOPE int tkMacOSXGCEnabled;
MODULE_SCOPE long tkMacOSXMacOSXVersion;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-MODULE_SCOPE int tkMacOSXUseCompatibilityMetrics;
-#endif
/*
* Prototypes for TkMacOSXRegion.c.
diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c
index 3658f7e..d591436 100644
--- a/macosx/tkMacOSXScrlbr.c
+++ b/macosx/tkMacOSXScrlbr.c
@@ -1,5 +1,5 @@
/*
- * tkMacOSXScrollbar.c --
+ * tkMacOSXScrollbar.c --
*
* This file implements the Macintosh specific portion of the scrollbar
* widget.
@@ -7,79 +7,24 @@
* Copyright (c) 1996 by Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
- *
+ * Copyright (c) 2015 Kevin Walzer/WordTech Commununications LLC.
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#include "tkMacOSXPrivate.h"
+#include "tkInt.h"
#include "tkScrollbar.h"
+#include "tkMacOSXPrivate.h"
-/*
-#ifdef TK_MAC_DEBUG
-#define TK_MAC_DEBUG_SCROLLBAR
-#endif
-*/
-
-NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr);
-
-/*
- * A subclass of NSScroller with sanity checking:
- *
- * NSScrollers created by Tk will have their tag set to a pointer to the
- * TkScrollbar which manages the NSScroller. This allows an NSScroller to be
- * aware of the state of its Tk parent. This subclass overrides the drawRect
- * method so that it will not draw itself if the widget is completely outside
- * of its container.
- */
-
-@interface TkNSScroller: NSScroller
--(void) drawRect:(NSRect)dirtyRect;
-
-@end
-
-@implementation TkNSScroller
-
- - (void)drawRect:(NSRect)dirtyRect
- {
- NSInteger tag = [self tag];
- if ( tag != -1) {
- TkScrollbar *scrollPtr = (TkScrollbar *)tag;
- MacDrawable* macWin = (MacDrawable *)scrollPtr;
- Tk_Window tkwin = scrollPtr->tkwin;
- NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr);
- /* Do not draw if the widget is misplaced or unmapped. */
- if ( NSIsEmptyRect(Tkframe) ||
- ! macWin->winPtr->flags & TK_MAPPED ||
- ! NSEqualRects(Tkframe, [self frame])
- ) {
- return;
- }
-
- /*
- * Do not draw if the widget is completely outside of its parent.
- */
- if (tkwin) {
- int parent_height = Tk_Height(Tk_Parent(tkwin));
- int widget_height = Tk_Height(tkwin);
- int y = Tk_Y(tkwin);
- if ( y > parent_height || y + widget_height < 0 ) {
- return;
- }
-
- int parent_width = Tk_Width(Tk_Parent(tkwin));
- int widget_width = Tk_Width(tkwin);
- int x = Tk_X(tkwin);
- if (x > parent_width || x + widget_width < 0) {
- return;
- }
- }
- }
- [super drawRect:dirtyRect];
- }
-@end
+#define MIN_SCROLLBAR_VALUE 0
+/*Borrowed from ttkMacOSXTheme.c to provide appropriate scaling of scrollbar values.*/
+#ifdef __LP64__
+#define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum))
+#else
+#define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum))
+#endif /* __LP64__ */
/*
@@ -87,11 +32,26 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr);
*/
typedef struct MacScrollbar {
- TkScrollbar info;
- TkNSScroller *scroller;
- int variant;
+ TkScrollbar information; /* Generic scrollbar info. */
+ GC troughGC; /* For drawing trough. */
+ GC copyGC; /* Used for copying from pixmap onto screen. */
} MacScrollbar;
+/*
+ * The class procedure table for the scrollbar widget. All fields except size
+ * are left initialized to NULL, which should happen automatically since the
+ * variable is declared at this scope.
+ */
+
+const Tk_ClassProcs tkpScrollbarProcs = {
+ sizeof(Tk_ClassProcs), /* size */
+ NULL, /* worldChangedProc */
+ NULL, /* createProc */
+ NULL /* modalProc */
+};
+
+
+/*Information on scrollbar layout, metrics, and draw info.*/
typedef struct ScrollbarMetrics {
SInt32 width, minThumbHeight;
int minHeight, topArrowHeight, bottomArrowHeight;
@@ -103,170 +63,24 @@ static ScrollbarMetrics metrics[2] = {
{11, 40, 20, 10, 10, NSSmallControlSize}, /* kThemeScrollBarSmall */
};
-/*
- * Declarations for functions defined in this file.
- */
-
-static void UpdateScrollbarMetrics(void);
-static void ScrollbarEventProc(ClientData clientData,
- XEvent *eventPtr);
+HIThemeTrackDrawInfo info = {
+ .version = 0,
+ .min = 0.0,
+ .max = 100.0,
+ .attributes = kThemeTrackShowThumb,
+ .kind = kThemeScrollBarMedium,
+};
/*
- * The class procedure table for the scrollbar widget.
+ * Forward declarations for procedures defined later in this file:
*/
-Tk_ClassProcs tkpScrollbarProcs = {
- sizeof(Tk_ClassProcs), /* size */
- NULL, /* worldChangedProc */
- NULL, /* createProc */
- NULL /* modalProc */
-};
-
-#pragma mark TKApplication(TKScrlbr)
+static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr);
+static int ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr);
+static void UpdateControlValues(TkScrollbar *scrollPtr);
-#define NSAppleAquaScrollBarVariantChanged @"AppleAquaScrollBarVariantChanged"
-@implementation TKApplication(TKScrlbr)
-- (void) tkScroller: (TkNSScroller *) 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_BackgroundError(interp);
- }
- 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 -
-
-/*
- *----------------------------------------------------------------------
- *
- * UpdateScrollbarMetrics --
- *
- * This function retrieves the current system metrics for a scrollbar.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Updates the geometry cache info for all scrollbars.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-UpdateScrollbarMetrics(void)
-{
- const short height = 100, width = 50;
- 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;
-
- ChkErr(GetThemeMetric, kThemeMetricScrollBarWidth, &metrics[0].width);
- ChkErr(GetThemeMetric, kThemeMetricScrollBarMinThumbHeight,
- &metrics[0].minThumbHeight);
- info.kind = kThemeScrollBarMedium;
- 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(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(tkDefScrollbarWidth, "%d", (int)(metrics[0].width));
-}
-
/*
*----------------------------------------------------------------------
*
@@ -285,41 +99,19 @@ UpdateScrollbarMetrics(void)
TkScrollbar *
TkpCreateScrollbar(
- Tk_Window tkwin)
+ Tk_Window tkwin)
{
- MacScrollbar *scrollPtr = (MacScrollbar *) ckalloc(sizeof(MacScrollbar));
- scrollPtr->scroller = nil;
- Tk_CreateEventHandler(tkwin, StructureNotifyMask|FocusChangeMask|
- ActivateMask|ExposureMask, ScrollbarEventProc, (ClientData) scrollPtr);
- return (TkScrollbar *) scrollPtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkpDestroyScrollbar --
- *
- * Free data structures associated with the scrollbar control.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
+ static int initialized = 0;
+ MacScrollbar *scrollPtr = ckalloc(sizeof(MacScrollbar));
-void
-TkpDestroyScrollbar(
- TkScrollbar *scrollPtr)
-{
- MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
- TkNSScroller *scroller = macScrollPtr->scroller;
- [scroller setTag:(NSInteger)-1];
+ scrollPtr->troughGC = None;
+ scrollPtr->copyGC = None;
+ TkWindow *winPtr = (TkWindow *)tkwin;
- TkMacOSXMakeCollectableAndRelease(macScrollPtr->scroller);
+ Tk_CreateEventHandler(tkwin,ExposureMask|StructureNotifyMask|FocusChangeMask|ButtonPressMask|VisibilityChangeMask, ScrollbarEventProc, scrollPtr);
+
+ return (TkScrollbar *) scrollPtr;
}
/*
@@ -328,8 +120,8 @@ TkpDestroyScrollbar(
* TkpDisplayScrollbar --
*
* This procedure redraws the contents of a scrollbar window. It is
- * invoked as a do-when-idle handler, so it only runs when there's nothing
- * else for the application to do.
+ * invoked as a do-when-idle handler, so it only runs when there's
+ * nothing else for the application to do.
*
* Results:
* None.
@@ -342,75 +134,67 @@ TkpDestroyScrollbar(
void
TkpDisplayScrollbar(
- ClientData clientData) /* Information about window. */
+ ClientData clientData) /* Information about window. */
{
- TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
- MacScrollbar *macScrollPtr = (MacScrollbar *) clientData;
- TkNSScroller *scroller = macScrollPtr->scroller;
- Tk_Window tkwin = scrollPtr->tkwin;
+ register TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
+ register Tk_Window tkwin = scrollPtr->tkwin;
+
+
+ if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
+ return;
+ }
+
+ MacScrollbar *macScrollPtr = clientData;
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;
+ .ty = viewHeight};
+
scrollPtr->flags &= ~REDRAW_PENDING;
if (!scrollPtr->tkwin || !Tk_IsMapped(tkwin) || !view ||
- !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
- return;
+ !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
+ return;
}
+
CGContextConcatCTM(dc.context, t);
+
+ /*Draw Unix-style scroll trough to provide rect for native scrollbar.*/
if (scrollPtr->highlightWidth != 0) {
- GC fgGC, bgGC;
-
- bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin);
- if (scrollPtr->flags & GOT_FOCUS) {
- fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin);
- } else {
- fgGC = bgGC;
- }
- TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth,
- (Pixmap) macWin);
+ GC fgGC, bgGC;
+
+ bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin);
+ if (scrollPtr->flags & GOT_FOCUS) {
+ fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin);
+ } else {
+ fgGC = bgGC;
+ }
+ 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);
+ 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);
+ scrollPtr->inset, scrollPtr->inset,
+ Tk_Width(tkwin) - 2*scrollPtr->inset,
+ Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT);
- 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 setEnabled: YES];
- [scroller setDoubleValue:scrollPtr->firstFraction / (1.0 - knobProportion)];
- [scroller setKnobProportion:knobProportion];
- [scroller displayRectIgnoringOpacity:[scroller bounds]];
+ /*Update values and draw in native rect.*/
+ UpdateControlValues(scrollPtr);
+ HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal);
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
+
+ scrollPtr->flags &= ~REDRAW_PENDING;
}
-
+
/*
*----------------------------------------------------------------------
*
@@ -429,123 +213,106 @@ TkpDisplayScrollbar(
*----------------------------------------------------------------------
*/
-void
+extern void
TkpComputeScrollbarGeometry(
- register TkScrollbar *scrollPtr)
- /* Scrollbar whose geometry may have
- * changed. */
+ register TkScrollbar *scrollPtr)
+/* Scrollbar whose geometry may have
+ * changed. */
{
- MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
- TkNSScroller *scroller = macScrollPtr->scroller;
+
int width, height, variant, fieldLength;
if (scrollPtr->highlightWidth < 0) {
- scrollPtr->highlightWidth = 0;
+ scrollPtr->highlightWidth = 0;
}
scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
- 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 horizontalness 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 = [[TkNSScroller 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];
-
+ variant = ((scrollPtr->vertical ? Tk_Width(scrollPtr->tkwin) :
+ Tk_Height(scrollPtr->tkwin)) - 2 * scrollPtr->inset
+ < metrics[0].width) ? 1 : 0;
scrollPtr->arrowLength = (metrics[variant].topArrowHeight +
- metrics[variant].bottomArrowHeight) / 2;
+ metrics[variant].bottomArrowHeight) / 2;
fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
- : Tk_Width(scrollPtr->tkwin))
- - 2 * (scrollPtr->arrowLength + scrollPtr->inset);
+ : Tk_Width(scrollPtr->tkwin))
+ - 2 * (scrollPtr->arrowLength + scrollPtr->inset);
if (fieldLength < 0) {
- fieldLength = 0;
+ fieldLength = 0;
}
scrollPtr->sliderFirst = fieldLength * scrollPtr->firstFraction;
scrollPtr->sliderLast = fieldLength * scrollPtr->lastFraction;
/*
- * Adjust the slider so that some piece of it is always displayed in the
- * scrollbar and so that it has at least a minimal width (so it can be
- * grabbed with the mouse).
+ * Adjust the slider so that some piece of it is always
+ * displayed in the scrollbar and so that it has at least
+ * a minimal width (so it can be grabbed with the mouse).
*/
if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) {
- scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
+ scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
}
if (scrollPtr->sliderFirst < 0) {
- scrollPtr->sliderFirst = 0;
+ scrollPtr->sliderFirst = 0;
}
if (scrollPtr->sliderLast < (scrollPtr->sliderFirst +
- metrics[variant].minThumbHeight)) {
- scrollPtr->sliderLast = scrollPtr->sliderFirst +
- metrics[variant].minThumbHeight;
+ metrics[variant].minThumbHeight)) {
+ scrollPtr->sliderLast = scrollPtr->sliderFirst +
+ metrics[variant].minThumbHeight;
}
if (scrollPtr->sliderLast > fieldLength) {
- scrollPtr->sliderLast = fieldLength;
+ scrollPtr->sliderLast = fieldLength;
}
scrollPtr->sliderFirst += scrollPtr->inset +
- metrics[variant].topArrowHeight;
+ metrics[variant].topArrowHeight;
scrollPtr->sliderLast += scrollPtr->inset +
- metrics[variant].bottomArrowHeight;
+ metrics[variant].bottomArrowHeight;
/*
- * Register the desired geometry for the window (leave enough space for
- * the two arrows plus a minimum-size slider, plus border around the whole
- * window, if any). Then arrange for the window to be redisplayed.
+ * Register the desired geometry for the window (leave enough space
+ * for the two arrows plus a minimum-size slider, plus border around
+ * the whole window, if any). Then arrange for the window to be
+ * redisplayed.
*/
if (scrollPtr->vertical) {
- Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width +
- 2 * scrollPtr->inset, 2 * (scrollPtr->arrowLength +
- scrollPtr->borderWidth + scrollPtr->inset) +
- metrics[variant].minThumbHeight);
+ Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width + 2 * scrollPtr->inset, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics[variant].minThumbHeight);
} else {
- Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength +
- scrollPtr->borderWidth + scrollPtr->inset) +
- metrics[variant].minThumbHeight, scrollPtr->width +
- 2 * scrollPtr->inset);
+ Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics[variant].minThumbHeight, scrollPtr->width + 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 --
+ *
+ * Free data structures associated with the scrollbar control.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Frees the GCs associated with the scrollbar.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpDestroyScrollbar(
+ TkScrollbar *scrollPtr)
+{
+ MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr;
+
+ if (macScrollPtr->troughGC != None) {
+ Tk_FreeGC(scrollPtr->display, macScrollPtr->troughGC);
+ }
+ if (macScrollPtr->copyGC != None) {
+ Tk_FreeGC(scrollPtr->display, macScrollPtr->copyGC);
+ }
+
+ macScrollPtr=NULL;
+}
+
/*
*----------------------------------------------------------------------
*
@@ -559,19 +326,20 @@ TkpComputeScrollbarGeometry(
* None.
*
* Side effects:
- * None.
+ * Configuration info may get changed.
*
*----------------------------------------------------------------------
*/
void
TkpConfigureScrollbar(
- register TkScrollbar *scrollPtr)
- /* Information about widget; may or may not
- * already have values for some fields. */
+ register TkScrollbar *scrollPtr)
+/* Information about widget; may or may not
+ * already have values for some fields. */
{
+
}
-
+
/*
*--------------------------------------------------------------
*
@@ -596,30 +364,159 @@ TkpScrollbarPosition(
/* Scrollbar widget record. */
int x, int y) /* Coordinates within scrollPtr's window. */
{
- TkNSScroller *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:
+ /*Using code from tkUnixScrlbr.c because Unix scroll bindings are driving the display at the script level. All the Mac scrollbar has to do is re-draw itself.*/
+
+ int length, width, tmp;
+ register const int inset = scrollPtr->inset;
+
+ if (scrollPtr->vertical) {
+ length = Tk_Height(scrollPtr->tkwin);
+ width = Tk_Width(scrollPtr->tkwin);
+ } else {
+ tmp = x;
+ x = y;
+ y = tmp;
+ length = Tk_Width(scrollPtr->tkwin);
+ width = Tk_Height(scrollPtr->tkwin);
+ }
+
+ if (x<inset || x>=width-inset || y<inset || y>=length-inset) {
+ return OUTSIDE;
+ }
+
+ /*
+ * All of the calculations in this procedure mirror those in
+ * TkpDisplayScrollbar. Be sure to keep the two consistent.
+ */
+
+ if (y < inset + scrollPtr->arrowLength) {
return TOP_ARROW;
- case NSScrollerDecrementPage:
+ }
+ if (y < scrollPtr->sliderFirst) {
return TOP_GAP;
- case NSScrollerKnob:
+ }
+ if (y < scrollPtr->sliderLast) {
return SLIDER;
- case NSScrollerIncrementPage:
- return BOTTOM_GAP;
- case NSScrollerIncrementLine:
+ }
+ if (y >= length - (scrollPtr->arrowLength + inset)) {
return BOTTOM_ARROW;
- case NSScrollerKnobSlot:
- case NSScrollerNoPart:
- default:
- return OUTSIDE;
}
+ return BOTTOM_GAP;
}
-
+
+/*
+ *--------------------------------------------------------------
+ *
+ * UpdateControlValues --
+ *
+ * This procedure updates the Macintosh scrollbar control to display the
+ * values defined by the Tk scrollbar. This is the key interface to the Mac-native * scrollbar; the Unix bindings drive scrolling in the Tk window and all the Mac
+ * scrollbar has to do is redraw itself.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The Macintosh control is updated.
+ *
+ *--------------------------------------------------------------
+ */
+
+static void
+UpdateControlValues(
+ TkScrollbar *scrollPtr) /* Scrollbar data struct. */
+{
+
+ Tk_Window tkwin = scrollPtr->tkwin;
+ MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin);
+ double dViewSize;
+ HIRect contrlRect;
+ int variant, active;
+ short width, height;
+
+ NSView *view = TkMacOSXDrawableView(macWin);
+ CGFloat viewHeight = [view bounds].size.height;
+ NSRect frame;
+ 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);
+
+ contrlRect = NSRectToCGRect(frame);
+ info.bounds = contrlRect;
+
+ width = contrlRect.size.width;
+ height = contrlRect.size.height;
+
+ variant = contrlRect.size.width < metrics[0].width ? 1 : 0;
+
+ /*
+ * Ensure we set scrollbar control bounds only once all size adjustments
+ * have been computed.
+ */
+
+ info.bounds = contrlRect;
+ if (!scrollPtr->vertical) {
+ info.attributes |= kThemeTrackHorizontal;
+ }
+
+ /*
+ * 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.
+ */
+
+ double maximum = 100, factor;
+ factor = RangeToFactor(maximum);
+ dViewSize = (scrollPtr->lastFraction - scrollPtr->firstFraction)
+ * factor;
+ info.max = MIN_SCROLLBAR_VALUE +
+ factor - dViewSize;
+ info.trackInfo.scrollbar.viewsize = dViewSize;
+ if (scrollPtr->vertical) {
+ info.value = info.max - factor * scrollPtr->firstFraction;
+ } else {
+ info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction;
+ }
+
+ if((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0)
+ || height <= metrics[variant].minHeight) {
+ info.enableState = kThemeTrackHideTrack;
+ } else {
+ info.enableState = kThemeTrackActive;
+ info.attributes = kThemeTrackShowThumb | kThemeTrackThumbRgnIsNotGhost;
+ }
+
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ScrollbarPress --
+ *
+ * This procedure is invoked in response to <ButtonPress> events.
+ * Enters a modal loop to handle scrollbar interactions.
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr)
+{
+
+ if (eventPtr->type == ButtonPress) {
+ UpdateControlValues(scrollPtr);
+ return TCL_OK;
+ }
+}
+
+
+
/*
*--------------------------------------------------------------
*
@@ -640,10 +537,10 @@ TkpScrollbarPosition(
static void
ScrollbarEventProc(
- ClientData clientData, /* Information about window. */
- XEvent *eventPtr) /* Information about event. */
+ ClientData clientData, /* Information about window. */
+ XEvent *eventPtr) /* Information about event. */
{
- TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
+ TkScrollbar *scrollPtr = clientData;
switch (eventPtr->type) {
case UnmapNotify:
@@ -651,57 +548,13 @@ ScrollbarEventProc(
break;
case ActivateNotify:
case DeactivateNotify:
- TkScrollbarEventuallyRedraw((ClientData) scrollPtr);
+ TkScrollbarEventuallyRedraw(scrollPtr);
+ break;
+ case ButtonPress:
+ ScrollbarPress(clientData, eventPtr);
break;
default:
TkScrollbarEventProc(clientData, eventPtr);
}
}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * TkMacOSXGetScrollFrame --
- *
- * Computes a frame for an NSScroller that will correspond to where
- * Tk thinks the scroller is located.
- *
- * Results:
- * Returns an NSRect describing a frame for an NSScrollbar.
- *
- * Side effects:
- * None
- *
- *----------------------------------------------------------------------
- */
-NSRect TkMacOSXGetScrollFrame(
- TkScrollbar *scrlPtr)
-{
- MacScrollbar *macscrlPtr = (MacScrollbar *) scrlPtr;
- Tk_Window tkwin = scrlPtr->tkwin;
- TkWindow *winPtr = (TkWindow *) tkwin;
- if (tkwin) {
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
- NSView *view = TkMacOSXDrawableView(macWin);
- CGFloat viewHeight = [view bounds].size.height;
- NSRect frame = NSMakeRect(macWin->xOff, macWin->yOff,
- Tk_Width(tkwin), Tk_Height(tkwin));
-
- frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
- return frame;
- } else {
- return NSZeroRect;
- }
-}
-
-
-
-/*
- * Local Variables:
- * mode: objc
- * c-basic-offset: 4
- * fill-column: 79
- * coding: utf-8
- * End:
- */
+
diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c
index f5e506f..0f1e2be 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -80,6 +80,10 @@ extern NSString *opaqueTag;
NSWindow *w = [notification object];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
+ /*Disable drawing until window is resized removes flicker and drawing artifacts;necessary after removal of private API.*/
+ NSDisableScreenUpdates();
+ [ [w contentView] setHidden:YES];
+
if (winPtr) {
WmInfo *wmPtr = winPtr->wmInfoPtr;
NSRect bounds = [w frame];
@@ -107,6 +111,8 @@ extern NSString *opaqueTag;
}
TkGenWMConfigureEvent((Tk_Window) winPtr, x, y, width, height, flags);
}
+ [[w contentView] setHidden:NO];
+ NSEnableScreenUpdates();
}
- (void) windowExpanded: (NSNotification *) notification
@@ -771,6 +777,8 @@ Tk_MacOSXIsAppInFront(void)
@interface TKContentView(TKWindowEvent)
- (void) drawRect: (NSRect) rect;
- (void) generateExposeEvents: (HIMutableShapeRef) shape;
+- (BOOL) preservesContentDuringLiveResize;
+- (void) viewWillStartLiveResize;
- (void) viewDidEndLiveResize;
- (void) viewWillDraw;
- (BOOL) isOpaque;
@@ -782,15 +790,6 @@ Tk_MacOSXIsAppInFront(void)
@implementation TKContentView
@end
-double drawTime;
-
-/*
- * Set a minimum time for drawing to render. With removal of private NSView API's, default drawing
- * is slower and less responsive. This number, which seems feasible after some experimentatation, skips
- * some drawing to avoid lag.
- */
-
-#define MAX_DYNAMIC_TIME .000000001
/*Restrict event processing to Expose events.*/
static Tk_RestrictAction
@@ -807,10 +806,12 @@ ExposeRestrictProc(
- (void) drawRect: (NSRect) rect
{
+
const NSRect *rectsBeingDrawn;
NSInteger rectsBeingDrawnCount;
[self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount];
+
#ifdef TK_MAC_DEBUG_DRAWING
TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, NSStringFromRect(rect));
[[NSColor colorWithDeviceRed:0.0 green:1.0 blue:0.0 alpha:.1] setFill];
@@ -818,17 +819,12 @@ ExposeRestrictProc(
NSCompositeSourceOver);
#endif
- NSDate *beginTime=[NSDate date];
-
- /*Skip drawing during live resize if redraw is too slow.*/
- if([self inLiveResize] && drawTime>MAX_DYNAMIC_TIME) return;
-
+
CGFloat height = [self bounds].size.height;
HIMutableShapeRef drawShape = HIShapeCreateMutable();
while (rectsBeingDrawnCount--) {
CGRect r = NSRectToCGRect(*rectsBeingDrawn++);
-
r.origin.y = height - (r.origin.y + r.size.height);
HIShapeUnionWithRect(drawShape, &r);
}
@@ -841,24 +837,47 @@ ExposeRestrictProc(
NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode,
nil]];
}
+
CFRelease(drawShape);
- drawTime=-[beginTime timeIntervalSinceNow];
- [super setNeedsDisplayInRect:rect];
+
}
-/*At conclusion of resize event, send notification and set view for redraw if earlier drawing was skipped because of lagginess.*/
+
+/*Provide more fine-grained control over resizing of content to reduce flicker after removal of private API's.*/
+
+-(void) viewWillDraw
+{
+
+ [super viewWillDraw];
+}
+
+
+- (BOOL) preservesContentDuringLiveResize
+{
+ return YES;
+}
+
+- (void)viewWillStartLiveResize
+{
+ NSDisableScreenUpdates();
+ [super viewWillStartLiveResize];
+ [self setNeedsDisplay:NO];
+ [self setHidden:YES];
+}
+
+
- (void)viewDidEndLiveResize
{
- if(drawTime>MAX_DYNAMIC_TIME) {
+
+ NSEnableScreenUpdates();
+ [self setHidden:NO];
[self setNeedsDisplay:YES];
+ [super setNeedsDisplay:YES];
[super viewDidEndLiveResize];
- }
+
}
--(void) viewWillDraw {
- [self setNeedsDisplay:YES];
- }
-
+/*Core function of this class, generates expose events for redrawing.*/
- (void) generateExposeEvents: (HIMutableShapeRef) shape
{
@@ -870,6 +889,7 @@ ExposeRestrictProc(
return;
}
+
HIShapeGetBounds(shape, &updateBounds);
serial = LastKnownRequestProcessed(Tk_Display(winPtr));
if (GenerateUpdates(shape, &updateBounds, winPtr) &&
@@ -880,7 +900,7 @@ ExposeRestrictProc(
* just posted Expose events from generating new redraws.
*/
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
+ while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
/*
* For smoother drawing, process Expose events and resulting redraws
@@ -892,12 +912,13 @@ ExposeRestrictProc(
UINT2PTR(serial), &oldArg);
while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {}
-
+
Tk_RestrictEvents(oldProc, oldArg, &oldArg);
+
while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
- }
-
+ }
+
}
/*This is no-op on 10.7 and up because Apple has removed this widget, but leaving here for backwards compatibility.*/
@@ -933,11 +954,6 @@ ExposeRestrictProc(
[super setFrameSize:newSize];
}
-- (void) setNeedsDisplayInRect: (NSRect) invalidRect
-{
- [super setNeedsDisplayInRect:invalidRect];
-}
-
- (BOOL) isOpaque
{
NSWindow *w = [self window];
@@ -969,7 +985,6 @@ ExposeRestrictProc(
}
@end
-
/*
* Local Variables:
diff --git a/tests/canvText.test b/tests/canvText.test
index 20a39b0..7eef938 100644
--- a/tests/canvText.test
+++ b/tests/canvText.test
@@ -485,8 +485,8 @@ test canvText-17.1 {TextToPostscript procedure} {
.c itemconfig test -font $font -text "00000000" -width [expr 3*$ax]
.c itemconfig test -anchor n -fill black
set x [.c postscript]
- set x [string range $x [string first "/Courier-Oblique" $x] end]
-} "/Courier-Oblique findfont [font actual $font -size] scalefont ISOEncode setfont
+ set x [string range $x [string first "findfont " $x] end]
+} "findfont [font actual $font -size] scalefont ISOEncode setfont
0.000 0.000 0.000 setrgbcolor AdjustColor
100 200 \[
\[(000)\]
diff --git a/tests/text.test b/tests/text.test
index 52689ba..e75f38a 100644
--- a/tests/text.test
+++ b/tests/text.test
@@ -698,7 +698,59 @@ test text-9.2.44 {TextWidgetCmd procedure, "count" option} -setup {
.t tag add hidden 2.9 3.17
.t tag configure hidden -elide true
lappend res [.t count -displaylines 1.19 3.24] [.t count -displaylines 1.0 end]
-} -result {2 6 2 5}
+} -result {2 6 1 5}
+test text-9.2.45 {TextWidgetCmd procedure, "count" option} -setup {
+ .t delete 1.0 end
+ update
+ set res {}
+} -body {
+ for {set i 1} {$i < 5} {incr i} {
+ .t insert end "Line $i+++Line $i---Line $i///Line $i - This is Line [format %c [expr 64+$i]]\n"
+ }
+ .t tag configure hidden -elide true
+ .t tag add hidden 2.15 3.10
+ .t configure -wrap none
+ set res [.t count -displaylines 2.0 3.0]
+} -result {0}
+test text-9.2.46 {TextWidgetCmd procedure, "count" option} -setup {
+ toplevel .mytop
+ pack [text .mytop.t]
+ wm geometry .mytop 100x300+0+0
+ .mytop.t delete 1.0 end
+ update
+ set res {}
+} -body {
+ for {set i 1} {$i < 5} {incr i} {
+ # 0 1 2 3 4
+ # 012345 678901234 567890123 456789012 34567890123456789
+ .mytop.t insert end "Line $i+++Line $i---Line $i///Line $i - This is Line [format %c [expr 64+$i]]\n"
+ }
+ .mytop.t tag configure hidden -elide true
+ .mytop.t tag add hidden 2.15 3.10
+ .mytop.t configure -wrap char
+ lappend res [.mytop.t count -displaylines 2.0 3.0]
+ lappend res [.mytop.t count -displaylines 2.0 3.40]
+} -cleanup {
+ destroy .mytop
+} -result {1 3}
+test text-9.2.47 {TextWidgetCmd procedure, "count" option} -setup {
+ .t delete 1.0 end
+ update
+ set res {}
+} -body {
+ for {set i 1} {$i < 25} {incr i} {
+ .t insert end "Line $i\n"
+ }
+ .t tag configure hidden -elide true
+ .t tag add hidden 5.7 11.0
+ update
+ set y1 [lindex [.t yview] 1]
+ .t count -displaylines 5.0 11.0
+ set y2 [lindex [.t yview] 1]
+ .t count -displaylines 5.0 12.0
+ set y3 [lindex [.t yview] 1]
+ list [expr {$y1 == $y2}] [expr {$y1 == $y3}]
+} -result {1 1}
# Newer tags are higher priority
.t tag configure elide1 -elide 0
diff --git a/tests/textDisp.test b/tests/textDisp.test
index ae294c6..12a20c6 100644
--- a/tests/textDisp.test
+++ b/tests/textDisp.test
@@ -537,20 +537,24 @@ test textDisp-4.1 {UpdateDisplayInfo, basic} {textfonts} {
.t insert end "Line 1\nLine 2\nLine 3\n"
update
.t delete 2.0 2.end
+ update
+ set res $tk_textRelayout
.t insert 2.0 "New Line 2"
update
- list [.t bbox 1.0] [.t bbox 2.0] [.t bbox 3.0] $tk_textRelayout
-} [list [list 5 5 7 $fixedHeight] [list 5 [expr {$fixedDiff + 18}] 7 $fixedHeight] [list 5 [expr {2*$fixedDiff + 31}] 7 $fixedHeight] 2.0]
+ lappend res [.t bbox 1.0] [.t bbox 2.0] [.t bbox 3.0] $tk_textRelayout
+} [list 2.0 [list 5 5 7 $fixedHeight] [list 5 [expr {$fixedDiff + 18}] 7 $fixedHeight] [list 5 [expr {2*$fixedDiff + 31}] 7 $fixedHeight] 2.0]
test textDisp-4.2 {UpdateDisplayInfo, re-use tail of text line} {textfonts} {
.t delete 1.0 end
.t insert end "Line 1\nLine 2 is so long that it wraps around\nLine 3"
update
.t mark set x 2.21
.t delete 2.2
+ update
+ set res $tk_textRelayout
.t insert 2.0 X
update
- list [.t bbox 2.0] [.t bbox x] [.t bbox 3.0] $tk_textRelayout
-} [list [list 5 [expr {$fixedDiff + 18}] 7 $fixedHeight] [list 12 [expr {2*$fixedDiff + 31}] 7 $fixedHeight] [list 5 [expr {3*$fixedDiff + 44}] 7 $fixedHeight] {2.0 2.20}]
+ lappend res [.t bbox 2.0] [.t bbox x] [.t bbox 3.0] $tk_textRelayout
+} [list 2.0 2.20 [list 5 [expr {$fixedDiff + 18}] 7 $fixedHeight] [list 12 [expr {2*$fixedDiff + 31}] 7 $fixedHeight] [list 5 [expr {3*$fixedDiff + 44}] 7 $fixedHeight] {2.0 2.20}]
test textDisp-4.3 {UpdateDisplayInfo, tail of text line shifts} {textfonts} {
.t delete 1.0 end
.t insert end "Line 1\nLine 2 is so long that it wraps around\nLine 3"
@@ -1148,6 +1152,41 @@ test textDisp-8.11 {TkTextChanged, scrollbar notification when changes are off-s
.t configure -yscrollcommand ""
set scrollInfo
} {0.0 0.625}
+test textDisp-8.12 {TkTextChanged, moving the insert cursor redraws only past and new lines} {
+ .t delete 1.0 end
+ .t configure -wrap none
+ for {set i 1} {$i < 25} {incr i} {
+ .t insert end "Line $i Line $i\n"
+ }
+ .t tag add hidden 5.0 8.0
+ .t tag configure hidden -elide true
+ .t mark set insert 9.0
+ update
+ .t mark set insert 8.0 ; # up one line
+ update
+ set res [list $tk_textRedraw]
+ .t mark set insert 12.2 ; # in the visible text
+ update
+ lappend res $tk_textRedraw
+ .t mark set insert 6.5 ; # in the hidden text
+ update
+ lappend res $tk_textRedraw
+ .t mark set insert 3.5 ; # in the visible text again
+ update
+ lappend res $tk_textRedraw
+ .t mark set insert 3.8 ; # within the same line
+ update
+ lappend res $tk_textRedraw
+ # This last one is tricky: correct result really is {2.0 3.0} when
+ # calling .t mark set insert, two calls to TkTextChanged are done:
+ # (a) to redraw the line of the past position of the cursor
+ # (b) to redraw the line of the new position of the cursor
+ # During (a) the display line showing the cursor gets unlinked,
+ # which leads TkTextChanged in (b) to schedule a redraw starting
+ # one line _before_ the line containing the insert cursor. This is
+ # because during (b) findDLine cannot return the display line the
+ # cursor is in since this display line was just unlinked in (a).
+} {{8.0 9.0} {8.0 12.0} {8.0 12.0} {3.0 8.0} {2.0 3.0}}
test textDisp-9.1 {TkTextRedrawTag} {
.t configure -wrap char
@@ -1173,40 +1212,44 @@ test textDisp-9.3 {TkTextRedrawTag} {
.t insert 1.0 "Line 1\nLine 2 is long enough to wrap around\nLine 3\nLine 4"
update
.t tag add big 2.2 2.4
+ update
.t tag remove big 1.0 end
update
list $tk_textRelayout $tk_textRedraw
-} {2.0 2.0}
+} {{2.0 2.20} {2.0 2.20 eof}}
test textDisp-9.4 {TkTextRedrawTag} {
.t configure -wrap char
.t delete 1.0 end
.t insert 1.0 "Line 1\nLine 2 is long enough to wrap around\nLine 3\nLine 4"
update
.t tag add big 2.2 2.20
+ update
.t tag remove big 1.0 end
update
list $tk_textRelayout $tk_textRedraw
-} {2.0 2.0}
+} {{2.0 2.20} {2.0 2.20 eof}}
test textDisp-9.5 {TkTextRedrawTag} {
.t configure -wrap char
.t delete 1.0 end
.t insert 1.0 "Line 1\nLine 2 is long enough to wrap around\nLine 3\nLine 4"
update
.t tag add big 2.2 2.end
+ update
.t tag remove big 1.0 end
update
list $tk_textRelayout $tk_textRedraw
-} {{2.0 2.20} {2.0 2.20}}
+} {{2.0 2.20} {2.0 2.20 eof}}
test textDisp-9.6 {TkTextRedrawTag} {
.t configure -wrap char
.t delete 1.0 end
- .t insert 1.0 "Line 1\nLine 2 is long enough to wrap\nLine 3 is also long enough to wrap\nLine 4"
+ .t insert 1.0 "Line 1\nLine 2 is long enough to wrap\nLine 3 is also long enough to wrap"
update
.t tag add big 2.2 3.5
+ update
.t tag remove big 1.0 end
update
list $tk_textRelayout $tk_textRedraw
-} {{2.0 2.20 3.0} {2.0 2.20 3.0}}
+} {{2.0 2.20 3.0 3.20} {2.0 2.20 3.0 3.20 eof}}
test textDisp-9.7 {TkTextRedrawTag} {
.t configure -wrap char
.t delete 1.0 end
@@ -1258,6 +1301,34 @@ test textDisp-9.11 {TkTextRedrawTag} {
update
set tk_textRedraw
} {}
+test textDisp-9.12 {TkTextRedrawTag} {
+ .t configure -wrap char
+ .t delete 1.0 end
+ for {set i 1} {$i < 5} {incr i} {
+ .t insert end "Line $i+++Line $i\n"
+ }
+ .t tag configure hidden -elide true
+ .t tag add hidden 2.6 3.6
+ update
+ .t tag add hidden 3.11 4.6
+ update
+ list $tk_textRelayout $tk_textRedraw
+} {2.0 {2.0 eof}}
+test textDisp-9.13 {TkTextRedrawTag} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ for {set i 1} {$i < 10} {incr i} {
+ .t insert end "Line $i - This is Line [format %c [expr 64+$i]]\n"
+ }
+ .t tag add hidden 2.8 2.17
+ .t tag add hidden 6.8 7.17
+ .t tag configure hidden -background red
+ .t tag configure hidden -elide true
+ update
+ .t tag configure hidden -elide false
+ update
+ list $tk_textRelayout $tk_textRedraw
+} {{2.0 6.0 7.0} {2.0 6.0 7.0}}
test textDisp-10.1 {TkTextRelayoutWindow} {
.t configure -wrap char
@@ -1426,7 +1497,7 @@ test textDisp-11.15 {TkTextSetYView, only a few lines visible} {
update
.top.t see 11.0
.top.t index @0,0
- # Thie index 9.0 should be just visible by a couple of pixels
+ # The index 9.0 should be just visible by a couple of pixels
} {9.0}
test textDisp-11.16 {TkTextSetYView, only a few lines visible} {
.top.t yview 8.0
@@ -1439,9 +1510,54 @@ test textDisp-11.17 {TkTextSetYView, only a few lines visible} {
update
.top.t see 4.0
.top.t index @0,0
- # Thie index 2.0 should be just visible by a couple of pixels
+ # The index 2.0 should be just visible by a couple of pixels
} {2.0}
-destroy .top
+test textDisp-11.18 {TkTextSetYView, see in elided lines} {
+ .top.t delete 1.0 end
+ for {set i 1} {$i < 20} {incr i} {
+ .top.t insert end [string repeat "Line $i" 10]
+ .top.t insert end "\n"
+ }
+ .top.t yview 4.0
+ .top.t tag add hidden 4.10 "4.10 lineend"
+ .top.t tag add hidden 5.15 10.3
+ .top.t tag configure hidden -elide true
+ update
+ .top.t see "8.0 lineend"
+ # The index "8.0 lineend" is on screen despite elided -> no scroll
+ .top.t index @0,0
+} {4.0}
+test textDisp-11.19 {TkTextSetYView, see in elided lines} {
+ .top.t delete 1.0 end
+ for {set i 1} {$i < 50} {incr i} {
+ .top.t insert end "Line $i\n"
+ }
+ # button just for having a line with a larger height
+ button .top.t.b -text "Test" -bd 2 -highlightthickness 2
+ .top.t window create 21.0 -window .top.t.b
+ .top.t tag add hidden 15.36 21.0
+ .top.t tag configure hidden -elide true
+ .top.t configure -height 15
+ wm geometry .top 300x200+0+0
+ # Indices 21.0, 17.0 and 15.0 are all on the same display line
+ # therefore index @0,0 shall be the same for all of them
+ .top.t see end
+ update
+ .top.t see 21.0
+ update
+ set ind1 [.top.t index @0,0]
+ .top.t see end
+ update
+ .top.t see 17.0
+ update
+ set ind2 [.top.t index @0,0]
+ .top.t see end
+ update
+ .top.t see 15.0
+ update
+ set ind3 [.top.t index @0,0]
+ list [expr {$ind1 == $ind2}] [expr {$ind1 == $ind3}]
+} {1 1}
.t configure -wrap word
.t delete 50.0 51.0
@@ -1583,6 +1699,29 @@ test textDisp-13.10 {TkTextSeeCmd procedure} {} {
destroy $w
set res
} {}
+test textDisp-13.11 {TkTextSeeCmd procedure} {} {
+ # insertion of a character at end of a line containing multi-byte
+ # characters and calling see at the line end shall actually show
+ # this character
+ toplevel .top2
+ pack [text .top2.t2 -wrap none]
+ for {set i 1} {$i < 5} {incr i} {
+ .top2.t2 insert end [string repeat "Line $i: éèàçù" 5]\n
+
+ }
+ wm geometry .top2 300x200+0+0
+ update
+ .top2.t2 see "1.0 lineend"
+ update
+ set ref [.top2.t2 index @0,0]
+ .top2.t2 insert "1.0 lineend" ç
+ .top2.t2 see "1.0 lineend"
+ update
+ set new [.top2.t2 index @0,0]
+ set res [.top2.t2 compare $ref == $new]
+ destroy .top2
+ set res
+} {0}
wm geom . {}
.t configure -wrap none
@@ -2019,6 +2158,70 @@ test textDisp-16.40 {text count -xpixels} {
[.t count -xpixels 1.0 "1.0 displaylineend"] \
[.t count -xpixels 1.0 end]
} {35 -35 0 42 42 42 0}
+test textDisp-16.41 {text count -xpixels with indices in elided lines} {
+ set res {}
+ .t delete 1.0 end
+ for {set i 1} {$i < 40} {incr i} {
+ .t insert end [string repeat "Line $i" 20]
+ .t insert end "\n"
+ }
+ .t configure -wrap none
+ .t tag add hidden 5.15 20.15
+ .t tag configure hidden -elide true
+ lappend res [.t count -xpixels 5.15 6.0] \
+ [.t count -xpixels 5.15 6.1] \
+ [.t count -xpixels 6.0 6.1] \
+ [.t count -xpixels 6.1 6.2] \
+ [.t count -xpixels 6.1 6.0] \
+ [.t count -xpixels 6.0 7.0] \
+ [.t count -xpixels 6.1 7.1] \
+ [.t count -xpixels 15.0 20.15] \
+ [.t count -xpixels 20.15 20.16] \
+ [.t count -xpixels 20.16 20.15]
+ .t tag remove hidden 20.0 20.15
+ lappend res [expr {[.t count -xpixels 5.0 20.0] != 0}]
+} [list 0 0 0 0 0 0 0 0 $fixedWidth -$fixedWidth 1]
+test textDisp-16.42 {TkTextYviewCmd procedure with indices in elided lines} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ for {set i 1} {$i < 100} {incr i} {
+ .t insert end [string repeat "Line $i" 20]
+ .t insert end "\n"
+ }
+ .t tag add hidden 5.15 20.15
+ .t tag configure hidden -elide true
+ .t yview 35.0
+ .t yview scroll [expr {- 15 * $fixedHeight}] pixels
+ update
+ .t index @0,0
+} {5.0}
+test textDisp-16.43 {TkTextYviewCmd procedure with indices in elided lines} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ for {set i 1} {$i < 100} {incr i} {
+ .t insert end [string repeat "Line $i" 20]
+ .t insert end "\n"
+ }
+ .t tag add hidden 5.15 20.15
+ .t tag configure hidden -elide true
+ .t yview 35.0
+ .t yview scroll -15 units
+ update
+ .t index @0,0
+} {5.0}
+test textDisp-16.44 {TkTextYviewCmd procedure, scroll down, with elided lines} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ foreach x [list 0 1 2 3 4 5 6 7 8 9 0] {
+ .t insert end "$x aaa1\n$x bbb2\n$x ccc3\n$x ddd4\n$x eee5\n$x fff6"
+ .t insert end "$x 1111\n$x 2222\n$x 3333\n$x 4444\n$x 5555\n$x 6666" hidden
+ }
+ .t tag configure hidden -elide true ; # 5 hidden lines
+ update
+ .t see [expr {5 + [winfo height .t] / $fixedHeight} + 1].0
+ update
+ .t index @0,0
+} {2.0}
.t delete 1.0 end
foreach i {a b c d e f g h i j k l m n o p q r s t u v w x y z} {
@@ -2553,6 +2756,63 @@ test textDisp-19.16 {count -ypixels} {
[.t count -ypixels 16.0 "16.0 displaylineend +1c"] \
[.t count -ypixels "16.0 +1 displaylines" "16.0 +4 displaylines +3c"]
} [list [expr {260 + 20 * $fixedDiff}] [expr {260 + 20 * $fixedDiff}] $fixedHeight [expr {2*$fixedHeight}] $fixedHeight [expr {3*$fixedHeight}]]
+test textDisp-19.17 {count -ypixels with indices in elided lines} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ for {set i 1} {$i < 100} {incr i} {
+ .t insert end [string repeat "Line $i" 20]
+ .t insert end "\n"
+ }
+ .t tag add hidden 5.15 20.15
+ .t tag configure hidden -elide true
+ set res {}
+ update
+ lappend res \
+ [.t count -ypixels 1.0 6.0] \
+ [.t count -ypixels 2.0 7.5] \
+ [.t count -ypixels 5.0 8.5] \
+ [.t count -ypixels 6.1 6.2] \
+ [.t count -ypixels 6.1 18.8] \
+ [.t count -ypixels 18.0 20.50] \
+ [.t count -ypixels 5.2 20.60] \
+ [.t count -ypixels 20.60 20.70] \
+ [.t count -ypixels 5.0 25.0] \
+ [.t count -ypixels 25.0 5.0] \
+ [.t count -ypixels 25.4 27.50] \
+ [.t count -ypixels 35.0 38.0]
+ .t yview 35.0
+ lappend res [.t count -ypixels 5.0 25.0]
+} [list [expr {4 * $fixedHeight}] [expr {3 * $fixedHeight}] 0 0 0 0 0 0 [expr {5 * $fixedHeight}] [expr {- 5 * $fixedHeight}] [expr {2 * $fixedHeight}] [expr {3 * $fixedHeight}] [expr {5 * $fixedHeight}]]
+test textDisp-19.18 {count -ypixels with indices in elided lines} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ for {set i 1} {$i < 100} {incr i} {
+ .t insert end [string repeat "Line $i" 20]
+ .t insert end "\n"
+ }
+ .t tag add hidden 5.15 20.15
+ .t tag configure hidden -elide true
+ .t yview 35.0
+ set res {}
+ update
+ lappend res [.t count -ypixels 5.0 25.0]
+ .t yview scroll [expr {- 15 * $fixedHeight}] pixels
+ update
+ lappend res [.t count -ypixels 5.0 25.0]
+} [list [expr {5 * $fixedHeight}] [expr {5 * $fixedHeight}]]
+test textDisp-19.19 {count -ypixels with indices in elided lines} {
+ .t configure -wrap char
+ .t delete 1.0 end
+ for {set i 1} {$i < 25} {incr i} {
+ .t insert end [string repeat "Line $i -" 6]
+ .t insert end "\n"
+ }
+ .t tag add hidden 5.27 11.0
+ .t tag configure hidden -elide true
+ .t yview 5.0
+ update
+ set res [list [.t count -ypixels 5.0 11.0] [.t count -ypixels 5.0 11.20]]
+} [list [expr {1 * $fixedHeight}] [expr {2 * $fixedHeight}]]
.t delete 1.0 end
.t insert end "Line 1"
for {set i 2} {$i <= 200} {incr i} {
@@ -2722,6 +2982,42 @@ test textDisp-22.9 {TkTextCharBbox, handling of spacing} {textfonts} {
[.t bbox 1.1] [.t bbox 2.9]
} [list [list 24 11 10 4] [list 55 [expr {$fixedDiff/2 + 15}] 10 4] [list 10 [expr {2*$fixedDiff + 43}] 10 4] [list 76 [expr {2*$fixedDiff + 40}] 10 4] [list 10 11 7 $fixedHeight] [list 69 [expr {$fixedDiff + 34}] 7 $fixedHeight]]
.t tag delete spacing
+test textDisp-22.10 {TkTextCharBbox, handling of elided lines} {textfonts} {
+ .t configure -wrap char
+ .t delete 1.0 end
+ for {set i 1} {$i < 10} {incr i} {
+ .t insert end "Line $i - Line [format %c [expr 64+$i]]\n"
+ }
+ .t tag add hidden 2.8 2.13
+ .t tag add hidden 6.8 7.13
+ .t tag configure hidden -elide true
+ update
+ list \
+ [expr {[lindex [.t bbox 2.9] 0] - [lindex [.t bbox 2.8] 0]}] \
+ [expr {[lindex [.t bbox 2.10] 0] - [lindex [.t bbox 2.8] 0]}] \
+ [expr {[lindex [.t bbox 2.13] 0] - [lindex [.t bbox 2.8] 0]}] \
+ [expr {[lindex [.t bbox 6.9] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 6.10] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 6.13] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 6.14] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 6.15] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 7.0] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 7.1] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 7.12] 0] - [lindex [.t bbox 6.8] 0]}]
+} [list 0 0 0 0 0 0 0 0 0 0 0]
+test textDisp-22.11 {TkTextCharBbox, handling of wrapped elided lines} {textfonts} {
+ .t configure -wrap char
+ .t delete 1.0 end
+ for {set i 1} {$i < 10} {incr i} {
+ .t insert end "Line $i - Line _$i - Lines .$i - Line [format %c [expr 64+$i]]\n"
+ }
+ .t tag add hidden 1.30 2.5
+ .t tag configure hidden -elide true
+ update
+ list \
+ [expr {[lindex [.t bbox 1.30] 0] - [lindex [.t bbox 2.4] 0]}] \
+ [expr {[lindex [.t bbox 1.30] 0] - [lindex [.t bbox 2.5] 0]}]
+} [list 0 0]
.t delete 1.0 end
.t insert end "Line 1"
diff --git a/tests/ttk/spinbox.test b/tests/ttk/spinbox.test
index 3397e37..f7741c6 100644
--- a/tests/ttk/spinbox.test
+++ b/tests/ttk/spinbox.test
@@ -144,7 +144,7 @@ test spinbox-1.8.4 "-validate option: " -setup {
pack .sb
.sb set 50
focus .sb
- after 100 {set ::spinbox_wait 1} ; vwait ::spinbox_wait
+ after 500 {set ::spinbox_wait 1} ; vwait ::spinbox_wait
set ::spinbox_test
} -cleanup {
destroy .sb