summaryrefslogtreecommitdiffstats
path: root/win
diff options
context:
space:
mode:
authorcsaba <csaba>2023-11-05 15:24:15 (GMT)
committercsaba <csaba>2023-11-05 15:24:15 (GMT)
commitfe2ec559ed6b54e2b693f74ca0dcfabb9776e6c0 (patch)
tree795f688becdb1ab5b7efe53296ab01fff4a82002 /win
parent7b562ef10e88fa07f7439e279490e20eaf528944 (diff)
downloadtk-fe2ec559ed6b54e2b693f74ca0dcfabb9776e6c0.zip
tk-fe2ec559ed6b54e2b693f74ca0dcfabb9776e6c0.tar.gz
tk-fe2ec559ed6b54e2b693f74ca0dcfabb9776e6c0.tar.bz2
Attempt to fix the bug [eedd2e078d] (ttk::notebook looks bad when tabs are positioned on edges other than the top).
Diffstat (limited to 'win')
-rw-r--r--win/ttkWinTheme.c163
-rw-r--r--win/ttkWinXPTheme.c107
2 files changed, 267 insertions, 3 deletions
diff --git a/win/ttkWinTheme.c b/win/ttkWinTheme.c
index d526bfe..7f5450f 100644
--- a/win/ttkWinTheme.c
+++ b/win/ttkWinTheme.c
@@ -725,6 +725,168 @@ static const Ttk_ElementSpec SliderElementSpec = {
* +++ Notebook elements.
*/
+typedef struct {
+ Tcl_Obj *borderWidthObj;
+ Tcl_Obj *backgroundObj;
+} TabElement;
+
+static const Ttk_ElementOptionSpec TabElementOptions[] = {
+ { "-borderwidth", TK_OPTION_PIXELS,
+ offsetof(TabElement,borderWidthObj), "1" },
+ { "-background", TK_OPTION_BORDER,
+ offsetof(TabElement,backgroundObj), DEFAULT_BACKGROUND },
+ {0,TK_OPTION_BOOLEAN,0,0}
+};
+
+extern Ttk_PositionSpec nbTabsStickBit; /* see ttkNotebook.c */
+
+static void TabElementSize(
+ TCL_UNUSED(void *),
+ void *elementRecord,
+ Tk_Window tkwin,
+ TCL_UNUSED(void *),
+ TCL_UNUSED(void *),
+ Ttk_Padding *paddingPtr)
+{
+ TabElement *tab = (TabElement *)elementRecord;
+ int borderWidth = 1;
+
+ Tk_GetPixelsFromObj(0, tkwin, tab->borderWidthObj, &borderWidth);
+ *paddingPtr = Ttk_UniformPadding((short)borderWidth);
+}
+
+static void TabElementDraw(
+ TCL_UNUSED(void *),
+ void *elementRecord,
+ Tk_Window tkwin,
+ Drawable d,
+ Ttk_Box b,
+ unsigned int state)
+{
+ TabElement *tab = (TabElement *)elementRecord;
+ Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, tab->backgroundObj);
+ XPoint pts[6];
+ double scalingLevel = TkScalingLevel(tkwin);
+ int cut = round(2 * scalingLevel);
+ Display *disp = Tk_Display(tkwin);
+ int borderWidth = 1;
+
+ /*
+ * Correct the coordinates of b if needed.
+ */
+ switch (nbTabsStickBit) {
+ default:
+ case TTK_STICK_S:
+ break;
+ case TTK_STICK_N:
+ b.y -= 2;
+ break;
+ case TTK_STICK_E:
+ b.x += 2;
+ break;
+ case TTK_STICK_W:
+ b.x -= 2;
+ break;
+ }
+
+ if (state & TTK_STATE_SELECTED) {
+ /*
+ * Draw slightly outside of the allocated parcel,
+ * to overwrite the client area border.
+ */
+ switch (nbTabsStickBit) {
+ default:
+ case TTK_STICK_S:
+ b.height += 2;
+ break;
+ case TTK_STICK_N:
+ b.height += 2; b.y -= 2;
+ break;
+ case TTK_STICK_E:
+ b.width += 2;
+ break;
+ case TTK_STICK_W:
+ b.width += 2; b.x -= 2;
+ break;
+ }
+ }
+
+ switch (nbTabsStickBit) {
+ default:
+ case TTK_STICK_S:
+ pts[0].x = b.x; pts[0].y = b.y + b.height-1;
+ pts[1].x = b.x; pts[1].y = b.y + cut;
+ pts[2].x = b.x + cut; pts[2].y = b.y;
+ pts[3].x = b.x + b.width-1 - cut; pts[3].y = b.y;
+ pts[4].x = b.x + b.width-1; pts[4].y = b.y + cut;
+ pts[5].x = b.x + b.width-1; pts[5].y = b.y + b.height;
+ break;
+ case TTK_STICK_N:
+ pts[0].x = b.x; pts[0].y = b.y;
+ pts[1].x = b.x; pts[1].y = b.y + b.height-1 - cut;
+ pts[2].x = b.x + cut; pts[2].y = b.y + b.height-1;
+ pts[3].x = b.x + b.width-1 - cut; pts[3].y = b.y + b.height-1;
+ pts[4].x = b.x + b.width-1; pts[4].y = b.y + b.height-1 - cut;
+ pts[5].x = b.x + b.width-1; pts[5].y = b.y-1;
+ break;
+ case TTK_STICK_E:
+ pts[0].x = b.x + b.width-1; pts[0].y = b.y;
+ pts[1].x = b.x + cut; pts[1].y = b.y;
+ pts[2].x = b.x; pts[2].y = b.y + cut;
+ pts[3].x = b.x; pts[3].y = b.y + b.height-1 - cut;
+ pts[4].x = b.x + cut; pts[4].y = b.y + b.height-1;
+ pts[5].x = b.x + b.width; pts[5].y = b.y + b.height-1;
+ break;
+ case TTK_STICK_W:
+ pts[0].x = b.x; pts[0].y = b.y;
+ pts[1].x = b.x + b.width-1 - cut; pts[1].y = b.y;
+ pts[2].x = b.x + b.width-1; pts[2].y = b.y + cut;
+ pts[3].x = b.x + b.width-1; pts[3].y = b.y + b.height-1 - cut;
+ pts[4].x = b.x + b.width-1 - cut; pts[4].y = b.y + b.height-1;
+ pts[5].x = b.x-1; pts[5].y = b.y + b.height-1;
+ break;
+ }
+
+ XFillPolygon(disp, d, Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC),
+ pts, 6, Convex, CoordModeOrigin);
+
+ Tcl_GetIntFromObj(NULL, tab->borderWidthObj, &borderWidth);
+ while (borderWidth--) {
+ XDrawLines(disp, d, Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC),
+ pts, 4, CoordModeOrigin);
+ XDrawLines(disp, d, Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC),
+ pts+3, 3, CoordModeOrigin);
+
+ switch (nbTabsStickBit) {
+ default:
+ case TTK_STICK_S:
+ ++pts[0].x; ++pts[1].x; ++pts[2].y;
+ ++pts[3].y; --pts[4].x; --pts[5].x;
+ break;
+ case TTK_STICK_N:
+ ++pts[0].x; ++pts[1].x; --pts[2].y;
+ --pts[3].y; --pts[4].x; --pts[5].x;
+ break;
+ case TTK_STICK_E:
+ ++pts[0].y; ++pts[1].y; ++pts[2].x;
+ ++pts[3].x; --pts[4].y; --pts[5].y;
+ break;
+ case TTK_STICK_W:
+ ++pts[0].y; ++pts[1].y; --pts[2].x;
+ --pts[3].x; --pts[4].y; --pts[5].y;
+ break;
+ }
+ }
+}
+
+static const Ttk_ElementSpec TabElementSpec = {
+ TK_STYLE_VERSION_2,
+ sizeof(TabElement),
+ TabElementOptions,
+ TabElementSize,
+ TabElementDraw
+};
+
static void ClientElementSize(
TCL_UNUSED(void *),
TCL_UNUSED(void *),
@@ -814,6 +976,7 @@ int TtkWinTheme_Init(
Ttk_RegisterElementSpec(themePtr, "Scrollbar.trough", &TroughElementSpec,
TroughClientDataInit(interp));
+ Ttk_RegisterElementSpec(themePtr, "tab", &TabElementSpec, NULL);
Ttk_RegisterElementSpec(themePtr, "client", &ClientElementSpec, NULL);
for (fce = FrameControlElements; fce->name != 0; ++fce) {
diff --git a/win/ttkWinXPTheme.c b/win/ttkWinXPTheme.c
index 1ad3bfc..a4b53fc 100644
--- a/win/ttkWinXPTheme.c
+++ b/win/ttkWinXPTheme.c
@@ -27,6 +27,10 @@ typedef HRESULT (STDAPICALLTYPE CloseThemeDataProc)(HTHEME hTheme);
typedef HRESULT (STDAPICALLTYPE DrawThemeBackgroundProc)(HTHEME hTheme,
HDC hdc, int iPartId, int iStateId, const RECT *pRect,
OPTIONAL const RECT *pClipRect);
+typedef HRESULT (STDAPICALLTYPE DrawThemeEdgeProc)(HTHEME hTheme,
+ HDC hdc, int iPartId, int iStateId, const RECT *pDestRect,
+ unsigned int uEdge, unsigned int uFlags,
+ OPTIONAL RECT *pContentRect);
typedef HRESULT (STDAPICALLTYPE GetThemePartSizeProc)(HTHEME,HDC,
int iPartId, int iStateId,
RECT *prc, enum THEMESIZE eSize, SIZE *psz);
@@ -48,6 +52,7 @@ typedef struct
GetThemePartSizeProc *GetThemePartSize;
GetThemeSysSizeProc *GetThemeSysSize;
DrawThemeBackgroundProc *DrawThemeBackground;
+ DrawThemeEdgeProc *DrawThemeEdge;
DrawThemeTextProc *DrawThemeText;
GetThemeTextExtentProc *GetThemeTextExtent;
IsThemeActiveProc *IsThemeActive;
@@ -101,6 +106,7 @@ LoadXPThemeProcs(HINSTANCE *phlib)
&& LOADPROC(GetThemePartSize)
&& LOADPROC(GetThemeSysSize)
&& LOADPROC(DrawThemeBackground)
+ && LOADPROC(DrawThemeEdge)
&& LOADPROC(GetThemeTextExtent)
&& LOADPROC(DrawThemeText)
&& LOADPROC(IsThemeActive)
@@ -719,6 +725,38 @@ static const Ttk_ElementSpec PbarElementSpec =
* The TIS_* and TILES_* definitions are identical, so
* we can use the same statemap no matter what the partId.
*/
+
+extern Ttk_PositionSpec nbTabsStickBit; /* see ttkNotebook.c */
+
+static void TabElementSize(
+ void *clientData,
+ void *elementRecord,
+ Tk_Window tkwin,
+ int *widthPtr,
+ int *heightPtr,
+ Ttk_Padding *paddingPtr)
+{
+ GenericElementSize(clientData, elementRecord, tkwin,
+ widthPtr, heightPtr, paddingPtr);
+
+ *paddingPtr = Ttk_UniformPadding(3);
+ switch (nbTabsStickBit) {
+ default:
+ case TTK_STICK_S:
+ paddingPtr->bottom = 0;
+ break;
+ case TTK_STICK_N:
+ paddingPtr->top = 0;
+ break;
+ case TTK_STICK_E:
+ paddingPtr->right = 0;
+ break;
+ case TTK_STICK_W:
+ paddingPtr->left = 0;
+ break;
+ }
+}
+
static void TabElementDraw(
void *clientData,
TCL_UNUSED(void *),
@@ -729,15 +767,78 @@ static void TabElementDraw(
{
ElementData *elementData = (ElementData *)clientData;
int partId = elementData->info->partId;
+ int stateId = Ttk_StateTableLookup(elementData->info->statemap, state);
+
+ /*
+ * Correct the coordinates of b if needed
+ */
+ switch (nbTabsStickBit) {
+ default:
+ case TTK_STICK_S:
+ break;
+ case TTK_STICK_N:
+ b.y -= 4;
+ break;
+ case TTK_STICK_E:
+ b.x += 3;
+ break;
+ case TTK_STICK_W:
+ b.x -= 5;
+ break;
+ }
+
RECT rc = BoxToRect(b);
if (!InitElementData(elementData, tkwin, d))
return;
+
if (state & TTK_STATE_USER1)
partId = TABP_TABITEMLEFTEDGE;
elementData->procs->DrawThemeBackground(
- elementData->hTheme, elementData->hDC, partId,
- Ttk_StateTableLookup(elementData->info->statemap, state), &rc, NULL);
+ elementData->hTheme, elementData->hDC, partId, stateId, &rc, NULL);
+
+ if (nbTabsStickBit != TTK_STICK_S) {
+ /*
+ * Erase the border
+ */
+ elementData->procs->DrawThemeEdge(
+ elementData->hTheme, elementData->hDC, partId, stateId, &rc,
+ BDR_RAISEDINNER, BF_MONO|BF_RECT, NULL);
+ }
+
+ if (state & TTK_STATE_SELECTED) {
+ /*
+ * Draw a flat border at 3 edges
+ */
+ switch (nbTabsStickBit) {
+ default:
+ case TTK_STICK_S:
+ break;
+ case TTK_STICK_N:
+ elementData->procs->DrawThemeEdge(
+ elementData->hTheme, elementData->hDC, partId, stateId, &rc,
+ BDR_RAISEDINNER, BF_FLAT|BF_LEFT|BF_RIGHT|BF_BOTTOM, NULL);
+ break;
+ case TTK_STICK_E:
+ elementData->procs->DrawThemeEdge(
+ elementData->hTheme, elementData->hDC, partId, stateId, &rc,
+ BDR_RAISEDINNER, BF_FLAT|BF_LEFT|BF_TOP|BF_BOTTOM, NULL);
+ break;
+ case TTK_STICK_W:
+ elementData->procs->DrawThemeEdge(
+ elementData->hTheme, elementData->hDC, partId, stateId, &rc,
+ BDR_RAISEDINNER, BF_FLAT|BF_TOP|BF_RIGHT|BF_BOTTOM, NULL);
+ break;
+ }
+ } else if (nbTabsStickBit != TTK_STICK_S) {
+ /*
+ * Draw a flat border at all 4 edges
+ */
+ elementData->procs->DrawThemeEdge(
+ elementData->hTheme, elementData->hDC, partId, stateId, &rc,
+ BDR_RAISEDINNER, BF_FLAT|BF_RECT, NULL);
+ }
+
FreeElementData(elementData);
}
@@ -746,7 +847,7 @@ static const Ttk_ElementSpec TabElementSpec =
TK_STYLE_VERSION_2,
sizeof(NullElement),
TtkNullElementOptions,
- GenericElementSize,
+ TabElementSize,
TabElementDraw
};