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 f2e3656 + 4a89f7e commit 609726a
Showing 1 changed file with 124 additions and 32 deletions.
156 changes: 124 additions & 32 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 @@ -1754,6 +1754,10 @@ static int BoundingBox(
int dispRow;
Ttk_Box bbox = tv->tree.treeArea;

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

if (tv->tree.rowPosNeedsUpdate) {
UpdatePositionTree(tv);
}
Expand Down Expand Up @@ -1920,7 +1924,9 @@ static Ttk_Layout TreeviewGetLayout(
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, "-columnseparatorwidth", 0))) {
(void)Tk_GetPixelsFromObj(NULL, tv->core.tkwin, objPtr, &tv->tree.colSeparatorWidth);
Expand Down Expand Up @@ -2178,11 +2184,6 @@ static void DrawCells(
xPad = tv->tree.colSeparatorWidth/2;
}

/* 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;
}

/* An Item's image should not propagate to a Cell.
A Cell's image can only be set by cell tags. */
displayItemCell = *displayItem;
Expand Down Expand Up @@ -2264,31 +2265,28 @@ static void DrawItem(
Ttk_Style style = Ttk_LayoutStyle(tv->core.layout);
Ttk_State state = ItemState(tv, item);
DisplayItem displayItem, displayItemSel, displayItemLocal;
int rowHeight = tv->tree.rowHeight * item->height;
int x = tv->tree.treeArea.x - tv->tree.xscroll.first;
int xTitle = tv->tree.treeArea.x;
int dispRow = DisplayRow(item->rowPos, tv);
int y = tv->tree.treeArea.y + tv->tree.rowHeight * dispRow;
int x, y, h, xTitle, dispRow, rowHeight;

/* 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;
dispRow = DisplayRow(item->rowPos, tv);
h = tv->tree.rowHeight * dispRow;
if (h >= tv->tree.treeArea.height) {
/* The item is outside the visible area */
return;
}

rowHeight = tv->tree.rowHeight * item->height;
x = tv->tree.treeArea.x - tv->tree.xscroll.first;
xTitle = tv->tree.treeArea.x;
y = tv->tree.treeArea.y + h;

PrepareItem(tv, item, &displayItem, state);
PrepareItem(tv, item, &displayItemSel, state | TTK_STATE_SELECTED);

/* 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 @@ -2406,19 +2404,99 @@ static void DrawForest(
}
}

/* + 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);
DrawSeparators(tv, d);
}

/* + 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;
}

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

/*------------------------------------------------------------------------
Expand Down Expand Up @@ -2877,6 +2955,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 @@ -3465,11 +3547,18 @@ static int TreeviewSeeCommand(
- tv->tree.titleRows;
scrollRow1 = item->rowPos - tv->tree.titleRows;
scrollRow2 = scrollRow1 + item->height - 1;

if (scrollRow2 >= tv->tree.yscroll.first + visibleRows) {
scrollRow2 = 1 + scrollRow2 - visibleRows;
TtkScrollTo(tv->tree.yscrollHandle, scrollRow2, 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 (scrollRow1 < tv->tree.yscroll.first || item->height > visibleRows) {
TtkScrollTo(tv->tree.yscrollHandle, scrollRow1, 1);
} else if (scrollRow2 >= tv->tree.yscroll.first + visibleRows) {
scrollRow1 = 1 + scrollRow2 - visibleRows;
TtkScrollTo(tv->tree.yscrollHandle, scrollRow1, 1);
}

return TCL_OK;
Expand Down Expand Up @@ -4174,7 +4263,10 @@ static int TreeviewTagAddCommand(
/* Make sure tagset at column is allocated and initialised */
static void AllocCellTagSets(Treeview *tv, TreeItem *item, Tcl_Size columnNumber)
{
Tcl_Size i, newSize = MAX(columnNumber + 1, tv->tree.nColumns + 1);
Tcl_Size i, newSize = columnNumber + 1;
if (newSize < tv->tree.nColumns + 1) {
newSize = tv->tree.nColumns + 1;
}
if (item->nTagSets < newSize) {
if (item->cellTagSets == NULL) {
item->cellTagSets = (Ttk_TagSet *)
Expand Down

0 comments on commit 609726a

Please sign in to comment.