Author: gadamopoulos Date: Tue May 17 07:57:17 2011 New Revision: 51804
URL: http://svn.reactos.org/svn/reactos?rev=51804&view=rev Log: [uxtheme] - Implement drawing windows caption and borders with themes
Modified: branches/GSoC_2011/ThemesSupport/dll/win32/uxtheme/nonclient.c
Modified: branches/GSoC_2011/ThemesSupport/dll/win32/uxtheme/nonclient.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2011/ThemesSupport/dll/win3... ============================================================================== --- branches/GSoC_2011/ThemesSupport/dll/win32/uxtheme/nonclient.c [iso-8859-1] (original) +++ branches/GSoC_2011/ThemesSupport/dll/win32/uxtheme/nonclient.c [iso-8859-1] Tue May 17 07:57:17 2011 @@ -10,6 +10,7 @@ #include "undocuser.h" #include "vfwmsgs.h" #include "uxtheme.h" +#include <tmschema.h>
#include "wine/debug.h"
@@ -21,8 +22,136 @@ HDC hDC; HTHEME theme; WINDOWINFO wi; + BOOL Active; /* wi.dwWindowStatus isn't correct for mdi child windows */ HRGN hRgn; + int CaptionHeight; } DRAW_CONTEXT, *PDRAW_CONTEXT; + +typedef enum +{ + CLOSEBUTTON, + MAXBUTTON, + MINBUTTON, + HELPBUTTON +} CAPTIONBUTTON; + +/* +The following values specify all possible vutton states +Note that not all of them are documented but it is easy to +find them by opening a theme file +*/ +typedef enum { + BUTTON_NORMAL = 1 , + BUTTON_HOT , + BUTTON_PRESSED , + BUTTON_DISABLED , + BUTTON_INACTIVE +} THEME_BUTTON_STATES; + +#define HAS_MENU(hwnd,style) ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd)) + +#define BUTTON_GAP_SIZE 2 + +static BOOL +IsWindowActive(HWND hWnd, DWORD ExStyle) +{ + BOOL ret; + + if (ExStyle & WS_EX_MDICHILD) + { + ret = IsChild(GetForegroundWindow(), hWnd); + if (ret) + ret = (hWnd == (HWND)SendMessageW(GetParent(hWnd), WM_MDIGETACTIVE, 0, 0)); + } + else + { + ret = (GetForegroundWindow() == hWnd); + } + + return ret; +} + +HICON +UserGetWindowIcon(HWND hwnd) +{ + HICON hIcon = 0; + + SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon); + + if (!hIcon) + SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon); + + if (!hIcon) + SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon); + + if (!hIcon) + hIcon = (HICON)GetClassLong(hwnd, GCL_HICONSM); + + if (!hIcon) + hIcon = (HICON)GetClassLong(hwnd, GCL_HICON); + + if(!hIcon) + hIcon = LoadIcon(NULL, IDI_WINLOGO); + + 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; +} + +static void +ThemeDrawTitle(PDRAW_CONTEXT context, RECT* prcCurrent) +{ + +} + +HRESULT WINAPI ThemeDrawCaptionText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, + LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, + DWORD dwTextFlags2, const RECT *pRect, BOOL Active) +{ + HRESULT hr; + HFONT hFont = NULL; + HGDIOBJ oldFont = NULL; + LOGFONTW logfont; + COLORREF textColor; + COLORREF oldTextColor; + int oldBkMode; + RECT rt; + + hr = GetThemeSysFont(0,TMT_CAPTIONFONT,&logfont); + + if(SUCCEEDED(hr)) { + hFont = CreateFontIndirectW(&logfont); + } + CopyRect(&rt, pRect); + if(hFont) + oldFont = SelectObject(hdc, hFont); + + if(dwTextFlags2 & DTT_GRAYED) + textColor = GetSysColor(COLOR_GRAYTEXT); + else if (!Active) + textColor = GetSysColor(COLOR_INACTIVECAPTIONTEXT); + else + textColor = GetSysColor(COLOR_CAPTIONTEXT); + + oldTextColor = SetTextColor(hdc, textColor); + oldBkMode = SetBkMode(hdc, TRANSPARENT); + DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags); + SetBkMode(hdc, oldBkMode); + SetTextColor(hdc, oldTextColor); + + if(hFont) { + SelectObject(hdc, oldFont); + DeleteObject(hFont); + } + return S_OK; +}
static void ThemeInitDrawContext(PDRAW_CONTEXT pcontext, @@ -31,7 +160,11 @@ { GetWindowInfo(hWnd, &pcontext->wi); pcontext->hWnd = hWnd; + pcontext->Active = IsWindowActive(hWnd, pcontext->wi.dwExStyle); pcontext->theme = OpenThemeData(pcontext->hWnd, L"WINDOW"); + + pcontext->CaptionHeight = pcontext->wi.cyWindowBorders; + pcontext->CaptionHeight += GetSystemMetrics(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
if(hRgn <= 0) { @@ -57,17 +190,200 @@ { DeleteObject(pcontext->hRgn); } +} + +static void +ThemeDrawCaptionButton(PDRAW_CONTEXT pcontext, + RECT* prcCurrent, + CAPTIONBUTTON buttonId, + INT iStateId) +{ + RECT rcPart; + INT ButtonWidth, ButtonHeight, iPartId; + + ButtonHeight = GetThemeSysSize(pcontext->theme, pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMSIZE : SM_CYSIZE); + ButtonWidth = GetThemeSysSize(pcontext->theme, pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CXSMSIZE : SM_CXSIZE); + + switch(buttonId) + { + case CLOSEBUTTON: + iPartId = pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON; + break; + + case MAXBUTTON: + if (!(pcontext->wi.dwStyle & WS_MAXIMIZEBOX)) + { + if (!(pcontext->wi.dwStyle & WS_MINIMIZEBOX)) + return; + else + iStateId = BUTTON_DISABLED; + } + + iPartId = pcontext->wi.dwStyle & WS_MAXIMIZE ? WP_RESTOREBUTTON : WP_MAXBUTTON; + break; + + case MINBUTTON: + if (!(pcontext->wi.dwStyle & WS_MINIMIZEBOX)) + { + if (!(pcontext->wi.dwStyle & WS_MAXIMIZEBOX)) + return; + else + iStateId = BUTTON_DISABLED; + } + + iPartId = WP_MINBUTTON; + break; + + default: + //FIXME: Implement Help Button + return; + } + + 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); +} + +static void +ThemeDrawCaption(PDRAW_CONTEXT pcontext, RECT* prcCurrent) +{ + RECT rcPart; + int iPart, iState; + HICON hIcon; + WCHAR *CaptionText; + + hIcon = UserGetWindowIcon(pcontext->hWnd); + CaptionText = UserGetWindowCaption(pcontext->hWnd); + + /* Get the caption part and state id */ + if (pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW) + iPart = WP_SMALLCAPTION; + else if (pcontext->wi.dwStyle & WS_MAXIMIZE) + iPart = WP_MAXCAPTION; + else + iPart = WP_CAPTION; + + iState = pcontext->Active ? FS_ACTIVE : FS_INACTIVE; + + /* Draw the caption background*/ + rcPart = *prcCurrent; + rcPart.bottom = pcontext->CaptionHeight; + prcCurrent->top = rcPart.bottom; + DrawThemeBackground(pcontext->theme, pcontext->hDC,iPart,iState,&rcPart,NULL); + + /* Add a padding around the objects of the caption */ + InflateRect(&rcPart, -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE, + -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE); + + /* Draw the caption buttons */ + if (pcontext->wi.dwStyle & WS_SYSMENU) + { + 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); + } + + rcPart.top += 3 ; + + /* Draw the icon */ + if(hIcon && !(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW)) + { + int IconHeight = GetSystemMetrics(SM_CYSMICON); + int IconWidth = GetSystemMetrics(SM_CXSMICON); + DrawIconEx(pcontext->hDC, rcPart.left, rcPart.top , hIcon, IconWidth, IconHeight, 0, NULL, DI_NORMAL); + rcPart.left += IconWidth + 4; + } + + rcPart.right -= 4; + + /* Draw the caption */ + if(CaptionText) + { + /*FIXME: Use DrawThemeTextEx*/ + ThemeDrawCaptionText(pcontext->theme, + pcontext->hDC, + iPart, + iState, + CaptionText, + lstrlenW(CaptionText), + DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS, + 0, + &rcPart , + pcontext->Active); + HeapFree(GetProcessHeap(), 0, CaptionText); + } +} + +static void +ThemeDrawBorders(PDRAW_CONTEXT pcontext, RECT* prcCurrent) +{ + +} + +static void +DrawClassicFrame(PDRAW_CONTEXT context, RECT* prcCurrent) +{ + +} + +static void +ThemeDrawMenuBar(PDRAW_CONTEXT pcontext, PRECT prcCurrent) +{ + +} + +static void +ThemeDrawScrollBar(PDRAW_CONTEXT pcontext, INT Bar) +{ + +} + +static void +ThemePaintWindow(PDRAW_CONTEXT pcontext, RECT* prcCurrent) +{ + if(!(pcontext->wi.dwStyle & WS_VISIBLE)) + return; + + if(pcontext->wi.dwStyle & WS_MINIMIZE) + { + ThemeDrawTitle(pcontext, prcCurrent); + return; + } + + if((pcontext->wi.dwStyle & WS_CAPTION)==WS_CAPTION) + { + ThemeDrawCaption(pcontext, prcCurrent); + ThemeDrawBorders(pcontext, prcCurrent); + } + else + { + DrawClassicFrame(pcontext, prcCurrent); + } + + if(HAS_MENU(pcontext->hWnd, pcontext->wi.dwStyle)) + ThemeDrawMenuBar(pcontext, prcCurrent); + + if(pcontext->wi.dwStyle & WS_HSCROLL) + ThemeDrawScrollBar(pcontext, OBJID_VSCROLL); + + if(pcontext->wi.dwStyle & WS_VSCROLL) + ThemeDrawScrollBar(pcontext, OBJID_HSCROLL); }
/* Message handlers */ - -static void -ThemePaintWindow(PDRAW_CONTEXT pcontext, RECT* prcCurrent) -{ - UNIMPLEMENTED; -}
static LRESULT ThemeHandleNCPaint(HWND hWnd, HRGN hRgn)