[PATCH 1/1] [bug1175 & 2663] TOOLBAR SetRows is unimplemented

Jason Edmeades jason.edmeades at googlemail.com
Mon Aug 27 15:30:16 CDT 2007


SetRows specifies the requested number of rows, and a flag to say grow or
not if you cannot achieve that number. Currently this is unimplemented and
this patch adds enough basic support to make the program in question display
better. (I would say perfect, but I think the known issues with toolbar sizes
results in a small strip of garbage on the toolbar).

What this patch does not handle is separators, and I spent too long trying
to work out an algorithum to match windows and in the end left it as a fixme
for future implementation as I dont need it for the app in question. Tests
are included to ensure the code I have added functions as expected (tested on
XP and wine).
---
 dlls/comctl32/tests/toolbar.c |   56 ++++++++++++++++++++++
 dlls/comctl32/toolbar.c       |  104 +++++++++++++++++++++++++++++++++++++----
 2 files changed, 150 insertions(+), 10 deletions(-)

diff --git a/dlls/comctl32/tests/toolbar.c b/dlls/comctl32/tests/toolbar.c
index b46ef0d..c9274e9 100644
--- a/dlls/comctl32/tests/toolbar.c
+++ b/dlls/comctl32/tests/toolbar.c
@@ -1032,6 +1032,61 @@ static void test_dispinfo(void)
     g_dwExpectedDispInfoMask = 0;
 }
 
+typedef struct
+{
+    int  nRows;
+    BOOL bLarger;
+    int  expectedRows;
+} tbrows_result_t;
+
+static tbrows_result_t tbrows_results[] =
+{
+    {1, TRUE,  1}, /* 0: Simple case 9 in a row */
+    {2, TRUE,  2}, /* 1: Another simple case 5 on one row, 4 on another*/
+    {3, FALSE, 3}, /* 2: 3 lines - should be 3 lines of 3 buttons */
+    {8, FALSE, 5}, /* 3: 8 lines - should be 5 lines of 2 buttons */
+    {8, TRUE,  9}, /* 4: 8 lines but grow - should be 9 lines */
+    {1, TRUE,  1}  /* 5: Back to simple case */
+};
+
+static void test_setrows(void)
+{
+    TBBUTTON buttons[9];
+    HWND hToolbar;
+    int i;
+
+    for (i=0; i<9; i++)
+        MakeButton(buttons+i, 1000+i, TBSTYLE_FLAT | TBSTYLE_CHECKGROUP, 0);
+
+    /* Test 1 - 9 buttons */
+    hToolbar = CreateToolbarEx(hMainWnd,
+        WS_VISIBLE | WS_CLIPCHILDREN | WS_CHILD | CCS_NORESIZE | CCS_NOPARENTALIGN  
+        | CCS_NOMOVEY | CCS_TOP,
+        0,
+        0, NULL, (UINT)0,
+        buttons, sizeof(buttons)/sizeof(buttons[0]),
+        20, 20, 0, 0, sizeof(TBBUTTON));
+    ok(hToolbar != NULL, "Toolbar creation\n");
+    ok(SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
+
+    /* test setting rows to each of 1-10 with bLarger true and false */
+    for (i=0; i<(sizeof(tbrows_results) / sizeof(tbrows_result_t)); i++) {
+        RECT rc;
+        int rows;
+
+        memset(&rc, 0xCC, sizeof(rc));
+        SendMessageA(hToolbar, TB_SETROWS,
+                     MAKELONG(tbrows_results[i].nRows, tbrows_results[i].bLarger),
+                     (LONG) &rc);
+
+        rows = SendMessageA(hToolbar, TB_GETROWS, MAKELONG(0,0), MAKELONG(0,0));
+        ok(rows == tbrows_results[i].expectedRows, 
+                   "[%d] Unexpected number of rows %d (expected %d)\n", i, rows, 
+                   tbrows_results[i].expectedRows);
+    }
+
+    DestroyWindow(hToolbar);
+}
 
 START_TEST(toolbar)
 {
@@ -1066,6 +1121,7 @@ START_TEST(toolbar)
     test_getbuttoninfo();
     test_createtoolbarex();
     test_dispinfo();
+    test_setrows();
 
     PostQuitMessage(0);
     while(GetMessageA(&msg,0,0,0)) {
diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c
index 275d3d5..8ca4e6b 100644
--- a/dlls/comctl32/toolbar.c
+++ b/dlls/comctl32/toolbar.c
@@ -44,7 +44,7 @@
  *     - TBN_GETOBJECT
  *     - TBN_SAVE
  *   - Button wrapping (under construction).
- *   - Fix TB_SETROWS.
+ *   - Fix TB_SETROWS and Separators.
  *   - iListGap custom draw support.
  *
  * Testing:
@@ -3637,10 +3637,7 @@ TOOLBAR_GetRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
 
-    if (infoPtr->dwStyle & TBSTYLE_WRAPABLE)
-	return infoPtr->nRows;
-    else
-	return 1;
+    return infoPtr->nRows;
 }
 
 
@@ -4947,20 +4944,107 @@ TOOLBAR_SetRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
     LPRECT lprc = (LPRECT)lParam;
+    int rows = LOWORD(wParam);
+    BOOL bLarger = HIWORD(wParam);
 
     TRACE("\n");
 
-    if (LOWORD(wParam) > 1) {
-	FIXME("multiple rows not supported!\n");
-    }
+    TRACE("Setting rows to %d (%d)\n", rows, bLarger);
 
-    if(infoPtr->nRows != LOWORD(wParam))
+    if(infoPtr->nRows != rows)
     {
-        infoPtr->nRows = LOWORD(wParam);
+        TBUTTON_INFO *btnPtr = infoPtr->buttons;
+        int curColumn = 0; /* Current column                      */
+        int curRow    = 0; /* Current row                         */
+        int hidden    = 0; /* Number of hidden buttons */
+        int seps      = 0; /* Number of separators     */
+        int idealWrap = 0; /* Ideal wrap point         */
+        int i;
+        BOOL wrap;
+
+        /*
+           Calculate new size and wrap points - Under windows, setrows will
+           change the dimensions if needed to show the number of requested
+           rows (if CCS_NORESIZE is set), or will take up the whole window
+           (if no CCS_NORESIZE).
+
+           Basic algorithum - If N buttons, and y rows requested, each row
+           contains N/y buttons.
+
+           FIXME: Handling of separators not obvious from testing results
+           FIXME: Take width of window into account?
+         */
+
+        /* Loop through the buttons one by one counting key items  */
+        for (i = 0; i < infoPtr->nNumButtons; i++ )
+        {
+            btnPtr[i].fsState &= ~TBSTATE_WRAP;
+            if (btnPtr[i].fsState & TBSTATE_HIDDEN)
+                hidden++;
+            else if (btnPtr[i].fsStyle & BTNS_SEP)
+                seps++;
+        }
+
+        /* FIXME: Separators make this quite complex */
+        if (seps) FIXME("Separators unhandled\n");
+
+        /* Round up so more per line, ie less rows */
+        idealWrap = (infoPtr->nNumButtons - hidden + (rows-1)) / rows;
+
+        /* Calculate ideal wrap point if we are allowed to grow, but cannot
+           achieve the requested number of rows. */
+        if (bLarger && idealWrap > 1)
+        {
+            int resRows = (infoPtr->nNumButtons + (idealWrap-1)) / idealWrap;
+            int moreRows = (infoPtr->nNumButtons + (idealWrap-2)) / (idealWrap-1);
+
+            if (resRows < rows && moreRows > rows)
+            {
+                idealWrap--;
+                TRACE("Changing idealWrap due to bLarger (now %d)\n", idealWrap);
+            }
+        }
+
+        curColumn = curRow = 0;
+        wrap = FALSE;
+        TRACE("Trying to wrap at %d (%d,%d,%d)\n", idealWrap,
+              infoPtr->nNumButtons, hidden, rows);
+
+        for (i = 0; i < infoPtr->nNumButtons; i++ )
+        {
+            if (btnPtr[i].fsState & TBSTATE_HIDDEN)
+                continue;
+
+            /* Step on, wrap if necessary or flag next to wrap */
+            if (!wrap) {
+                curColumn++;
+            } else {
+                wrap = FALSE;
+                curColumn = 1;
+                curRow++;
+            }
+
+            if (curColumn > (idealWrap-1)) {
+                wrap = TRUE;
+                btnPtr[i].fsState |= TBSTATE_WRAP;
+            }
+        }
+
+        TRACE("Result - %d rows\n", curRow + 1);
 
         /* recalculate toolbar */
         TOOLBAR_CalcToolbar (hwnd);
 
+        /* Resize if necessary (Only if NORESIZE is set - odd, but basically
+           if NORESIZE is NOT set, then the toolbar will always be resized to
+           take up the whole window. With it set, sizing needs to be manual. */
+        if (infoPtr->dwStyle & CCS_NORESIZE) {
+            SetWindowPos(hwnd, NULL, 0, 0,
+                         infoPtr->rcBound.right - infoPtr->rcBound.left,
+                         infoPtr->rcBound.bottom - infoPtr->rcBound.top,
+                         SWP_NOMOVE);
+        }
+
         /* repaint toolbar */
         InvalidateRect(hwnd, NULL, TRUE);
     }
-- 
1.5.0




More information about the wine-patches mailing list