[UXHTEME] - ThemeDrawCaptionText: Get the TMT_CONTENTALIGNMENT theme property and...
[reactos.git] / reactos / dll / win32 / uxtheme / nonclient.c
index e57ca74..ccf812c 100644 (file)
@@ -100,16 +100,7 @@ UserGetWindowIcon(PDRAW_CONTEXT pcontext)
     return hIcon;
 }
 
-WCHAR *UserGetWindowCaption(HWND hwnd)
-{
-    INT len = 512;
-    WCHAR *text;
-    text = (WCHAR*)HeapAlloc(GetProcessHeap(), 0, len  * sizeof(WCHAR));
-    if (text) InternalGetWindowText(hwnd, text, len);
-    return text;
-}
-
-HRESULT WINAPI ThemeDrawCaptionText(PDRAW_CONTEXT pcontext, RECT* pRect, int iPartId, int iStateId, LPCWSTR pszText)
+HRESULT WINAPI ThemeDrawCaptionText(PDRAW_CONTEXT pcontext, RECT* pRect, int iPartId, int iStateId)
 {
     HRESULT hr;
     HFONT hFont = NULL;
@@ -117,6 +108,27 @@ HRESULT WINAPI ThemeDrawCaptionText(PDRAW_CONTEXT pcontext, RECT* pRect, int iPa
     LOGFONTW logfont;
     COLORREF textColor;
     COLORREF oldTextColor;
+    int align = CA_LEFT;
+    int drawStyles = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS;
+
+    WCHAR buffer[50];
+    WCHAR *pszText = buffer;
+    INT len;
+
+    len = InternalGetWindowText(pcontext->hWnd, NULL, 0);
+    if (!len)
+        return S_OK;
+
+    len++; /* From now on this is the size of the buffer so include the null */
+
+    if (len > ARRAYSIZE(buffer))
+    {
+        pszText = HeapAlloc(GetProcessHeap(), 0, len  * sizeof(WCHAR));
+        if (!pszText)
+            return E_OUTOFMEMORY;
+    }
+
+    InternalGetWindowText(pcontext->hWnd, pszText, len);
 
     hr = GetThemeSysFont(0,TMT_CAPTIONFONT,&logfont);
     if(SUCCEEDED(hr))
@@ -130,23 +142,33 @@ HRESULT WINAPI ThemeDrawCaptionText(PDRAW_CONTEXT pcontext, RECT* pRect, int iPa
     else
         textColor = GetSysColor(COLOR_CAPTIONTEXT);
 
+    GetThemeEnumValue(pcontext->theme, iPartId, iStateId, TMT_CONTENTALIGNMENT, &align);
+    if (align == CA_CENTER)
+        drawStyles |= DT_CENTER;
+    else if (align == CA_RIGHT)
+        drawStyles |= DT_RIGHT;
+
     oldTextColor = SetTextColor(pcontext->hDC, textColor);
     DrawThemeText(pcontext->theme, 
                   pcontext->hDC, 
                   iPartId, 
                   iStateId, 
                   pszText, 
-                  lstrlenW(pszText)
-                  DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS
+                  len - 1
+                  drawStyles
                   0, 
                   pRect);
     SetTextColor(pcontext->hDC, oldTextColor);
 
-    if(hFont)
+    if (hFont)
     {
         SelectObject(pcontext->hDC, oldFont);
         DeleteObject(hFont);
     }
+    if (pszText != buffer)
+    {
+        HeapFree(GetProcessHeap(), 0, pszText);
+    }
     return S_OK;
 }
 
@@ -159,8 +181,8 @@ ThemeInitDrawContext(PDRAW_CONTEXT pcontext,
     GetWindowInfo(hWnd, &pcontext->wi);
     pcontext->hWnd = hWnd;
     pcontext->Active = IsWindowActive(hWnd, pcontext->wi.dwExStyle);
-    pcontext->theme = MSSTYLES_OpenThemeClass(ActiveThemeFile, NULL, L"WINDOW");
-    pcontext->scrolltheme = MSSTYLES_OpenThemeClass(ActiveThemeFile, NULL, L"SCROLLBAR");
+    pcontext->theme = GetNCCaptionTheme(hWnd, pcontext->wi.dwStyle);
+    pcontext->scrolltheme = GetNCScrollbarTheme(hWnd, pcontext->wi.dwStyle);
 
     pcontext->CaptionHeight = pcontext->wi.cyWindowBorders;
     pcontext->CaptionHeight += GetSystemMetrics(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
@@ -179,9 +201,6 @@ ThemeCleanupDrawContext(PDRAW_CONTEXT pcontext)
 {
     ReleaseDC(pcontext->hWnd ,pcontext->hDC);
 
-    CloseThemeData (pcontext->theme);
-    CloseThemeData (pcontext->scrolltheme);
-
     if(pcontext->hRgn != NULL)
     {
         DeleteObject(pcontext->hRgn);
@@ -211,15 +230,88 @@ ThemeEndBufferedPaint(PDRAW_CONTEXT pcontext, int x, int y, int cx, int cy)
     pcontext->hDC = pcontext->hDCScreen;
 }
 
+void ThemeCalculateCaptionButtonsPos(HWND hWnd, HTHEME htheme)
+{
+    PWND_DATA pwndData;
+    DWORD style;
+    INT ButtonWidth, ButtonHeight, iPartId, i;
+    WINDOWINFO wi = {sizeof(wi)};
+    RECT rcCurrent;
+
+    /* First of all check if we have something to do here */
+    style = GetWindowLongW(hWnd, GWL_STYLE);
+    if((style & (WS_CAPTION | WS_SYSMENU)) != (WS_CAPTION | WS_SYSMENU))
+        return;
+
+    /* Get theme data for this window */
+    pwndData = ThemeGetWndData(hWnd);
+    if (pwndData == NULL)
+        return;
+
+    if (!htheme)
+        htheme = pwndData->hthemeWindow;
+
+    if(!GetWindowInfo(hWnd, &wi))
+        return;
+
+    /* Calculate the area of the caption */
+    rcCurrent.top = rcCurrent.left = 0;
+    rcCurrent.right = wi.rcWindow.right - wi.rcWindow.left;
+    rcCurrent.bottom = wi.rcWindow.bottom - wi.rcWindow.top;
+
+    /* Add a padding around the objects of the caption */
+    InflateRect(&rcCurrent, -(int)wi.cyWindowBorders-BUTTON_GAP_SIZE, 
+                            -(int)wi.cyWindowBorders-BUTTON_GAP_SIZE);
+
+    for (i = CLOSEBUTTON; i <= HELPBUTTON; i++)
+    {
+        SIZE ButtonSize;
+
+        switch(i)
+        {
+            case CLOSEBUTTON:
+                iPartId = wi.dwExStyle & WS_EX_TOOLWINDOW ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON;
+                break;
+
+            case MAXBUTTON:
+                iPartId = wi.dwStyle & WS_MAXIMIZE ? WP_RESTOREBUTTON : WP_MAXBUTTON;
+                break;
+
+            case MINBUTTON:
+                iPartId = wi.dwStyle & WS_MINIMIZE ? WP_RESTOREBUTTON : WP_MINBUTTON;
+                break;
+
+            default:
+                iPartId = WP_HELPBUTTON ;
+        }
+
+        GetThemePartSize(htheme, NULL, iPartId, 0, NULL, TS_MIN, &ButtonSize);
+
+        ButtonHeight = GetSystemMetrics( wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMSIZE : SM_CYSIZE);
+        ButtonWidth = MulDiv(ButtonSize.cx, ButtonHeight, ButtonSize.cy);
+
+        ButtonHeight -= 4;
+        ButtonWidth -= 4;
+
+        SetRect(&pwndData->rcCaptionButtons[i],
+                rcCurrent.right - ButtonWidth,
+                rcCurrent.top,
+                rcCurrent.right,
+                rcCurrent.top + ButtonHeight);
+
+        rcCurrent.right -= ButtonWidth + BUTTON_GAP_SIZE;
+    }
+}
+
 static void 
 ThemeDrawCaptionButton(PDRAW_CONTEXT pcontext, 
-                       RECT* prcCurrent, 
                        CAPTIONBUTTON buttonId, 
                        INT iStateId)
 {
-    RECT rcPart;
-    INT ButtonWidth, ButtonHeight, iPartId;
-    SIZE ButtonSize;
+    INT iPartId;
+    PWND_DATA pwndData = ThemeGetWndData(pcontext->hWnd);
+    if (!pwndData)
+        return;
 
     switch(buttonId)
     {
@@ -256,22 +348,7 @@ ThemeDrawCaptionButton(PDRAW_CONTEXT pcontext,
         return;
     }
 
-    GetThemePartSize(pcontext->theme, pcontext->hDC, iPartId, 0, NULL, TS_MIN, &ButtonSize);
-
-    ButtonHeight = GetSystemMetrics( pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMSIZE : SM_CYSIZE);
-    ButtonWidth = MulDiv(ButtonSize.cx, ButtonHeight, ButtonSize.cy);
-
-    ButtonHeight -= 4;
-    ButtonWidth -= 4;
-
-    /* Calculate the position */
-    rcPart.top = prcCurrent->top;
-    rcPart.right = prcCurrent->right;
-    rcPart.bottom = rcPart.top + ButtonHeight ;
-    rcPart.left = rcPart.right - ButtonWidth ;
-    prcCurrent->right -= ButtonWidth + BUTTON_GAP_SIZE;
-
-    DrawThemeBackground(pcontext->theme, pcontext->hDC, iPartId, iStateId, &rcPart, NULL);
+    DrawThemeBackground(pcontext->theme, pcontext->hDC, iPartId, iStateId, &pwndData->rcCaptionButtons[buttonId], NULL);
 }
 
 static DWORD
@@ -291,25 +368,14 @@ ThemeGetButtonState(DWORD htCurrect, DWORD htHot, DWORD htDown, BOOL Active)
 static void 
 ThemeDrawCaptionButtons(PDRAW_CONTEXT pcontext, DWORD htHot, DWORD htDown)
 {
-    RECT rcCurrent;
-
-    /* Calculate the area of the caption */
-    rcCurrent.top = rcCurrent.left = 0;
-    rcCurrent.right = pcontext->wi.rcWindow.right - pcontext->wi.rcWindow.left;
-    rcCurrent.bottom = pcontext->CaptionHeight;
-    
-    /* Add a padding around the objects of the caption */
-    InflateRect(&rcCurrent, -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE, 
-                            -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE);
-
     /* Draw the buttons */
-    ThemeDrawCaptionButton(pcontext, &rcCurrent, CLOSEBUTTON, 
+    ThemeDrawCaptionButton(pcontext, CLOSEBUTTON, 
                            ThemeGetButtonState(HTCLOSE, htHot, htDown, pcontext->Active));
-    ThemeDrawCaptionButton(pcontext, &rcCurrent, MAXBUTTON,  
+    ThemeDrawCaptionButton(pcontext, MAXBUTTON,  
                            ThemeGetButtonState(HTMAXBUTTON, htHot, htDown, pcontext->Active));
-    ThemeDrawCaptionButton(pcontext, &rcCurrent, MINBUTTON,
+    ThemeDrawCaptionButton(pcontext, MINBUTTON,
                            ThemeGetButtonState(HTMINBUTTON, htHot, htDown, pcontext->Active));
-    ThemeDrawCaptionButton(pcontext, &rcCurrent, HELPBUTTON,
+    ThemeDrawCaptionButton(pcontext, HELPBUTTON,
                            ThemeGetButtonState(HTHELP, htHot, htDown, pcontext->Active));
 }
 
@@ -320,7 +386,6 @@ ThemeDrawCaption(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
     RECT rcPart;
     int iPart, iState;
     HICON hIcon;
-    WCHAR *CaptionText;
 
     // See also win32ss/user/ntuser/nonclient.c!UserDrawCaptionBar
     // and win32ss/user/ntuser/nonclient.c!UserDrawCaption
@@ -329,8 +394,6 @@ ThemeDrawCaption(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
     else
         hIcon = NULL;
 
-    CaptionText = UserGetWindowCaption(pcontext->hWnd);
-
     /* Get the caption part and state id */
     if (pcontext->wi.dwStyle & WS_MINIMIZE)
         iPart = WP_MINCAPTION;
@@ -358,10 +421,10 @@ ThemeDrawCaption(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
     {
         iState = pcontext->Active ? BUTTON_NORMAL : BUTTON_INACTIVE;
 
-        ThemeDrawCaptionButton(pcontext, &rcPart, CLOSEBUTTON, iState);
-        ThemeDrawCaptionButton(pcontext, &rcPart, MAXBUTTON, iState);
-        ThemeDrawCaptionButton(pcontext, &rcPart, MINBUTTON, iState);
-        ThemeDrawCaptionButton(pcontext, &rcPart, HELPBUTTON, iState);
+        ThemeDrawCaptionButton(pcontext, CLOSEBUTTON, iState);
+        ThemeDrawCaptionButton(pcontext, MAXBUTTON, iState);
+        ThemeDrawCaptionButton(pcontext, MINBUTTON, iState);
+        ThemeDrawCaptionButton(pcontext, HELPBUTTON, iState);
     }
     
     rcPart.top += 3 ;
@@ -378,11 +441,7 @@ ThemeDrawCaption(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
     rcPart.right -= 4;
 
     /* Draw the caption */
-    if (CaptionText)
-    {
-        ThemeDrawCaptionText(pcontext, &rcPart, iPart, iState, CaptionText);
-        HeapFree(GetProcessHeap(), 0, CaptionText);
-    }
+    ThemeDrawCaptionText(pcontext, &rcPart, iPart, iState);
 }
 
 static void 
@@ -589,7 +648,7 @@ ThemeHandleNcMouseMove(HWND hWnd, DWORD ht, POINT* pt)
     DRAW_CONTEXT context;
     TRACKMOUSEEVENT tme;
     DWORD style;
-    PWND_CONTEXT pcontext;
+    PWND_DATA pwndData;
 
     /* First of all check if we have something to do here */
     style = GetWindowLongW(hWnd, GWL_STYLE);
@@ -597,8 +656,8 @@ ThemeHandleNcMouseMove(HWND hWnd, DWORD ht, POINT* pt)
         return 0;
 
     /* Get theme data for this window */
-    pcontext = ThemeGetWndContext(hWnd);
-    if (pcontext == NULL)
+    pwndData = ThemeGetWndData(hWnd);
+    if (pwndData == NULL)
         return 0;
 
     /* Begin tracking in the non client area if we are not tracking yet */
@@ -616,24 +675,24 @@ ThemeHandleNcMouseMove(HWND hWnd, DWORD ht, POINT* pt)
     ThemeInitDrawContext(&context, hWnd, 0);
     if (context.wi.dwStyle & WS_SYSMENU)
     {
-        if (HT_ISBUTTON(ht) || HT_ISBUTTON(pcontext->lastHitTest))
+        if (HT_ISBUTTON(ht) || HT_ISBUTTON(pwndData->lastHitTest))
             ThemeDrawCaptionButtons(&context, ht, 0);
     }
 
    if (context.wi.dwStyle & WS_HSCROLL)
    {
-       if (ht == HTHSCROLL || pcontext->lastHitTest == HTHSCROLL)
+       if (ht == HTHSCROLL || pwndData->lastHitTest == HTHSCROLL)
            ThemeDrawScrollBar(&context, SB_HORZ , ht == HTHSCROLL ? pt : NULL);
    }
 
     if (context.wi.dwStyle & WS_VSCROLL)
     {
-        if (ht == HTVSCROLL || pcontext->lastHitTest == HTVSCROLL)
+        if (ht == HTVSCROLL || pwndData->lastHitTest == HTVSCROLL)
             ThemeDrawScrollBar(&context, SB_VERT, ht == HTVSCROLL ? pt : NULL);
     }
     ThemeCleanupDrawContext(&context);
 
-    pcontext->lastHitTest = ht;
+    pwndData->lastHitTest = ht;
 
     return 0;
 }
@@ -643,7 +702,7 @@ ThemeHandleNcMouseLeave(HWND hWnd)
 {
     DRAW_CONTEXT context;
     DWORD style;
-    PWND_CONTEXT pWndContext;
+    PWND_DATA pwndData;
 
     /* First of all check if we have something to do here */
     style = GetWindowLongW(hWnd, GWL_STYLE);
@@ -651,23 +710,23 @@ ThemeHandleNcMouseLeave(HWND hWnd)
         return 0;
 
     /* Get theme data for this window */
-    pWndContext = ThemeGetWndContext(hWnd);
-    if (pWndContext == NULL)
+    pwndData = ThemeGetWndData(hWnd);
+    if (pwndData == NULL)
         return 0;
 
     ThemeInitDrawContext(&context, hWnd, 0);
-    if (context.wi.dwStyle & WS_SYSMENU && HT_ISBUTTON(pWndContext->lastHitTest))
+    if (context.wi.dwStyle & WS_SYSMENU && HT_ISBUTTON(pwndData->lastHitTest))
         ThemeDrawCaptionButtons(&context, 0, 0);
 
-   if (context.wi.dwStyle & WS_HSCROLL && pWndContext->lastHitTest == HTHSCROLL)
+   if (context.wi.dwStyle & WS_HSCROLL && pwndData->lastHitTest == HTHSCROLL)
         ThemeDrawScrollBar(&context, SB_HORZ,  NULL);
 
-    if (context.wi.dwStyle & WS_VSCROLL && pWndContext->lastHitTest == HTVSCROLL)
+    if (context.wi.dwStyle & WS_VSCROLL && pwndData->lastHitTest == HTVSCROLL)
         ThemeDrawScrollBar(&context, SB_VERT, NULL);
 
     ThemeCleanupDrawContext(&context);
 
-    pWndContext->lastHitTest = HTNOWHERE;
+    pwndData->lastHitTest = HTNOWHERE;
 
     return 0;
 }
@@ -680,7 +739,7 @@ ThemeHandleButton(HWND hWnd, WPARAM wParam)
     WPARAM SCMsg, ht;
     ULONG Style;
     DRAW_CONTEXT context;
-    PWND_CONTEXT pWndContext;
+    PWND_DATA pwndData;
 
     Style = GetWindowLongW(hWnd, GWL_STYLE);
     if (!((Style & WS_CAPTION) && (Style & WS_SYSMENU)))
@@ -706,13 +765,13 @@ ThemeHandleButton(HWND hWnd, WPARAM wParam)
     }
 
     /* Get theme data for this window */
-    pWndContext = ThemeGetWndContext(hWnd);
-    if (pWndContext == NULL)
+    pwndData = ThemeGetWndData(hWnd);
+    if (pwndData == NULL)
         return;
 
     ThemeInitDrawContext(&context, hWnd, 0);
     ThemeDrawCaptionButtons(&context, 0,  wParam);
-    pWndContext->lastHitTest = wParam;
+    pwndData->lastHitTest = wParam;
 
     SetCapture(hWnd);
 
@@ -733,11 +792,11 @@ ThemeHandleButton(HWND hWnd, WPARAM wParam)
         Pressed = (ht == wParam);
 
         /* Only draw the buttons if the hit test changed */
-        if (ht != pWndContext->lastHitTest &&
-            (HT_ISBUTTON(ht) || HT_ISBUTTON(pWndContext->lastHitTest)))
+        if (ht != pwndData->lastHitTest &&
+            (HT_ISBUTTON(ht) || HT_ISBUTTON(pwndData->lastHitTest)))
         {
             ThemeDrawCaptionButtons(&context, 0, Pressed ? wParam: 0);
-            pWndContext->lastHitTest = ht;
+            pwndData->lastHitTest = ht;
         }
     }
 
@@ -847,23 +906,11 @@ DefWndNCHitTest(HWND hWnd, POINT Point)
 
         if (!PtInRect(&WindowRect, Point))
         {
-            INT ButtonWidth;
-
-            if (wi.dwExStyle & WS_EX_TOOLWINDOW)
-                ButtonWidth = GetSystemMetrics(SM_CXSMSIZE);
-            else
-                ButtonWidth = GetSystemMetrics(SM_CXSIZE);
-
-            ButtonWidth -= 4;
-            ButtonWidth += BUTTON_GAP_SIZE;
-
             if (wi.dwStyle & WS_SYSMENU)
             {
-                if (wi.dwExStyle & WS_EX_TOOLWINDOW)
-                {
-                    WindowRect.right -= ButtonWidth;
-                }
-                else
+                PWND_DATA pwndData = ThemeGetWndData(hWnd);
+
+                if (!(wi.dwExStyle & WS_EX_TOOLWINDOW))
                 {
                     // if(!(wi.dwExStyle & WS_EX_DLGMODALFRAME))
                     // FIXME: The real test should check whether there is
@@ -872,22 +919,22 @@ DefWndNCHitTest(HWND hWnd, POINT Point)
                     // See win32ss/user/user32/windows/nonclient.c!DefWndNCHitTest
                     // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does
                     // the test better.
-                        WindowRect.left += ButtonWidth;
-                    WindowRect.right -= ButtonWidth;
+                        WindowRect.left += GetSystemMetrics(SM_CXSMICON);
+                }
+
+                if (pwndData)
+                {
+                    POINT pt = {Point.x - wi.rcWindow.left, Point.y - wi.rcWindow.top};
+                    if (PtInRect(&pwndData->rcCaptionButtons[CLOSEBUTTON], pt))
+                        return HTCLOSE;
+                    if (PtInRect(&pwndData->rcCaptionButtons[MAXBUTTON], pt))
+                        return HTMAXBUTTON;
+                    if (PtInRect(&pwndData->rcCaptionButtons[MINBUTTON], pt))
+                        return HTMINBUTTON;
                 }
             }
             if (Point.x < WindowRect.left)
                 return HTSYSMENU;
-            if (WindowRect.right <= Point.x)
-                return HTCLOSE;
-            if (wi.dwStyle & WS_MAXIMIZEBOX || wi.dwStyle & WS_MINIMIZEBOX)
-                WindowRect.right -= ButtonWidth;
-            if (Point.x >= WindowRect.right)
-                return HTMAXBUTTON;
-            if (wi.dwStyle & WS_MINIMIZEBOX)
-                WindowRect.right -= ButtonWidth;
-            if (Point.x >= WindowRect.right)
-                return HTMINBUTTON;
             return HTCAPTION;
         }
     }
@@ -1107,8 +1154,15 @@ HRESULT WINAPI DrawNCPreview(HDC hDC,
 
     /* Paint the window on the preview hDC */
     rcCurrent = context.wi.rcWindow;
+    OffsetRect( &rcCurrent, -context.wi.rcWindow.left, -context.wi.rcWindow.top);
+    SetViewportOrgEx(hDC, context.wi.rcWindow.left, context.wi.rcWindow.top, NULL);
+    ThemeCalculateCaptionButtonsPos(hwndDummy, context.theme);
     ThemePaintWindow(&context, &rcCurrent, FALSE);
+    SetViewportOrgEx(hDC, 0, 0, NULL);
+
     context.hDC = NULL;
+    CloseThemeData (context.theme);
+    CloseThemeData (context.scrolltheme);
     ThemeCleanupDrawContext(&context);
 
     /* Cleanup */