Skip to content

Commit

Permalink
Merge more ttk::treeview improvements related to bug [d82fa2953a].
Browse files Browse the repository at this point in the history
  • Loading branch information
sbron committed Aug 28, 2024
2 parents 1d99e1c + c3a4df9 commit 4a89f7e
Showing 1 changed file with 119 additions and 29 deletions.
148 changes: 119 additions & 29 deletions generic/ttk/ttkTreeview.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#ifdef _WIN32
#include "tkWinInt.h"
#elif defined(MAC_OSX_TK)
#include "tkMacOSXPrivate.h"
#endif

#define DEF_TREE_ROWS "10"
Expand All @@ -25,8 +27,6 @@ static const int HALO = 4; /* heading separator */

#define STATE_CHANGED (0x100) /* item state option changed */

#define MAX(a,b) (((a) > (b)) ? (a) : (b))

/*------------------------------------------------------------------------
* +++ Tree items.
*
Expand Down Expand Up @@ -1457,6 +1457,10 @@ static int BoundingBox(
int row = ItemRow(tv, item);
Ttk_Box bbox = tv->tree.treeArea;

/* Make sure the scroll information is current before use */
TtkUpdateScrollInfo(tv->tree.xscrollHandle);
TtkUpdateScrollInfo(tv->tree.yscrollHandle);

if (row < tv->tree.yscroll.first || row > tv->tree.yscroll.last) {
/* not viewable, or off-screen */
return 0;
Expand Down Expand Up @@ -1597,7 +1601,9 @@ static Ttk_Layout TreeviewGetLayout(
tv->tree.indent = DEFAULT_INDENT;
if ((objPtr = Ttk_QueryOption(treeLayout, "-rowheight", 0))) {
(void)Tk_GetPixelsFromObj(NULL, tv->core.tkwin, objPtr, &tv->tree.rowHeight);
tv->tree.rowHeight = MAX(tv->tree.rowHeight, 1);
if (tv->tree.rowHeight < 1) {
tv->tree.rowHeight = 1;
}
}
if ((objPtr = Ttk_QueryOption(treeLayout, "-indent", 0))) {
(void)Tk_GetPixelsFromObj(NULL, tv->core.tkwin, objPtr, &tv->tree.indent);
Expand Down Expand Up @@ -1733,11 +1739,6 @@ static void DrawCells(
return;
}

/* Make sure that the cells won't overlap the border's bottom edge */
if (y + rowHeight > tv->tree.treeArea.y + tv->tree.treeArea.height) {
rowHeight = tv->tree.treeArea.y + tv->tree.treeArea.height - y;
}

Tcl_ListObjGetElements(NULL, item->valuesObj, &nValues, &values);
for (i = 0; i < tv->tree.nColumns; ++i) {
tv->tree.columns[i].data = (i < nValues) ? values[i] : 0;
Expand All @@ -1764,15 +1765,16 @@ static void DrawItem(
{
Ttk_State state = ItemState(tv, item);
DisplayItem displayItem;
int rowHeight = tv->tree.rowHeight;
int x = tv->tree.treeArea.x - tv->tree.xscroll.first;
int y = tv->tree.treeArea.y + rowHeight * (row - tv->tree.yscroll.first);

/* Make sure that the item won't overlap the border's bottom edge:
*/
if (y + rowHeight > tv->tree.treeArea.y + tv->tree.treeArea.height) {
rowHeight = tv->tree.treeArea.y + tv->tree.treeArea.height - y;
int x, y, h, rowHeight;

rowHeight = tv->tree.rowHeight;
h = rowHeight * (row - tv->tree.yscroll.first);
if (h >= tv->tree.treeArea.height) {
/* The item is outside the visible area */
return;
}
x = tv->tree.treeArea.x - tv->tree.xscroll.first;
y = tv->tree.treeArea.y + h;

if (row % 2) state |= TTK_STATE_ALTERNATE;

Expand All @@ -1781,13 +1783,8 @@ static void DrawItem(
/* Draw row background:
*/
{
int itemWidth = TreeWidth(tv);
/* Make sure that the background won't overlap the border's right edge:
*/
if (itemWidth > tv->tree.treeArea.width) {
itemWidth = tv->tree.treeArea.width;
}
Ttk_Box rowBox = Ttk_MakeBox(x, y, itemWidth, rowHeight);
Ttk_Box rowBox = Ttk_MakeBox(tv->tree.treeArea.x, y,
TreeWidth(tv), rowHeight);
DisplayLayout(tv->tree.rowLayout, &displayItem, state, rowBox, d);
}

Expand Down Expand Up @@ -1850,18 +1847,98 @@ static int DrawForest(
return row;
}

/* + DrawTreeArea --
* Draw the tree area including the headings, if any
*/
static void DrawTreeArea(Treeview *tv, Drawable d) {
if (tv->tree.showFlags & SHOW_HEADINGS) {
DrawHeadings(tv, d);
}
DrawForest(tv, tv->tree.root->children, d, 0, 0);
}

/* + TreeviewDisplay --
* Display() widget hook. Draw the widget contents.
*/
static void TreeviewDisplay(void *clientData, Drawable d)
{
Treeview *tv = (Treeview *)clientData;
Tk_Window tkwin = tv->core.tkwin;
int width, height, winWidth, winHeight;

/* Draw the general layout of the treeview widget */
Ttk_DrawLayout(tv->core.layout, tv->core.state, d);
if (tv->tree.showFlags & SHOW_HEADINGS) {
DrawHeadings(tv, d);

/* When the tree area does not fit in the available space, there is a
* risk that it will be drawn over other areas of the layout.
*/

winWidth = Tk_Width(tkwin);
winHeight = Tk_Height(tkwin);
width = tv->tree.treeArea.width;
height = tv->tree.headingArea.height + tv->tree.treeArea.height;

if ((width == winWidth && height == winHeight)
|| (tv->tree.treeArea.height % tv->tree.rowHeight == 0
&& TreeWidth(tv) <= width)) {
/* No protection is needed; either the tree area fills the entire
* widget, or everything fits within the available area.
*/
DrawTreeArea(tv, d);
} else {
/* The tree area needs to be clipped
*/

int x, y;

x = tv->tree.treeArea.x;
if (tv->tree.showFlags & SHOW_HEADINGS) {
y = tv->tree.headingArea.y;
} else {
y = tv->tree.treeArea.y;
}

#ifndef TK_NO_DOUBLE_BUFFERING
Drawable p;
XGCValues gcValues;
GC gc;

/* Create a temporary helper drawable */
p = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
winWidth, winHeight, Tk_Depth(tkwin));

/* Get a graphics context for copying the drawable content */
gcValues.function = GXcopy;
gcValues.graphics_exposures = False;
gc = Tk_GetGC(tkwin, GCFunction|GCGraphicsExposures, &gcValues);

/* Copy the widget background into the helper */
XCopyArea(Tk_Display(tkwin), d, p, gc, 0, 0,
(unsigned) winWidth, (unsigned) winHeight, 0, 0);

/* Draw the tree onto the helper without regard for borders */
DrawTreeArea(tv, p);

/* Copy only the tree area inside the borders back */
XCopyArea(Tk_Display(tkwin), p, d, gc, x, y,
(unsigned) width, (unsigned) height, x, y);

/* Clean up the temporary resources */
Tk_FreePixmap(Tk_Display(tkwin), p);
Tk_FreeGC(Tk_Display(tkwin), gc);
#else
Ttk_Theme currentTheme = Ttk_GetCurrentTheme(tv->core.interp);
Ttk_Theme aquaTheme = Ttk_GetTheme(tv->core.interp, "aqua");
if (currentTheme == aquaTheme && [NSApp macOSVersion] > 100800) {
y -= 4;
height += 4;
}

TkpClipDrawableToRect(Tk_Display(tkwin), d, x, y, width, height);
DrawTreeArea(tv, d);
TkpClipDrawableToRect(Tk_Display(tkwin), d, 0, 0, -1, -1);
#endif
}
DrawForest(tv, tv->tree.root->children, d, 0, 0);
}

/*------------------------------------------------------------------------
Expand Down Expand Up @@ -2318,6 +2395,10 @@ static int TreeviewIdentifyCommand(
return TCL_ERROR;
}

/* Make sure the scroll information is current before use */
TtkUpdateScrollInfo(tv->tree.xscrollHandle);
TtkUpdateScrollInfo(tv->tree.yscrollHandle);

region = IdentifyRegion(tv, x, y);
item = IdentifyItem(tv, y);
colno = IdentifyDisplayColumn(tv, x, &x1);
Expand Down Expand Up @@ -2873,12 +2954,21 @@ static int TreeviewSeeCommand(
/* Make sure item is visible:
*/
rowNumber = RowNumber(tv, item);
if (rowNumber < tv->tree.yscroll.first) {
TtkScrollTo(tv->tree.yscrollHandle, rowNumber, 1);
} else if (rowNumber >= tv->tree.yscroll.last) {
if (rowNumber < 0) {
/* The item cannot be moved into view because it is detached */
return TCL_OK;
}
if (rowNumber >= tv->tree.yscroll.last) {
TtkScrollTo(tv->tree.yscrollHandle,
tv->tree.yscroll.first + (1+rowNumber - tv->tree.yscroll.last), 1);
}
/* On small widgets (shorter than one row high, which is also the case
* before the widget is initially mapped) the above command will have
* scrolled down too far. This is why both conditions must be checked.
*/
if (rowNumber < tv->tree.yscroll.first) {
TtkScrollTo(tv->tree.yscrollHandle, rowNumber, 1);
}

return TCL_OK;
}
Expand Down

0 comments on commit 4a89f7e

Please sign in to comment.