diff --git a/reactos/dll/win32/comctl32/animate.c b/reactos/dll/win32/comctl32/animate.c
index 3aad68b2a42..a86ff851ba4 100644
--- a/reactos/dll/win32/comctl32/animate.c
+++ b/reactos/dll/win32/comctl32/animate.c
@@ -717,7 +717,7 @@ static BOOL ANIMATE_OpenW(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPWSTR lps
TRACE("(%s)\n", debugstr_w(lpszName));
- if (HIWORD(lpszName))
+ if (!IS_INTRESOURCE(lpszName))
{
if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName))
{
@@ -775,7 +775,7 @@ static BOOL ANIMATE_OpenA(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPSTR lpsz
LRESULT result;
INT len;
- if (!HIWORD(lpszName))
+ if (IS_INTRESOURCE(lpszName))
return ANIMATE_OpenW(infoPtr, hInstance, (LPWSTR)lpszName);
len = MultiByteToWideChar(CP_ACP, 0, lpszName, -1, NULL, 0);
diff --git a/reactos/dll/win32/comctl32/comboex.c b/reactos/dll/win32/comctl32/comboex.c
index 1484ba87f1d..4b5e079ac99 100644
--- a/reactos/dll/win32/comctl32/comboex.c
+++ b/reactos/dll/win32/comctl32/comboex.c
@@ -67,8 +67,6 @@ typedef struct
HWND hwndNotify; /* my parent hwnd */
HWND hwndCombo;
HWND hwndEdit;
- WNDPROC prevEditWndProc; /* previous Edit WNDPROC value */
- WNDPROC prevComboWndProc; /* previous Combo WNDPROC value */
DWORD dwExtStyle;
INT selected; /* index of selected item */
DWORD flags; /* WINE internal flags */
@@ -121,17 +119,15 @@ typedef struct
/* Offset between image and text */
#define CBE_SEP 4
-static const WCHAR COMBOEX_SUBCLASS_PROP[] = {
- 'C','C','C','o','m','b','o','E','x','3','2',
- 'S','u','b','c','l','a','s','s','I','n','f','o',0
-};
+#define COMBO_SUBCLASSID 1
+#define EDIT_SUBCLASSID 2
#define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongPtrW (hwnd, 0))
-
-/* Things common to the entire DLL */
-static LRESULT WINAPI COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-static LRESULT WINAPI COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+ UINT_PTR uId, DWORD_PTR ref_data);
+static LRESULT CALLBACK COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+ UINT_PTR uId, DWORD_PTR ref_data);
static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr);
typedef INT (WINAPI *cmp_func_t)(LPCWSTR, LPCWSTR);
@@ -177,7 +173,7 @@ static void COMBOEX_DumpInput (COMBOBOXEXITEMW const *input)
static inline CBE_ITEMDATA *get_item_data(const COMBOEX_INFO *infoPtr, INT index)
{
return (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo, CB_GETITEMDATA,
- (WPARAM)index, 0);
+ index, 0);
}
static inline cmp_func_t get_cmp_func(COMBOEX_INFO const *infoPtr)
@@ -455,10 +451,7 @@ static void COMBOEX_ReSize (const COMBOEX_INFO *infoPtr)
static void COMBOEX_SetEditText (const COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item)
{
if (!infoPtr->hwndEdit) return;
- /* native issues the following messages to the {Edit} control */
- /* WM_SETTEXT (0,addr) */
- /* EM_SETSEL32 (0,0) */
- /* EM_SETSEL32 (0,-1) */
+
if (item->mask & CBEIF_TEXT) {
SendMessageW (infoPtr->hwndEdit, WM_SETTEXT, 0, (LPARAM)COMBOEX_GetText(infoPtr, item));
SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0);
@@ -491,13 +484,6 @@ static CBE_ITEMDATA * COMBOEX_FindItem(const COMBOEX_INFO *infoPtr, INT_PTR inde
return item;
}
-
-static inline BOOL COMBOEX_HasEdit(COMBOEX_INFO const *infoPtr)
-{
- return infoPtr->hwndEdit ? TRUE : FALSE;
-}
-
-
/* *** CBEM_xxx message support *** */
static UINT COMBOEX_GetListboxText(const COMBOEX_INFO *infoPtr, INT_PTR n, LPWSTR buf)
@@ -510,6 +496,17 @@ static UINT COMBOEX_GetListboxText(const COMBOEX_INFO *infoPtr, INT_PTR n, LPWST
return 0;
str = COMBOEX_GetText(infoPtr, item);
+ if (!str)
+ {
+ if (buf)
+ {
+ if (infoPtr->unicode)
+ buf[0] = 0;
+ else
+ *((LPSTR)buf) = 0;
+ }
+ return 0;
+ }
if (infoPtr->unicode)
{
@@ -536,7 +533,7 @@ static INT COMBOEX_DeleteItem (const COMBOEX_INFO *infoPtr, INT_PTR index)
if (!COMBOEX_FindItem(infoPtr, index)) return CB_ERR;
/* doing this will result in WM_DELETEITEM being issued */
- SendMessageW (infoPtr->hwndCombo, CB_DELETESTRING, (WPARAM)index, 0);
+ SendMessageW (infoPtr->hwndCombo, CB_DELETESTRING, index, 0);
return infoPtr->nb_items;
}
@@ -547,13 +544,13 @@ static BOOL COMBOEX_GetItemW (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit)
INT_PTR index = cit->iItem;
CBE_ITEMDATA *item;
- TRACE("(...)\n");
+ TRACE("\n");
/* if item number requested does not exist then return failure */
if ((index >= infoPtr->nb_items) || (index < -1)) return FALSE;
/* if the item is the edit control and there is no edit control, skip */
- if ((index == -1) && !COMBOEX_HasEdit(infoPtr)) return FALSE;
+ if ((index == -1) && !infoPtr->hwndEdit) return FALSE;
if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE;
@@ -567,7 +564,7 @@ static BOOL COMBOEX_GetItemA (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit)
{
COMBOBOXEXITEMW tmpcit;
- TRACE("(...)\n");
+ TRACE("\n");
tmpcit.mask = cit->mask;
tmpcit.iItem = cit->iItem;
@@ -600,8 +597,7 @@ static BOOL COMBOEX_GetItemA (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit)
static inline BOOL COMBOEX_HasEditChanged (COMBOEX_INFO const *infoPtr)
{
- return COMBOEX_HasEdit(infoPtr) &&
- (infoPtr->flags & WCBE_EDITHASCHANGED) == WCBE_EDITHASCHANGED;
+ return infoPtr->hwndEdit && (infoPtr->flags & WCBE_EDITHASCHANGED) == WCBE_EDITHASCHANGED;
}
@@ -678,8 +674,7 @@ static INT COMBOEX_InsertItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW const *ci
if (TRACE_ON(comboex)) COMBOEX_DumpItem (item);
- SendMessageW (infoPtr->hwndCombo, CB_INSERTSTRING,
- (WPARAM)cit->iItem, (LPARAM)item);
+ SendMessageW (infoPtr->hwndCombo, CB_INSERTSTRING, cit->iItem, (LPARAM)item);
memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem));
COMBOEX_CopyItem (item, &nmcit.ceItem);
@@ -751,7 +746,7 @@ static HIMAGELIST COMBOEX_SetImageList (COMBOEX_INFO *infoPtr, HIMAGELIST himl)
{
HIMAGELIST himlTemp = infoPtr->himl;
- TRACE("(...)\n");
+ TRACE("\n");
infoPtr->himl = himl;
@@ -774,7 +769,7 @@ static BOOL COMBOEX_SetItemW (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit)
if ((index >= infoPtr->nb_items) || (index < -1)) return FALSE;
/* if the item is the edit control and there is no edit control, skip */
- if ((index == -1) && !COMBOEX_HasEdit(infoPtr)) return FALSE;
+ if ((index == -1) && !infoPtr->hwndEdit) return FALSE;
if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE;
@@ -802,7 +797,7 @@ static BOOL COMBOEX_SetItemW (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit)
if (cit->mask & CBEIF_INDENT)
item->iIndent = cit->iIndent;
if (cit->mask & CBEIF_LPARAM)
- cit->lParam = cit->lParam;
+ item->lParam = cit->lParam;
if (TRACE_ON(comboex)) COMBOEX_DumpItem (item);
@@ -968,12 +963,10 @@ static INT COMBOEX_SetItemHeight (COMBOEX_INFO const *infoPtr, INT index, UINT h
static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
{
- static const WCHAR COMBOBOX[] = { 'C', 'o', 'm', 'b', 'o', 'B', 'o', 'x', 0 };
- static const WCHAR EDIT[] = { 'E', 'D', 'I', 'T', 0 };
static const WCHAR NIL[] = { 0 };
COMBOEX_INFO *infoPtr;
LOGFONTW mylogfont;
- RECT wnrc1, clrc1, cmbwrc;
+ RECT win_rect;
INT i;
/* allocate memory for info structure */
@@ -998,11 +991,13 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
- /* create combo box */
- GetWindowRect(hwnd, &wnrc1);
- GetClientRect(hwnd, &clrc1);
- TRACE("EX window=(%s), client=(%s)\n",
- wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1));
+ if (TRACE_ON(comboex)) {
+ RECT client, rect;
+ GetWindowRect(hwnd, &rect);
+ GetClientRect(hwnd, &client);
+ TRACE("EX window=(%s), client=(%s)\n",
+ wine_dbgstr_rect(&rect), wine_dbgstr_rect(&client));
+ }
/* Native version of ComboEx creates the ComboBox with DROPDOWNLIST */
/* specified. It then creates it's own version of the EDIT control */
@@ -1011,7 +1006,7 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
/* We also need to place the edit control at the proper location */
/* (allow space for the icons). */
- infoPtr->hwndCombo = CreateWindowW (COMBOBOX, NIL,
+ infoPtr->hwndCombo = CreateWindowW (WC_COMBOBOXW, NIL,
/* following line added to match native */
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL |
CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST |
@@ -1030,22 +1025,16 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
* GetCurrentProcessId()
*/
- /*
- * Setup a property to hold the pointer to the COMBOBOXEX
- * data structure.
- */
- SetPropW(infoPtr->hwndCombo, COMBOEX_SUBCLASS_PROP, hwnd);
- infoPtr->prevComboWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndCombo,
- GWLP_WNDPROC, (DWORD_PTR)COMBOEX_ComboWndProc);
+ SetWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID,
+ (DWORD_PTR)hwnd);
infoPtr->font = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
-
/*
* Now create our own EDIT control so we can position it.
* It is created only for CBS_DROPDOWN style
*/
if ((cs->style & CBS_DROPDOWNLIST) == CBS_DROPDOWN) {
- infoPtr->hwndEdit = CreateWindowExW (0, EDIT, NIL,
+ infoPtr->hwndEdit = CreateWindowExW (0, WC_EDITW, NIL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_AUTOHSCROLL,
0, 0, 0, 0, /* will set later */
infoPtr->hwndCombo,
@@ -1058,14 +1047,9 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
* GetWindowThreadProcessId(hwndEdit, &???)
* GetCurrentProcessId()
*/
+ SetWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID,
+ (DWORD_PTR)hwnd);
- /*
- * Setup a property to hold the pointer to the COMBOBOXEX
- * data structure.
- */
- SetPropW(infoPtr->hwndEdit, COMBOEX_SUBCLASS_PROP, hwnd);
- infoPtr->prevEditWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndEdit,
- GWLP_WNDPROC, (DWORD_PTR)COMBOEX_EditWndProc);
infoPtr->font = (HFONT)SendMessageW(infoPtr->hwndCombo, WM_GETFONT, 0, 0);
}
@@ -1081,27 +1065,31 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
SendMessageW (infoPtr->hwndCombo, WM_SETFONT, (WPARAM)infoPtr->font, 0);
if (infoPtr->hwndEdit) {
SendMessageW (infoPtr->hwndEdit, WM_SETFONT, (WPARAM)infoPtr->font, 0);
- SendMessageW (infoPtr->hwndEdit, EM_SETMARGINS, (WPARAM)EC_USEFONTINFO, 0);
+ SendMessageW (infoPtr->hwndEdit, EM_SETMARGINS, EC_USEFONTINFO, 0);
}
COMBOEX_ReSize (infoPtr);
/* Above is fairly certain, below is much less certain. */
- GetWindowRect(hwnd, &wnrc1);
- GetClientRect(hwnd, &clrc1);
- GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
- TRACE("EX window=(%s) client=(%s) CB wnd=(%s)\n",
- wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1),
- wine_dbgstr_rect(&cmbwrc));
- SetWindowPos(infoPtr->hwndCombo, HWND_TOP,
- 0, 0, wnrc1.right-wnrc1.left, wnrc1.bottom-wnrc1.top,
+ GetWindowRect(hwnd, &win_rect);
+
+ if (TRACE_ON(comboex)) {
+ RECT client, rect;
+ GetClientRect(hwnd, &client);
+ GetWindowRect(infoPtr->hwndCombo, &rect);
+ TRACE("EX window=(%s) client=(%s) CB wnd=(%s)\n",
+ wine_dbgstr_rect(&win_rect), wine_dbgstr_rect(&client),
+ wine_dbgstr_rect(&rect));
+ }
+ SetWindowPos(infoPtr->hwndCombo, HWND_TOP, 0, 0,
+ win_rect.right - win_rect.left, win_rect.bottom - win_rect.top,
SWP_NOACTIVATE | SWP_NOREDRAW);
- GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
- TRACE("CB window=(%s)\n", wine_dbgstr_rect(&cmbwrc));
- SetWindowPos(hwnd, HWND_TOP,
- 0, 0, cmbwrc.right-cmbwrc.left, cmbwrc.bottom-cmbwrc.top,
+ GetWindowRect(infoPtr->hwndCombo, &win_rect);
+ TRACE("CB window=(%s)\n", wine_dbgstr_rect(&win_rect));
+ SetWindowPos(hwnd, HWND_TOP, 0, 0,
+ win_rect.right - win_rect.left, win_rect.bottom - win_rect.top,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
COMBOEX_AdjustEditPos (infoPtr);
@@ -1158,7 +1146,7 @@ static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam)
*/
ShowWindow (infoPtr->hwndEdit, SW_SHOW);
InvalidateRect (infoPtr->hwndCombo, 0, TRUE);
- InvalidateRect (infoPtr->hwndEdit, 0, TRUE);
+ if (infoPtr->hwndEdit) InvalidateRect (infoPtr->hwndEdit, 0, TRUE);
cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
if (cursel == -1) {
cmp_func_t cmptext = get_cmp_func(infoPtr);
@@ -1173,8 +1161,7 @@ static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam)
if ((cursel == n) || ((INT_PTR)item == CB_ERR)) {
TRACE("failed to find match??? item=%p cursel=%d\n",
item, cursel);
- if (infoPtr->hwndEdit)
- SetFocus(infoPtr->hwndEdit);
+ if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit);
return 0;
}
}
@@ -1183,8 +1170,7 @@ static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam)
if ((INT_PTR)item == CB_ERR) {
TRACE("failed to find match??? item=%p cursel=%d\n",
item, cursel);
- if (infoPtr->hwndEdit)
- SetFocus(infoPtr->hwndEdit);
+ if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit);
return 0;
}
}
@@ -1280,8 +1266,7 @@ static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam)
* after passing the command to the parent of the ComboEx.
*/
lret = SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
- if (infoPtr->hwndEdit)
- SetFocus(infoPtr->hwndEdit);
+ if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit);
return lret;
}
return 0;
@@ -1377,14 +1362,12 @@ static LRESULT COMBOEX_DrawItem (const COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT con
(dis->itemAction == ODA_DRAWENTIRE)) {
/* draw of edit control data */
- /* testing */
- {
+ if (TRACE_ON(comboex)) {
RECT exrc, cbrc, edrc;
GetWindowRect (infoPtr->hwndSelf, &exrc);
GetWindowRect (infoPtr->hwndCombo, &cbrc);
- edrc.left=edrc.top=edrc.right=edrc.bottom=-1;
- if (infoPtr->hwndEdit)
- GetWindowRect (infoPtr->hwndEdit, &edrc);
+ edrc.left = edrc.top = edrc.right = edrc.bottom = -1;
+ if (infoPtr->hwndEdit) GetWindowRect (infoPtr->hwndEdit, &edrc);
TRACE("window rects ex=(%s), cb=(%s), ed=(%s)\n",
wine_dbgstr_rect(&exrc), wine_dbgstr_rect(&cbrc),
wine_dbgstr_rect(&edrc));
@@ -1595,8 +1578,12 @@ static void COMBOEX_ResetContent (COMBOEX_INFO *infoPtr)
static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr)
{
if (infoPtr->hwndCombo)
- DestroyWindow (infoPtr->hwndCombo);
+ RemoveWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID);
+ if (infoPtr->hwndEdit)
+ RemoveWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID);
+
+ COMBOEX_FreeText (infoPtr->edit);
Free (infoPtr->edit);
infoPtr->edit = 0;
@@ -1720,11 +1707,11 @@ static LRESULT COMBOEX_WindowPosChanging (const COMBOEX_INFO *infoPtr, WINDOWPOS
return 0;
}
-static LRESULT WINAPI
-COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+static LRESULT CALLBACK
+COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+ UINT_PTR uId, DWORD_PTR ref_data)
{
- HWND hwndComboex = GetPropW(hwnd, COMBOEX_SUBCLASS_PROP);
- COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex);
+ COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr ((HWND)ref_data);
NMCBEENDEDITW cbeend;
WCHAR edit_text[260];
COLORREF obkc;
@@ -1744,8 +1731,7 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
/* handle (ignore) the return character */
if (wParam == VK_RETURN) return 0;
/* all other characters pass into the real Edit */
- return CallWindowProcW (infoPtr->prevEditWndProc,
- hwnd, uMsg, wParam, lParam);
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
case WM_ERASEBKGND:
/*
@@ -1757,8 +1743,7 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect));
ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
SetBkColor (hDC, obkc);
- return CallWindowProcW (infoPtr->prevEditWndProc,
- hwnd, uMsg, wParam, lParam);
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
case WM_KEYDOWN: {
INT_PTR oldItem, selected, step = 1;
@@ -1864,8 +1849,7 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
oldItem = SendMessageW (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0);
if (oldItem != -1) {
/* if something is selected, then deselect it */
- SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL,
- (WPARAM)-1, 0);
+ SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, -1, 0);
}
InvalidateRect (infoPtr->hwndCombo, 0, 0);
SetFocus(infoPtr->hwndEdit);
@@ -1880,16 +1864,14 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, oldItem + step, 0);
return 0;
default:
- return CallWindowProcW (infoPtr->prevEditWndProc,
- hwnd, uMsg, wParam, lParam);
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
case WM_SETFOCUS:
/* remember the focus to set state of icon */
- lret = CallWindowProcW (infoPtr->prevEditWndProc,
- hwnd, uMsg, wParam, lParam);
+ lret = DefSubclassProc(hwnd, uMsg, wParam, lParam);
infoPtr->flags |= WCBE_EDITFOCUSED;
return lret;
@@ -1912,17 +1894,16 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
/* fall through */
default:
- return CallWindowProcW (infoPtr->prevEditWndProc,
- hwnd, uMsg, wParam, lParam);
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
}
-static LRESULT WINAPI
-COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+static LRESULT CALLBACK
+COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+ UINT_PTR uId, DWORD_PTR ref_data)
{
- HWND hwndComboex = GetPropW(hwnd, COMBOEX_SUBCLASS_PROP);
- COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex);
+ COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr ((HWND)ref_data);
NMCBEENDEDITW cbeend;
NMMOUSE nmmse;
COLORREF obkc;
@@ -1947,8 +1928,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
* that ComboEx knows this is listbox.
*/
((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX;
- return CallWindowProcW (infoPtr->prevComboWndProc,
- hwnd, uMsg, wParam, lParam);
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
case WM_ERASEBKGND:
/*
@@ -1960,8 +1940,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect));
ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
SetBkColor (hDC, obkc);
- return CallWindowProcW (infoPtr->prevComboWndProc,
- hwnd, uMsg, wParam, lParam);
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
case WM_SETCURSOR:
/*
@@ -1975,8 +1954,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
nmmse.pt.y = 0;
nmmse.dwHitInfo = lParam;
COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse);
- return CallWindowProcW (infoPtr->prevComboWndProc,
- hwnd, uMsg, wParam, lParam);
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
case WM_LBUTTONDOWN:
GetClientRect (hwnd, &rect);
@@ -1986,16 +1964,16 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
pt.x = (short)LOWORD(lParam);
pt.y = (short)HIWORD(lParam);
if (PtInRect(&rect, pt))
- return CallWindowProcW (infoPtr->prevComboWndProc,
- hwnd, uMsg, wParam, lParam);
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+
infoPtr->flags |= WCBE_MOUSECAPTURED;
SetCapture(hwnd);
break;
case WM_LBUTTONUP:
if (!(infoPtr->flags & WCBE_MOUSECAPTURED))
- return CallWindowProcW (infoPtr->prevComboWndProc,
- hwnd, uMsg, wParam, lParam);
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+
ReleaseCapture();
infoPtr->flags &= ~WCBE_MOUSECAPTURED;
if (infoPtr->flags & WCBE_MOUSEDRAGGED) {
@@ -2012,8 +1990,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
COMBOEX_NotifyDragBegin(infoPtr, edit_text);
infoPtr->flags |= WCBE_MOUSEDRAGGED;
}
- return CallWindowProcW (infoPtr->prevComboWndProc,
- hwnd, uMsg, wParam, lParam);
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
case WM_COMMAND:
switch (HIWORD(wParam)) {
@@ -2157,8 +2134,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
break;
}/* fall through */
default:
- return CallWindowProcW (infoPtr->prevComboWndProc,
- hwnd, uMsg, wParam, lParam);
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
diff --git a/reactos/dll/win32/comctl32/comctl32.h b/reactos/dll/win32/comctl32/comctl32.h
index 300831434ee..3d172ae7605 100644
--- a/reactos/dll/win32/comctl32/comctl32.h
+++ b/reactos/dll/win32/comctl32/comctl32.h
@@ -231,18 +231,7 @@ extern void UPDOWN_Unregister(void);
int MONTHCAL_MonthLength(int month, int year);
-
-static inline void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to)
-{
- to->wYear = from->wYear;
- to->wMonth = from->wMonth;
- to->wDayOfWeek = from->wDayOfWeek;
- to->wDay = from->wDay;
- to->wHour = from->wHour;
- to->wMinute = from->wMinute;
- to->wSecond = from->wSecond;
- to->wMilliseconds = from->wMilliseconds;
-}
+int MONTHCAL_CalculateDayOfWeek(SYSTEMTIME *date, BOOL inplace);
extern void THEMING_Initialize(void);
extern void THEMING_Uninitialize(void);
diff --git a/reactos/dll/win32/comctl32/comctl32.rbuild b/reactos/dll/win32/comctl32/comctl32.rbuild
index 150241f9440..958edb05d11 100644
--- a/reactos/dll/win32/comctl32/comctl32.rbuild
+++ b/reactos/dll/win32/comctl32/comctl32.rbuild
@@ -47,6 +47,7 @@
treeview.c
updown.c
rsrc.rc
+ uuid
wine
user32
gdi32
diff --git a/reactos/dll/win32/comctl32/comctl32undoc.c b/reactos/dll/win32/comctl32/comctl32undoc.c
index ee684c627d4..ff94051bcc0 100644
--- a/reactos/dll/win32/comctl32/comctl32undoc.c
+++ b/reactos/dll/win32/comctl32/comctl32undoc.c
@@ -885,9 +885,11 @@ INT WINAPI EnumMRUListA (HANDLE hList, INT nItemPos, LPVOID lpBuffer,
} else {
lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
NULL, 0, NULL, NULL);
- datasize = min( witem->size, nBufferSize );
+ datasize = min( lenA, nBufferSize );
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
lpBuffer, datasize, NULL, NULL);
+ ((char *)lpBuffer)[ datasize - 1 ] = '\0';
+ datasize = lenA - 1;
}
TRACE("(%p, %d, %p, %d): returning len=%d\n",
hList, nItemPos, lpBuffer, nBufferSize, datasize);
diff --git a/reactos/dll/win32/comctl32/comctl_Bg.rc b/reactos/dll/win32/comctl32/comctl_Bg.rc
index 94dd8703c64..6c64f9ac0c8 100644
--- a/reactos/dll/win32/comctl32/comctl_Bg.rc
+++ b/reactos/dll/win32/comctl32/comctl_Bg.rc
@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Cs.rc b/reactos/dll/win32/comctl32/comctl_Cs.rc
index 63cc0bbc68b..e770e331e5c 100644
--- a/reactos/dll/win32/comctl32/comctl_Cs.rc
+++ b/reactos/dll/win32/comctl32/comctl_Cs.rc
@@ -20,6 +20,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
/* Czech strings in CP1250 */
diff --git a/reactos/dll/win32/comctl32/comctl_De.rc b/reactos/dll/win32/comctl32/comctl_De.rc
index 831e2ee9b94..87730c881f9 100644
--- a/reactos/dll/win32/comctl32/comctl_De.rc
+++ b/reactos/dll/win32/comctl32/comctl_De.rc
@@ -16,11 +16,15 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
+#pragma code_page(65001)
+
LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
STRINGTABLE DISCARDABLE
{
- IDS_CLOSE "Schlieen"
+ IDS_CLOSE "Schließen"
}
STRINGTABLE DISCARDABLE
@@ -41,7 +45,7 @@ STRINGTABLE DISCARDABLE
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Eigenschaften fr %s"
+CAPTION "Eigenschaften für %s"
FONT 8, "MS Shell Dlg"
BEGIN
DEFPUSHBUTTON "&OK", IDOK,4,122,50,14, WS_TABSTOP | WS_GROUP
@@ -57,9 +61,9 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
CAPTION "Wizard"
FONT 8, "MS Shell Dlg"
BEGIN
- PUSHBUTTON "< &Zurck", IDC_BACK_BUTTON,71,138,50,14
+ PUSHBUTTON "< &Zurück", IDC_BACK_BUTTON,71,138,50,14
DEFPUSHBUTTON "&Weiter >", IDC_NEXT_BUTTON,121,138,50,14
- DEFPUSHBUTTON "&Beenden", IDC_FINISH_BUTTON,121,138,50,14
+ DEFPUSHBUTTON "&Fertig", IDC_FINISH_BUTTON,121,138,50,14
PUSHBUTTON "Abbrechen", IDCANCEL,178,138,50,14
PUSHBUTTON "&Hilfe", IDHELP,235,138,50,14,WS_GROUP
LTEXT "", IDC_SUNKEN_LINE,7,129,278,1,SS_SUNKEN
@@ -73,15 +77,15 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Toolbar einrichten"
FONT 8, "MS Shell Dlg"
BEGIN
- DEFPUSHBUTTON "&Schlieen", IDCANCEL,308,6,44,14
- PUSHBUTTON "&Zurcksetzen", IDC_RESET_BTN,308,23,44,14
+ DEFPUSHBUTTON "&Schließen", IDCANCEL,308,6,44,14
+ PUSHBUTTON "&Zurücksetzen", IDC_RESET_BTN,308,23,44,14
PUSHBUTTON "&Hilfe", IDC_HELP_BTN,308,40,44,14
PUSHBUTTON "Nach &Oben verschieben", IDC_MOVEUP_BTN,308,74,44,14
PUSHBUTTON "Nach &Unten verschieben", IDC_MOVEDN_BTN,308,91,44,14
- LTEXT "&Vorhandene Knpfe:", -1,4,5,84,10
+ LTEXT "&Vorhandene Knöpfe:", -1,4,5,84,10
LISTBOX IDC_AVAILBTN_LBOX,4,17,120,100, LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
- PUSHBUTTON "H&inzufgen ->", IDOK, 131, 42, 44, 14
- PUSHBUTTON "<- &Lschen", IDC_REMOVE_BTN,131,62,44,14
- LTEXT "&Toolbarknpfe:", -1,182,5,78,10
+ PUSHBUTTON "H&inzufügen ->", IDOK, 131, 42, 44, 14
+ PUSHBUTTON "<- &Löschen", IDC_REMOVE_BTN,131,62,44,14
+ LTEXT "&Toolbarknöpfe:", -1,182,5,78,10
LISTBOX IDC_TOOLBARBTN_LBOX, 182,17,120,100,LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
END
diff --git a/reactos/dll/win32/comctl32/comctl_El.rc b/reactos/dll/win32/comctl32/comctl_El.rc
index a505620adfa..de08357270d 100644
--- a/reactos/dll/win32/comctl32/comctl_El.rc
+++ b/reactos/dll/win32/comctl32/comctl_El.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_GREEK, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_En.rc b/reactos/dll/win32/comctl32/comctl_En.rc
index 369eecd90ff..d8055e98f3f 100644
--- a/reactos/dll/win32/comctl32/comctl_En.rc
+++ b/reactos/dll/win32/comctl32/comctl_En.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Eo.rc b/reactos/dll/win32/comctl32/comctl_Eo.rc
index bda181759f8..59fe39ed8e8 100644
--- a/reactos/dll/win32/comctl32/comctl_Eo.rc
+++ b/reactos/dll/win32/comctl32/comctl_Eo.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_ESPERANTO, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Es.rc b/reactos/dll/win32/comctl32/comctl_Es.rc
index ea2968edcaa..ce4621791f0 100644
--- a/reactos/dll/win32/comctl32/comctl_Es.rc
+++ b/reactos/dll/win32/comctl32/comctl_Es.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Fr.rc b/reactos/dll/win32/comctl32/comctl_Fr.rc
index df56339f4c6..2fd2f89dde7 100644
--- a/reactos/dll/win32/comctl32/comctl_Fr.rc
+++ b/reactos/dll/win32/comctl32/comctl_Fr.rc
@@ -3,7 +3,7 @@
* French language support
*
* Copyright 1999 Eric Kohl
- * Copyright 2003 Vincent Bron
+ * Copyright 2003 Vincent Béron
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,11 +20,16 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
+/* UTF-8 */
+#pragma code_page(65001)
+
LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Proprits pour %s"
+CAPTION "Propriétés pour %s"
FONT 8, "MS Shell Dlg"
BEGIN
DEFPUSHBUTTON "OK", IDOK,4,122,50,14, WS_TABSTOP | WS_GROUP
@@ -40,9 +45,9 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
CAPTION "Assistant"
FONT 8, "MS Shell Dlg"
BEGIN
- PUSHBUTTON "< &Prcdent", IDC_BACK_BUTTON,71,138,50,14
- DEFPUSHBUTTON "&Suivant >", IDC_NEXT_BUTTON,121,138,50,14
- DEFPUSHBUTTON "Terminer", IDC_FINISH_BUTTON,121,138,50,14
+ PUSHBUTTON "< &Précédent", IDC_BACK_BUTTON,71,138,50,14
+ DEFPUSHBUTTON "&Suivant >", IDC_NEXT_BUTTON,123,138,50,14
+ DEFPUSHBUTTON "Terminer", IDC_FINISH_BUTTON,123,138,50,14
PUSHBUTTON "Annuler", IDCANCEL,178,138,50,14
PUSHBUTTON "Aide", IDHELP,235,138,50,14,WS_GROUP
LTEXT "", IDC_SUNKEN_LINE,7,129,278,1,SS_SUNKEN
@@ -57,15 +62,15 @@ CAPTION "Personnaliser la barre d'outils"
FONT 8, "MS Shell Dlg"
BEGIN
DEFPUSHBUTTON "&Fermer", IDCANCEL,308,6,44,14
- PUSHBUTTON "&Rinitialiser", IDC_RESET_BTN,308,23,44,14
+ PUSHBUTTON "&Réinitialiser", IDC_RESET_BTN,308,23,44,14
PUSHBUTTON "Aid&e", IDC_HELP_BTN,308,40,44,14
PUSHBUTTON "&Monter", IDC_MOVEUP_BTN,308,74,44,14
PUSHBUTTON "&Descendre", IDC_MOVEDN_BTN,308,91,44,14
- LTEXT "Boutons disponibles :", -1,4,5,84,10
+ LTEXT "Boutons &disponibles :", -1,4,5,84,10
LISTBOX IDC_AVAILBTN_LBOX,4,17,120,100, LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
PUSHBUTTON "A&jouter ->", IDOK, 131, 42, 44, 14
PUSHBUTTON "<- E&nlever", IDC_REMOVE_BTN,131,62,44,14
- LTEXT "&Boutons de la barre d'outils :", -1,182,5,78,10
+ LTEXT "&Boutons de la barre d'outils :", -1,182,5,93,10
LISTBOX IDC_TOOLBARBTN_LBOX, 182,17,120,100,LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
END
@@ -77,12 +82,12 @@ STRINGTABLE DISCARDABLE
STRINGTABLE DISCARDABLE
{
IDM_TODAY "Aujourd'hui:"
- IDM_GOTODAY "Aller aujourd'hui"
+ IDM_GOTODAY "Aller à aujourd'hui"
}
STRINGTABLE DISCARDABLE
{
- IDS_SEPARATOR "Sparateur"
+ IDS_SEPARATOR "Séparateur"
}
STRINGTABLE DISCARDABLE
diff --git a/reactos/dll/win32/comctl32/comctl_Hu.rc b/reactos/dll/win32/comctl32/comctl_Hu.rc
index 6019777c1bd..2ba1160efc1 100644
--- a/reactos/dll/win32/comctl32/comctl_Hu.rc
+++ b/reactos/dll/win32/comctl32/comctl_Hu.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_It.rc b/reactos/dll/win32/comctl32/comctl_It.rc
index 2b2f315589e..75bd9c19c4c 100644
--- a/reactos/dll/win32/comctl32/comctl_It.rc
+++ b/reactos/dll/win32/comctl32/comctl_It.rc
@@ -17,6 +17,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Ja.rc b/reactos/dll/win32/comctl32/comctl_Ja.rc
index e3c1272f29a..ce16f5a2f53 100644
--- a/reactos/dll/win32/comctl32/comctl_Ja.rc
+++ b/reactos/dll/win32/comctl32/comctl_Ja.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
/* UTF-8 */
#pragma code_page(65001)
@@ -23,7 +25,7 @@ LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Properties for %s"
+CAPTION "%sのプロパティ"
FONT 9, "MS Shell Dlg"
BEGIN
DEFPUSHBUTTON "OK", IDOK,4,122,50,14, WS_TABSTOP | WS_GROUP
@@ -36,11 +38,11 @@ END
IDD_WIZARD DIALOG DISCARDABLE 0, 0, 290, 159
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Wizard"
+CAPTION "ウィザード"
FONT 9, "MS Shell Dlg"
BEGIN
PUSHBUTTON "< 戻る(&B)", IDC_BACK_BUTTON,71,138,50,14
- DEFPUSHBUTTON "進む(&N) >", IDC_NEXT_BUTTON,121,138,50,14
+ DEFPUSHBUTTON "次へ(&N) >", IDC_NEXT_BUTTON,121,138,50,14
DEFPUSHBUTTON "完了", IDC_FINISH_BUTTON,121,138,50,14
PUSHBUTTON "キャンセル", IDCANCEL,178,138,50,14
PUSHBUTTON "ヘルプ", IDHELP,235,138,50,14,WS_GROUP
@@ -52,7 +54,7 @@ END
IDD_TBCUSTOMIZE DIALOG DISCARDABLE 10, 20, 357, 125
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-CAPTION "Customize Toolbar"
+CAPTION "ツールバーのカスタマイズ"
FONT 9, "MS Shell Dlg"
BEGIN
DEFPUSHBUTTON "閉じる(&C)", IDCANCEL,308,6,44,14
@@ -60,33 +62,31 @@ BEGIN
PUSHBUTTON "ヘルプ(&H)", IDC_HELP_BTN,308,40,44,14
PUSHBUTTON "上へ (&U)", IDC_MOVEUP_BTN,308,74,44,14
PUSHBUTTON "下へ (&D)", IDC_MOVEDN_BTN,308,91,44,14
- LTEXT "A&vailable buttons:", -1,4,5,84,10
+ LTEXT "利用可能なボタン(&V):", -1,4,5,84,10
LISTBOX IDC_AVAILBTN_LBOX,4,17,120,100, LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
PUSHBUTTON "追加(&A) ->", IDOK, 131, 42, 44, 14
PUSHBUTTON "<- 削除(&R)", IDC_REMOVE_BTN,131,62,44,14
- LTEXT "&Toolbar buttons:", -1,182,5,78,10
+ LTEXT "ツールバーのボタン(&T):", -1,182,5,78,10
LISTBOX IDC_TOOLBARBTN_LBOX, 182,17,120,100,LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
END
STRINGTABLE DISCARDABLE
{
- IDS_CLOSE "Close"
+ IDS_CLOSE "閉じる"
}
STRINGTABLE DISCARDABLE
{
- IDM_TODAY "Today:"
- IDM_GOTODAY "Go to today"
+ IDM_TODAY "今日:"
+ IDM_GOTODAY "今日へ移動"
}
STRINGTABLE DISCARDABLE
{
- IDS_SEPARATOR "Separator"
+ IDS_SEPARATOR "区切り"
}
STRINGTABLE DISCARDABLE
{
- HKY_NONE "None"
+ HKY_NONE "なし"
}
-
-#pragma code_page(default)
diff --git a/reactos/dll/win32/comctl32/comctl_Ko.rc b/reactos/dll/win32/comctl32/comctl_Ko.rc
index 6574b66a74e..daf9917e62a 100644
--- a/reactos/dll/win32/comctl32/comctl_Ko.rc
+++ b/reactos/dll/win32/comctl32/comctl_Ko.rc
@@ -17,6 +17,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Lt.rc b/reactos/dll/win32/comctl32/comctl_Lt.rc
index bfe0986d749..f5f329429cb 100644
--- a/reactos/dll/win32/comctl32/comctl_Lt.rc
+++ b/reactos/dll/win32/comctl32/comctl_Lt.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
/* UTF-8 */
#pragma code_page(65001)
@@ -88,5 +90,3 @@ STRINGTABLE DISCARDABLE
{
HKY_NONE "Joks"
}
-
-#pragma code_page(default)
diff --git a/reactos/dll/win32/comctl32/comctl_Nl.rc b/reactos/dll/win32/comctl32/comctl_Nl.rc
index a277b0f6cb9..fe2bf7a9d4a 100644
--- a/reactos/dll/win32/comctl32/comctl_Nl.rc
+++ b/reactos/dll/win32/comctl32/comctl_Nl.rc
@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
@@ -75,7 +77,7 @@ STRINGTABLE DISCARDABLE
STRINGTABLE DISCARDABLE
{
IDM_TODAY "Vandaag:"
- IDM_GOTODAY "Ga vandaag naar"
+ IDM_GOTODAY "Ga naar vandaag"
}
STRINGTABLE DISCARDABLE
diff --git a/reactos/dll/win32/comctl32/comctl_No.rc b/reactos/dll/win32/comctl32/comctl_No.rc
index 77b9ec8da70..6361f048943 100644
--- a/reactos/dll/win32/comctl32/comctl_No.rc
+++ b/reactos/dll/win32/comctl32/comctl_No.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Pl.rc b/reactos/dll/win32/comctl32/comctl_Pl.rc
index 91441344597..12f13a63fa1 100644
--- a/reactos/dll/win32/comctl32/comctl_Pl.rc
+++ b/reactos/dll/win32/comctl32/comctl_Pl.rc
@@ -17,6 +17,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Pt.rc b/reactos/dll/win32/comctl32/comctl_Pt.rc
index 3ab75fda596..914c4c22439 100644
--- a/reactos/dll/win32/comctl32/comctl_Pt.rc
+++ b/reactos/dll/win32/comctl32/comctl_Pt.rc
@@ -1,6 +1,7 @@
/*
* Copyright 2003 Marcelo Duarte
- * Copyright 2006-2007 Amrico Jos Melo
+ * Copyright 2006-2007 Américo José Melo
+ * Copyright 2009 Ricardo Filipe
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,21 +18,11 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
+#include "comctl32.h"
-IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
-STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Propriedades para %s"
-FONT 8, "MS Shell Dlg"
-BEGIN
- DEFPUSHBUTTON "OK", IDOK,4,122,50,14, WS_TABSTOP | WS_GROUP
- PUSHBUTTON "Cancelar", IDCANCEL,58,122,50,14
- PUSHBUTTON "&Aplicar", IDC_APPLY_BUTTON,112,122,50,14,WS_DISABLED
- PUSHBUTTON "Ajuda", IDHELP,166,122,50,14,WS_TABSTOP|WS_GROUP
- CONTROL "Tab", IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS|WS_GROUP|WS_TABSTOP|TCS_MULTILINE,4,4,212,114
-END
+#pragma code_page(65001)
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE
+LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
@@ -45,27 +36,21 @@ BEGIN
CONTROL "Separador", IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS|WS_GROUP|WS_TABSTOP|TCS_MULTILINE,4,4,212,114
END
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
IDD_WIZARD DIALOG DISCARDABLE 0, 0, 290, 159
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
CAPTION "Assistente"
FONT 8, "MS Shell Dlg"
BEGIN
PUSHBUTTON "< &Voltar", IDC_BACK_BUTTON,71,138,50,14
- DEFPUSHBUTTON "&Avanar >", IDC_NEXT_BUTTON,121,138,50,14
+ DEFPUSHBUTTON "&Avançar >", IDC_NEXT_BUTTON,121,138,50,14
DEFPUSHBUTTON "Finalizar", IDC_FINISH_BUTTON,121,138,50,14
PUSHBUTTON "Cancelar", IDCANCEL,178,138,50,14
PUSHBUTTON "Ajuda", IDHELP,235,138,50,14,WS_GROUP
LTEXT "", IDC_SUNKEN_LINE,7,129,278,1,SS_SUNKEN
- CONTROL "Tab", IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS | WS_DISABLED,7,7,258,5
+ CONTROL "Separador", IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS | WS_DISABLED,7,7,258,5
LTEXT "", IDC_SUNKEN_LINEHEADER,0,35,290,1,SS_LEFT | SS_SUNKEN | WS_CHILD | WS_VISIBLE
END
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
IDD_TBCUSTOMIZE DIALOG DISCARDABLE 10, 20, 357, 125
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Personalizar barra de ferramentas"
@@ -76,42 +61,30 @@ BEGIN
PUSHBUTTON "&Ajuda", IDC_HELP_BTN,308,40,44,14
PUSHBUTTON "A&cima", IDC_MOVEUP_BTN,308,74,44,14
PUSHBUTTON "A&baixo", IDC_MOVEDN_BTN,308,91,44,14
- LTEXT "Botes &disponveis:", -1,4,5,84,10
+ LTEXT "Botões &disponíveis:", -1,4,5,84,10
LISTBOX IDC_AVAILBTN_LBOX,4,17,120,100, LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
PUSHBUTTON "&Adicionar ->", IDOK, 131, 42, 44, 14
PUSHBUTTON "<- &Remover", IDC_REMOVE_BTN,131,62,44,14
- LTEXT "&Botes da barra de ferramentas:", -1,182,5,78,10
+ LTEXT "&Botões da barra de ferramentas:", -1,182,5,78,10
LISTBOX IDC_TOOLBARBTN_LBOX, 182,17,120,100,LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
END
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
STRINGTABLE DISCARDABLE
{
IDS_CLOSE "Fechar"
}
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
STRINGTABLE DISCARDABLE
{
IDM_TODAY "Hoje:"
IDM_GOTODAY "Ir para hoje"
}
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
STRINGTABLE DISCARDABLE
{
IDS_SEPARATOR "Separador"
}
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
STRINGTABLE DISCARDABLE
{
HKY_NONE "Nenhum"
diff --git a/reactos/dll/win32/comctl32/comctl_Ro.rc b/reactos/dll/win32/comctl32/comctl_Ro.rc
index 0581d0dadbd..497f626ee5b 100644
--- a/reactos/dll/win32/comctl32/comctl_Ro.rc
+++ b/reactos/dll/win32/comctl32/comctl_Ro.rc
@@ -17,6 +17,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
#pragma code_page(65001)
@@ -88,5 +90,3 @@ STRINGTABLE DISCARDABLE
{
HKY_NONE "Nimic"
}
-
-#pragma code_page(default)
diff --git a/reactos/dll/win32/comctl32/comctl_Ru.rc b/reactos/dll/win32/comctl32/comctl_Ru.rc
index 2bbb513a09c..9cba44d1b62 100644
--- a/reactos/dll/win32/comctl32/comctl_Ru.rc
+++ b/reactos/dll/win32/comctl32/comctl_Ru.rc
@@ -18,31 +18,36 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
+/* UTF-8 */
+#pragma code_page(65001)
+
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION " %s"
+CAPTION "Свойства для %s"
FONT 8, "MS Shell Dlg"
BEGIN
DEFPUSHBUTTON "OK", IDOK,4,122,50,14, WS_TABSTOP | WS_GROUP
- PUSHBUTTON "", IDCANCEL,58,122,50,14
- PUSHBUTTON "&", IDC_APPLY_BUTTON,112,122,50,14,WS_DISABLED
- PUSHBUTTON "&", IDHELP,166,122,50,14,WS_TABSTOP|WS_GROUP
+ PUSHBUTTON "Отмена", IDCANCEL,58,122,50,14
+ PUSHBUTTON "При&менить", IDC_APPLY_BUTTON,112,122,50,14,WS_DISABLED
+ PUSHBUTTON "&Справка", IDHELP,166,122,50,14,WS_TABSTOP|WS_GROUP
CONTROL "Tab", IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS|WS_GROUP|WS_TABSTOP|TCS_MULTILINE,4,4,212,114
END
IDD_WIZARD DIALOG DISCARDABLE 0, 0, 290, 159
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION ""
+CAPTION "Мастер"
FONT 8, "MS Shell Dlg"
BEGIN
- PUSHBUTTON "< &", IDC_BACK_BUTTON,71,138,50,14
- DEFPUSHBUTTON "& >", IDC_NEXT_BUTTON,121,138,50,14
- DEFPUSHBUTTON "", IDC_FINISH_BUTTON,121,138,50,14
- PUSHBUTTON "", IDCANCEL,178,138,50,14
- PUSHBUTTON "&", IDHELP,235,138,50,14,WS_GROUP
+ PUSHBUTTON "< &Назад", IDC_BACK_BUTTON,71,138,50,14
+ DEFPUSHBUTTON "&Далее >", IDC_NEXT_BUTTON,121,138,50,14
+ DEFPUSHBUTTON "Готово", IDC_FINISH_BUTTON,121,138,50,14
+ PUSHBUTTON "Отмена", IDCANCEL,178,138,50,14
+ PUSHBUTTON "&Справка", IDHELP,235,138,50,14,WS_GROUP
LTEXT "", IDC_SUNKEN_LINE,7,129,278,1,SS_SUNKEN
CONTROL "Tab", IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS | WS_DISABLED,7,7,258,5
LTEXT "", IDC_SUNKEN_LINEHEADER,0,35,290,1,SS_LEFT | SS_SUNKEN | WS_CHILD | WS_VISIBLE
@@ -51,39 +56,39 @@ END
IDD_TBCUSTOMIZE DIALOG DISCARDABLE 10, 20, 357, 125
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-CAPTION " "
+CAPTION "Настройка панели инструментов"
FONT 8, "MS Shell Dlg"
BEGIN
- DEFPUSHBUTTON "&", IDCANCEL,308,6,44,14
- PUSHBUTTON "&", IDC_RESET_BTN,308,23,44,14
- PUSHBUTTON "&", IDC_HELP_BTN,308,40,44,14
- PUSHBUTTON " &", IDC_MOVEUP_BTN,308,74,44,14
- PUSHBUTTON " &", IDC_MOVEDN_BTN,308,91,44,14
- LTEXT "& :", -1,4,5,84,10
+ DEFPUSHBUTTON "&Закрыть", IDCANCEL,308,6,44,14
+ PUSHBUTTON "С&бросить", IDC_RESET_BTN,308,23,44,14
+ PUSHBUTTON "&Справка", IDC_HELP_BTN,308,40,44,14
+ PUSHBUTTON "Переместить &вверх", IDC_MOVEUP_BTN,308,74,44,14
+ PUSHBUTTON "Переместить &вниз", IDC_MOVEDN_BTN,308,91,44,14
+ LTEXT "&Доступные кнопки:", -1,4,5,84,10
LISTBOX IDC_AVAILBTN_LBOX,4,17,120,100, LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
- PUSHBUTTON "& ->", IDOK, 131, 42, 44, 14
- PUSHBUTTON "<- &", IDC_REMOVE_BTN,131,62,44,14
- LTEXT "& :", -1,182,5,78,10
+ PUSHBUTTON "&Добавить ->", IDOK, 131, 42, 44, 14
+ PUSHBUTTON "<- &Удалить", IDC_REMOVE_BTN,131,62,44,14
+ LTEXT "&Кнопки панели инструментов:", -1,182,5,78,10
LISTBOX IDC_TOOLBARBTN_LBOX, 182,17,120,100,LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
END
STRINGTABLE DISCARDABLE
{
- IDS_CLOSE ""
+ IDS_CLOSE "Закрыть"
}
STRINGTABLE DISCARDABLE
{
- IDM_TODAY ":"
- IDM_GOTODAY " "
+ IDM_TODAY "Сегодня:"
+ IDM_GOTODAY "Текущая дата"
}
STRINGTABLE DISCARDABLE
{
- IDS_SEPARATOR ""
+ IDS_SEPARATOR "Разделитель"
}
STRINGTABLE DISCARDABLE
{
- HKY_NONE ""
+ HKY_NONE "Нет"
}
diff --git a/reactos/dll/win32/comctl32/comctl_Si.rc b/reactos/dll/win32/comctl32/comctl_Si.rc
index aa9a7b69975..cc1053f18f6 100644
--- a/reactos/dll/win32/comctl32/comctl_Si.rc
+++ b/reactos/dll/win32/comctl32/comctl_Si.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
#pragma code_page(65001)
LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT
@@ -87,5 +89,3 @@ STRINGTABLE DISCARDABLE
{
HKY_NONE "Brez"
}
-
-#pragma code_page(default)
diff --git a/reactos/dll/win32/comctl32/comctl_Sk.rc b/reactos/dll/win32/comctl32/comctl_Sk.rc
index fb5f65dcfa0..c543e376f30 100644
--- a/reactos/dll/win32/comctl32/comctl_Sk.rc
+++ b/reactos/dll/win32/comctl32/comctl_Sk.rc
@@ -17,6 +17,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
/* Slovak strings in CP1250 */
LANGUAGE LANG_SLOVAK, SUBLANG_DEFAULT
diff --git a/reactos/dll/win32/comctl32/comctl_Sv.rc b/reactos/dll/win32/comctl32/comctl_Sv.rc
index 2037d797c24..18bfefc6635 100644
--- a/reactos/dll/win32/comctl32/comctl_Sv.rc
+++ b/reactos/dll/win32/comctl32/comctl_Sv.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Th.rc b/reactos/dll/win32/comctl32/comctl_Th.rc
index 3195e1b9a55..ff1e1fa4feb 100644
--- a/reactos/dll/win32/comctl32/comctl_Th.rc
+++ b/reactos/dll/win32/comctl32/comctl_Th.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_THAI, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Tr.rc b/reactos/dll/win32/comctl32/comctl_Tr.rc
index c0f65127f9d..cdc89ca0533 100644
--- a/reactos/dll/win32/comctl32/comctl_Tr.rc
+++ b/reactos/dll/win32/comctl32/comctl_Tr.rc
@@ -16,6 +16,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Uk.rc b/reactos/dll/win32/comctl32/comctl_Uk.rc
index 95e502dd471..608697da80a 100644
--- a/reactos/dll/win32/comctl32/comctl_Uk.rc
+++ b/reactos/dll/win32/comctl32/comctl_Uk.rc
@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT
IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
diff --git a/reactos/dll/win32/comctl32/comctl_Zh.rc b/reactos/dll/win32/comctl32/comctl_Zh.rc
index b6c5692dea6..8919119cae9 100644
--- a/reactos/dll/win32/comctl32/comctl_Zh.rc
+++ b/reactos/dll/win32/comctl32/comctl_Zh.rc
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "comctl32.h"
+
/* Chinese text is encoded in UTF-8 */
#pragma code_page(65001)
@@ -161,5 +163,3 @@ STRINGTABLE DISCARDABLE
{
HKY_NONE "無"
}
-
-#pragma code_page(default)
diff --git a/reactos/dll/win32/comctl32/commctrl.c b/reactos/dll/win32/comctl32/commctrl.c
index db0eade682b..eb0f6b5293e 100644
--- a/reactos/dll/win32/comctl32/commctrl.c
+++ b/reactos/dll/win32/comctl32/commctrl.c
@@ -784,7 +784,7 @@ CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
if(hwndTB) {
TBADDBITMAP tbab;
- SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM)uStructSize, 0);
+ SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
/* set bitmap and button size */
/*If CreateToolbarEx receives 0, windows sets default values*/
@@ -811,12 +811,11 @@ CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
tbab.hInst = hBMInst;
tbab.nID = wBMID;
- SendMessageW (hwndTB, TB_ADDBITMAP, (WPARAM)nBitmaps, (LPARAM)&tbab);
+ SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
}
/* add buttons */
if(iNumButtons > 0)
- SendMessageW (hwndTB, TB_ADDBUTTONSW,
- (WPARAM)iNumButtons, (LPARAM)lpButtons);
+ SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
}
return hwndTB;
@@ -923,8 +922,7 @@ CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
if (hbm) {
HDC hdcDst = CreateCompatibleDC (hdcScreen);
HBITMAP hbmOld = SelectObject (hdcDst, hbm);
- const BYTE *lpBits = (const BYTE *)(lpBitmap + 1);
- lpBits += nColorTableSize * sizeof(RGBQUAD);
+ const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
SRCCOPY);
@@ -1403,9 +1401,8 @@ COMCTL32_CreateToolTip(HWND hwndOwner)
nmttc.hdr.code = NM_TOOLTIPSCREATED;
nmttc.hwndToolTips = hwndToolTip;
- SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
- (WPARAM)GetWindowLongPtrW(hwndTrueOwner, GWLP_ID),
- (LPARAM)&nmttc);
+ SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
+ GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
}
return hwndToolTip;
diff --git a/reactos/dll/win32/comctl32/datetime.c b/reactos/dll/win32/comctl32/datetime.c
index ae538a535e9..24189507d64 100644
--- a/reactos/dll/win32/comctl32/datetime.c
+++ b/reactos/dll/win32/comctl32/datetime.c
@@ -31,7 +31,6 @@
* TODO:
* -- DTS_APPCANPARSE
* -- DTS_SHORTDATECENTURYFORMAT
- * -- DTN_CLOSEUP
* -- DTN_FORMAT
* -- DTN_FORMATQUERY
* -- DTN_USERSTRING
@@ -88,6 +87,7 @@ typedef struct
/* in monthcal.c */
extern int MONTHCAL_MonthLength(int month, int year);
+extern int MONTHCAL_CalculateDayOfWeek(SYSTEMTIME *date, BOOL inplace);
/* this list of defines is closely related to `allowedformatchars' defined
* in datetime.c; the high nibble indicates the `base type' of the format
@@ -125,10 +125,11 @@ extern int MONTHCAL_MonthLength(int month, int year);
#define DTHT_DATEFIELD 0xff /* for hit-testing */
-#define DTHT_NONE 0
-#define DTHT_CHECKBOX 0x200 /* these should end at '00' , to make */
-#define DTHT_MCPOPUP 0x300 /* & DTHT_DATEFIELD 0 when DATETIME_KeyDown */
-#define DTHT_GOTFOCUS 0x400 /* tests for date-fields */
+#define DTHT_NONE 0x1000
+#define DTHT_CHECKBOX 0x2000 /* these should end at '00' , to make */
+#define DTHT_MCPOPUP 0x3000 /* & DTHT_DATEFIELD 0 when DATETIME_KeyDown */
+#define DTHT_GOTFOCUS 0x4000 /* tests for date-fields */
+#define DTHT_NODATEMASK 0xf000 /* to mask check and drop down from others */
static BOOL DATETIME_SendSimpleNotify (const DATETIME_INFO *infoPtr, UINT code);
static BOOL DATETIME_SendDateTimeChangeNotify (const DATETIME_INFO *infoPtr);
@@ -138,43 +139,45 @@ static const int maxrepetition [] = {4,2,2,2,4,2,2,4,-1};
static DWORD
-DATETIME_GetSystemTime (const DATETIME_INFO *infoPtr, SYSTEMTIME *lprgSysTimeArray)
+DATETIME_GetSystemTime (const DATETIME_INFO *infoPtr, SYSTEMTIME *systime)
{
- if (!lprgSysTimeArray) return GDT_NONE;
+ if (!systime) return GDT_NONE;
if ((infoPtr->dwStyle & DTS_SHOWNONE) &&
(SendMessageW (infoPtr->hwndCheckbut, BM_GETCHECK, 0, 0) == BST_UNCHECKED))
return GDT_NONE;
- MONTHCAL_CopyTime (&infoPtr->date, lprgSysTimeArray);
+ *systime = infoPtr->date;
return GDT_VALID;
}
static BOOL
-DATETIME_SetSystemTime (DATETIME_INFO *infoPtr, DWORD flag, const SYSTEMTIME *lprgSysTimeArray)
+DATETIME_SetSystemTime (DATETIME_INFO *infoPtr, DWORD flag, const SYSTEMTIME *systime)
{
- if (!lprgSysTimeArray) return 0;
+ if (!systime) return 0;
TRACE("%04d/%02d/%02d %02d:%02d:%02d\n",
- lprgSysTimeArray->wYear, lprgSysTimeArray->wMonth, lprgSysTimeArray->wDay,
- lprgSysTimeArray->wHour, lprgSysTimeArray->wMinute, lprgSysTimeArray->wSecond);
+ systime->wYear, systime->wMonth, systime->wDay,
+ systime->wHour, systime->wMinute, systime->wSecond);
if (flag == GDT_VALID) {
- if (lprgSysTimeArray->wYear < 1601 || lprgSysTimeArray->wYear > 30827 ||
- lprgSysTimeArray->wMonth < 1 || lprgSysTimeArray->wMonth > 12 ||
- lprgSysTimeArray->wDayOfWeek > 6 ||
- lprgSysTimeArray->wDay < 1 || lprgSysTimeArray->wDay > 31 ||
- lprgSysTimeArray->wHour > 23 ||
- lprgSysTimeArray->wMinute > 59 ||
- lprgSysTimeArray->wSecond > 59 ||
- lprgSysTimeArray->wMilliseconds > 999
+ if (systime->wYear < 1601 || systime->wYear > 30827 ||
+ systime->wMonth < 1 || systime->wMonth > 12 ||
+ systime->wDay < 1 || systime->wDay > 31 ||
+ systime->wHour > 23 ||
+ systime->wMinute > 59 ||
+ systime->wSecond > 59 ||
+ systime->wMilliseconds > 999
)
- return 0;
+ return FALSE;
infoPtr->dateValid = TRUE;
- MONTHCAL_CopyTime (lprgSysTimeArray, &infoPtr->date);
+ infoPtr->date = *systime;
+ /* always store a valid day of week */
+ MONTHCAL_CalculateDayOfWeek(&infoPtr->date, TRUE);
+
SendMessageW (infoPtr->hMonthCal, MCM_SETCURSEL, 0, (LPARAM)(&infoPtr->date));
SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_CHECKED, 0);
} else if ((infoPtr->dwStyle & DTS_SHOWNONE) && (flag == GDT_NONE)) {
@@ -182,7 +185,7 @@ DATETIME_SetSystemTime (DATETIME_INFO *infoPtr, DWORD flag, const SYSTEMTIME *lp
SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_UNCHECKED, 0);
}
else
- return 0;
+ return FALSE;
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
return TRUE;
@@ -286,7 +289,7 @@ DATETIME_SetFormatW (DATETIME_INFO *infoPtr, LPCWSTR lpszFormat)
format_item = LOCALE_STIMEFORMAT;
else /* DTS_SHORTDATEFORMAT */
format_item = LOCALE_SSHORTDATE;
- GetLocaleInfoW( GetSystemDefaultLCID(), format_item, format_buf, sizeof(format_buf)/sizeof(format_buf[0]));
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, format_item, format_buf, sizeof(format_buf)/sizeof(format_buf[0]));
lpszFormat = format_buf;
}
@@ -407,12 +410,12 @@ DATETIME_ReturnTxt (const DATETIME_INFO *infoPtr, int count, LPWSTR result, int
wsprintfW (result, fmt__2dW, date.wMonth);
break;
case THREECHARMONTH:
- GetLocaleInfoW(GetSystemDefaultLCID(), LOCALE_SMONTHNAME1+date.wMonth -1,
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1+date.wMonth -1,
buffer, sizeof(buffer)/sizeof(buffer[0]));
wsprintfW (result, fmt__3sW, buffer);
break;
case FULLMONTH:
- GetLocaleInfoW(GetSystemDefaultLCID(),LOCALE_SMONTHNAME1+date.wMonth -1,
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1+date.wMonth -1,
result, resultSize);
break;
case ONELETTERAMPM:
@@ -444,19 +447,6 @@ DATETIME_ReturnTxt (const DATETIME_INFO *infoPtr, int count, LPWSTR result, int
TRACE ("arg%d=%x->[%s]\n", count, infoPtr->fieldspec[count], debugstr_w(result));
}
-/* Offsets of days in the week to the weekday of january 1 in a leap year. */
-static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
-
-/* returns the day in the week(0 == sunday, 6 == saturday) */
-/* day(1 == 1st, 2 == 2nd... etc), year is the year value */
-static int DATETIME_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year)
-{
- year-=(month < 3);
-
- return((year + year/4 - year/100 + year/400 +
- DayOfWeekTable[month-1] + day ) % 7);
-}
-
static int wrap(int val, int delta, int minVal, int maxVal)
{
val += delta;
@@ -480,14 +470,14 @@ DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number, int delta)
case TWODIGITYEAR:
case FULLYEAR:
date->wYear = wrap(date->wYear, delta, 1752, 9999);
- date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear);
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
break;
case ONEDIGITMONTH:
case TWODIGITMONTH:
case THREECHARMONTH:
case FULLMONTH:
date->wMonth = wrap(date->wMonth, delta, 1, 12);
- date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear);
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
delta = 0;
/* fall through */
case ONEDIGITDAY:
@@ -495,7 +485,7 @@ DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number, int delta)
case THREECHARDAY:
case FULLDAY:
date->wDay = wrap(date->wDay, delta, 1, MONTHCAL_MonthLength(date->wMonth, date->wYear));
- date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear);
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
break;
case ONELETTERAMPM:
case TWOLETTERAMPM:
@@ -537,7 +527,7 @@ DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number, int delta)
static void
-DATETIME_ReturnFieldWidth (const DATETIME_INFO *infoPtr, HDC hdc, int count, SHORT *fieldWidthPtr)
+DATETIME_ReturnFieldWidth (const DATETIME_INFO *infoPtr, HDC hdc, int count, SHORT *width)
{
/* fields are a fixed width, determined by the largest possible string */
/* presumably, these widths should be language dependent */
@@ -546,10 +536,6 @@ DATETIME_ReturnFieldWidth (const DATETIME_INFO *infoPtr, HDC hdc, int count, SHO
static const WCHAR fld_d4W[] = { '2', '2', '2', '2', 0 };
static const WCHAR fld_am1[] = { 'A', 0 };
static const WCHAR fld_am2[] = { 'A', 'M', 0 };
- static const WCHAR fld_day[] = { 'W', 'e', 'd', 'n', 'e', 's', 'd', 'a', 'y', 0 };
- static const WCHAR fld_day3[] = { 'W', 'e', 'd', 0 };
- static const WCHAR fld_mon[] = { 'S', 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r', 0 };
- static const WCHAR fld_mon3[] = { 'D', 'e', 'c', 0 };
int spec;
WCHAR buffer[80];
LPCWSTR bufptr;
@@ -596,18 +582,64 @@ DATETIME_ReturnFieldWidth (const DATETIME_INFO *infoPtr, HDC hdc, int count, SHO
case FULLYEAR:
bufptr = fld_d4W;
break;
- case THREECHARDAY:
- bufptr = fld_day3;
- break;
- case FULLDAY:
- bufptr = fld_day;
- break;
case THREECHARMONTH:
- bufptr = fld_mon3;
- break;
case FULLMONTH:
- bufptr = fld_mon;
- break;
+ case THREECHARDAY:
+ case FULLDAY:
+ {
+ static const WCHAR fld_day[] = {'W','e','d','n','e','s','d','a','y',0};
+ static const WCHAR fld_abbrday[] = {'W','e','d',0};
+ static const WCHAR fld_mon[] = {'S','e','p','t','e','m','b','e','r',0};
+ static const WCHAR fld_abbrmon[] = {'D','e','c',0};
+
+ const WCHAR *fall;
+ LCTYPE lctype;
+ INT i, max_count;
+ LONG cx;
+
+ /* choose locale data type and fallback string */
+ switch (spec) {
+ case THREECHARDAY:
+ fall = fld_abbrday;
+ lctype = LOCALE_SABBREVDAYNAME1;
+ max_count = 7;
+ break;
+ case FULLDAY:
+ fall = fld_day;
+ lctype = LOCALE_SDAYNAME1;
+ max_count = 7;
+ break;
+ case THREECHARMONTH:
+ fall = fld_abbrmon;
+ lctype = LOCALE_SABBREVMONTHNAME1;
+ max_count = 12;
+ break;
+ default: /* FULLMONTH */
+ fall = fld_mon;
+ lctype = LOCALE_SMONTHNAME1;
+ max_count = 12;
+ break;
+ }
+
+ cx = 0;
+ for (i = 0; i < max_count; i++)
+ {
+ if(GetLocaleInfoW(LOCALE_USER_DEFAULT, lctype + i,
+ buffer, lstrlenW(buffer)))
+ {
+ GetTextExtentPoint32W(hdc, buffer, lstrlenW(buffer), &size);
+ if (size.cx > cx) cx = size.cx;
+ }
+ else /* locale independent fallback on failure */
+ {
+ GetTextExtentPoint32W(hdc, fall, lstrlenW(fall), &size);
+ cx = size.cx;
+ break;
+ }
+ }
+ *width = cx;
+ return;
+ }
case ONELETTERAMPM:
bufptr = fld_am1;
break;
@@ -620,25 +652,21 @@ DATETIME_ReturnFieldWidth (const DATETIME_INFO *infoPtr, HDC hdc, int count, SHO
}
}
GetTextExtentPoint32W (hdc, bufptr, strlenW(bufptr), &size);
- *fieldWidthPtr = size.cx;
+ *width = size.cx;
}
static void
DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc)
{
- int i,prevright;
- RECT *field;
- RECT *rcDraw = &infoPtr->rcDraw;
- RECT *calbutton = &infoPtr->calbutton;
- RECT *checkbox = &infoPtr->checkbox;
- SIZE size;
- COLORREF oldTextColor;
- SHORT fieldWidth = 0;
-
- /* draw control edge */
TRACE("\n");
if (infoPtr->dateValid) {
+ int i, prevright;
+ RECT *field;
+ RECT *rcDraw = &infoPtr->rcDraw;
+ SIZE size;
+ COLORREF oldTextColor;
+ SHORT fieldWidth = 0;
HFONT oldFont = SelectObject (hdc, infoPtr->hFont);
INT oldBkMode = SetBkMode (hdc, TRANSPARENT);
WCHAR txt[80];
@@ -647,25 +675,36 @@ DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc)
GetTextExtentPoint32W (hdc, txt, strlenW(txt), &size);
rcDraw->bottom = size.cy + 2;
- prevright = checkbox->right = ((infoPtr->dwStyle & DTS_SHOWNONE) ? 18 : 2);
+ prevright = infoPtr->checkbox.right = ((infoPtr->dwStyle & DTS_SHOWNONE) ? 18 : 2);
for (i = 0; i < infoPtr->nrFields; i++) {
DATETIME_ReturnTxt (infoPtr, i, txt, sizeof(txt)/sizeof(txt[0]));
GetTextExtentPoint32W (hdc, txt, strlenW(txt), &size);
DATETIME_ReturnFieldWidth (infoPtr, hdc, i, &fieldWidth);
field = &infoPtr->fieldRect[i];
- field->left = prevright;
- field->right = prevright + fieldWidth;
- field->top = rcDraw->top;
+ field->left = prevright;
+ field->right = prevright + fieldWidth;
+ field->top = rcDraw->top;
field->bottom = rcDraw->bottom;
prevright = field->right;
if (infoPtr->dwStyle & WS_DISABLED)
oldTextColor = SetTextColor (hdc, comctl32_color.clrGrayText);
else if ((infoPtr->haveFocus) && (i == infoPtr->select)) {
- /* fill if focussed */
+ RECT selection;
+
+ /* fill if focused */
HBRUSH hbr = CreateSolidBrush (comctl32_color.clrActiveCaption);
- FillRect(hdc, field, hbr);
+
+ selection.left = 0;
+ selection.top = 0;
+ selection.right = size.cx;
+ selection.bottom = size.cy;
+ /* center rectangle */
+ OffsetRect(&selection, (field->right + field->left - size.cx)/2,
+ (field->bottom - size.cy)/2);
+
+ FillRect(hdc, &selection, hbr);
DeleteObject (hbr);
oldTextColor = SetTextColor (hdc, comctl32_color.clrWindow);
}
@@ -673,7 +712,7 @@ DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc)
oldTextColor = SetTextColor (hdc, comctl32_color.clrWindowText);
/* draw the date text using the colour set above */
- DrawTextW (hdc, txt, strlenW(txt), field, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
+ DrawTextW (hdc, txt, strlenW(txt), field, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
SetTextColor (hdc, oldTextColor);
}
SetBkMode (hdc, oldBkMode);
@@ -681,7 +720,7 @@ DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc)
}
if (!(infoPtr->dwStyle & DTS_UPDOWN)) {
- DrawFrameControl(hdc, calbutton, DFC_SCROLL,
+ DrawFrameControl(hdc, &infoPtr->calbutton, DFC_SCROLL,
DFCS_SCROLLDOWN | (infoPtr->bCalDepressed ? DFCS_PUSHED : 0) |
(infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
}
@@ -698,30 +737,54 @@ DATETIME_HitTest (const DATETIME_INFO *infoPtr, POINT pt)
if (PtInRect (&infoPtr->calbutton, pt)) return DTHT_MCPOPUP;
if (PtInRect (&infoPtr->checkbox, pt)) return DTHT_CHECKBOX;
- for (i=0; i < infoPtr->nrFields; i++) {
+ for (i = 0; i < infoPtr->nrFields; i++) {
if (PtInRect (&infoPtr->fieldRect[i], pt)) return i;
}
return DTHT_NONE;
}
+/* Returns index of a closest date field from given counting to left
+ or -1 if there's no such fields at left */
+static int DATETIME_GetPrevDateField(const DATETIME_INFO *infoPtr, int i)
+{
+ for(--i; i >= 0; i--)
+ {
+ if (infoPtr->fieldspec[i] & DTHT_DATEFIELD) return i;
+ }
+ return -1;
+}
static LRESULT
DATETIME_LButtonDown (DATETIME_INFO *infoPtr, INT x, INT y)
{
POINT pt;
- int old, new;
+ int new;
pt.x = x;
pt.y = y;
- old = infoPtr->select;
new = DATETIME_HitTest (infoPtr, pt);
- /* FIXME: might be conditions where we don't want to update infoPtr->select */
- infoPtr->select = new;
-
SetFocus(infoPtr->hwndSelf);
+ if (!(new & DTHT_NODATEMASK) || (new == DTHT_NONE))
+ {
+ if (new == DTHT_NONE)
+ new = infoPtr->nrFields - 1;
+ else
+ {
+ /* hitting string part moves selection to next date field to left */
+ if (infoPtr->fieldspec[new] & DT_STRING)
+ {
+ new = DATETIME_GetPrevDateField(infoPtr, new);
+ if (new == -1) return 0;
+ }
+ /* never select full day of week */
+ if (infoPtr->fieldspec[new] == FULLDAY) return 0;
+ }
+ }
+ infoPtr->select = new;
+
if (infoPtr->select == DTHT_MCPOPUP) {
RECT rcMonthCal;
SendMessageW(infoPtr->hMonthCal, MCM_GETMINREQRECT, 0, (LPARAM)&rcMonthCal);
@@ -746,20 +809,23 @@ DATETIME_LButtonDown (DATETIME_INFO *infoPtr, INT x, INT y)
if(IsWindowVisible(infoPtr->hMonthCal)) {
ShowWindow(infoPtr->hMonthCal, SW_HIDE);
+ infoPtr->bDropdownEnabled = FALSE;
+ DATETIME_SendSimpleNotify (infoPtr, DTN_CLOSEUP);
} else {
const SYSTEMTIME *lprgSysTimeArray = &infoPtr->date;
TRACE("update calendar %04d/%02d/%02d\n",
lprgSysTimeArray->wYear, lprgSysTimeArray->wMonth, lprgSysTimeArray->wDay);
SendMessageW(infoPtr->hMonthCal, MCM_SETCURSEL, 0, (LPARAM)(&infoPtr->date));
- if (infoPtr->bDropdownEnabled)
+ if (infoPtr->bDropdownEnabled) {
ShowWindow(infoPtr->hMonthCal, SW_SHOW);
+ DATETIME_SendSimpleNotify (infoPtr, DTN_DROPDOWN);
+ }
infoPtr->bDropdownEnabled = TRUE;
}
TRACE ("dt:%p mc:%p mc parent:%p, desktop:%p\n",
infoPtr->hwndSelf, infoPtr->hMonthCal, infoPtr->hwndNotify, GetDesktopWindow ());
- DATETIME_SendSimpleNotify (infoPtr, DTN_DROPDOWN);
}
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
@@ -865,7 +931,7 @@ DATETIME_EraseBackground (const DATETIME_INFO *infoPtr, HDC hdc)
static LRESULT
-DATETIME_Notify (DATETIME_INFO *infoPtr, LPNMHDR lpnmh)
+DATETIME_Notify (DATETIME_INFO *infoPtr, const NMHDR *lpnmh)
{
TRACE ("Got notification %x from %p\n", lpnmh->code, lpnmh->hwndFrom);
TRACE ("info: %p %p %p\n", infoPtr->hwndSelf, infoPtr->hMonthCal, infoPtr->hUpdown);
@@ -879,9 +945,10 @@ DATETIME_Notify (DATETIME_INFO *infoPtr, LPNMHDR lpnmh)
SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_CHECKED, 0);
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
DATETIME_SendDateTimeChangeNotify (infoPtr);
+ DATETIME_SendSimpleNotify(infoPtr, DTN_CLOSEUP);
}
if ((lpnmh->hwndFrom == infoPtr->hUpdown) && (lpnmh->code == UDN_DELTAPOS)) {
- LPNMUPDOWN lpnmud = (LPNMUPDOWN)lpnmh;
+ const NM_UPDOWN *lpnmud = (const NM_UPDOWN*)lpnmh;
TRACE("Delta pos %d\n", lpnmud->iDelta);
infoPtr->pendingUpdown = lpnmud->iDelta;
}
@@ -964,15 +1031,14 @@ DATETIME_Char (DATETIME_INFO *infoPtr, WPARAM vkCode)
case TWODIGITYEAR:
date->wYear = date->wYear - (date->wYear%100) +
(date->wYear%10)*10 + num;
- date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
- date->wDay,date->wMonth,date->wYear);
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case INVALIDFULLYEAR:
case FULLYEAR:
- date->wYear = (date->wYear%1000)*10 + num;
- date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
- date->wDay,date->wMonth,date->wYear);
+ /* reset current year initialy */
+ date->wYear = ((date->wYear/1000) ? 0 : 1)*(date->wYear%1000)*10 + num;
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGITMONTH:
@@ -981,8 +1047,7 @@ DATETIME_Char (DATETIME_INFO *infoPtr, WPARAM vkCode)
date->wMonth = num;
else
date->wMonth = (date->wMonth%10)*10+num;
- date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
- date->wDay,date->wMonth,date->wYear);
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGITDAY:
@@ -992,8 +1057,7 @@ DATETIME_Char (DATETIME_INFO *infoPtr, WPARAM vkCode)
date->wDay = num;
else
date->wDay = newDays;
- date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
- date->wDay,date->wMonth,date->wYear);
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGIT12HOUR:
@@ -1126,9 +1190,9 @@ DATETIME_SendDateTimeChangeNotify (const DATETIME_INFO *infoPtr)
dtdtc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
dtdtc.nmhdr.code = DTN_DATETIMECHANGE;
- dtdtc.dwFlags = (infoPtr->dwStyle & DTS_SHOWNONE) ? GDT_NONE : GDT_VALID;
+ dtdtc.dwFlags = infoPtr->dateValid ? GDT_VALID : GDT_NONE;
- MONTHCAL_CopyTime (&infoPtr->date, &dtdtc.st);
+ dtdtc.st = infoPtr->date;
return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
dtdtc.nmhdr.idFrom, (LPARAM)&dtdtc);
}
@@ -1186,12 +1250,27 @@ DATETIME_Size (DATETIME_INFO *infoPtr, INT width, INT height)
return 0;
}
+static LRESULT
+DATETIME_StyleChanging(DATETIME_INFO *infoPtr, WPARAM wStyleType, STYLESTRUCT *lpss)
+{
+ TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
+ wStyleType, lpss->styleOld, lpss->styleNew);
+
+ /* block DTS_SHOWNONE change */
+ if ((lpss->styleNew ^ lpss->styleOld) & DTS_SHOWNONE)
+ {
+ if (lpss->styleOld & DTS_SHOWNONE)
+ lpss->styleNew |= DTS_SHOWNONE;
+ else
+ lpss->styleNew &= ~DTS_SHOWNONE;
+ }
+
+ return 0;
+}
static LRESULT
DATETIME_StyleChanged(DATETIME_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss)
{
- static const WCHAR buttonW[] = { 'b', 'u', 't', 't', 'o', 'n', 0 };
-
TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
wStyleType, lpss->styleOld, lpss->styleNew);
@@ -1200,7 +1279,7 @@ DATETIME_StyleChanged(DATETIME_INFO *infoPtr, WPARAM wStyleType, const STYLESTRU
infoPtr->dwStyle = lpss->styleNew;
if ( !(lpss->styleOld & DTS_SHOWNONE) && (lpss->styleNew & DTS_SHOWNONE) ) {
- infoPtr->hwndCheckbut = CreateWindowExW (0, buttonW, 0, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
+ infoPtr->hwndCheckbut = CreateWindowExW (0, WC_BUTTONW, 0, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
2, 2, 13, 13, infoPtr->hwndSelf, 0,
(HINSTANCE)GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_HINSTANCE), 0);
SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, 1, 0);
@@ -1235,7 +1314,6 @@ DATETIME_SetFont (DATETIME_INFO *infoPtr, HFONT font, BOOL repaint)
static LRESULT
DATETIME_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
{
- static const WCHAR SysMonthCal32W[] = { 'S', 'y', 's', 'M', 'o', 'n', 't', 'h', 'C', 'a', 'l', '3', '2', 0 };
DATETIME_INFO *infoPtr = Alloc (sizeof(DATETIME_INFO));
STYLESTRUCT ss = { 0, lpcs->style };
@@ -1256,7 +1334,7 @@ DATETIME_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
DATETIME_SetFormatW (infoPtr, 0);
/* create the monthcal control */
- infoPtr->hMonthCal = CreateWindowExW (0, SysMonthCal32W, 0, WS_BORDER | WS_POPUP | WS_CLIPSIBLINGS,
+ infoPtr->hMonthCal = CreateWindowExW (0, MONTHCAL_CLASSW, 0, WS_BORDER | WS_POPUP | WS_CLIPSIBLINGS,
0, 0, 0, 0, infoPtr->hwndSelf, 0, 0, 0);
/* initialize info structure */
@@ -1281,11 +1359,34 @@ DATETIME_Destroy (DATETIME_INFO *infoPtr)
if (infoPtr->hMonthCal)
DestroyWindow(infoPtr->hMonthCal);
SetWindowLongPtrW( infoPtr->hwndSelf, 0, 0 ); /* clear infoPtr */
+ Free (infoPtr->buflen);
+ Free (infoPtr->fieldRect);
+ Free (infoPtr->fieldspec);
Free (infoPtr);
return 0;
}
+static INT
+DATETIME_GetText (DATETIME_INFO *infoPtr, INT count, LPWSTR dst)
+{
+ WCHAR buf[80];
+ int i;
+
+ if (!dst || (count <= 0)) return 0;
+
+ dst[0] = 0;
+ for (i = 0; i < infoPtr->nrFields; i++)
+ {
+ DATETIME_ReturnTxt(infoPtr, i, buf, sizeof(buf)/sizeof(buf[0]));
+ if ((strlenW(dst) + strlenW(buf)) < count)
+ strcatW(dst, buf);
+ else break;
+ }
+ return strlenW(dst);
+}
+
+
static LRESULT WINAPI
DATETIME_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
@@ -1385,6 +1486,9 @@ DATETIME_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_COMMAND:
return DATETIME_Command (infoPtr, wParam, lParam);
+ case WM_STYLECHANGING:
+ return DATETIME_StyleChanging(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
+
case WM_STYLECHANGED:
return DATETIME_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
@@ -1394,6 +1498,12 @@ DATETIME_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_GETFONT:
return (LRESULT) infoPtr->hFont;
+ case WM_GETTEXT:
+ return (LRESULT) DATETIME_GetText(infoPtr, wParam, (LPWSTR)lParam);
+
+ case WM_SETTEXT:
+ return CB_ERR;
+
default:
if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
ERR("unknown msg %04x wp=%08lx lp=%08lx\n",
diff --git a/reactos/dll/win32/comctl32/dpa.c b/reactos/dll/win32/comctl32/dpa.c
index e3c03c88c8f..96823442864 100644
--- a/reactos/dll/win32/comctl32/dpa.c
+++ b/reactos/dll/win32/comctl32/dpa.c
@@ -426,12 +426,27 @@ BOOL WINAPI DPA_Destroy (const HDPA hdpa)
*/
BOOL WINAPI DPA_Grow (HDPA hdpa, INT nGrow)
{
+ INT items;
TRACE("(%p %d)\n", hdpa, nGrow);
if (!hdpa)
return FALSE;
- hdpa->nGrow = max(8, nGrow);
+ nGrow = max( 8, nGrow );
+ items = nGrow * (((hdpa->nMaxCount - 1) / nGrow) + 1);
+ if (items > hdpa->nMaxCount)
+ {
+ void *ptr;
+
+ if (hdpa->ptrs)
+ ptr = HeapReAlloc( hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, items * sizeof(LPVOID) );
+ else
+ ptr = HeapAlloc( hdpa->hHeap, HEAP_ZERO_MEMORY, items * sizeof(LPVOID) );
+ if (!ptr) return FALSE;
+ hdpa->nMaxCount = items;
+ hdpa->ptrs = ptr;
+ }
+ hdpa->nGrow = nGrow;
return TRUE;
}
diff --git a/reactos/dll/win32/comctl32/draglist.c b/reactos/dll/win32/comctl32/draglist.c
index 9ecade558c1..2097edb42fd 100644
--- a/reactos/dll/win32/comctl32/draglist.c
+++ b/reactos/dll/win32/comctl32/draglist.c
@@ -334,7 +334,7 @@ INT WINAPI LBItemFromPt (HWND hwndLB, POINT pt, BOOL bAutoScroll)
dwLastScrollTime = dwScrollTime;
- SendMessageW (hwndLB, LB_SETTOPINDEX, (WPARAM)nIndex, 0);
+ SendMessageW (hwndLB, LB_SETTOPINDEX, nIndex, 0);
}
return -1;
diff --git a/reactos/dll/win32/comctl32/header.c b/reactos/dll/win32/comctl32/header.c
index d84965c21d5..d916c7297d5 100644
--- a/reactos/dll/win32/comctl32/header.c
+++ b/reactos/dll/win32/comctl32/header.c
@@ -374,8 +374,7 @@ HEADER_DrawItem (HEADER_INFO *infoPtr, HDC hdc, INT iItem, BOOL bHotTrack, LRESU
dis.rcItem = phdi->rect;
dis.itemData = phdi->lParam;
oldBkMode = SetBkMode(hdc, TRANSPARENT);
- SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM,
- (WPARAM)dis.CtlID, (LPARAM)&dis);
+ SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
if (oldBkMode != TRANSPARENT)
SetBkMode(hdc, oldBkMode);
}
@@ -1214,20 +1213,64 @@ HEADER_GetOrderArray(const HEADER_INFO *infoPtr, INT size, LPINT order)
return TRUE;
}
+/* Returns index of first duplicate 'value' from [0,to) range,
+ or -1 if there isn't any */
+static INT has_duplicate(INT *array, INT to, INT value)
+{
+ INT i;
+ for(i = 0; i < to; i++)
+ if (array[i] == value) return i;
+ return -1;
+}
+
+/* returns next available value from [0,max] not to duplicate in [0,to) */
+static INT get_nextvalue(INT *array, INT to, INT max)
+{
+ INT i;
+ for(i = 0; i < max; i++)
+ if (has_duplicate(array, to, i) == -1) return i;
+ return 0;
+}
+
static LRESULT
HEADER_SetOrderArray(HEADER_INFO *infoPtr, INT size, const INT *order)
{
- INT i;
HEADER_ITEM *lpItem;
+ INT i;
- if ((UINT)size uNumItem)
+ if ((UINT)size != infoPtr->uNumItem)
return FALSE;
- memcpy(infoPtr->order, order, infoPtr->uNumItem * sizeof(INT));
+
for (i=0; iitems[*order++];
- lpItem->iOrder=i;
- }
+ {
+ if (order[i] >= size || order[i] < 0)
+ /* on invalid index get next available */
+ /* FIXME: if i==0 array item is out of range behaviour is
+ different, see tests */
+ infoPtr->order[i] = get_nextvalue(infoPtr->order, i, size);
+ else
+ {
+ INT j, dup;
+
+ infoPtr->order[i] = order[i];
+ j = i;
+ /* remove duplicates */
+ while ((dup = has_duplicate(infoPtr->order, j, order[j])) != -1)
+ {
+ INT next;
+
+ next = get_nextvalue(infoPtr->order, j, size);
+ infoPtr->order[dup] = next;
+ j--;
+ }
+ }
+ }
+ /* sync with item data */
+ for (i=0; iitems[infoPtr->order[i]];
+ lpItem->iOrder = i;
+ }
HEADER_SetItemBounds(infoPtr);
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
return TRUE;
@@ -1704,7 +1747,7 @@ HEADER_NotifyFormat (HEADER_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
case NF_REQUERY:
infoPtr->nNotifyFormat =
SendMessageW ((HWND)wParam, WM_NOTIFYFORMAT,
- (WPARAM)infoPtr->hwndSelf, (LPARAM)NF_QUERY);
+ (WPARAM)infoPtr->hwndSelf, NF_QUERY);
return infoPtr->nNotifyFormat;
}
diff --git a/reactos/dll/win32/comctl32/idb_hist_large.bmp b/reactos/dll/win32/comctl32/idb_hist_large.bmp
index 20596fac20a..b7818fbafb2 100644
Binary files a/reactos/dll/win32/comctl32/idb_hist_large.bmp and b/reactos/dll/win32/comctl32/idb_hist_large.bmp differ
diff --git a/reactos/dll/win32/comctl32/idb_hist_small.bmp b/reactos/dll/win32/comctl32/idb_hist_small.bmp
index 3cc2ab4e51a..c735f54377f 100644
Binary files a/reactos/dll/win32/comctl32/idb_hist_small.bmp and b/reactos/dll/win32/comctl32/idb_hist_small.bmp differ
diff --git a/reactos/dll/win32/comctl32/idb_std_large.bmp b/reactos/dll/win32/comctl32/idb_std_large.bmp
index 4f0e09e7e2e..7e19185c929 100644
Binary files a/reactos/dll/win32/comctl32/idb_std_large.bmp and b/reactos/dll/win32/comctl32/idb_std_large.bmp differ
diff --git a/reactos/dll/win32/comctl32/idb_std_small.bmp b/reactos/dll/win32/comctl32/idb_std_small.bmp
index 8318e447fe2..7db2f3ca805 100644
Binary files a/reactos/dll/win32/comctl32/idb_std_small.bmp and b/reactos/dll/win32/comctl32/idb_std_small.bmp differ
diff --git a/reactos/dll/win32/comctl32/idb_view_large.bmp b/reactos/dll/win32/comctl32/idb_view_large.bmp
index 6331b5eb691..22e4d1d8b8b 100644
Binary files a/reactos/dll/win32/comctl32/idb_view_large.bmp and b/reactos/dll/win32/comctl32/idb_view_large.bmp differ
diff --git a/reactos/dll/win32/comctl32/idb_view_small.bmp b/reactos/dll/win32/comctl32/idb_view_small.bmp
index d1632f207b4..6ba3d831637 100644
Binary files a/reactos/dll/win32/comctl32/idb_view_small.bmp and b/reactos/dll/win32/comctl32/idb_view_small.bmp differ
diff --git a/reactos/dll/win32/comctl32/imagelist.c b/reactos/dll/win32/comctl32/imagelist.c
index a2bc10a80e5..11ff27fe8ff 100644
--- a/reactos/dll/win32/comctl32/imagelist.c
+++ b/reactos/dll/win32/comctl32/imagelist.c
@@ -33,7 +33,7 @@
*
* TODO:
* - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
- * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
+ * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE
* - Thread-safe locking
*/
@@ -51,6 +51,7 @@
#include "winuser.h"
#include "commctrl.h"
#include "comctl32.h"
+#include "commoncontrols.h"
#include "imagelist.h"
#include "wine/debug.h"
@@ -78,12 +79,9 @@ typedef struct
static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
-static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT width);
-
-static inline BOOL is_valid(HIMAGELIST himl)
-{
- return himl && himl->magic == IMAGELIST_MAGIC;
-}
+static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count);
+static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv);
+static inline BOOL is_valid(HIMAGELIST himl);
/*
* An imagelist with N images is tiled like this:
@@ -109,9 +107,9 @@ static inline void imagelist_point_from_index( HIMAGELIST himl, UINT index, LPPO
pt->y = (index/TILE_COUNT) * himl->cy;
}
-static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, UINT cx, SIZE *sz )
+static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, SIZE *sz )
{
- sz->cx = cx * TILE_COUNT;
+ sz->cx = himl->cx * TILE_COUNT;
sz->cy = imagelist_height( count ) * himl->cy;
}
@@ -140,6 +138,109 @@ static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDe
}
}
+/* add images with an alpha channel when the image list is 32 bpp */
+static BOOL add_with_alpha( HIMAGELIST himl, HDC hdc, int pos, int count,
+ int width, int height, HBITMAP hbmImage, HBITMAP hbmMask )
+{
+ BOOL ret = FALSE;
+ HDC hdcMask = 0;
+ BITMAP bm;
+ BITMAPINFO *info, *mask_info = NULL;
+ DWORD *bits = NULL;
+ BYTE *mask_bits = NULL;
+ int i, j, n;
+ POINT pt;
+ DWORD mask_width;
+
+ if (!GetObjectW( hbmImage, sizeof(bm), &bm )) return FALSE;
+
+ /* if neither the imagelist nor the source bitmap can have an alpha channel, bail out now */
+ if (himl->uBitsPixel != 32 && bm.bmBitsPixel != 32) return FALSE;
+
+ SelectObject( hdc, hbmImage );
+ mask_width = (bm.bmWidth + 31) / 32 * 4;
+
+ if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
+ info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ info->bmiHeader.biWidth = bm.bmWidth;
+ info->bmiHeader.biHeight = -height;
+ info->bmiHeader.biPlanes = 1;
+ info->bmiHeader.biBitCount = 32;
+ info->bmiHeader.biCompression = BI_RGB;
+ info->bmiHeader.biSizeImage = bm.bmWidth * height * 4;
+ info->bmiHeader.biXPelsPerMeter = 0;
+ info->bmiHeader.biYPelsPerMeter = 0;
+ info->bmiHeader.biClrUsed = 0;
+ info->bmiHeader.biClrImportant = 0;
+ if (!(bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
+ if (!GetDIBits( hdc, hbmImage, 0, height, bits, info, DIB_RGB_COLORS )) goto done;
+
+ if (hbmMask)
+ {
+ if (!(mask_info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[2] ))))
+ goto done;
+ mask_info->bmiHeader = info->bmiHeader;
+ mask_info->bmiHeader.biBitCount = 1;
+ mask_info->bmiHeader.biSizeImage = mask_width * height;
+ if (!(mask_bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
+ if (!GetDIBits( hdc, hbmMask, 0, height, mask_bits, mask_info, DIB_RGB_COLORS )) goto done;
+ hdcMask = CreateCompatibleDC( 0 );
+ SelectObject( hdcMask, hbmMask );
+ }
+
+ for (n = 0; n < count; n++)
+ {
+ int has_alpha = 0;
+
+ imagelist_point_from_index( himl, pos + n, &pt );
+
+ /* check if bitmap has an alpha channel */
+ for (i = 0; i < height && !has_alpha; i++)
+ for (j = n * width; j < (n + 1) * width; j++)
+ if ((has_alpha = ((bits[i * bm.bmWidth + j] & 0xff000000) != 0))) break;
+
+ if (!has_alpha) /* generate alpha channel from the mask */
+ {
+ for (i = 0; i < height; i++)
+ for (j = n * width; j < (n + 1) * width; j++)
+ if (!mask_bits || !((mask_bits[i * mask_width + j / 8] << (j % 8)) & 0x80))
+ bits[i * bm.bmWidth + j] |= 0xff000000;
+ else
+ bits[i * bm.bmWidth + j] = 0;
+ if (hdcMask) StretchBlt( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
+ hdcMask, n * width, 0, width, height, SRCCOPY );
+ }
+ else
+ {
+ if (himl->has_alpha) himl->has_alpha[pos + n] = 1;
+
+ if (mask_info && himl->hbmMask) /* generate the mask from the alpha channel */
+ {
+ for (i = 0; i < height; i++)
+ for (j = n * width; j < (n + 1) * width; j++)
+ if ((bits[i * bm.bmWidth + j] >> 24) > 25) /* more than 10% alpha */
+ mask_bits[i * mask_width + j / 8] &= ~(0x80 >> (j % 8));
+ else
+ mask_bits[i * mask_width + j / 8] |= 0x80 >> (j % 8);
+ StretchDIBits( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
+ n * width, 0, width, height, mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY );
+ }
+ }
+ StretchDIBits( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
+ n * width, 0, width, height, bits, info, DIB_RGB_COLORS, SRCCOPY );
+
+ }
+ ret = TRUE;
+
+done:
+ if (hdcMask) DeleteDC( hdcMask );
+ HeapFree( GetProcessHeap(), 0, info );
+ HeapFree( GetProcessHeap(), 0, mask_info );
+ HeapFree( GetProcessHeap(), 0, bits );
+ HeapFree( GetProcessHeap(), 0, mask_bits );
+ return ret;
+}
+
/*************************************************************************
* IMAGELIST_InternalExpandBitmaps [Internal]
*
@@ -156,28 +257,29 @@ static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDe
* This function CANNOT be used to reduce the number of images.
*/
static void
-IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cy)
+IMAGELIST_InternalExpandBitmaps(HIMAGELIST himl, INT nImageCount)
{
HDC hdcBitmap;
HBITMAP hbmNewBitmap, hbmNull;
INT nNewCount;
SIZE sz;
- if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
- && (himl->cy >= cy))
+ TRACE("%p has %d allocated %d images\n", himl, himl->cCurImage, himl->cMaxImage);
+
+ if (himl->cCurImage + nImageCount <= himl->cMaxImage)
return;
- nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
+ nNewCount = himl->cCurImage + max(nImageCount, himl->cGrow) + 1;
- imagelist_get_bitmap_size(himl, nNewCount, himl->cx, &sz);
+ imagelist_get_bitmap_size(himl, nNewCount, &sz);
- TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, cy, nNewCount);
+ TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, sz.cy, nNewCount);
hdcBitmap = CreateCompatibleDC (0);
- hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, himl->cx);
+ hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
if (hbmNewBitmap == 0)
- ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, cy);
+ ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, sz.cy);
if (himl->cCurImage)
{
@@ -209,6 +311,17 @@ IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cy)
himl->hbmMask = hbmNewBitmap;
}
+ if (himl->has_alpha)
+ {
+ char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
+ if (new_alpha) himl->has_alpha = new_alpha;
+ else
+ {
+ HeapFree( GetProcessHeap(), 0, himl->has_alpha );
+ himl->has_alpha = NULL;
+ }
+ }
+
himl->cMaxImage = nNewCount;
DeleteDC (hdcBitmap);
@@ -233,10 +346,9 @@ IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cy)
INT WINAPI
ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
{
- HDC hdcBitmap, hdcTemp;
+ HDC hdcBitmap, hdcTemp = 0;
INT nFirstIndex, nImageCount, i;
BITMAP bmp;
- HBITMAP hOldBitmap, hOldBitmapTemp;
POINT pt;
TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
@@ -246,13 +358,28 @@ ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
return -1;
+ TRACE("himl %p, cCurImage %d, cMaxImage %d, cGrow %d, cx %d, cy %d\n",
+ himl, himl->cCurImage, himl->cMaxImage, himl->cGrow, himl->cx, himl->cy);
+
nImageCount = bmp.bmWidth / himl->cx;
- IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmHeight);
+ TRACE("%p has %d images (%d x %d)\n", hbmImage, nImageCount, bmp.bmWidth, bmp.bmHeight);
+
+ IMAGELIST_InternalExpandBitmaps(himl, nImageCount);
hdcBitmap = CreateCompatibleDC(0);
- hOldBitmap = SelectObject(hdcBitmap, hbmImage);
+ SelectObject(hdcBitmap, hbmImage);
+
+ if (add_with_alpha( himl, hdcBitmap, himl->cCurImage, nImageCount,
+ himl->cx, min( himl->cy, bmp.bmHeight), hbmImage, hbmMask ))
+ goto done;
+
+ if (himl->hbmMask)
+ {
+ hdcTemp = CreateCompatibleDC(0);
+ SelectObject(hdcTemp, hbmMask);
+ }
for (i=0; ihbmMask)
continue;
- hdcTemp = CreateCompatibleDC(0);
- hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
-
BitBlt( himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
hdcTemp, i*himl->cx, 0, SRCCOPY );
- SelectObject(hdcTemp, hOldBitmapTemp);
- DeleteDC(hdcTemp);
-
/* Remove the background from the image
*/
BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
himl->hdcMask, pt.x, pt.y, 0x220326 ); /* NOTSRCAND */
}
+ if (hdcTemp) DeleteDC(hdcTemp);
- SelectObject(hdcBitmap, hOldBitmap);
+done:
DeleteDC(hdcBitmap);
nFirstIndex = himl->cCurImage;
@@ -331,12 +453,10 @@ INT WINAPI
ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
{
HDC hdcMask, hdcBitmap;
- INT i, nIndex, nImageCount;
+ INT ret;
BITMAP bmp;
- HBITMAP hOldBitmap;
- HBITMAP hMaskBitmap=0;
+ HBITMAP hMaskBitmap;
COLORREF bkColor;
- POINT pt;
TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
if (!is_valid(himl))
@@ -345,18 +465,8 @@ ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
if (!GetObjectW(hBitmap, sizeof(BITMAP), &bmp))
return -1;
- if (himl->cx > 0)
- nImageCount = bmp.bmWidth / himl->cx;
- else
- nImageCount = 0;
-
- IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmHeight);
-
- nIndex = himl->cCurImage;
- himl->cCurImage += nImageCount;
-
hdcBitmap = CreateCompatibleDC(0);
- hOldBitmap = SelectObject(hdcBitmap, hBitmap);
+ SelectObject(hdcBitmap, hBitmap);
/* Create a temp Mask so we can remove the background of the Image */
hdcMask = CreateCompatibleDC(0);
@@ -385,23 +495,13 @@ ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
*/
BitBlt(hdcBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMask, 0, 0, 0x220326);
- /* Copy result to the imagelist */
- for (i=0; ihdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
- hdcBitmap, i*himl->cx, 0, SRCCOPY);
- BitBlt(himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
- hdcMask, i*himl->cx, 0, SRCCOPY);
- }
-
- /* Clean up */
- SelectObject(hdcBitmap, hOldBitmap);
DeleteDC(hdcBitmap);
- DeleteObject(hMaskBitmap);
DeleteDC(hdcMask);
- return nIndex;
+ ret = ImageList_Add( himl, hBitmap, hMaskBitmap );
+
+ DeleteObject(hMaskBitmap);
+ return ret;
}
@@ -598,13 +698,12 @@ ImageList_Create (INT cx, INT cy, UINT flags,
TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
- himl = Alloc (sizeof(struct _IMAGELIST));
- if (!himl)
+ /* Create the IImageList interface for the image list */
+ if (FAILED(ImageListImpl_CreateInstance(NULL, &IID_IImageList, (void **)&himl)))
return NULL;
cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
- himl->magic = IMAGELIST_MAGIC;
himl->cx = cx;
himl->cy = cy;
himl->flags = flags;
@@ -638,7 +737,7 @@ ImageList_Create (INT cx, INT cy, UINT flags,
himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
if (himl->cMaxImage > 0) {
- himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, cx);
+ himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
SelectObject(himl->hdcImage, himl->hbmImage);
} else
himl->hbmImage = 0;
@@ -646,7 +745,7 @@ ImageList_Create (INT cx, INT cy, UINT flags,
if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
SIZE sz;
- imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz);
+ imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
if (himl->hbmMask == 0) {
ERR("Error creating mask bitmap!\n");
@@ -657,6 +756,11 @@ ImageList_Create (INT cx, INT cy, UINT flags,
else
himl->hbmMask = 0;
+ if (himl->uBitsPixel == 32)
+ himl->has_alpha = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->cMaxImage );
+ else
+ himl->has_alpha = NULL;
+
/* create blending brushes */
hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend25);
himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
@@ -670,7 +774,7 @@ ImageList_Create (INT cx, INT cy, UINT flags,
return himl;
cleanup:
- if (himl) ImageList_Destroy(himl);
+ ImageList_Destroy(himl);
return NULL;
}
@@ -694,27 +798,7 @@ ImageList_Destroy (HIMAGELIST himl)
if (!is_valid(himl))
return FALSE;
- /* delete image bitmaps */
- if (himl->hbmImage)
- DeleteObject (himl->hbmImage);
- if (himl->hbmMask)
- DeleteObject (himl->hbmMask);
-
- /* delete image & mask DCs */
- if (himl->hdcImage)
- DeleteDC(himl->hdcImage);
- if (himl->hdcMask)
- DeleteDC(himl->hdcMask);
-
- /* delete blending brushes */
- if (himl->hbrBlend25)
- DeleteObject (himl->hbrBlend25);
- if (himl->hbrBlend50)
- DeleteObject (himl->hbrBlend50);
-
- ZeroMemory(himl, sizeof(*himl));
- Free (himl);
-
+ IImageList_Release((IImageList *) himl);
return TRUE;
}
@@ -832,10 +916,7 @@ ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
imldp.rgbFg = CLR_DEFAULT;
imldp.fStyle = ILD_NORMAL;
imldp.fState = ILS_ALPHA;
- imldp.Frame = 128;
-
- /* FIXME: instead of using the alpha blending, we should
- * create a 50% mask, and draw it semitransparantly that way */
+ imldp.Frame = 192;
ImageList_DrawIndirect (&imldp);
}
@@ -855,9 +936,6 @@ ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
* NOTES
* The position of the drag image is relative to the window, not
* the client area.
- *
- * BUGS
- * The drag image should be drawn semitransparent.
*/
BOOL WINAPI
@@ -941,9 +1019,6 @@ ImageList_DragMove (INT x, INT y)
* RETURNS
* Success: TRUE
* Failure: FALSE
- *
- * BUGS
- * The drag image should be drawn semitransparent.
*/
BOOL WINAPI
@@ -1081,6 +1156,73 @@ ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
}
+static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
+ int src_x, int src_y, int cx, int cy, BLENDFUNCTION func )
+{
+ BOOL ret = FALSE;
+ HDC hdc;
+ HBITMAP bmp = 0, mask = 0;
+ BITMAPINFO *info;
+ void *bits, *mask_bits;
+ unsigned int *ptr;
+ int i, j;
+
+ if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
+ if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
+ info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ info->bmiHeader.biWidth = cx;
+ info->bmiHeader.biHeight = cy;
+ info->bmiHeader.biPlanes = 1;
+ info->bmiHeader.biBitCount = 32;
+ info->bmiHeader.biCompression = BI_RGB;
+ info->bmiHeader.biSizeImage = cx * cy * 4;
+ info->bmiHeader.biXPelsPerMeter = 0;
+ info->bmiHeader.biYPelsPerMeter = 0;
+ info->bmiHeader.biClrUsed = 0;
+ info->bmiHeader.biClrImportant = 0;
+ if (!(bmp = CreateDIBSection( himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
+ SelectObject( hdc, bmp );
+ BitBlt( hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY );
+
+ if (himl->uBitsPixel == 32) /* we already have an alpha channel in this case */
+ {
+ /* pre-multiply by the alpha channel */
+ for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
+ {
+ DWORD alpha = *ptr >> 24;
+ *ptr = ((*ptr & 0xff000000) |
+ (((*ptr & 0x00ff0000) * alpha / 255) & 0x00ff0000) |
+ (((*ptr & 0x0000ff00) * alpha / 255) & 0x0000ff00) |
+ (((*ptr & 0x000000ff) * alpha / 255)));
+ }
+ }
+ else if (himl->hbmMask)
+ {
+ unsigned int width_bytes = (cx + 31) / 32 * 4;
+ /* generate alpha channel from the mask */
+ info->bmiHeader.biBitCount = 1;
+ info->bmiHeader.biSizeImage = width_bytes * cy;
+ if (!(mask = CreateDIBSection( himl->hdcMask, info, DIB_RGB_COLORS, &mask_bits, 0, 0 )))
+ goto done;
+ SelectObject( hdc, mask );
+ BitBlt( hdc, 0, 0, cx, cy, himl->hdcMask, src_x, src_y, SRCCOPY );
+ SelectObject( hdc, bmp );
+ for (i = 0, ptr = bits; i < cy; i++)
+ for (j = 0; j < cx; j++, ptr++)
+ if ((((BYTE *)mask_bits)[i * width_bytes + j / 8] << (j % 8)) & 0x80) *ptr = 0;
+ else *ptr |= 0xff000000;
+ }
+
+ ret = GdiAlphaBlend( dest_dc, dest_x, dest_y, cx, cy, hdc, 0, 0, cx, cy, func );
+
+done:
+ DeleteDC( hdc );
+ if (bmp) DeleteObject( bmp );
+ if (mask) DeleteObject( mask );
+ HeapFree( GetProcessHeap(), 0, info );
+ return ret;
+}
+
/*************************************************************************
* ImageList_DrawIndirect [COMCTL32.@]
*
@@ -1105,7 +1247,9 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
HIMAGELIST himl;
+ HBRUSH hOldBrush;
POINT pt;
+ BOOL has_alpha;
if (!pimldp || !(himl = pimldp->himl)) return FALSE;
if (!is_valid(himl)) return FALSE;
@@ -1149,18 +1293,46 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
/*
* To obtain a transparent look, background color should be set
- * to white and foreground color to black when blting the
+ * to white and foreground color to black when blitting the
* monochrome mask.
*/
oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
+ has_alpha = (himl->has_alpha && himl->has_alpha[pimldp->i]);
+ if (!bMask && (has_alpha || (fState & ILS_ALPHA)))
+ {
+ COLORREF colour;
+ BLENDFUNCTION func;
+
+ func.BlendOp = AC_SRC_OVER;
+ func.BlendFlags = 0;
+ func.SourceConstantAlpha = (fState & ILS_ALPHA) ? pimldp->Frame : 255;
+ func.AlphaFormat = AC_SRC_ALPHA;
+
+ if (bIsTransparent)
+ {
+ bResult = alpha_blend_image( himl, pimldp->hdcDst, pimldp->x, pimldp->y,
+ pt.x, pt.y, cx, cy, func );
+ goto end;
+ }
+ colour = pimldp->rgbBk;
+ if (colour == CLR_DEFAULT) colour = himl->clrBk;
+ if (colour == CLR_NONE) colour = GetBkColor( pimldp->hdcDst );
+
+ hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
+ PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
+ alpha_blend_image( himl, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func );
+ DeleteObject (SelectObject (hImageDC, hOldBrush));
+ bResult = BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCCOPY );
+ goto end;
+ }
+
/*
* Draw the initial image
*/
if( bMask ) {
if (himl->hbmMask) {
- HBRUSH hOldBrush;
hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
@@ -1172,14 +1344,13 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
goto end;
}
} else {
- HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
+ hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
SelectObject(hImageDC, hOldBrush);
}
} else {
/* blend the image with the needed solid background */
COLORREF colour = RGB(0,0,0);
- HBRUSH hOldBrush;
if( !bIsTransparent )
{
@@ -1204,7 +1375,7 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
/* Time for blending, if required */
if (bBlend) {
- HBRUSH hBlendBrush, hOldBrush;
+ HBRUSH hBlendBrush;
COLORREF clrBlend = pimldp->rgbFg;
HDC hBlendMaskDC = hImageListDC;
HBITMAP hOldBitmap;
@@ -1248,7 +1419,6 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
- if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
@@ -1306,13 +1476,13 @@ ImageList_Duplicate (HIMAGELIST himlSrc)
}
himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
- himlSrc->cInitial, himlSrc->cGrow);
+ himlSrc->cCurImage, himlSrc->cGrow);
if (himlDst)
{
SIZE sz;
- imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, himlSrc->cx, &sz);
+ imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, &sz);
BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
himlSrc->hdcImage, 0, 0, SRCCOPY);
@@ -1322,6 +1492,8 @@ ImageList_Duplicate (HIMAGELIST himlSrc)
himlDst->cCurImage = himlSrc->cCurImage;
himlDst->cMaxImage = himlSrc->cMaxImage;
+ if (himlSrc->has_alpha && himlDst->has_alpha)
+ memcpy( himlDst->has_alpha, himlSrc->has_alpha, himlDst->cCurImage );
}
return himlDst;
}
@@ -1656,7 +1828,7 @@ ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
LPWSTR lpbmpW;
DWORD len;
- if (!HIWORD(lpbmp))
+ if (IS_INTRESOURCE(lpbmp))
return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
uType, uFlags);
@@ -2080,14 +2252,14 @@ ImageList_Remove (HIMAGELIST himl, INT i)
for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
himl->nOvlIdx[nCount] = -1;
- hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cx);
+ hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
SelectObject (himl->hdcImage, hbmNewImage);
DeleteObject (himl->hbmImage);
himl->hbmImage = hbmNewImage;
if (himl->hbmMask) {
- imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz);
+ imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
SelectObject (himl->hdcMask, hbmNewMask);
DeleteObject (himl->hbmMask);
@@ -2102,9 +2274,9 @@ ImageList_Remove (HIMAGELIST himl, INT i)
TRACE(" - Number of images: %d / %d (Old/New)\n",
himl->cCurImage, himl->cCurImage - 1);
- hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cx);
+ hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
- imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz );
+ imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz );
if (himl->hbmMask)
hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
else
@@ -2181,7 +2353,6 @@ ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
{
HDC hdcImage;
BITMAP bmp;
- HBITMAP hOldBitmap;
POINT pt;
TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
@@ -2202,7 +2373,10 @@ ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
hdcImage = CreateCompatibleDC (0);
/* Replace Image */
- hOldBitmap = SelectObject (hdcImage, hbmImage);
+ SelectObject (hdcImage, hbmImage);
+
+ if (add_with_alpha( himl, hdcImage, i, 1, bmp.bmWidth, bmp.bmHeight, hbmImage, hbmMask ))
+ goto done;
imagelist_point_from_index(himl, i, &pt);
StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
@@ -2227,7 +2401,7 @@ ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
}
- SelectObject (hdcImage, hOldBitmap);
+done:
DeleteDC (hdcImage);
return TRUE;
@@ -2254,7 +2428,6 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
{
HDC hdcImage;
HICON hBestFitIcon;
- HBITMAP hbmOldSrc;
ICONINFO ii;
BITMAP bmp;
BOOL ret;
@@ -2304,7 +2477,7 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
if (nIndex == -1) {
if (himl->cCurImage + 1 > himl->cMaxImage)
- IMAGELIST_InternalExpandBitmaps (himl, 1, 0);
+ IMAGELIST_InternalExpandBitmaps(himl, 1);
nIndex = himl->cCurImage;
himl->cCurImage++;
@@ -2315,6 +2488,25 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
if (hdcImage == 0)
ERR("invalid hdcImage!\n");
+ if (himl->uBitsPixel == 32)
+ {
+ if (!ii.hbmColor)
+ {
+ UINT height = bmp.bmHeight / 2;
+ HDC hdcMask = CreateCompatibleDC( 0 );
+ HBITMAP color = CreateBitmap( bmp.bmWidth, height, 1, 1, NULL );
+ SelectObject( hdcImage, color );
+ SelectObject( hdcMask, ii.hbmMask );
+ BitBlt( hdcImage, 0, 0, bmp.bmWidth, height, hdcMask, 0, height, SRCCOPY );
+ add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, height, color, ii.hbmMask );
+ DeleteDC( hdcMask );
+ DeleteObject( color );
+ }
+ else add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, bmp.bmHeight, ii.hbmColor, ii.hbmMask );
+
+ goto done;
+ }
+
imagelist_point_from_index(himl, nIndex, &pt);
SetTextColor(himl->hdcImage, RGB(0,0,0));
@@ -2322,7 +2514,7 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
if (ii.hbmColor)
{
- hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
+ SelectObject (hdcImage, ii.hbmColor);
StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
if (himl->hbmMask)
@@ -2335,7 +2527,7 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
else
{
UINT height = bmp.bmHeight / 2;
- hbmOldSrc = SelectObject (hdcImage, ii.hbmMask);
+ SelectObject (hdcImage, ii.hbmMask);
StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
hdcImage, 0, height, bmp.bmWidth, height, SRCCOPY);
if (himl->hbmMask)
@@ -2343,8 +2535,7 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
hdcImage, 0, 0, bmp.bmWidth, height, SRCCOPY);
}
- SelectObject (hdcImage, hbmOldSrc);
-
+done:
DestroyIcon(hBestFitIcon);
if (hdcImage)
DeleteDC (hdcImage);
@@ -2539,14 +2730,14 @@ ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
himl->nOvlIdx[nCount] = -1;
- hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cx);
+ hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
SelectObject (himl->hdcImage, hbmNew);
DeleteObject (himl->hbmImage);
himl->hbmImage = hbmNew;
if (himl->hbmMask) {
SIZE sz;
- imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz);
+ imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
SelectObject (himl->hdcMask, hbmNew);
DeleteObject (himl->hbmMask);
@@ -2594,7 +2785,7 @@ ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
hdcBitmap = CreateCompatibleDC (0);
- hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, himl->cx);
+ hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
if (hbmNewBitmap != 0)
{
@@ -2614,7 +2805,7 @@ ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
if (himl->hbmMask)
{
SIZE sz;
- imagelist_get_bitmap_size( himl, nNewCount, himl->cx, &sz );
+ imagelist_get_bitmap_size( himl, nNewCount, &sz );
hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
if (hbmNewBitmap != 0)
{
@@ -2813,13 +3004,13 @@ ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
}
-static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT width)
+static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count)
{
HBITMAP hbmNewBitmap;
UINT ilc = (himl->flags & 0xFE);
SIZE sz;
- imagelist_get_bitmap_size( himl, count, width, &sz );
+ imagelist_get_bitmap_size( himl, count, &sz );
if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
{
@@ -2925,8 +3116,466 @@ ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST
HRESULT WINAPI
ImageList_CoCreateInstance (REFCLSID rclsid, const IUnknown *punkOuter, REFIID riid, void **ppv)
{
- FIXME("STUB: %s %p %s %p\n", debugstr_guid(rclsid), punkOuter, debugstr_guid(riid), ppv);
- return E_NOINTERFACE;
+ TRACE("(%s,%p,%s,%p)\n", debugstr_guid(rclsid), punkOuter, debugstr_guid(riid), ppv);
+
+ if (!IsEqualCLSID(&CLSID_ImageList, rclsid))
+ return E_NOINTERFACE;
+
+ return ImageListImpl_CreateInstance(punkOuter, riid, ppv);
+}
+
+
+/*************************************************************************
+ * IImageList implementation
+ */
+
+static HRESULT WINAPI ImageListImpl_QueryInterface(IImageList *iface,
+ REFIID iid, void **ppv)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+ if (!ppv) return E_INVALIDARG;
+
+ if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IImageList, iid))
+ *ppv = This;
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown*)*ppv);
+ return S_OK;
+}
+
+static ULONG WINAPI ImageListImpl_AddRef(IImageList *iface)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) refcount=%u\n", iface, ref);
+ return ref;
+}
+
+static ULONG WINAPI ImageListImpl_Release(IImageList *iface)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) refcount=%u\n", iface, ref);
+
+ if (ref == 0)
+ {
+ /* delete image bitmaps */
+ if (This->hbmImage) DeleteObject (This->hbmImage);
+ if (This->hbmMask) DeleteObject (This->hbmMask);
+
+ /* delete image & mask DCs */
+ if (This->hdcImage) DeleteDC (This->hdcImage);
+ if (This->hdcMask) DeleteDC (This->hdcMask);
+
+ /* delete blending brushes */
+ if (This->hbrBlend25) DeleteObject (This->hbrBlend25);
+ if (This->hbrBlend50) DeleteObject (This->hbrBlend50);
+
+ This->lpVtbl = NULL;
+ HeapFree(GetProcessHeap(), 0, This->has_alpha);
+ HeapFree(GetProcessHeap(), 0, This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI ImageListImpl_Add(IImageList *iface, HBITMAP hbmImage,
+ HBITMAP hbmMask, int *pi)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ int ret;
+
+ if (!pi)
+ return E_FAIL;
+
+ ret = ImageList_Add(This, hbmImage, hbmMask);
+
+ if (ret == -1)
+ return E_FAIL;
+
+ *pi = ret;
+ return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_ReplaceIcon(IImageList *iface, int i,
+ HICON hicon, int *pi)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ int ret;
+
+ if (!pi)
+ return E_FAIL;
+
+ ret = ImageList_ReplaceIcon(This, i, hicon);
+
+ if (ret == -1)
+ return E_FAIL;
+
+ *pi = ret;
+ return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_SetOverlayImage(IImageList *iface,
+ int iImage, int iOverlay)
+{
+ return ImageList_SetOverlayImage((HIMAGELIST) iface, iImage, iOverlay)
+ ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_Replace(IImageList *iface, int i,
+ HBITMAP hbmImage, HBITMAP hbmMask)
+{
+ return ImageList_Replace((HIMAGELIST) iface, i, hbmImage, hbmMask) ? S_OK :
+ E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_AddMasked(IImageList *iface, HBITMAP hbmImage,
+ COLORREF crMask, int *pi)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ int ret;
+
+ if (!pi)
+ return E_FAIL;
+
+ ret = ImageList_AddMasked(This, hbmImage, crMask);
+
+ if (ret == -1)
+ return E_FAIL;
+
+ *pi = ret;
+ return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_Draw(IImageList *iface,
+ IMAGELISTDRAWPARAMS *pimldp)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ HIMAGELIST old_himl = 0;
+ int ret = 0;
+
+ if (!pimldp)
+ return E_FAIL;
+
+ /* As far as I can tell, Windows simply ignores the contents of pimldp->himl
+ so we shall simulate the same */
+ old_himl = pimldp->himl;
+ pimldp->himl = This;
+
+ ret = ImageList_DrawIndirect(pimldp);
+
+ pimldp->himl = old_himl;
+ return ret ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_Remove(IImageList *iface, int i)
+{
+ return (ImageList_Remove((HIMAGELIST) iface, i) == 0) ? E_FAIL : S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_GetIcon(IImageList *iface, int i, UINT flags,
+ HICON *picon)
+{
+ HICON hIcon;
+
+ if (!picon)
+ return E_FAIL;
+
+ hIcon = ImageList_GetIcon((HIMAGELIST) iface, i, flags);
+
+ if (hIcon == NULL)
+ return E_FAIL;
+
+ *picon = hIcon;
+ return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_GetImageInfo(IImageList *iface, int i,
+ IMAGEINFO *pImageInfo)
+{
+ return ImageList_GetImageInfo((HIMAGELIST) iface, i, pImageInfo) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_Copy(IImageList *iface, int iDst,
+ IUnknown *punkSrc, int iSrc, UINT uFlags)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ IImageList *src = NULL;
+ HRESULT ret;
+
+ if (!punkSrc)
+ return E_FAIL;
+
+ /* TODO: Add test for IID_ImageList2 too */
+ if (FAILED(IImageList_QueryInterface(punkSrc, &IID_IImageList,
+ (void **) &src)))
+ return E_FAIL;
+
+ if (ImageList_Copy(This, iDst, (HIMAGELIST) src, iSrc, uFlags))
+ ret = S_OK;
+ else
+ ret = E_FAIL;
+
+ IImageList_Release(src);
+ return ret;
+}
+
+static HRESULT WINAPI ImageListImpl_Merge(IImageList *iface, int i1,
+ IUnknown *punk2, int i2, int dx, int dy, REFIID riid, PVOID *ppv)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ IImageList *iml2 = NULL;
+ HIMAGELIST hNew;
+ HRESULT ret = E_FAIL;
+
+ if (!punk2 || !ppv)
+ return E_FAIL;
+
+ /* TODO: Add test for IID_ImageList2 too */
+ if (FAILED(IImageList_QueryInterface(punk2, &IID_IImageList,
+ (void **) &iml2)))
+ return E_FAIL;
+
+ hNew = ImageList_Merge(This, i1, (HIMAGELIST) iml2, i2, dx, dy);
+
+ /* Get the interface for the new image list */
+ if (hNew)
+ ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
+
+ IImageList_Release(iml2);
+ return ret;
+}
+
+static HRESULT WINAPI ImageListImpl_Clone(IImageList *iface, REFIID riid,
+ PVOID *ppv)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ HIMAGELIST hNew;
+ HRESULT ret = E_FAIL;
+
+ if (!ppv)
+ return E_FAIL;
+
+ hNew = ImageList_Duplicate(This);
+
+ /* Get the interface for the new image list */
+ if (hNew)
+ ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
+
+ return ret;
+}
+
+static HRESULT WINAPI ImageListImpl_GetImageRect(IImageList *iface, int i,
+ RECT *prc)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ IMAGEINFO info;
+
+ if (!prc)
+ return E_FAIL;
+
+ if (!ImageList_GetImageInfo(This, i, &info))
+ return E_FAIL;
+
+ return CopyRect(prc, &info.rcImage) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_GetIconSize(IImageList *iface, int *cx,
+ int *cy)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+
+ return ImageList_GetIconSize(This, cx, cy) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_SetIconSize(IImageList *iface, int cx,
+ int cy)
+{
+ return ImageList_SetIconSize((HIMAGELIST) iface, cx, cy) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_GetImageCount(IImageList *iface, int *pi)
+{
+ if (!pi)
+ return E_FAIL;
+
+ *pi = ImageList_GetImageCount((HIMAGELIST) iface);
+ return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_SetImageCount(IImageList *iface,
+ UINT uNewCount)
+{
+ return ImageList_SetImageCount((HIMAGELIST) iface, uNewCount) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_SetBkColor(IImageList *iface, COLORREF clrBk,
+ COLORREF *pclr)
+{
+ if (!pclr)
+ return E_FAIL;
+
+ *pclr = ImageList_SetBkColor((HIMAGELIST) iface, clrBk);
+ return *pclr == CLR_NONE ? E_FAIL : S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_GetBkColor(IImageList *iface, COLORREF *pclr)
+{
+ if (!pclr)
+ return E_FAIL;
+
+ *pclr = ImageList_GetBkColor((HIMAGELIST) iface);
+ return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_BeginDrag(IImageList *iface, int iTrack,
+ int dxHotspot, int dyHotspot)
+{
+ return ImageList_BeginDrag((HIMAGELIST) iface, iTrack, dxHotspot, dyHotspot) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_EndDrag(IImageList *iface)
+{
+ ImageList_EndDrag();
+ return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_DragEnter(IImageList *iface, HWND hwndLock,
+ int x, int y)
+{
+ return ImageList_DragEnter(hwndLock, x, y) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_DragLeave(IImageList *iface, HWND hwndLock)
+{
+ return ImageList_DragLeave(hwndLock) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_DragMove(IImageList *iface, int x, int y)
+{
+ return ImageList_DragMove(x, y) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_SetDragCursorImage(IImageList *iface,
+ IUnknown *punk, int iDrag, int dxHotspot, int dyHotspot)
+{
+ IImageList *iml2 = NULL;
+ HRESULT ret;
+
+ if (!punk)
+ return E_FAIL;
+
+ /* TODO: Add test for IID_ImageList2 too */
+ if (FAILED(IImageList_QueryInterface(punk, &IID_IImageList,
+ (void **) &iml2)))
+ return E_FAIL;
+
+ ret = ImageList_SetDragCursorImage((HIMAGELIST) iml2, iDrag, dxHotspot,
+ dyHotspot);
+
+ IImageList_Release(iml2);
+
+ return ret ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_DragShowNolock(IImageList *iface, BOOL fShow)
+{
+ return ImageList_DragShowNolock(fShow) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_GetDragImage(IImageList *iface, POINT *ppt,
+ POINT *pptHotspot, REFIID riid, PVOID *ppv)
+{
+ HRESULT ret = E_FAIL;
+ HIMAGELIST hNew;
+
+ if (!ppv)
+ return E_FAIL;
+
+ hNew = ImageList_GetDragImage(ppt, pptHotspot);
+
+ /* Get the interface for the new image list */
+ if (hNew)
+ ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
+
+ return ret;
+}
+
+static HRESULT WINAPI ImageListImpl_GetItemFlags(IImageList *iface, int i,
+ DWORD *dwFlags)
+{
+ FIXME("STUB: %p %d %p\n", iface, i, dwFlags);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImageListImpl_GetOverlayImage(IImageList *iface, int iOverlay,
+ int *piIndex)
+{
+ HIMAGELIST This = (HIMAGELIST) iface;
+ int i;
+
+ if ((iOverlay < 0) || (iOverlay > This->cCurImage))
+ return E_FAIL;
+
+ for (i = 0; i < MAX_OVERLAYIMAGE; i++)
+ {
+ if (This->nOvlIdx[i] == iOverlay)
+ {
+ *piIndex = i + 1;
+ return S_OK;
+ }
+ }
+
+ return E_FAIL;
+}
+
+
+static const IImageListVtbl ImageListImpl_Vtbl = {
+ ImageListImpl_QueryInterface,
+ ImageListImpl_AddRef,
+ ImageListImpl_Release,
+ ImageListImpl_Add,
+ ImageListImpl_ReplaceIcon,
+ ImageListImpl_SetOverlayImage,
+ ImageListImpl_Replace,
+ ImageListImpl_AddMasked,
+ ImageListImpl_Draw,
+ ImageListImpl_Remove,
+ ImageListImpl_GetIcon,
+ ImageListImpl_GetImageInfo,
+ ImageListImpl_Copy,
+ ImageListImpl_Merge,
+ ImageListImpl_Clone,
+ ImageListImpl_GetImageRect,
+ ImageListImpl_GetIconSize,
+ ImageListImpl_SetIconSize,
+ ImageListImpl_GetImageCount,
+ ImageListImpl_SetImageCount,
+ ImageListImpl_SetBkColor,
+ ImageListImpl_GetBkColor,
+ ImageListImpl_BeginDrag,
+ ImageListImpl_EndDrag,
+ ImageListImpl_DragEnter,
+ ImageListImpl_DragLeave,
+ ImageListImpl_DragMove,
+ ImageListImpl_SetDragCursorImage,
+ ImageListImpl_DragShowNolock,
+ ImageListImpl_GetDragImage,
+ ImageListImpl_GetItemFlags,
+ ImageListImpl_GetOverlayImage
+};
+
+static inline BOOL is_valid(HIMAGELIST himl)
+{
+ return himl && himl->lpVtbl == &ImageListImpl_Vtbl;
}
/*************************************************************************
@@ -2947,6 +3596,31 @@ ImageList_CoCreateInstance (REFCLSID rclsid, const IUnknown *punkOuter, REFIID r
HRESULT WINAPI
HIMAGELIST_QueryInterface (HIMAGELIST himl, REFIID riid, void **ppv)
{
- FIXME("STUB: %p %s %p\n", himl, debugstr_guid(riid), ppv);
- return E_NOINTERFACE;
+ TRACE("(%p,%s,%p)\n", himl, debugstr_guid(riid), ppv);
+ return IImageList_QueryInterface((IImageList *) himl, riid, ppv);
+}
+
+static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+ HIMAGELIST This;
+ HRESULT ret;
+
+ TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+
+ *ppv = NULL;
+
+ if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+
+ This = HeapAlloc(GetProcessHeap(), 0, sizeof(struct _IMAGELIST));
+ if (!This) return E_OUTOFMEMORY;
+
+ ZeroMemory(This, sizeof(struct _IMAGELIST));
+
+ This->lpVtbl = &ImageListImpl_Vtbl;
+ This->ref = 1;
+
+ ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
+ IUnknown_Release((IUnknown*)This);
+
+ return ret;
}
diff --git a/reactos/dll/win32/comctl32/imagelist.h b/reactos/dll/win32/comctl32/imagelist.h
index 73ccd8a376c..f6f1d1b9e71 100644
--- a/reactos/dll/win32/comctl32/imagelist.h
+++ b/reactos/dll/win32/comctl32/imagelist.h
@@ -27,32 +27,35 @@
#include "winbase.h"
#include "wingdi.h"
-/* the ones with offsets at the end are the same as in Windows */
struct _IMAGELIST
{
- DWORD magic; /* 00: 'SAMX' */
- INT cCurImage; /* 04: ImageCount */
- INT cMaxImage; /* 08: maximages */
- INT cGrow; /* 0c: cGrow */
- INT cx; /* 10: cx */
- INT cy; /* 14: cy */
+ const struct IImageListVtbl *lpVtbl; /* 00: IImageList vtable */
+
+ INT cCurImage; /* 04: ImageCount */
+ INT cMaxImage; /* 08: maximages */
+ INT cGrow; /* 0C: cGrow */
+ INT cx; /* 10: cx */
+ INT cy; /* 14: cy */
DWORD x4;
- UINT flags; /* 1c: flags */
- COLORREF clrFg; /* 20: foreground color */
- COLORREF clrBk; /* 24: background color */
+ UINT flags; /* 1C: flags */
+ COLORREF clrFg; /* 20: foreground color */
+ COLORREF clrBk; /* 24: background color */
- HBITMAP hbmImage; /* 30: images Bitmap */
- HBITMAP hbmMask; /* 34: masks Bitmap */
- HDC hdcImage; /* 38: images MemDC */
- HDC hdcMask; /* 3C: masks MemDC */
- INT nOvlIdx[15]; /* 40: overlay images index */
+ HBITMAP hbmImage; /* 28: images Bitmap */
+ HBITMAP hbmMask; /* 2C: masks Bitmap */
+ HDC hdcImage; /* 30: images MemDC */
+ HDC hdcMask; /* 34: masks MemDC */
+ INT nOvlIdx[15]; /* 38: overlay images index */
/* not yet found out */
HBRUSH hbrBlend25;
HBRUSH hbrBlend50;
INT cInitial;
UINT uBitsPixel;
+ char *has_alpha;
+
+ LONG ref; /* reference count */
};
#define IMAGELIST_MAGIC 0x53414D58
diff --git a/reactos/dll/win32/comctl32/ipaddress.c b/reactos/dll/win32/comctl32/ipaddress.c
index 42ac703b287..03b8d1c9ed3 100644
--- a/reactos/dll/win32/comctl32/ipaddress.c
+++ b/reactos/dll/win32/comctl32/ipaddress.c
@@ -189,7 +189,6 @@ static LRESULT IPADDRESS_Draw (const IPADDRESS_INFO *infoPtr, HDC hdc)
static LRESULT IPADDRESS_Create (HWND hwnd, const CREATESTRUCTA *lpCreate)
{
- static const WCHAR EDIT[] = { 'E', 'd', 'i', 't', 0 };
IPADDRESS_INFO *infoPtr;
RECT rcClient, edit;
int i, fieldsize;
@@ -230,7 +229,7 @@ static LRESULT IPADDRESS_Create (HWND hwnd, const CREATESTRUCTA *lpCreate)
edit.left = rcClient.left + i*fieldsize + 6;
edit.right = rcClient.left + (i+1)*fieldsize - 2;
part->EditHwnd =
- CreateWindowW (EDIT, NULL, WS_CHILD | WS_VISIBLE | ES_CENTER,
+ CreateWindowW (WC_EDITW, NULL, WS_CHILD | WS_VISIBLE | ES_CENTER,
edit.left, edit.top, edit.right - edit.left,
edit.bottom - edit.top, hwnd, (HMENU) 1,
(HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE), NULL);
diff --git a/reactos/dll/win32/comctl32/listview.c b/reactos/dll/win32/comctl32/listview.c
index 4e13577b48f..2c27aa90f12 100644
--- a/reactos/dll/win32/comctl32/listview.c
+++ b/reactos/dll/win32/comctl32/listview.c
@@ -168,6 +168,9 @@
WINE_DEFAULT_DEBUG_CHANNEL(listview);
+/* make sure you set this to 0 for production use! */
+#define DEBUG_RANGES 1
+
typedef struct tagCOLUMN_INFO
{
RECT rcHeader; /* tracks the header's rectangle */
@@ -2965,7 +2968,11 @@ static INT CALLBACK ranges_cmp(LPVOID range1, LPVOID range2, LPARAM flags)
return cmp;
}
-#define ranges_check(ranges, desc) if (TRACE_ON(listview)) ranges_assert(ranges, desc, __FUNCTION__, __LINE__)
+#if DEBUG_RANGES
+#define ranges_check(ranges, desc) ranges_assert(ranges, desc, __FUNCTION__, __LINE__)
+#else
+#define ranges_check(ranges, desc) do { } while(0)
+#endif
static void ranges_assert(RANGES ranges, LPCSTR desc, const char *func, int line)
{
@@ -6946,7 +6953,7 @@ static BOOL LISTVIEW_GetItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT
*/
static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc)
{
- POINT Position, Origin;
+ POINT Position;
LVITEMW lvItem;
INT nColumn;
@@ -6954,7 +6961,7 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
nColumn = lprc->top;
- TRACE("(nItem=%d, nSubItem=%d, type=%d)\n", nItem, lprc->top, lprc->left);
+ TRACE("(nItem=%d, nSubItem=%d)\n", nItem, lprc->top);
/* On WinNT, a subitem of '0' calls LISTVIEW_GetItemRect */
if (lprc->top == 0)
return LISTVIEW_GetItemRect(infoPtr, nItem, lprc);
@@ -6979,8 +6986,7 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
}
}
- if (!LISTVIEW_GetItemPosition(infoPtr, nItem, &Position)) return FALSE;
- LISTVIEW_GetOrigin(infoPtr, &Origin);
+ LISTVIEW_GetOrigin(infoPtr, &Position);
if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
@@ -6988,6 +6994,7 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
lvItem.iItem = nItem;
lvItem.iSubItem = nColumn;
+ if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
switch(lprc->left)
{
case LVIR_ICON:
@@ -7004,9 +7011,7 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
return FALSE;
}
- OffsetRect(lprc, Origin.x, Position.y);
- TRACE("return rect %s\n", wine_dbgstr_rect(lprc));
-
+ OffsetRect(lprc, Position.x, Position.y);
return TRUE;
}
diff --git a/reactos/dll/win32/comctl32/monthcal.c b/reactos/dll/win32/comctl32/monthcal.c
index 7a49c7025bf..a9795e09c40 100644
--- a/reactos/dll/win32/comctl32/monthcal.c
+++ b/reactos/dll/win32/comctl32/monthcal.c
@@ -1,11 +1,12 @@
-/* Month calendar control
-
+/*
+ * Month calendar control
*
* Copyright 1998, 1999 Eric Kohl (ekohl@abo.rhein-zeitung.de)
* Copyright 1999 Alex Priem (alexp@sci.kun.nl)
* Copyright 1999 Chris Morgan and
* James Abbatiello
* Copyright 2000 Uwe Bonnes
+ * Copyright 2009 Nikolay Sivov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -36,9 +37,6 @@
* -- handle resources better (doesn't work now);
* -- take care of internationalization.
* -- keyboard handling.
- * -- GetRange: At the moment, we copy ranges anyway, regardless of
- * infoPtr->rangeValid; an invalid range is simply filled
- * with zeros in SetRange. Is this the right behavior?
* -- search for FIXME
*/
@@ -66,14 +64,19 @@ WINE_DEFAULT_DEBUG_CHANNEL(monthcal);
#define MC_SEL_LBUTDOWN 2 /* Left button pressed in calendar */
#define MC_PREVPRESSED 4 /* Prev month button pressed */
#define MC_NEXTPRESSED 8 /* Next month button pressed */
-#define MC_NEXTMONTHDELAY 350 /* when continuously pressing `next */
- /* month', wait 500 ms before going */
- /* to the next month */
-#define MC_NEXTMONTHTIMER 1 /* Timer ID's */
-#define MC_PREVMONTHTIMER 2
+#define MC_PREVNEXTMONTHDELAY 350 /* when continuously pressing `next/prev
+ month', wait 500 ms before going
+ to the next/prev month */
+#define MC_TODAYUPDATEDELAY 120000 /* time between today check for update (2 min) */
+
+#define MC_PREVNEXTMONTHTIMER 1 /* Timer ID's */
+#define MC_TODAYUPDATETIMER 2
#define countof(arr) (sizeof(arr)/sizeof(arr[0]))
+/* convert from days to 100 nanoseconds unit - used as FILETIME unit */
+#define DAYSTO100NSECS(days) (((ULONGLONG)(days))*24*60*60*10000000)
+
typedef struct
{
HWND hwndSelf;
@@ -90,23 +93,26 @@ typedef struct
int textWidth;
int height_increment;
int width_increment;
- int firstDayplace; /* place of the first day of the current month */
INT delta; /* scroll rate; # of months that the */
/* control moves when user clicks a scroll button */
int visible; /* # of months visible */
- int firstDay; /* Start month calendar with firstDay's day */
- int firstDayHighWord; /* High word only used externally */
+ int firstDay; /* Start month calendar with firstDay's day,
+ stored in SYSTEMTIME format */
+ BOOL firstDaySet; /* first week day differs from locale defined */
+
+ BOOL isUnicode; /* value set with MCM_SETUNICODE format */
+
int monthRange;
MONTHDAYSTATE *monthdayState;
SYSTEMTIME todaysDate;
- DWORD currentMonth;
- DWORD currentYear;
+ BOOL todaySet; /* Today was forced with MCM_SETTODAY */
int status; /* See MC_SEL flags */
- int curSelDay; /* current selected day */
- int firstSelDay; /* first selected day */
+ SYSTEMTIME firstSel; /* first selected day */
INT maxSelCount;
SYSTEMTIME minSel;
SYSTEMTIME maxSel;
+ SYSTEMTIME curSel; /* contains currently selected year, month and day */
+ SYSTEMTIME focusedSel; /* date currently focused with mouse movement */
DWORD rangeValid;
SYSTEMTIME minDate;
SYSTEMTIME maxDate;
@@ -123,29 +129,65 @@ typedef struct
HWND hwndNotify; /* Window to receive the notifications */
HWND hWndYearEdit; /* Window Handle of edit box to handle years */
HWND hWndYearUpDown;/* Window Handle of updown box to handle years */
+ WNDPROC EditWndProc; /* original Edit window procedure */
} MONTHCAL_INFO, *LPMONTHCAL_INFO;
-
-/* Offsets of days in the week to the weekday of january 1 in a leap year */
-static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
-
static const WCHAR themeClass[] = { 'S','c','r','o','l','l','b','a','r',0 };
+/* empty SYSTEMTIME const */
+static const SYSTEMTIME st_null;
+/* valid date limits */
+static const SYSTEMTIME max_allowed_date = { .wYear = 9999, .wMonth = 12, .wDay = 31 };
+static const SYSTEMTIME min_allowed_date = { .wYear = 1752, .wMonth = 9, .wDay = 14 };
+
+
#define MONTHCAL_GetInfoPtr(hwnd) ((MONTHCAL_INFO *)GetWindowLongPtrW(hwnd, 0))
/* helper functions */
+/* send a single MCN_SELCHANGE notification */
+static inline void MONTHCAL_NotifySelectionChange(const MONTHCAL_INFO *infoPtr)
+{
+ NMSELCHANGE nmsc;
+
+ nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
+ nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
+ nmsc.nmhdr.code = MCN_SELCHANGE;
+ nmsc.stSelStart = infoPtr->minSel;
+ nmsc.stSelEnd = infoPtr->maxSel;
+ SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
+}
+
+/* send a single MCN_SELECT notification */
+static inline void MONTHCAL_NotifySelect(const MONTHCAL_INFO *infoPtr)
+{
+ NMSELCHANGE nmsc;
+
+ nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
+ nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
+ nmsc.nmhdr.code = MCN_SELECT;
+ nmsc.stSelStart = infoPtr->minSel;
+ nmsc.stSelEnd = infoPtr->maxSel;
+
+ SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
+}
+
/* returns the number of days in any given month, checking for leap days */
/* january is 1, december is 12 */
int MONTHCAL_MonthLength(int month, int year)
{
- const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
- /*Wrap around, this eases handling*/
+ const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+ /* Wrap around, this eases handling. Getting length only we shouldn't care
+ about year change here cause January and December have
+ the same day quantity */
if(month == 0)
month = 12;
- if(month == 13)
+ else if(month == 13)
month = 1;
+ /* special case for calendar transition year */
+ if(month == min_allowed_date.wMonth && year == min_allowed_date.wYear) return 19;
+
/* if we have a leap year add 1 day to February */
/* a leap year is a year either divisible by 400 */
/* or divisible by 4 and not by 100 */
@@ -165,17 +207,206 @@ static inline BOOL MONTHCAL_IsDateEqual(const SYSTEMTIME *first, const SYSTEMTIM
(first->wDay == second->wDay);
}
-/* make sure that time is valid */
-static BOOL MONTHCAL_ValidateTime(SYSTEMTIME time)
+/* make sure that date fields are valid */
+static BOOL MONTHCAL_ValidateDate(const SYSTEMTIME *time)
{
- if(time.wMonth < 1 || time.wMonth > 12 ) return FALSE;
- if(time.wDayOfWeek > 6) return FALSE;
- if(time.wDay > MONTHCAL_MonthLength(time.wMonth, time.wYear))
+ if(time->wMonth < 1 || time->wMonth > 12 ) return FALSE;
+ if(time->wDayOfWeek > 6) return FALSE;
+ if(time->wDay > MONTHCAL_MonthLength(time->wMonth, time->wYear))
return FALSE;
return TRUE;
}
+/* Copies timestamp part only.
+ *
+ * PARAMETERS
+ *
+ * [I] from : source date
+ * [O] to : dest date
+ */
+static void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to)
+{
+ to->wHour = from->wHour;
+ to->wMinute = from->wMinute;
+ to->wSecond = from->wSecond;
+}
+
+/* Copies date part only.
+ *
+ * PARAMETERS
+ *
+ * [I] from : source date
+ * [O] to : dest date
+ */
+static void MONTHCAL_CopyDate(const SYSTEMTIME *from, SYSTEMTIME *to)
+{
+ to->wYear = from->wYear;
+ to->wMonth = from->wMonth;
+ to->wDay = from->wDay;
+ to->wDayOfWeek = from->wDayOfWeek;
+}
+
+/* Compares two dates in SYSTEMTIME format
+ *
+ * PARAMETERS
+ *
+ * [I] first : pointer to valid first date data to compare
+ * [I] second : pointer to valid second date data to compare
+ *
+ * RETURN VALUE
+ *
+ * -1 : first < second
+ * 0 : first == second
+ * 1 : first > second
+ *
+ * Note that no date validation performed, alreadt validated values expected.
+ */
+static LONG MONTHCAL_CompareSystemTime(const SYSTEMTIME *first, const SYSTEMTIME *second)
+{
+ FILETIME ft_first, ft_second;
+
+ SystemTimeToFileTime(first, &ft_first);
+ SystemTimeToFileTime(second, &ft_second);
+
+ return CompareFileTime(&ft_first, &ft_second);
+}
+
+static LONG MONTHCAL_CompareMonths(const SYSTEMTIME *first, const SYSTEMTIME *second)
+{
+ SYSTEMTIME st_first, st_second;
+
+ st_first = st_second = st_null;
+ MONTHCAL_CopyDate(first, &st_first);
+ MONTHCAL_CopyDate(second, &st_second);
+ st_first.wDay = st_second.wDay = 1;
+
+ return MONTHCAL_CompareSystemTime(&st_first, &st_second);
+}
+
+static LONG MONTHCAL_CompareDate(const SYSTEMTIME *first, const SYSTEMTIME *second)
+{
+ SYSTEMTIME st_first, st_second;
+
+ st_first = st_second = st_null;
+ MONTHCAL_CopyDate(first, &st_first);
+ MONTHCAL_CopyDate(second, &st_second);
+
+ return MONTHCAL_CompareSystemTime(&st_first, &st_second);
+}
+
+/* Checks largest possible date range and configured one
+ *
+ * PARAMETERS
+ *
+ * [I] infoPtr : valid pointer to control data
+ * [I] date : pointer to valid date data to check
+ * [I] fix : make date fit valid range
+ *
+ * RETURN VALUE
+ *
+ * TRUE - date whithin largest and configured range
+ * FALSE - date is outside largest or configured range
+ */
+static BOOL MONTHCAL_IsDateInValidRange(const MONTHCAL_INFO *infoPtr,
+ SYSTEMTIME *date, BOOL fix)
+{
+ const SYSTEMTIME *fix_st = NULL;
+
+ if(MONTHCAL_CompareSystemTime(date, &max_allowed_date) == 1) {
+ fix_st = &max_allowed_date;
+ }
+ else if(MONTHCAL_CompareSystemTime(date, &min_allowed_date) == -1) {
+ fix_st = &min_allowed_date;
+ }
+ else if(infoPtr->rangeValid & GDTR_MAX) {
+ if((MONTHCAL_CompareSystemTime(date, &infoPtr->maxDate) == 1)) {
+ fix_st = &infoPtr->maxDate;
+ }
+ }
+ else if(infoPtr->rangeValid & GDTR_MIN) {
+ if((MONTHCAL_CompareSystemTime(date, &infoPtr->minDate) == -1)) {
+ fix_st = &infoPtr->minDate;
+ }
+ }
+
+ if (fix && fix_st) {
+ date->wYear = fix_st->wYear;
+ date->wMonth = fix_st->wMonth;
+ }
+
+ return fix_st ? FALSE : TRUE;
+}
+
+/* Checks passed range width with configured maximum selection count
+ *
+ * PARAMETERS
+ *
+ * [I] infoPtr : valid pointer to control data
+ * [I] range0 : pointer to valid date data (requested bound)
+ * [I] range1 : pointer to valid date data (primary bound)
+ * [O] adjust : returns adjusted range bound to fit maximum range (optional)
+ *
+ * Adjust value computed basing on primary bound and current maximum selection
+ * count. For simple range check (without adjusted value required) (range0, range1)
+ * relation means nothing.
+ *
+ * RETURN VALUE
+ *
+ * TRUE - range is shorter or equal to maximum
+ * FALSE - range is larger than maximum
+ */
+static BOOL MONTHCAL_IsSelRangeValid(const MONTHCAL_INFO *infoPtr,
+ const SYSTEMTIME *range0,
+ const SYSTEMTIME *range1,
+ SYSTEMTIME *adjust)
+{
+ ULARGE_INTEGER ul_range0, ul_range1, ul_diff;
+ FILETIME ft_range0, ft_range1;
+ LONG cmp;
+
+ SystemTimeToFileTime(range0, &ft_range0);
+ SystemTimeToFileTime(range1, &ft_range1);
+
+ ul_range0.u.LowPart = ft_range0.dwLowDateTime;
+ ul_range0.u.HighPart = ft_range0.dwHighDateTime;
+ ul_range1.u.LowPart = ft_range1.dwLowDateTime;
+ ul_range1.u.HighPart = ft_range1.dwHighDateTime;
+
+ cmp = CompareFileTime(&ft_range0, &ft_range1);
+
+ if(cmp == 1)
+ ul_diff.QuadPart = ul_range0.QuadPart - ul_range1.QuadPart;
+ else
+ ul_diff.QuadPart = -ul_range0.QuadPart + ul_range1.QuadPart;
+
+ if(ul_diff.QuadPart >= DAYSTO100NSECS(infoPtr->maxSelCount)) {
+
+ if(adjust) {
+ if(cmp == 1)
+ ul_range0.QuadPart = ul_range1.QuadPart + DAYSTO100NSECS(infoPtr->maxSelCount - 1);
+ else
+ ul_range0.QuadPart = ul_range1.QuadPart - DAYSTO100NSECS(infoPtr->maxSelCount - 1);
+
+ ft_range0.dwLowDateTime = ul_range0.u.LowPart;
+ ft_range0.dwHighDateTime = ul_range0.u.HighPart;
+ FileTimeToSystemTime(&ft_range0, adjust);
+ }
+
+ return FALSE;
+ }
+ else return TRUE;
+}
+
+/* Used in MCM_SETRANGE/MCM_SETSELRANGE to determine resulting time part.
+ Milliseconds are intentionally not validated. */
+static BOOL MONTHCAL_ValidateTime(const SYSTEMTIME *time)
+{
+ if((time->wHour > 24) || (time->wMinute > 59) || (time->wSecond > 59))
+ return FALSE;
+ else
+ return TRUE;
+}
/* Note:Depending on DST, this may be offset by a day.
Need to find out if we're on a DST place & adjust the clock accordingly.
@@ -184,14 +415,89 @@ static BOOL MONTHCAL_ValidateTime(SYSTEMTIME time)
0 = Sunday.
*/
-/* returns the day in the week(0 == sunday, 6 == saturday) */
-/* day(1 == 1st, 2 == 2nd... etc), year is the year value */
-static int MONTHCAL_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year)
+/* Returns the day in the week
+ *
+ * PARAMETERS
+ * [i] date : input date
+ * [I] inplace : set calculated value back to date structure
+ *
+ * RETURN VALUE
+ * day of week in SYSTEMTIME format: (0 == sunday,..., 6 == saturday)
+ */
+int MONTHCAL_CalculateDayOfWeek(SYSTEMTIME *date, BOOL inplace)
{
- year-=(month < 3);
+ SYSTEMTIME st = st_null;
+ FILETIME ft;
- return((year + year/4 - year/100 + year/400 +
- DayOfWeekTable[month-1] + day ) % 7);
+ MONTHCAL_CopyDate(date, &st);
+
+ SystemTimeToFileTime(&st, &ft);
+ FileTimeToSystemTime(&ft, &st);
+
+ if (inplace) date->wDayOfWeek = st.wDayOfWeek;
+
+ return st.wDayOfWeek;
+}
+
+/* properly updates date to point on next month */
+static inline void MONTHCAL_GetNextMonth(SYSTEMTIME *date)
+{
+ if(++date->wMonth > 12)
+ {
+ date->wMonth = 1;
+ date->wYear++;
+ }
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
+}
+
+/* properly updates date to point on prev month */
+static inline void MONTHCAL_GetPrevMonth(SYSTEMTIME *date)
+{
+ if(--date->wMonth < 1)
+ {
+ date->wMonth = 12;
+ date->wYear--;
+ }
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
+}
+
+/* Returns full date for a first currently visible day */
+static void MONTHCAL_GetMinDate(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *date)
+{
+ SYSTEMTIME st_first = infoPtr->curSel;
+ int firstDay;
+
+ st_first.wDay = 1;
+ firstDay = MONTHCAL_CalculateDayOfWeek(&st_first, FALSE);
+
+ *date = infoPtr->curSel;
+ MONTHCAL_GetPrevMonth(date);
+
+ date->wDay = MONTHCAL_MonthLength(date->wMonth, date->wYear) +
+ (infoPtr->firstDay - firstDay) % 7 + 1;
+
+ if(date->wDay > MONTHCAL_MonthLength(date->wMonth, date->wYear))
+ date->wDay -= 7;
+
+ /* fix day of week */
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
+}
+
+/* Returns full date for a last currently visible day */
+static void MONTHCAL_GetMaxDate(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *date)
+{
+ SYSTEMTIME st;
+
+ *date = infoPtr->curSel;
+ MONTHCAL_GetNextMonth(date);
+
+ MONTHCAL_GetMinDate(infoPtr, &st);
+ /* Use month length to get max day. 42 means max day count in calendar area */
+ date->wDay = 42 - (MONTHCAL_MonthLength(st.wMonth, st.wYear) - st.wDay + 1) -
+ MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear);
+
+ /* fix day of week */
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
}
/* From a given point, calculate the row (weekpos), column(daypos)
@@ -202,6 +508,7 @@ static int MONTHCAL_CalcDayFromPos(const MONTHCAL_INFO *infoPtr, int x, int y,
{
int retval, firstDay;
RECT rcClient;
+ SYSTEMTIME st = infoPtr->curSel;
GetClientRect(infoPtr->hwndSelf, &rcClient);
@@ -214,44 +521,53 @@ static int MONTHCAL_CalcDayFromPos(const MONTHCAL_INFO *infoPtr, int x, int y,
*daypos = (x - infoPtr->days.left ) / infoPtr->width_increment;
*weekpos = (y - infoPtr->days.top ) / infoPtr->height_increment;
- firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear)+6 - infoPtr->firstDay)%7;
+ st.wDay = 1;
+ firstDay = (MONTHCAL_CalculateDayOfWeek(&st, FALSE) + 6 - infoPtr->firstDay) % 7;
retval = *daypos + (7 * *weekpos) - firstDay;
return retval;
}
-/* day is the day of the month, 1 == 1st day of the month */
-/* sets x and y to be the position of the day */
-/* x == day, y == week where(0,0) == firstDay, 1st week */
-static void MONTHCAL_CalcDayXY(const MONTHCAL_INFO *infoPtr, int day, int month,
- int *x, int *y)
+/* Sets the RECT struct r to the rectangle around the date
+ *
+ * PARAMETERS
+ *
+ * [I] infoPtr : pointer to control data
+ * [I] date : date value
+ * [O] x : day column (zero based)
+ * [O] y : week column (zero based)
+ */
+static void MONTHCAL_CalcDayXY(const MONTHCAL_INFO *infoPtr,
+ const SYSTEMTIME *date, int *x, int *y)
{
- int firstDay, prevMonth;
+ SYSTEMTIME st = infoPtr->curSel;
+ LONG cmp;
+ int first;
- firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear) +6 - infoPtr->firstDay)%7;
+ st.wDay = 1;
+ first = (MONTHCAL_CalculateDayOfWeek(&st, FALSE) + 6 - infoPtr->firstDay) % 7;
- if(month==infoPtr->currentMonth) {
- *x = (day + firstDay) % 7;
- *y = (day + firstDay - *x) / 7;
- return;
- }
- if(month < infoPtr->currentMonth) {
- prevMonth = month - 1;
- if(prevMonth==0)
- prevMonth = 12;
+ cmp = MONTHCAL_CompareMonths(date, &infoPtr->curSel);
- *x = (MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear) - firstDay) % 7;
+ /* previous month */
+ if(cmp == -1) {
+ *x = (first - MONTHCAL_MonthLength(date->wMonth, infoPtr->curSel.wYear) + date->wDay) % 7;
*y = 0;
return;
}
- *y = MONTHCAL_MonthLength(month, infoPtr->currentYear - 1) / 7;
- *x = (day + firstDay + MONTHCAL_MonthLength(month,
- infoPtr->currentYear)) % 7;
+ /* next month calculation is same as for current,
+ just add current month length */
+ if(cmp == 1) {
+ first += MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear);
+ }
+
+ *x = (date->wDay + first) % 7;
+ *y = (date->wDay + first - *x) / 7;
}
/* x: column(day), y: row(week) */
-static void MONTHCAL_CalcDayRect(const MONTHCAL_INFO *infoPtr, RECT *r, int x, int y)
+static inline void MONTHCAL_CalcDayRect(const MONTHCAL_INFO *infoPtr, RECT *r, int x, int y)
{
r->left = infoPtr->days.left + x * infoPtr->width_increment;
r->right = r->left + infoPtr->width_increment;
@@ -260,29 +576,67 @@ static void MONTHCAL_CalcDayRect(const MONTHCAL_INFO *infoPtr, RECT *r, int x, i
}
-/* sets the RECT struct r to the rectangle around the day and month */
-/* day is the day value of the month(1 == 1st), month is the month */
-/* value(january == 1, december == 12) */
+/* Sets the RECT struct r to the rectangle around the date */
static inline void MONTHCAL_CalcPosFromDay(const MONTHCAL_INFO *infoPtr,
- int day, int month, RECT *r)
+ const SYSTEMTIME *date, RECT *r)
{
int x, y;
- MONTHCAL_CalcDayXY(infoPtr, day, month, &x, &y);
+ MONTHCAL_CalcDayXY(infoPtr, date, &x, &y);
MONTHCAL_CalcDayRect(infoPtr, r, x, y);
}
+/* Focused day helper:
-/* day is the day in the month(1 == 1st of the month) */
-/* month is the month value(1 == january, 12 == december) */
-static void MONTHCAL_CircleDay(const MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month)
+ - set focused date to given value;
+ - reset to zero value if NULL passed;
+ - invalidate previous and new day rectangle only if needed.
+
+ Returns TRUE if focused day changed, FALSE otherwise.
+*/
+static BOOL MONTHCAL_SetDayFocus(MONTHCAL_INFO *infoPtr, const SYSTEMTIME *st)
+{
+ RECT r;
+
+ if(st)
+ {
+ /* there's nothing to do if it's the same date,
+ mouse move within same date rectangle case */
+ if(MONTHCAL_IsDateEqual(&infoPtr->focusedSel, st)) return FALSE;
+
+ /* invalidate old focused day */
+ MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->focusedSel, &r);
+ InvalidateRect(infoPtr->hwndSelf, &r, FALSE);
+
+ infoPtr->focusedSel = *st;
+ }
+
+ MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->focusedSel, &r);
+
+ if(!st && MONTHCAL_ValidateDate(&infoPtr->focusedSel))
+ infoPtr->focusedSel = st_null;
+
+ /* on set invalidates new day, on reset clears previous focused day */
+ InvalidateRect(infoPtr->hwndSelf, &r, FALSE);
+
+ return TRUE;
+}
+
+/* Draw today day mark rectangle
+ *
+ * [I] hdc : context to draw in
+ * [I] day : day to mark with rectangle
+ *
+ */
+static void MONTHCAL_CircleDay(const MONTHCAL_INFO *infoPtr, HDC hdc,
+ const SYSTEMTIME *date)
{
HPEN hRedPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
HPEN hOldPen2 = SelectObject(hdc, hRedPen);
HBRUSH hOldBrush;
RECT day_rect;
- MONTHCAL_CalcPosFromDay(infoPtr, day, month, &day_rect);
+ MONTHCAL_CalcPosFromDay(infoPtr, date, &day_rect);
hOldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
Rectangle(hdc, day_rect.left, day_rect.top, day_rect.right, day_rect.bottom);
@@ -292,78 +646,64 @@ static void MONTHCAL_CircleDay(const MONTHCAL_INFO *infoPtr, HDC hdc, int day, i
SelectObject(hdc, hOldPen2);
}
-static void MONTHCAL_DrawDay(const MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month,
- int x, int y, int bold)
+static void MONTHCAL_DrawDay(const MONTHCAL_INFO *infoPtr, HDC hdc, const SYSTEMTIME *st,
+ int bold, const PAINTSTRUCT *ps)
{
static const WCHAR fmtW[] = { '%','d',0 };
WCHAR buf[10];
- RECT r;
- static BOOL haveBoldFont, haveSelectedDay = FALSE;
+ RECT r, r_temp;
+ static BOOL bold_selected;
+ BOOL selected_day = FALSE;
HBRUSH hbr;
COLORREF oldCol = 0;
- COLORREF oldBk = 0;
-
- wsprintfW(buf, fmtW, day);
+ COLORREF oldBk = 0;
/* No need to check styles: when selection is not valid, it is set to zero.
* 1rcPaint), &r)) return;
- if((day>=infoPtr->minSel.wDay) && (day<=infoPtr->maxSel.wDay)
- && (month==infoPtr->currentMonth)) {
- RECT r2;
+ if ((MONTHCAL_CompareDate(st, &infoPtr->minSel) >= 0) &&
+ (MONTHCAL_CompareDate(st, &infoPtr->maxSel) <= 0)) {
- TRACE("%d %d %d\n",day, infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
+ TRACE("%d %d %d\n", st->wDay, infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
TRACE("%s\n", wine_dbgstr_rect(&r));
oldCol = SetTextColor(hdc, infoPtr->monthbk);
oldBk = SetBkColor(hdc, infoPtr->trailingtxt);
hbr = GetSysColorBrush(COLOR_HIGHLIGHT);
FillRect(hdc, &r, hbr);
- /* FIXME: this may need to be changed now b/c of the other
- drawing changes 11/3/99 CMM */
- r2.left = r.left - 0.25 * infoPtr->textWidth;
- r2.top = r.top;
- r2.right = r.left + 0.5 * infoPtr->textWidth;
- r2.bottom = r.bottom;
- if(haveSelectedDay) FillRect(hdc, &r2, hbr);
- haveSelectedDay = TRUE;
- } else {
- haveSelectedDay = FALSE;
+ selected_day = TRUE;
}
- /* need to add some code for multiple selections */
-
- if((bold) &&(!haveBoldFont)) {
+ if(bold && !bold_selected) {
SelectObject(hdc, infoPtr->hBoldFont);
- haveBoldFont = TRUE;
+ bold_selected = TRUE;
}
- if((!bold) &&(haveBoldFont)) {
+ if(!bold && bold_selected) {
SelectObject(hdc, infoPtr->hFont);
- haveBoldFont = FALSE;
+ bold_selected = FALSE;
}
SetBkMode(hdc,TRANSPARENT);
+ wsprintfW(buf, fmtW, st->wDay);
DrawTextW(hdc, buf, -1, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
- if(haveSelectedDay) {
+ if(selected_day) {
SetTextColor(hdc, oldCol);
SetBkColor(hdc, oldBk);
}
-
- /* draw a rectangle around the currently selected days text */
- if((day==infoPtr->curSelDay) && (month==infoPtr->currentMonth))
- DrawFocusRect(hdc, &r);
}
-static void paint_button (const MONTHCAL_INFO *infoPtr, HDC hdc, BOOL btnNext,
- BOOL pressed, RECT* r)
+static void MONTHCAL_PaintButton(MONTHCAL_INFO *infoPtr, HDC hdc, BOOL btnNext)
{
HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
-
+ RECT *r = btnNext ? &infoPtr->titlebtnnext : &infoPtr->titlebtnprev;
+ BOOL pressed = btnNext ? (infoPtr->status & MC_NEXTPRESSED) :
+ (infoPtr->status & MC_PREVPRESSED);
if (theme)
{
static const int states[] = {
@@ -394,350 +734,305 @@ static void paint_button (const MONTHCAL_INFO *infoPtr, HDC hdc, BOOL btnNext,
DrawFrameControl(hdc, r, DFC_SCROLL, style);
}
}
-
-
-static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+/* paint a title with buttons and month/year string */
+static void MONTHCAL_PaintTitle(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
{
- static const WCHAR todayW[] = { 'T','o','d','a','y',':',0 };
- static const WCHAR fmt1W[] = { '%','s',' ','%','l','d',0 };
- static const WCHAR fmt2W[] = { '%','s',' ','%','s',0 };
- static const WCHAR fmt3W[] = { '%','d',0 };
- RECT *title=&infoPtr->title;
- RECT *prev=&infoPtr->titlebtnprev;
- RECT *next=&infoPtr->titlebtnnext;
- RECT *titlemonth=&infoPtr->titlemonth;
- RECT *titleyear=&infoPtr->titleyear;
- RECT dayrect;
- RECT *days=&dayrect;
- RECT rtoday;
- int i, j, m, mask, day, firstDay, weeknum, weeknum1,prevMonth;
- int textHeight = infoPtr->textHeight;
- SIZE size;
+ static const WCHAR fmt_monthW[] = { '%','s',' ','%','l','d',0 };
+ WCHAR buf_month[80], buf_fmt[80];
HBRUSH hbr;
- HFONT currentFont;
- WCHAR buf[20];
- WCHAR buf1[20];
- WCHAR buf2[32];
- COLORREF oldTextColor, oldBkColor;
- RECT rcTemp;
- RECT rcDay; /* used in MONTHCAL_CalcDayRect() */
- SYSTEMTIME localtime;
- int startofprescal;
+ RECT *title = &infoPtr->title;
+ SIZE sz;
- oldTextColor = SetTextColor(hdc, comctl32_color.clrWindowText);
-
- /* fill background */
- hbr = CreateSolidBrush (infoPtr->bk);
- FillRect(hdc, &ps->rcPaint, hbr);
+ /* fill header box */
+ hbr = CreateSolidBrush(infoPtr->titlebk);
+ FillRect(hdc, title, hbr);
DeleteObject(hbr);
- /* draw header */
- if(IntersectRect(&rcTemp, &(ps->rcPaint), title))
- {
- hbr = CreateSolidBrush(infoPtr->titlebk);
- FillRect(hdc, title, hbr);
- DeleteObject(hbr);
- }
+ /* navigation buttons */
+ MONTHCAL_PaintButton(infoPtr, hdc, FALSE);
+ MONTHCAL_PaintButton(infoPtr, hdc, TRUE);
- /* if the previous button is pressed draw it depressed */
- if(IntersectRect(&rcTemp, &(ps->rcPaint), prev))
- paint_button (infoPtr, hdc, FALSE, infoPtr->status & MC_PREVPRESSED, prev);
-
- /* if next button is depressed draw it depressed */
- if(IntersectRect(&rcTemp, &(ps->rcPaint), next))
- paint_button (infoPtr, hdc, TRUE, infoPtr->status & MC_NEXTPRESSED, next);
-
- oldBkColor = SetBkColor(hdc, infoPtr->titlebk);
+ /* month/year string */
+ SetBkColor(hdc, infoPtr->titlebk);
SetTextColor(hdc, infoPtr->titletxt);
- currentFont = SelectObject(hdc, infoPtr->hBoldFont);
+ SelectObject(hdc, infoPtr->hBoldFont);
- GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+infoPtr->currentMonth -1,
- buf1,countof(buf1));
- wsprintfW(buf, fmt1W, buf1, infoPtr->currentYear);
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1+infoPtr->curSel.wMonth-1,
+ buf_month, countof(buf_month));
- if(IntersectRect(&rcTemp, &(ps->rcPaint), title))
- {
- DrawTextW(hdc, buf, strlenW(buf), title,
- DT_CENTER | DT_VCENTER | DT_SINGLELINE);
- }
+ wsprintfW(buf_fmt, fmt_monthW, buf_month, infoPtr->curSel.wYear);
+ DrawTextW(hdc, buf_fmt, strlenW(buf_fmt), title,
+ DT_CENTER | DT_VCENTER | DT_SINGLELINE);
-/* titlemonth left/right contained rect for whole titletxt('June 1999')
- * MCM_HitTestInfo wants month & year rects, so prepare these now.
- *(no, we can't draw them separately; the whole text is centered)
+ /* update title rectangles with current month - used while testing hits */
+ GetTextExtentPoint32W(hdc, buf_fmt, strlenW(buf_fmt), &sz);
+ infoPtr->titlemonth.left = title->right / 2 + title->left / 2 - sz.cx / 2;
+ infoPtr->titleyear.right = title->right / 2 + title->left / 2 + sz.cx / 2;
+
+ GetTextExtentPoint32W(hdc, buf_month, strlenW(buf_month), &sz);
+ infoPtr->titlemonth.right = infoPtr->titlemonth.left + sz.cx;
+ infoPtr->titleyear.left = infoPtr->titlemonth.right;
+}
+
+static void MONTHCAL_PaintWeeknumbers(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+{
+ static const WCHAR fmt_weekW[] = { '%','d',0 };
+ INT mindays, weeknum, weeknum1, startofprescal;
+ SYSTEMTIME st = infoPtr->curSel;
+ RECT r;
+ WCHAR buf[80];
+ INT i, prev_month;
+
+ if (!(infoPtr->dwStyle & MCS_WEEKNUMBERS)) return;
+
+ MONTHCAL_GetMinDate(infoPtr, &st);
+ startofprescal = st.wDay;
+ st = infoPtr->curSel;
+
+ prev_month = infoPtr->curSel.wMonth - 1;
+ if(prev_month == 0) prev_month = 12;
+
+ /*
+ Rules what week to call the first week of a new year:
+ LOCALE_IFIRSTWEEKOFYEAR == 0 (e.g US?):
+ The week containing Jan 1 is the first week of year
+ LOCALE_IFIRSTWEEKOFYEAR == 2 (e.g. Germany):
+ First week of year must contain 4 days of the new year
+ LOCALE_IFIRSTWEEKOFYEAR == 1 (what contries?)
+ The first week of the year must contain only days of the new year
*/
- GetTextExtentPoint32W(hdc, buf, strlenW(buf), &size);
- titlemonth->left = title->right / 2 + title->left / 2 - size.cx / 2;
- titleyear->right = title->right / 2 + title->left / 2 + size.cx / 2;
- GetTextExtentPoint32W(hdc, buf1, strlenW(buf1), &size);
- titlemonth->right = titlemonth->left + size.cx;
- titleyear->left = titlemonth->right;
-
- /* draw month area */
- rcTemp.top=infoPtr->wdays.top;
- rcTemp.left=infoPtr->wdays.left;
- rcTemp.bottom=infoPtr->todayrect.bottom;
- rcTemp.right =infoPtr->todayrect.right;
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcTemp))
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTWEEKOFYEAR, buf, countof(buf));
+ weeknum = atoiW(buf);
+ switch (weeknum)
{
- hbr = CreateSolidBrush(infoPtr->monthbk);
- FillRect(hdc, &rcTemp, hbr);
- DeleteObject(hbr);
+ case 1: mindays = 6;
+ break;
+ case 2: mindays = 3;
+ break;
+ case 0: mindays = 0;
+ break;
+ default:
+ WARN("Unknown LOCALE_IFIRSTWEEKOFYEAR value %d, defaulting to 0\n", weeknum);
+ mindays = 0;
}
-/* draw line under day abbreviations */
+ if (infoPtr->curSel.wMonth == 1)
+ {
+ /* calculate all those exceptions for january */
+ st.wDay = st.wMonth = 1;
+ weeknum1 = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
+ if ((infoPtr->firstDay - weeknum1) % 7 > mindays)
+ weeknum = 1;
+ else
+ {
+ weeknum = 0;
+ for(i = 0; i < 11; i++)
+ weeknum += MONTHCAL_MonthLength(i+1, infoPtr->curSel.wYear - 1);
- MoveToEx(hdc, infoPtr->days.left + 3, title->bottom + textHeight + 1, NULL);
- LineTo(hdc, infoPtr->days.right - 3, title->bottom + textHeight + 1);
+ weeknum += startofprescal + 7;
+ weeknum /= 7;
+ st.wYear -= 1;
+ weeknum1 = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
+ if ((infoPtr->firstDay - weeknum1) % 7 > mindays) weeknum++;
+ }
+ }
+ else
+ {
+ weeknum = 0;
+ for(i = 0; i < prev_month - 1; i++)
+ weeknum += MONTHCAL_MonthLength(i+1, infoPtr->curSel.wYear);
- prevMonth = infoPtr->currentMonth - 1;
- if(prevMonth == 0) /* if currentMonth is january(1) prevMonth is */
- prevMonth = 12; /* december(12) of the previous year */
+ weeknum += startofprescal + 7;
+ weeknum /= 7;
+ st.wDay = st.wMonth = 1;
+ weeknum1 = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
+ if ((infoPtr->firstDay - weeknum1) % 7 > mindays) weeknum++;
+ }
- infoPtr->wdays.left = infoPtr->days.left = infoPtr->weeknums.right;
-/* draw day abbreviations */
+ r = infoPtr->weeknums;
+ r.bottom = r.top + infoPtr->height_increment;
+ for(i = 0; i < 6; i++) {
+ if((i == 0) && (weeknum > 50))
+ {
+ wsprintfW(buf, fmt_weekW, weeknum);
+ weeknum = 0;
+ }
+ else if((i == 5) && (weeknum > 47))
+ {
+ wsprintfW(buf, fmt_weekW, 1);
+ }
+ else
+ wsprintfW(buf, fmt_weekW, weeknum + i);
+
+ DrawTextW(hdc, buf, -1, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+ OffsetRect(&r, 0, infoPtr->height_increment);
+ }
+
+ /* line separator for week numbers column */
+ MoveToEx(hdc, infoPtr->weeknums.right, infoPtr->weeknums.top + 3 , NULL);
+ LineTo(hdc, infoPtr->weeknums.right, infoPtr->weeknums.bottom);
+}
+
+/* paint a calendar area */
+static void MONTHCAL_PaintCalendar(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+{
+ INT prev_month, i, j;
+ WCHAR buf[80];
+ HBRUSH hbr;
+ RECT r;
+ int mask;
+ SYSTEMTIME st;
+
+ UnionRect(&r, &infoPtr->wdays, &infoPtr->todayrect);
+
+ hbr = CreateSolidBrush(infoPtr->monthbk);
+ FillRect(hdc, &r, hbr);
+ DeleteObject(hbr);
+
+ /* draw line under day abbreviations */
+ MoveToEx(hdc, infoPtr->days.left + 3,
+ infoPtr->title.bottom + infoPtr->textHeight + 1, NULL);
+ LineTo(hdc, infoPtr->days.right - 3,
+ infoPtr->title.bottom + infoPtr->textHeight + 1);
+
+ prev_month = infoPtr->curSel.wMonth - 1;
+ if(prev_month == 0) prev_month = 12;
+
+ infoPtr->wdays.left = infoPtr->days.left = infoPtr->weeknums.right;
+
+ /* 1. draw day abbreviations */
SelectObject(hdc, infoPtr->hFont);
SetBkColor(hdc, infoPtr->monthbk);
SetTextColor(hdc, infoPtr->trailingtxt);
-
- /* copy this rect so we can change the values without changing */
- /* the original version */
- days->left = infoPtr->wdays.left;
- days->right = days->left + infoPtr->width_increment;
- days->top = infoPtr->wdays.top;
- days->bottom = infoPtr->wdays.bottom;
+ /* rectangle to draw a single day abbreviation within */
+ r = infoPtr->wdays;
+ r.right = r.left + infoPtr->width_increment;
i = infoPtr->firstDay;
-
- for(j=0; j<7; j++) {
- GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SABBREVDAYNAME1 + (i+j+6)%7, buf, countof(buf));
- DrawTextW(hdc, buf, strlenW(buf), days, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
- days->left+=infoPtr->width_increment;
- days->right+=infoPtr->width_increment;
+ for(j = 0; j < 7; j++) {
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVDAYNAME1 + (i+j+6)%7, buf, countof(buf));
+ DrawTextW(hdc, buf, strlenW(buf), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+ OffsetRect(&r, infoPtr->width_increment, 0);
}
-/* draw day numbers; first, the previous month */
+ /* 2. previous and next months */
+ if (!(infoPtr->dwStyle & MCS_NOTRAILINGDATES))
+ {
+ SYSTEMTIME st_max;
- firstDay = MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear);
+ SetTextColor(hdc, infoPtr->trailingtxt);
- day = MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear) +
- (infoPtr->firstDay + 7 - firstDay)%7 + 1;
- if (day > MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear))
- day -=7;
- startofprescal = day;
- mask = 1<<(day-1);
+ MONTHCAL_GetMinDate(infoPtr, &st);
- i = 0;
- m = 0;
- while(day <= MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear)) {
- MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0);
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
- {
- MONTHCAL_DrawDay(infoPtr, hdc, day, prevMonth, i, 0,
- infoPtr->monthdayState[m] & mask);
+ /* draw prev month */
+ mask = 1 << (st.wDay-1);
+ while(st.wDay <= MONTHCAL_MonthLength(prev_month, infoPtr->curSel.wYear)) {
+ MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[0] & mask, ps);
+ mask <<= 1;
+ st.wDay++;
}
- mask<<=1;
- day++;
- i++;
+ /* draw next month */
+ st = infoPtr->curSel;
+ st.wDay = 1;
+ MONTHCAL_GetNextMonth(&st);
+ MONTHCAL_GetMaxDate(infoPtr, &st_max);
+ mask = 1;
+ while(st.wDay <= st_max.wDay) {
+ MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[2] & mask, ps);
+ mask <<= 1;
+ st.wDay++;
+ }
}
-/* draw `current' month */
-
- day = 1; /* start at the beginning of the current month */
-
- infoPtr->firstDayplace = i;
+ /* 3. current month */
SetTextColor(hdc, infoPtr->txt);
- m++;
+ st = infoPtr->curSel;
+ st.wDay = 1;
mask = 1;
-
- /* draw the first week of the current month */
- while(i<7) {
- MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0);
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
- {
-
- MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth, i, 0,
- infoPtr->monthdayState[m] & mask);
-
- if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) &&
- (day==infoPtr->todaysDate.wDay) &&
- (infoPtr->currentYear == infoPtr->todaysDate.wYear)) {
- if(!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE))
- MONTHCAL_CircleDay(infoPtr, hdc, day, infoPtr->currentMonth);
- }
- }
-
- mask<<=1;
- day++;
- i++;
+ while(st.wDay <= MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear)) {
+ MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[1] & mask,
+ ps);
+ mask <<= 1;
+ st.wDay++;
}
- j = 1; /* move to the 2nd week of the current month */
- i = 0; /* move back to sunday */
- while(day <= MONTHCAL_MonthLength(infoPtr->currentMonth, infoPtr->currentYear)) {
- MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j);
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
- {
- MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth, i, j,
- infoPtr->monthdayState[m] & mask);
-
- if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) &&
- (day==infoPtr->todaysDate.wDay) &&
- (infoPtr->currentYear == infoPtr->todaysDate.wYear))
- if(!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE))
- MONTHCAL_CircleDay(infoPtr, hdc, day, infoPtr->currentMonth);
- }
- mask<<=1;
- day++;
- i++;
- if(i>6) { /* past saturday, goto the next weeks sunday */
- i = 0;
- j++;
- }
- }
-
-/* draw `next' month */
-
- day = 1; /* start at the first day of the next month */
- m++;
- mask = 1;
-
- SetTextColor(hdc, infoPtr->trailingtxt);
- while((i<7) &&(j<6)) {
- MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j);
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
- {
- MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth + 1, i, j,
- infoPtr->monthdayState[m] & mask);
- }
-
- mask<<=1;
- day++;
- i++;
- if(i==7) { /* past saturday, go to next week's sunday */
- i = 0;
- j++;
- }
- }
- SetTextColor(hdc, infoPtr->txt);
-
-
-/* draw `today' date if style allows it, and draw a circle before today's
- * date if necessary */
-
+ /* 4. bottom today date */
if(!(infoPtr->dwStyle & MCS_NOTODAY)) {
- if(!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE)) {
- /*day is the number of days from nextmonth we put on the calendar */
- MONTHCAL_CircleDay(infoPtr, hdc,
- day+MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear),
- infoPtr->currentMonth);
+ static const WCHAR todayW[] = { 'T','o','d','a','y',':',0 };
+ static const WCHAR fmt_todayW[] = { '%','s',' ','%','s',0 };
+ WCHAR buf_todayW[30], buf_dateW[20];
+ RECT rtoday;
+
+ if(!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE)) {
+ SYSTEMTIME fake_st;
+
+ MONTHCAL_GetMaxDate(infoPtr, &fake_st);
+ /* this is always safe cause next month will never fully fit calendar */
+ fake_st.wDay += 1;
+ MONTHCAL_CircleDay(infoPtr, hdc, &fake_st);
}
- if (!LoadStringW(COMCTL32_hModule,IDM_TODAY,buf1,countof(buf1)))
- {
+ if (!LoadStringW(COMCTL32_hModule, IDM_TODAY, buf_todayW, countof(buf_todayW)))
+ {
WARN("Can't load resource\n");
- strcpyW(buf1, todayW);
- }
+ strcpyW(buf_todayW, todayW);
+ }
MONTHCAL_CalcDayRect(infoPtr, &rtoday, 1, 6);
- MONTHCAL_CopyTime(&infoPtr->todaysDate,&localtime);
- GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&localtime,NULL,buf2,countof(buf2));
- wsprintfW(buf, fmt2W, buf1, buf2);
+ GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &infoPtr->todaysDate, NULL,
+ buf_dateW, countof(buf_dateW));
SelectObject(hdc, infoPtr->hBoldFont);
+ wsprintfW(buf, fmt_todayW, buf_todayW, buf_dateW);
DrawTextW(hdc, buf, -1, &rtoday, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE);
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rtoday))
- {
- DrawTextW(hdc, buf, -1, &rtoday, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
- }
+ DrawTextW(hdc, buf, -1, &rtoday, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+
SelectObject(hdc, infoPtr->hFont);
}
-/*eventually draw week numbers*/
- if(infoPtr->dwStyle & MCS_WEEKNUMBERS) {
- /* display weeknumbers*/
- int mindays;
-
- /* Rules what week to call the first week of a new year:
- LOCALE_IFIRSTWEEKOFYEAR == 0 (e.g US?):
- The week containing Jan 1 is the first week of year
- LOCALE_IFIRSTWEEKOFYEAR == 2 (e.g. Germany):
- First week of year must contain 4 days of the new year
- LOCALE_IFIRSTWEEKOFYEAR == 1 (what contries?)
- The first week of the year must contain only days of the new year
- */
- GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTWEEKOFYEAR, buf, countof(buf));
- weeknum = atoiW(buf);
- switch (weeknum)
- {
- case 1: mindays = 6;
- break;
- case 2: mindays = 3;
- break;
- case 0:
- default:
- mindays = 0;
- }
- if (infoPtr->currentMonth < 2)
- {
- /* calculate all those exceptions for january */
- weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear);
- if ((infoPtr->firstDay +7 - weeknum1)%7 > mindays)
- weeknum =1;
- else
- {
- weeknum = 0;
- for(i=0; i<11; i++)
- weeknum+=MONTHCAL_MonthLength(i+1, infoPtr->currentYear-1);
- weeknum +=startofprescal+ 7;
- weeknum /=7;
- weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear-1);
- if ((infoPtr->firstDay + 7 - weeknum1)%7 > mindays)
- weeknum++;
- }
- }
- else
- {
- weeknum = 0;
- for(i=0; icurrentYear);
- weeknum +=startofprescal+ 7;
- weeknum /=7;
- weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear);
- if ((infoPtr->firstDay + 7 - weeknum1)%7 > mindays)
- weeknum++;
- }
- days->left = infoPtr->weeknums.left;
- days->right = infoPtr->weeknums.right;
- days->top = infoPtr->weeknums.top;
- days->bottom = days->top +infoPtr->height_increment;
- for(i=0; i<6; i++) {
- if((i==0)&&(weeknum>50))
- {
- wsprintfW(buf, fmt3W, weeknum);
- weeknum=0;
- }
- else if((i==5)&&(weeknum>47))
- {
- wsprintfW(buf, fmt3W, 1);
- }
- else
- wsprintfW(buf, fmt3W, weeknum + i);
- DrawTextW(hdc, buf, -1, days, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
- days->top+=infoPtr->height_increment;
- days->bottom+=infoPtr->height_increment;
- }
-
- MoveToEx(hdc, infoPtr->weeknums.right, infoPtr->weeknums.top + 3 , NULL);
- LineTo(hdc, infoPtr->weeknums.right, infoPtr->weeknums.bottom );
-
+ /* 5. today mark + focus */
+ if((infoPtr->curSel.wMonth == infoPtr->todaysDate.wMonth) &&
+ (infoPtr->curSel.wYear == infoPtr->todaysDate.wYear) &&
+ !(infoPtr->dwStyle & MCS_NOTODAYCIRCLE))
+ {
+ MONTHCAL_CircleDay(infoPtr, hdc, &infoPtr->todaysDate);
}
- /* currentFont was font at entering Refresh */
- SetBkColor(hdc, oldBkColor);
- SelectObject(hdc, currentFont);
- SetTextColor(hdc, oldTextColor);
+ if(!MONTHCAL_IsDateEqual(&infoPtr->focusedSel, &st_null))
+ {
+ MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->focusedSel, &r);
+ DrawFocusRect(hdc, &r);
+ }
}
+static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+{
+ RECT *title = &infoPtr->title;
+ COLORREF old_text_clr, old_bk_clr;
+ HFONT old_font;
+ RECT r_temp;
+
+ old_text_clr = SetTextColor(hdc, comctl32_color.clrWindowText);
+ old_bk_clr = GetBkColor(hdc);
+ old_font = GetCurrentObject(hdc, OBJ_FONT);
+
+ /* draw title, redraw all its elements */
+ if(IntersectRect(&r_temp, &(ps->rcPaint), title))
+ MONTHCAL_PaintTitle(infoPtr, hdc, ps);
+
+ /* draw calendar area */
+ UnionRect(&r_temp, &infoPtr->wdays, &infoPtr->todayrect);
+ if(IntersectRect(&r_temp, &(ps->rcPaint), &r_temp))
+ MONTHCAL_PaintCalendar(infoPtr, hdc, ps);
+
+ /* week numbers */
+ MONTHCAL_PaintWeeknumbers(infoPtr, hdc, ps);
+
+ /* restore context */
+ SetBkColor(hdc, old_bk_clr);
+ SelectObject(hdc, old_font);
+ SetTextColor(hdc, old_text_clr);
+}
static LRESULT
MONTHCAL_GetMinReqRect(const MONTHCAL_INFO *infoPtr, LPRECT lpRect)
@@ -746,12 +1041,16 @@ MONTHCAL_GetMinReqRect(const MONTHCAL_INFO *infoPtr, LPRECT lpRect)
if(!lpRect) return FALSE;
- lpRect->left = infoPtr->title.left;
- lpRect->top = infoPtr->title.top;
- lpRect->right = infoPtr->title.right;
+ lpRect->left = infoPtr->title.left;
+ lpRect->top = infoPtr->title.top;
+ lpRect->right = infoPtr->title.right;
lpRect->bottom = infoPtr->todayrect.bottom;
+
AdjustWindowRect(lpRect, infoPtr->dwStyle, FALSE);
+ /* minimal rectangle is zero based */
+ OffsetRect(lpRect, -lpRect->left, -lpRect->top);
+
TRACE("%s\n", wine_dbgstr_rect(lpRect));
return TRUE;
@@ -845,56 +1144,120 @@ MONTHCAL_SetMonthDelta(MONTHCAL_INFO *infoPtr, INT delta)
}
-static LRESULT
+static inline LRESULT
MONTHCAL_GetFirstDayOfWeek(const MONTHCAL_INFO *infoPtr)
{
- return MAKELONG(infoPtr->firstDay, infoPtr->firstDayHighWord);
+ int day;
+
+ /* convert from SYSTEMTIME to locale format */
+ day = (infoPtr->firstDay >= 0) ? (infoPtr->firstDay+6)%7 : infoPtr->firstDay;
+
+ return MAKELONG(day, infoPtr->firstDaySet);
}
-/* sets the first day of the week that will appear in the control */
-/* 0 == Sunday, 6 == Saturday */
-/* FIXME: this needs to be implemented properly in MONTHCAL_Refresh() */
-/* FIXME: we need more error checking here */
+/* Sets the first day of the week that will appear in the control
+ *
+ *
+ * PARAMETERS:
+ * [I] infoPtr : valid pointer to control data
+ * [I] day : day number to set as new first day (0 == Monday,...,6 == Sunday)
+ *
+ *
+ * RETURN VALUE:
+ * Low word contains previous first day,
+ * high word indicates was first day forced with this message before or is
+ * locale difined (TRUE - was forced, FALSE - wasn't).
+ *
+ * FIXME: this needs to be implemented properly in MONTHCAL_Refresh()
+ * FIXME: we need more error checking here
+ */
static LRESULT
MONTHCAL_SetFirstDayOfWeek(MONTHCAL_INFO *infoPtr, INT day)
{
- int prev = MAKELONG(infoPtr->firstDay, infoPtr->firstDayHighWord);
- int localFirstDay;
- WCHAR buf[40];
+ LRESULT prev = MONTHCAL_GetFirstDayOfWeek(infoPtr);
+ int new_day;
- TRACE("day %d\n", day);
-
- GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, buf, countof(buf));
- TRACE("%s %d\n", debugstr_w(buf), strlenW(buf));
-
- localFirstDay = atoiW(buf);
+ TRACE("%d\n", day);
if(day == -1)
{
- infoPtr->firstDay = localFirstDay;
- infoPtr->firstDayHighWord = FALSE;
+ WCHAR buf[80];
+
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, buf, countof(buf));
+ TRACE("%s %d\n", debugstr_w(buf), strlenW(buf));
+
+ new_day = atoiW(buf);
+
+ infoPtr->firstDaySet = FALSE;
}
else if(day >= 7)
{
- infoPtr->firstDay = 6; /* max first day allowed */
- infoPtr->firstDayHighWord = TRUE;
+ new_day = 6; /* max first day allowed */
+ infoPtr->firstDaySet = TRUE;
}
else
{
- infoPtr->firstDay = day;
- infoPtr->firstDayHighWord = TRUE;
+ /* Native behaviour for that case is broken: invalid date number >31
+ got displayed at (0,0) position, current month starts always from
+ (1,0) position. Should be implemnted here as well. */
+ if (day < -1)
+ FIXME("No bug compatibility for day=%d\n", day);
+
+ new_day = day;
+ infoPtr->firstDaySet = TRUE;
}
+ /* convert from locale to SYSTEMTIME format */
+ infoPtr->firstDay = (new_day >= 0) ? (++new_day) % 7 : new_day;
+
+ InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+
return prev;
}
static LRESULT
-MONTHCAL_GetMonthRange(const MONTHCAL_INFO *infoPtr)
+MONTHCAL_GetMonthRange(const MONTHCAL_INFO *infoPtr, DWORD flag, SYSTEMTIME *st)
{
TRACE("\n");
+ if(st)
+ {
+ switch (flag) {
+ case GMR_VISIBLE:
+ {
+ /*FIXME: currently multicalendar feature isn't implemented, so entirely
+ visible month is current */
+ st[0] = st[1] = infoPtr->curSel;
+
+ if (infoPtr->curSel.wMonth == min_allowed_date.wMonth &&
+ infoPtr->curSel.wYear == min_allowed_date.wYear)
+ {
+ st[0].wDay = min_allowed_date.wDay;
+ }
+ else
+ st[0].wDay = 1;
+ MONTHCAL_CalculateDayOfWeek(&st[0], TRUE);
+
+ st[1].wDay = MONTHCAL_MonthLength(st[1].wMonth, st[1].wYear);
+ MONTHCAL_CalculateDayOfWeek(&st[1], TRUE);
+ /* a single current month used */
+ return 1;
+ }
+ case GMR_DAYSTATE:
+ {
+ /*FIXME: currently multicalendar feature isn't implemented,
+ min date from previous month and max date from next one returned */
+ MONTHCAL_GetMinDate(infoPtr, &st[0]);
+ MONTHCAL_GetMaxDate(infoPtr, &st[1]);
+ break;
+ }
+ default:
+ WARN("Unknown flag value, got %d\n", flag);
+ }
+ }
+
return infoPtr->monthRange;
}
@@ -913,29 +1276,35 @@ MONTHCAL_SetRange(MONTHCAL_INFO *infoPtr, SHORT limits, SYSTEMTIME *range)
TRACE("%x %p\n", limits, range);
- if ((limits & GDTR_MIN && !MONTHCAL_ValidateTime(range[0])) ||
- (limits & GDTR_MAX && !MONTHCAL_ValidateTime(range[1])))
+ if ((limits & GDTR_MIN && !MONTHCAL_ValidateDate(&range[0])) ||
+ (limits & GDTR_MAX && !MONTHCAL_ValidateDate(&range[1])))
return FALSE;
if (limits & GDTR_MIN)
{
- MONTHCAL_CopyTime(&range[0], &infoPtr->minDate);
+ if (!MONTHCAL_ValidateTime(&range[0]))
+ MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[0]);
+
+ infoPtr->minDate = range[0];
infoPtr->rangeValid |= GDTR_MIN;
}
if (limits & GDTR_MAX)
{
- MONTHCAL_CopyTime(&range[1], &infoPtr->maxDate);
+ if (!MONTHCAL_ValidateTime(&range[1]))
+ MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[1]);
+
+ infoPtr->maxDate = range[1];
infoPtr->rangeValid |= GDTR_MAX;
}
/* Only one limit set - we are done */
if ((infoPtr->rangeValid & (GDTR_MIN | GDTR_MAX)) != (GDTR_MIN | GDTR_MAX))
return TRUE;
-
+
SystemTimeToFileTime(&infoPtr->maxDate, &ft_max);
SystemTimeToFileTime(&infoPtr->minDate, &ft_min);
- if (CompareFileTime(&ft_min, &ft_max) > 0)
+ if (CompareFileTime(&ft_min, &ft_max) >= 0)
{
if ((limits & (GDTR_MIN | GDTR_MAX)) == (GDTR_MIN | GDTR_MAX))
{
@@ -946,9 +1315,10 @@ MONTHCAL_SetRange(MONTHCAL_INFO *infoPtr, SHORT limits, SYSTEMTIME *range)
}
else
{
- /* Reset the other limit. */
- /* FIXME: native sets date&time to 0. Should we do this too? */
- infoPtr->rangeValid &= limits & GDTR_MIN ? ~GDTR_MAX : ~GDTR_MIN ;
+ /* reset the other limit */
+ if (limits & GDTR_MIN) infoPtr->maxDate = st_null;
+ if (limits & GDTR_MAX) infoPtr->minDate = st_null;
+ infoPtr->rangeValid &= limits & GDTR_MIN ? ~GDTR_MAX : ~GDTR_MIN;
}
}
@@ -963,8 +1333,8 @@ MONTHCAL_GetRange(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *range)
if(!range) return FALSE;
- MONTHCAL_CopyTime(&infoPtr->maxDate, &range[1]);
- MONTHCAL_CopyTime(&infoPtr->minDate, &range[0]);
+ range[1] = infoPtr->maxDate;
+ range[0] = infoPtr->minDate;
return infoPtr->rangeValid;
}
@@ -991,34 +1361,46 @@ MONTHCAL_GetCurSel(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *curSel)
if(!curSel) return FALSE;
if(infoPtr->dwStyle & MCS_MULTISELECT) return FALSE;
- MONTHCAL_CopyTime(&infoPtr->minSel, curSel);
+ *curSel = infoPtr->curSel;
TRACE("%d/%d/%d\n", curSel->wYear, curSel->wMonth, curSel->wDay);
return TRUE;
}
-/* FIXME: if the specified date is not visible, make it visible */
-/* FIXME: redraw? */
static LRESULT
MONTHCAL_SetCurSel(MONTHCAL_INFO *infoPtr, SYSTEMTIME *curSel)
{
+ SYSTEMTIME prev = infoPtr->curSel;
+
TRACE("%p\n", curSel);
if(!curSel) return FALSE;
if(infoPtr->dwStyle & MCS_MULTISELECT) return FALSE;
- if(!MONTHCAL_ValidateTime(*curSel)) return FALSE;
-
- MONTHCAL_CopyTime(curSel, &infoPtr->minSel);
- MONTHCAL_CopyTime(curSel, &infoPtr->maxSel);
-
+ if(!MONTHCAL_ValidateDate(curSel)) return FALSE;
/* exit earlier if selection equals current */
- if (infoPtr->currentMonth == curSel->wMonth &&
- infoPtr->currentYear == curSel->wYear &&
- infoPtr->curSelDay == curSel->wDay) return TRUE;
+ if (MONTHCAL_IsDateEqual(&infoPtr->curSel, curSel)) return TRUE;
- infoPtr->currentMonth = curSel->wMonth;
- infoPtr->currentYear = curSel->wYear;
+ if(!MONTHCAL_IsDateInValidRange(infoPtr, curSel, FALSE)) return FALSE;
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+ infoPtr->minSel = *curSel;
+ infoPtr->maxSel = *curSel;
+
+ /* if selection is still in current month, reduce rectangle */
+ prev.wDay = curSel->wDay;
+ if (MONTHCAL_IsDateEqual(&prev, curSel))
+ {
+ RECT r_prev, r_new;
+
+ /* note that infoPtr->curSel isn't updated yet */
+ MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->curSel, &r_prev);
+ MONTHCAL_CalcPosFromDay(infoPtr, curSel, &r_new);
+
+ InvalidateRect(infoPtr->hwndSelf, &r_prev, FALSE);
+ InvalidateRect(infoPtr->hwndSelf, &r_new, FALSE);
+ }
+ else
+ InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+
+ infoPtr->curSel = *curSel;
return TRUE;
}
@@ -1036,9 +1418,10 @@ MONTHCAL_SetMaxSelCount(MONTHCAL_INFO *infoPtr, INT max)
{
TRACE("%d\n", max);
- if(infoPtr->dwStyle & MCS_MULTISELECT) {
- infoPtr->maxSelCount = max;
- }
+ if(!(infoPtr->dwStyle & MCS_MULTISELECT)) return FALSE;
+ if(max <= 0) return FALSE;
+
+ infoPtr->maxSelCount = max;
return TRUE;
}
@@ -1053,8 +1436,8 @@ MONTHCAL_GetSelRange(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *range)
if(infoPtr->dwStyle & MCS_MULTISELECT)
{
- MONTHCAL_CopyTime(&infoPtr->maxSel, &range[1]);
- MONTHCAL_CopyTime(&infoPtr->minSel, &range[0]);
+ range[1] = infoPtr->maxSel;
+ range[0] = infoPtr->minSel;
TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
return TRUE;
}
@@ -1072,8 +1455,46 @@ MONTHCAL_SetSelRange(MONTHCAL_INFO *infoPtr, SYSTEMTIME *range)
if(infoPtr->dwStyle & MCS_MULTISELECT)
{
- MONTHCAL_CopyTime(&range[1], &infoPtr->maxSel);
- MONTHCAL_CopyTime(&range[0], &infoPtr->minSel);
+ SYSTEMTIME old_range[2];
+
+ /* adjust timestamps */
+ if(!MONTHCAL_ValidateTime(&range[0]))
+ MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[0]);
+ if(!MONTHCAL_ValidateTime(&range[1]))
+ MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[1]);
+
+ /* maximum range exceeded */
+ if(!MONTHCAL_IsSelRangeValid(infoPtr, &range[0], &range[1], NULL)) return FALSE;
+
+ old_range[0] = infoPtr->minSel;
+ old_range[1] = infoPtr->maxSel;
+
+ /* swap if min > max */
+ if(MONTHCAL_CompareSystemTime(&range[0], &range[1]) <= 0)
+ {
+ infoPtr->minSel = range[0];
+ infoPtr->maxSel = range[1];
+ }
+ else
+ {
+ infoPtr->minSel = range[1];
+ infoPtr->maxSel = range[0];
+ }
+ infoPtr->curSel = infoPtr->minSel;
+
+ /* update day of week */
+ MONTHCAL_CalculateDayOfWeek(&infoPtr->minSel, TRUE);
+ MONTHCAL_CalculateDayOfWeek(&infoPtr->maxSel, TRUE);
+ MONTHCAL_CalculateDayOfWeek(&infoPtr->curSel, TRUE);
+
+ /* redraw if bounds changed */
+ /* FIXME: no actual need to redraw everything */
+ if(!MONTHCAL_IsDateEqual(&old_range[0], &range[0]) ||
+ !MONTHCAL_IsDateEqual(&old_range[1], &range[1]))
+ {
+ InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+ }
+
TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
return TRUE;
}
@@ -1088,26 +1509,49 @@ MONTHCAL_GetToday(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *today)
TRACE("%p\n", today);
if(!today) return FALSE;
- MONTHCAL_CopyTime(&infoPtr->todaysDate, today);
+ *today = infoPtr->todaysDate;
return TRUE;
}
+/* Internal helper for MCM_SETTODAY handler and auto update timer handler
+ *
+ * RETURN VALUE
+ *
+ * TRUE - today date changed
+ * FALSE - today date isn't changed
+ */
+static BOOL
+MONTHCAL_UpdateToday(MONTHCAL_INFO *infoPtr, const SYSTEMTIME *today)
+{
+ RECT new_r, old_r;
+ if(MONTHCAL_IsDateEqual(today, &infoPtr->todaysDate)) return FALSE;
+
+ MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->todaysDate, &old_r);
+ MONTHCAL_CalcPosFromDay(infoPtr, today, &new_r);
+
+ infoPtr->todaysDate = *today;
+
+ /* only two days need redrawing */
+ InvalidateRect(infoPtr->hwndSelf, &old_r, FALSE);
+ InvalidateRect(infoPtr->hwndSelf, &new_r, FALSE);
+ return TRUE;
+}
+
+/* MCM_SETTODAT handler */
static LRESULT
-MONTHCAL_SetToday(MONTHCAL_INFO *infoPtr, SYSTEMTIME *today)
+MONTHCAL_SetToday(MONTHCAL_INFO *infoPtr, const SYSTEMTIME *today)
{
TRACE("%p\n", today);
if(!today) return FALSE;
- if(MONTHCAL_IsDateEqual(today, &infoPtr->todaysDate)) return TRUE;
+ /* remember if date was set successfully */
+ if(MONTHCAL_UpdateToday(infoPtr, today)) infoPtr->todaySet = TRUE;
- MONTHCAL_CopyTime(today, &infoPtr->todaysDate);
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
return TRUE;
}
-
static LRESULT
MONTHCAL_HitTest(const MONTHCAL_INFO *infoPtr, MCHITTESTINFO *lpht)
{
@@ -1115,6 +1559,7 @@ MONTHCAL_HitTest(const MONTHCAL_INFO *infoPtr, MCHITTESTINFO *lpht)
DWORD retval;
int day,wday,wnum;
+ if(!lpht || lpht->cbSize < MCHITTESTINFO_V1_SIZE) return -1;
x = lpht->pt.x;
y = lpht->pt.y;
@@ -1160,57 +1605,48 @@ MONTHCAL_HitTest(const MONTHCAL_INFO *infoPtr, MCHITTESTINFO *lpht)
day = MONTHCAL_CalcDayFromPos(infoPtr,x,y,&wday,&wnum);
if(PtInRect(&infoPtr->wdays, lpht->pt)) {
retval = MCHT_CALENDARDAY;
- lpht->st.wYear = infoPtr->currentYear;
- lpht->st.wMonth = (day < 1)? infoPtr->currentMonth -1 : infoPtr->currentMonth;
+ lpht->st.wYear = infoPtr->curSel.wYear;
+ lpht->st.wMonth = (day < 1)? infoPtr->curSel.wMonth -1 : infoPtr->curSel.wMonth;
lpht->st.wDay = (day < 1)?
- MONTHCAL_MonthLength(infoPtr->currentMonth-1,infoPtr->currentYear) -day : day;
+ MONTHCAL_MonthLength(infoPtr->curSel.wMonth-1, infoPtr->curSel.wYear) -day : day;
goto done;
}
if(PtInRect(&infoPtr->weeknums, lpht->pt)) {
retval = MCHT_CALENDARWEEKNUM;
- lpht->st.wYear = infoPtr->currentYear;
- lpht->st.wMonth = (day < 1) ? infoPtr->currentMonth -1 :
- (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) ?
- infoPtr->currentMonth +1 :infoPtr->currentMonth;
+ lpht->st.wYear = infoPtr->curSel.wYear;
+ lpht->st.wMonth = (day < 1) ? infoPtr->curSel.wMonth -1 :
+ (day > MONTHCAL_MonthLength(infoPtr->curSel.wMonth,infoPtr->curSel.wYear)) ?
+ infoPtr->curSel.wMonth +1 :infoPtr->curSel.wMonth;
lpht->st.wDay = (day < 1 ) ?
- MONTHCAL_MonthLength(infoPtr->currentMonth-1,infoPtr->currentYear) -day :
- (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) ?
- day - MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear) : day;
+ MONTHCAL_MonthLength(infoPtr->curSel.wMonth-1,infoPtr->curSel.wYear) -day :
+ (day > MONTHCAL_MonthLength(infoPtr->curSel.wMonth,infoPtr->curSel.wYear)) ?
+ day - MONTHCAL_MonthLength(infoPtr->curSel.wMonth,infoPtr->curSel.wYear) : day;
goto done;
}
if(PtInRect(&infoPtr->days, lpht->pt))
- {
- lpht->st.wYear = infoPtr->currentYear;
- if ( day < 1)
- {
+ {
+ lpht->st.wYear = infoPtr->curSel.wYear;
+ lpht->st.wMonth = infoPtr->curSel.wMonth;
+ if (day < 1)
+ {
retval = MCHT_CALENDARDATEPREV;
- lpht->st.wMonth = infoPtr->currentMonth - 1;
- if (lpht->st.wMonth <1)
- {
- lpht->st.wMonth = 12;
- lpht->st.wYear--;
- }
- lpht->st.wDay = MONTHCAL_MonthLength(lpht->st.wMonth,lpht->st.wYear) -day;
- }
- else if (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear))
- {
+ MONTHCAL_GetPrevMonth(&lpht->st);
+ lpht->st.wDay = MONTHCAL_MonthLength(lpht->st.wMonth, lpht->st.wYear) + day;
+ }
+ else if (day > MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear))
+ {
retval = MCHT_CALENDARDATENEXT;
- lpht->st.wMonth = infoPtr->currentMonth + 1;
- if (lpht->st.wMonth <12)
- {
- lpht->st.wMonth = 1;
- lpht->st.wYear++;
- }
- lpht->st.wDay = day - MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear) ;
- }
+ MONTHCAL_GetNextMonth(&lpht->st);
+ lpht->st.wDay = day - MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear);
+ }
else {
retval = MCHT_CALENDARDATE;
- lpht->st.wMonth = infoPtr->currentMonth;
- lpht->st.wDay = day;
- lpht->st.wDayOfWeek = MONTHCAL_CalculateDayOfWeek(day,lpht->st.wMonth,lpht->st.wYear);
+ lpht->st.wDay = day;
}
+ /* always update day of week */
+ MONTHCAL_CalculateDayOfWeek(&lpht->st, TRUE);
goto done;
- }
+ }
if(PtInRect(&infoPtr->todayrect, lpht->pt)) {
retval = MCHT_TODAYLINK;
goto done;
@@ -1225,20 +1661,12 @@ MONTHCAL_HitTest(const MONTHCAL_INFO *infoPtr, MCHITTESTINFO *lpht)
return retval;
}
-
-static void MONTHCAL_GoToNextMonth(MONTHCAL_INFO *infoPtr)
+/* MCN_GETDAYSTATE notification helper */
+static void MONTHCAL_NotifyDayState(MONTHCAL_INFO *infoPtr)
{
- TRACE("MONTHCAL_GoToNextMonth\n");
-
- infoPtr->currentMonth++;
- if(infoPtr->currentMonth > 12) {
- infoPtr->currentYear++;
- infoPtr->currentMonth = 1;
- }
-
if(infoPtr->dwStyle & MCS_DAYSTATE) {
NMDAYSTATE nmds;
- int i;
+ INT i;
nmds.nmhdr.hwndFrom = infoPtr->hwndSelf;
nmds.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
@@ -1247,51 +1675,58 @@ static void MONTHCAL_GoToNextMonth(MONTHCAL_INFO *infoPtr)
nmds.prgDayState = Alloc(infoPtr->monthRange * sizeof(MONTHDAYSTATE));
nmds.stStart = infoPtr->todaysDate;
- nmds.stStart.wYear = infoPtr->currentYear;
- nmds.stStart.wMonth = infoPtr->currentMonth;
+ nmds.stStart.wYear = infoPtr->curSel.wYear;
+ nmds.stStart.wMonth = infoPtr->curSel.wMonth;
nmds.stStart.wDay = 1;
SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmds.nmhdr.idFrom, (LPARAM)&nmds);
- for(i=0; imonthRange; i++)
+ for(i = 0; i < infoPtr->monthRange; i++)
infoPtr->monthdayState[i] = nmds.prgDayState[i];
+
+ Free(nmds.prgDayState);
}
}
-
-static void MONTHCAL_GoToPrevMonth(MONTHCAL_INFO *infoPtr)
+static void MONTHCAL_GoToPrevNextMonth(MONTHCAL_INFO *infoPtr, BOOL prev)
{
- TRACE("\n");
+ SYSTEMTIME st = infoPtr->curSel;
- infoPtr->currentMonth--;
- if(infoPtr->currentMonth < 1) {
- infoPtr->currentYear--;
- infoPtr->currentMonth = 12;
+ TRACE("%s\n", prev ? "prev" : "next");
+
+ if(prev) MONTHCAL_GetPrevMonth(&st); else MONTHCAL_GetNextMonth(&st);
+
+ if(!MONTHCAL_IsDateInValidRange(infoPtr, &st, FALSE)) return;
+
+ if(infoPtr->dwStyle & MCS_MULTISELECT)
+ {
+ SYSTEMTIME range[2];
+
+ range[0] = infoPtr->minSel;
+ range[1] = infoPtr->maxSel;
+
+ if(prev)
+ {
+ MONTHCAL_GetPrevMonth(&range[0]);
+ MONTHCAL_GetPrevMonth(&range[1]);
+ }
+ else
+ {
+ MONTHCAL_GetNextMonth(&range[0]);
+ MONTHCAL_GetNextMonth(&range[1]);
+ }
+
+ MONTHCAL_SetSelRange(infoPtr, range);
}
+ else
+ MONTHCAL_SetCurSel(infoPtr, &st);
- if(infoPtr->dwStyle & MCS_DAYSTATE) {
- NMDAYSTATE nmds;
- int i;
+ MONTHCAL_NotifyDayState(infoPtr);
- nmds.nmhdr.hwndFrom = infoPtr->hwndSelf;
- nmds.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
- nmds.nmhdr.code = MCN_GETDAYSTATE;
- nmds.cDayState = infoPtr->monthRange;
- nmds.prgDayState = Alloc
- (infoPtr->monthRange * sizeof(MONTHDAYSTATE));
-
- nmds.stStart = infoPtr->todaysDate;
- nmds.stStart.wYear = infoPtr->currentYear;
- nmds.stStart.wMonth = infoPtr->currentMonth;
- nmds.stStart.wDay = 1;
-
- SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmds.nmhdr.idFrom, (LPARAM)&nmds);
- for(i=0; imonthRange; i++)
- infoPtr->monthdayState[i] = nmds.prgDayState[i];
- }
+ MONTHCAL_NotifySelectionChange(infoPtr);
}
static LRESULT
-MONTHCAL_RButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam)
+MONTHCAL_RButtonUp(MONTHCAL_INFO *infoPtr, LPARAM lParam)
{
static const WCHAR todayW[] = { 'G','o',' ','t','o',' ','T','o','d','a','y',':',0 };
HMENU hMenu;
@@ -1299,182 +1734,205 @@ MONTHCAL_RButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam)
WCHAR buf[32];
hMenu = CreatePopupMenu();
- if (!LoadStringW(COMCTL32_hModule,IDM_GOTODAY,buf,countof(buf)))
- {
+ if (!LoadStringW(COMCTL32_hModule, IDM_GOTODAY, buf, countof(buf)))
+ {
WARN("Can't load resource\n");
strcpyW(buf, todayW);
- }
- AppendMenuW(hMenu, MF_STRING|MF_ENABLED,1, buf);
- menupoint.x=(short)LOWORD(lParam);
- menupoint.y=(short)HIWORD(lParam);
+ }
+ AppendMenuW(hMenu, MF_STRING|MF_ENABLED, 1, buf);
+ menupoint.x = (short)LOWORD(lParam);
+ menupoint.y = (short)HIWORD(lParam);
ClientToScreen(infoPtr->hwndSelf, &menupoint);
- if( TrackPopupMenu(hMenu,TPM_RIGHTBUTTON| TPM_NONOTIFY|TPM_RETURNCMD,
+ if( TrackPopupMenu(hMenu, TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD,
menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL))
- {
- infoPtr->currentMonth=infoPtr->todaysDate.wMonth;
- infoPtr->currentYear=infoPtr->todaysDate.wYear;
+ {
+ infoPtr->curSel = infoPtr->todaysDate;
+ infoPtr->minSel = infoPtr->todaysDate;
+ infoPtr->maxSel = infoPtr->todaysDate;
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
- }
+ }
+
return 0;
}
+/***
+ * DESCRIPTION:
+ * Subclassed edit control windproc function
+ *
+ * PARAMETER(S):
+ * [I] hwnd : the edit window handle
+ * [I] uMsg : the message that is to be processed
+ * [I] wParam : first message parameter
+ * [I] lParam : second message parameter
+ *
+ */
+static LRESULT CALLBACK EditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ MONTHCAL_INFO *infoPtr = (MONTHCAL_INFO *)GetWindowLongPtrW(GetParent(hwnd), 0);
+
+ TRACE("(hwnd=%p, uMsg=%x, wParam=%lx, lParam=%lx)\n",
+ hwnd, uMsg, wParam, lParam);
+
+ switch (uMsg)
+ {
+ case WM_GETDLGCODE:
+ return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
+
+ case WM_DESTROY:
+ {
+ WNDPROC editProc = infoPtr->EditWndProc;
+ infoPtr->EditWndProc = NULL;
+ SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (DWORD_PTR)editProc);
+ return CallWindowProcW(editProc, hwnd, uMsg, wParam, lParam);
+ }
+
+ case WM_KILLFOCUS:
+ break;
+
+ case WM_KEYDOWN:
+ if ((VK_ESCAPE == (INT)wParam) || (VK_RETURN == (INT)wParam))
+ break;
+
+ default:
+ return CallWindowProcW(infoPtr->EditWndProc, hwnd, uMsg, wParam, lParam);
+ }
+
+ SendMessageW(infoPtr->hWndYearUpDown, WM_CLOSE, 0, 0);
+ SendMessageW(hwnd, WM_CLOSE, 0, 0);
+ return 0;
+}
+
+/* creates updown control and edit box */
+static void MONTHCAL_EditYear(MONTHCAL_INFO *infoPtr)
+{
+ infoPtr->hWndYearEdit =
+ CreateWindowExW(0, WC_EDITW, 0, WS_VISIBLE | WS_CHILD | ES_READONLY,
+ infoPtr->titleyear.left + 3, infoPtr->titlebtnnext.top,
+ infoPtr->titleyear.right - infoPtr->titleyear.left + 4,
+ infoPtr->textHeight, infoPtr->hwndSelf,
+ NULL, NULL, NULL);
+
+ SendMessageW(infoPtr->hWndYearEdit, WM_SETFONT, (WPARAM)infoPtr->hBoldFont, TRUE);
+
+ infoPtr->hWndYearUpDown =
+ CreateWindowExW(0, UPDOWN_CLASSW, 0,
+ WS_VISIBLE | WS_CHILD | UDS_SETBUDDYINT | UDS_NOTHOUSANDS | UDS_ARROWKEYS,
+ infoPtr->titleyear.right + 7, infoPtr->titlebtnnext.top,
+ 18, infoPtr->textHeight, infoPtr->hwndSelf,
+ NULL, NULL, NULL);
+
+ /* attach edit box */
+ SendMessageW(infoPtr->hWndYearUpDown, UDM_SETRANGE, 0,
+ MAKELONG(max_allowed_date.wYear, min_allowed_date.wYear));
+ SendMessageW(infoPtr->hWndYearUpDown, UDM_SETBUDDY, (WPARAM)infoPtr->hWndYearEdit, 0);
+ SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, infoPtr->curSel.wYear);
+
+ /* subclass edit box */
+ infoPtr->EditWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hWndYearEdit,
+ GWLP_WNDPROC, (DWORD_PTR)EditWndProc);
+
+ SetFocus(infoPtr->hWndYearEdit);
+}
+
static LRESULT
MONTHCAL_LButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam)
{
- static const WCHAR EditW[] = { 'E','D','I','T',0 };
MCHITTESTINFO ht;
DWORD hit;
- HMENU hMenu;
- RECT rcDay; /* used in determining area to invalidate */
- WCHAR buf[32];
- int i;
- POINT menupoint;
- TRACE("%lx\n", lParam);
+ /* Actually we don't need input focus for calendar, this is used to kill
+ year updown and its buddy edit box */
+ if (IsWindow(infoPtr->hWndYearUpDown))
+ {
+ SetFocus(infoPtr->hwndSelf);
+ return 0;
+ }
- if (infoPtr->hWndYearUpDown)
- {
- infoPtr->currentYear=SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, 0);
- if(!DestroyWindow(infoPtr->hWndYearUpDown))
- {
- FIXME("Can't destroy Updown Control\n");
- }
- else
- infoPtr->hWndYearUpDown=0;
- if(!DestroyWindow(infoPtr->hWndYearEdit))
- {
- FIXME("Can't destroy Updown Control\n");
- }
- else
- infoPtr->hWndYearEdit=0;
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
- }
+ SetCapture(infoPtr->hwndSelf);
+ ht.cbSize = sizeof(MCHITTESTINFO);
ht.pt.x = (short)LOWORD(lParam);
ht.pt.y = (short)HIWORD(lParam);
+
hit = MONTHCAL_HitTest(infoPtr, &ht);
- /* FIXME: these flags should be checked by */
- /*((hit & MCHT_XXX) == MCHT_XXX) b/c some of the flags are */
- /* multi-bit */
- if(hit ==MCHT_TITLEBTNNEXT) {
- MONTHCAL_GoToNextMonth(infoPtr);
+ TRACE("%x at (%d, %d)\n", hit, ht.pt.x, ht.pt.y);
+
+ switch(hit)
+ {
+ case MCHT_TITLEBTNNEXT:
+ MONTHCAL_GoToPrevNextMonth(infoPtr, FALSE);
infoPtr->status = MC_NEXTPRESSED;
- SetTimer(infoPtr->hwndSelf, MC_NEXTMONTHTIMER, MC_NEXTMONTHDELAY, 0);
+ SetTimer(infoPtr->hwndSelf, MC_PREVNEXTMONTHTIMER, MC_PREVNEXTMONTHDELAY, 0);
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
return 0;
- }
- if(hit == MCHT_TITLEBTNPREV){
- MONTHCAL_GoToPrevMonth(infoPtr);
+
+ case MCHT_TITLEBTNPREV:
+ MONTHCAL_GoToPrevNextMonth(infoPtr, TRUE);
infoPtr->status = MC_PREVPRESSED;
- SetTimer(infoPtr->hwndSelf, MC_PREVMONTHTIMER, MC_NEXTMONTHDELAY, 0);
+ SetTimer(infoPtr->hwndSelf, MC_PREVNEXTMONTHTIMER, MC_PREVNEXTMONTHDELAY, 0);
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
return 0;
- }
- if(hit == MCHT_TITLEMONTH) {
- hMenu = CreatePopupMenu();
+ case MCHT_TITLEMONTH:
+ {
+ HMENU hMenu = CreatePopupMenu();
+ WCHAR buf[32];
+ POINT menupoint;
+ INT i;
- for (i=0; i<12;i++)
- {
- GetLocaleInfoW(LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+i, buf,countof(buf));
- AppendMenuW(hMenu, MF_STRING|MF_ENABLED,i+1, buf);
- }
- menupoint.x=infoPtr->titlemonth.right;
- menupoint.y=infoPtr->titlemonth.bottom;
- ClientToScreen(infoPtr->hwndSelf, &menupoint);
- i= TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_RETURNCMD,
- menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL);
- if ((i>0) && (i<13))
- {
- infoPtr->currentMonth=i;
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
- }
- }
- if(hit == MCHT_TITLEYEAR) {
- infoPtr->hWndYearEdit=CreateWindowExW(0,
- EditW,
- 0,
- WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT,
- infoPtr->titleyear.left+3,infoPtr->titlebtnnext.top,
- infoPtr->titleyear.right-infoPtr->titleyear.left+4,
- infoPtr->textHeight,
- infoPtr->hwndSelf,
- NULL,
- NULL,
- NULL);
- SendMessageW( infoPtr->hWndYearEdit, WM_SETFONT, (WPARAM) infoPtr->hBoldFont, (LPARAM)TRUE);
- infoPtr->hWndYearUpDown=CreateWindowExW(0,
- UPDOWN_CLASSW,
- 0,
- WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT|UDS_NOTHOUSANDS|UDS_ARROWKEYS,
- infoPtr->titleyear.right+7,infoPtr->titlebtnnext.top,
- 18,
- infoPtr->textHeight,
- infoPtr->hwndSelf,
- NULL,
- NULL,
- NULL);
- SendMessageW(infoPtr->hWndYearUpDown, UDM_SETRANGE, 0, MAKELONG (9999, 1753));
- SendMessageW(infoPtr->hWndYearUpDown, UDM_SETBUDDY, (WPARAM) infoPtr->hWndYearEdit, 0);
- SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, infoPtr->currentYear);
- return 0;
-
- }
- if(hit == MCHT_TODAYLINK) {
- NMSELCHANGE nmsc;
-
- infoPtr->curSelDay = infoPtr->todaysDate.wDay;
- infoPtr->firstSelDay = infoPtr->todaysDate.wDay;
- infoPtr->currentMonth=infoPtr->todaysDate.wMonth;
- infoPtr->currentYear=infoPtr->todaysDate.wYear;
- MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->minSel);
- MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxSel);
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
-
- nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
- nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
- nmsc.nmhdr.code = MCN_SELCHANGE;
- MONTHCAL_CopyTime(&infoPtr->minSel, &nmsc.stSelStart);
- MONTHCAL_CopyTime(&infoPtr->maxSel, &nmsc.stSelEnd);
- SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
-
- nmsc.nmhdr.code = MCN_SELECT;
- SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
- return 0;
- }
- if(hit == MCHT_CALENDARDATE) {
- SYSTEMTIME selArray[2];
- NMSELCHANGE nmsc;
-
- MONTHCAL_CopyTime(&ht.st, &selArray[0]);
- MONTHCAL_CopyTime(&ht.st, &selArray[1]);
- MONTHCAL_SetSelRange(infoPtr, selArray);
- MONTHCAL_SetCurSel(infoPtr, &selArray[0]);
- TRACE("MCHT_CALENDARDATE\n");
- nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
- nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
- nmsc.nmhdr.code = MCN_SELCHANGE;
- MONTHCAL_CopyTime(&infoPtr->minSel,&nmsc.stSelStart);
- MONTHCAL_CopyTime(&infoPtr->maxSel,&nmsc.stSelEnd);
-
- SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
-
-
- /* redraw both old and new days if the selected day changed */
- if(infoPtr->curSelDay != ht.st.wDay) {
- MONTHCAL_CalcPosFromDay(infoPtr, ht.st.wDay, ht.st.wMonth, &rcDay);
- InvalidateRect(infoPtr->hwndSelf, &rcDay, TRUE);
-
- MONTHCAL_CalcPosFromDay(infoPtr, infoPtr->curSelDay, infoPtr->currentMonth, &rcDay);
- InvalidateRect(infoPtr->hwndSelf, &rcDay, TRUE);
+ for (i = 0; i < 12; i++)
+ {
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1+i, buf, countof(buf));
+ AppendMenuW(hMenu, MF_STRING|MF_ENABLED, i + 1, buf);
}
+ menupoint.x = ht.pt.x;
+ menupoint.y = ht.pt.y;
+ ClientToScreen(infoPtr->hwndSelf, &menupoint);
+ i = TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_RETURNCMD,
+ menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL);
- infoPtr->firstSelDay = ht.st.wDay;
- infoPtr->curSelDay = ht.st.wDay;
- infoPtr->status = MC_SEL_LBUTDOWN;
+ if ((i > 0) && (i < 13) && infoPtr->curSel.wMonth != i)
+ {
+ infoPtr->curSel.wMonth = i;
+ MONTHCAL_IsDateInValidRange(infoPtr, &infoPtr->curSel, TRUE);
+ InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+ }
return 0;
}
+ case MCHT_TITLEYEAR:
+ {
+ MONTHCAL_EditYear(infoPtr);
+ return 0;
+ }
+ case MCHT_TODAYLINK:
+ {
+ infoPtr->curSel = infoPtr->todaysDate;
+ infoPtr->minSel = infoPtr->todaysDate;
+ infoPtr->maxSel = infoPtr->todaysDate;
+ InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+
+ MONTHCAL_NotifySelectionChange(infoPtr);
+ MONTHCAL_NotifySelect(infoPtr);
+ return 0;
+ }
+ case MCHT_CALENDARDATENEXT:
+ case MCHT_CALENDARDATEPREV:
+ case MCHT_CALENDARDATE:
+ {
+ SYSTEMTIME st[2];
+
+ MONTHCAL_CopyDate(&ht.st, &infoPtr->firstSel);
+
+ st[0] = st[1] = ht.st;
+ /* clear selection range */
+ MONTHCAL_SetSelRange(infoPtr, st);
+
+ infoPtr->status = MC_SEL_LBUTDOWN;
+ MONTHCAL_SetDayFocus(infoPtr, &ht.st);
+ return 0;
+ }
+ }
return 1;
}
@@ -1483,90 +1941,90 @@ MONTHCAL_LButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam)
static LRESULT
MONTHCAL_LButtonUp(MONTHCAL_INFO *infoPtr, LPARAM lParam)
{
- NMSELCHANGE nmsc;
NMHDR nmhdr;
- BOOL redraw = FALSE;
MCHITTESTINFO ht;
DWORD hit;
TRACE("\n");
- if(infoPtr->status & MC_NEXTPRESSED) {
- KillTimer(infoPtr->hwndSelf, MC_NEXTMONTHTIMER);
- infoPtr->status &= ~MC_NEXTPRESSED;
- redraw = TRUE;
- }
- if(infoPtr->status & MC_PREVPRESSED) {
- KillTimer(infoPtr->hwndSelf, MC_PREVMONTHTIMER);
- infoPtr->status &= ~MC_PREVPRESSED;
- redraw = TRUE;
+ if(infoPtr->status & (MC_PREVPRESSED | MC_NEXTPRESSED)) {
+ RECT *r;
+
+ KillTimer(infoPtr->hwndSelf, MC_PREVNEXTMONTHTIMER);
+ r = infoPtr->status & MC_PREVPRESSED ? &infoPtr->titlebtnprev : &infoPtr->titlebtnnext;
+ infoPtr->status &= ~(MC_PREVPRESSED | MC_NEXTPRESSED);
+
+ InvalidateRect(infoPtr->hwndSelf, r, FALSE);
}
- ht.pt.x = (short)LOWORD(lParam);
- ht.pt.y = (short)HIWORD(lParam);
- hit = MONTHCAL_HitTest(infoPtr, &ht);
+ ReleaseCapture();
- infoPtr->status = MC_SEL_LBUTUP;
-
- if(hit ==MCHT_CALENDARDATENEXT) {
- MONTHCAL_GoToNextMonth(infoPtr);
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
- return TRUE;
- }
- if(hit == MCHT_CALENDARDATEPREV){
- MONTHCAL_GoToPrevMonth(infoPtr);
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
- return TRUE;
- }
+ /* always send NM_RELEASEDCAPTURE notification */
nmhdr.hwndFrom = infoPtr->hwndSelf;
nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
nmhdr.code = NM_RELEASEDCAPTURE;
TRACE("Sent notification from %p to %p\n", infoPtr->hwndSelf, infoPtr->hwndNotify);
SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmhdr.idFrom, (LPARAM)&nmhdr);
- /* redraw if necessary */
- if(redraw)
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
- /* only send MCN_SELECT if currently displayed month's day was selected */
- if(hit == MCHT_CALENDARDATE) {
- nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
- nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
- nmsc.nmhdr.code = MCN_SELECT;
- MONTHCAL_CopyTime(&infoPtr->minSel, &nmsc.stSelStart);
- MONTHCAL_CopyTime(&infoPtr->maxSel, &nmsc.stSelEnd);
- SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
+ if(!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0;
+ ht.cbSize = sizeof(MCHITTESTINFO);
+ ht.pt.x = (short)LOWORD(lParam);
+ ht.pt.y = (short)HIWORD(lParam);
+ hit = MONTHCAL_HitTest(infoPtr, &ht);
+
+ infoPtr->status = MC_SEL_LBUTUP;
+ MONTHCAL_SetDayFocus(infoPtr, NULL);
+
+ if((hit & MCHT_CALENDARDATE) == MCHT_CALENDARDATE)
+ {
+ SYSTEMTIME sel = infoPtr->curSel;
+
+ /* will be invalidated here */
+ MONTHCAL_SetCurSel(infoPtr, &ht.st);
+
+ /* send MCN_SELCHANGE only if new date selected */
+ if (!MONTHCAL_IsDateEqual(&sel, &ht.st))
+ MONTHCAL_NotifySelectionChange(infoPtr);
+
+ MONTHCAL_NotifySelect(infoPtr);
}
+
return 0;
}
static LRESULT
-MONTHCAL_Timer(MONTHCAL_INFO *infoPtr, WPARAM wParam)
+MONTHCAL_Timer(MONTHCAL_INFO *infoPtr, WPARAM id)
{
- BOOL redraw = FALSE;
+ TRACE("%ld\n", id);
- TRACE("%ld\n", wParam);
+ switch(id) {
+ case MC_PREVNEXTMONTHTIMER:
+ if(infoPtr->status & MC_NEXTPRESSED) MONTHCAL_GoToPrevNextMonth(infoPtr, FALSE);
+ if(infoPtr->status & MC_PREVPRESSED) MONTHCAL_GoToPrevNextMonth(infoPtr, TRUE);
+ InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+ break;
+ case MC_TODAYUPDATETIMER:
+ {
+ SYSTEMTIME st;
- switch(wParam) {
- case MC_NEXTMONTHTIMER:
- redraw = TRUE;
- MONTHCAL_GoToNextMonth(infoPtr);
- break;
- case MC_PREVMONTHTIMER:
- redraw = TRUE;
- MONTHCAL_GoToPrevMonth(infoPtr);
- break;
+ if(infoPtr->todaySet) return 0;
+
+ GetLocalTime(&st);
+ MONTHCAL_UpdateToday(infoPtr, &st);
+
+ /* notification sent anyway */
+ MONTHCAL_NotifySelectionChange(infoPtr);
+
+ return 0;
+ }
default:
- ERR("got unknown timer\n");
+ ERR("got unknown timer %ld\n", id);
break;
}
- /* redraw only if necessary */
- if(redraw)
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
-
return 0;
}
@@ -1575,11 +2033,13 @@ static LRESULT
MONTHCAL_MouseMove(MONTHCAL_INFO *infoPtr, LPARAM lParam)
{
MCHITTESTINFO ht;
- int oldselday, selday, hit;
+ SYSTEMTIME st_ht;
+ INT hit;
RECT r;
if(!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0;
+ ht.cbSize = sizeof(MCHITTESTINFO);
ht.pt.x = (short)LOWORD(lParam);
ht.pt.y = (short)HIWORD(lParam);
@@ -1587,58 +2047,46 @@ MONTHCAL_MouseMove(MONTHCAL_INFO *infoPtr, LPARAM lParam)
/* not on the calendar date numbers? bail out */
TRACE("hit:%x\n",hit);
- if((hit & MCHT_CALENDARDATE) != MCHT_CALENDARDATE) return 0;
+ if((hit & MCHT_CALENDARDATE) != MCHT_CALENDARDATE)
+ {
+ MONTHCAL_SetDayFocus(infoPtr, NULL);
+ return 0;
+ }
- selday = ht.st.wDay;
- oldselday = infoPtr->curSelDay;
- infoPtr->curSelDay = selday;
- MONTHCAL_CalcPosFromDay(infoPtr, selday, ht.st. wMonth, &r);
+ st_ht = ht.st;
- if(infoPtr->dwStyle & MCS_MULTISELECT) {
- SYSTEMTIME selArray[2];
- int i;
+ /* if pointer is over focused day still there's nothing to do */
+ if(!MONTHCAL_SetDayFocus(infoPtr, &ht.st)) return 0;
- MONTHCAL_GetSelRange(infoPtr, selArray);
- i = 0;
- if(infoPtr->firstSelDay==selArray[0].wDay) i=1;
- TRACE("oldRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i);
- if(infoPtr->firstSelDay==selArray[1].wDay) {
- /* 1st time we get here: selArray[0]=selArray[1]) */
- /* if we're still at the first selected date, return */
- if(infoPtr->firstSelDay==selday) goto done;
- if(seldayfirstSelDay) i = 0;
- }
+ MONTHCAL_CalcPosFromDay(infoPtr, &ht.st, &r);
- if(abs(infoPtr->firstSelDay - selday) >= infoPtr->maxSelCount) {
- if(selday>infoPtr->firstSelDay)
- selday = infoPtr->firstSelDay + infoPtr->maxSelCount;
- else
- selday = infoPtr->firstSelDay - infoPtr->maxSelCount;
- }
+ if(infoPtr->dwStyle & MCS_MULTISELECT) {
+ SYSTEMTIME st[2];
- if(selArray[i].wDay!=selday) {
- TRACE("newRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i);
+ MONTHCAL_GetSelRange(infoPtr, st);
- selArray[i].wDay = selday;
+ /* If we're still at the first selected date and range is empty, return.
+ If range isn't empty we should change range to a single firstSel */
+ if(MONTHCAL_IsDateEqual(&infoPtr->firstSel, &st_ht) &&
+ MONTHCAL_IsDateEqual(&st[0], &st[1])) goto done;
- if(selArray[0].wDay>selArray[1].wDay) {
- DWORD tempday;
- tempday = selArray[1].wDay;
- selArray[1].wDay = selArray[0].wDay;
- selArray[0].wDay = tempday;
- }
+ MONTHCAL_IsSelRangeValid(infoPtr, &st_ht, &infoPtr->firstSel, &st_ht);
- MONTHCAL_SetSelRange(infoPtr, selArray);
- }
+ st[0] = infoPtr->firstSel;
+ /* we should overwrite timestamp here */
+ MONTHCAL_CopyDate(&st_ht, &st[1]);
+
+ /* bounds will be swapped here if needed */
+ MONTHCAL_SetSelRange(infoPtr, st);
+
+ return 0;
}
done:
- /* only redraw if the currently selected day changed */
- /* FIXME: this should specify a rectangle containing only the days that changed */
- /* using InvalidateRect */
- if(oldselday != infoPtr->curSelDay)
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+ /* FIXME: this should specify a rectangle containing only the days that changed
+ using InvalidateRect */
+ InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
return 0;
}
@@ -1663,21 +2111,39 @@ MONTHCAL_Paint(MONTHCAL_INFO *infoPtr, HDC hdc_paint)
return 0;
}
+static LRESULT
+MONTHCAL_EraseBkgnd(const MONTHCAL_INFO *infoPtr, HDC hdc)
+{
+ HBRUSH hbr;
+ RECT rc;
+
+ if (!GetClipBox(hdc, &rc)) return FALSE;
+
+ /* fill background */
+ hbr = CreateSolidBrush (infoPtr->bk);
+ FillRect(hdc, &rc, hbr);
+ DeleteObject(hbr);
+
+ return TRUE;
+}
static LRESULT
-MONTHCAL_KillFocus(const MONTHCAL_INFO *infoPtr, HWND hFocusWnd)
+MONTHCAL_PrintClient(MONTHCAL_INFO *infoPtr, HDC hdc, DWORD options)
{
- TRACE("\n");
+ FIXME("Partial Stub: (hdc=%p options=0x%08x)\n", hdc, options);
- if (infoPtr->hwndNotify != hFocusWnd)
- ShowWindow(infoPtr->hwndSelf, SW_HIDE);
- else
- InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
+ if ((options & PRF_CHECKVISIBLE) && !IsWindowVisible(infoPtr->hwndSelf))
+ return 0;
+
+ if (options & PRF_ERASEBKGND)
+ MONTHCAL_EraseBkgnd(infoPtr, hdc);
+
+ if (options & PRF_CLIENT)
+ MONTHCAL_Paint(infoPtr, hdc);
return 0;
}
-
static LRESULT
MONTHCAL_SetFocus(const MONTHCAL_INFO *infoPtr)
{
@@ -1691,7 +2157,6 @@ MONTHCAL_SetFocus(const MONTHCAL_INFO *infoPtr)
/* sets the size information */
static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
{
- static const WCHAR SunW[] = { 'S','u','n',0 };
static const WCHAR O0W[] = { '0','0',0 };
HDC hdc = GetDC(infoPtr->hwndSelf);
RECT *title=&infoPtr->title;
@@ -1703,11 +2168,12 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
RECT *weeknumrect=&infoPtr->weeknums;
RECT *days=&infoPtr->days;
RECT *todayrect=&infoPtr->todayrect;
- SIZE size;
+ SIZE size, sz;
TEXTMETRICW tm;
HFONT currentFont;
- int xdiv, left_offset;
+ INT xdiv, dx, dy, i;
RECT rcClient;
+ WCHAR buff[80];
GetClientRect(infoPtr->hwndSelf, &rcClient);
@@ -1716,7 +2182,26 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
/* get the height and width of each day's text */
GetTextMetricsW(hdc, &tm);
infoPtr->textHeight = tm.tmHeight + tm.tmExternalLeading + tm.tmInternalLeading;
- GetTextExtentPoint32W(hdc, SunW, 3, &size);
+
+ /* find largest abbreviated day name for current locale */
+ size.cx = sz.cx = 0;
+ for (i = 0; i < 7; i++)
+ {
+ if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVDAYNAME1 + i,
+ buff, countof(buff)))
+ {
+ GetTextExtentPoint32W(hdc, buff, lstrlenW(buff), &sz);
+ if (sz.cx > size.cx) size.cx = sz.cx;
+ }
+ else /* locale independent fallback on failure */
+ {
+ static const WCHAR SunW[] = { 'S','u','n',0 };
+
+ GetTextExtentPoint32W(hdc, SunW, lstrlenW(SunW), &size);
+ break;
+ }
+ }
+
infoPtr->textWidth = size.cx + 2;
/* recalculate the height and width increments and offsets */
@@ -1724,22 +2209,21 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
xdiv = (infoPtr->dwStyle & MCS_WEEKNUMBERS) ? 8 : 7;
- infoPtr->width_increment = size.cx * 2 + 4;
+ infoPtr->width_increment = size.cx * 2 + 4;
infoPtr->height_increment = infoPtr->textHeight;
- left_offset = (rcClient.right - rcClient.left) - (infoPtr->width_increment * xdiv);
/* calculate title area */
- title->top = rcClient.top;
- title->bottom = title->top + 3 * infoPtr->height_increment / 2;
- title->left = left_offset;
- title->right = rcClient.right;
+ title->top = 0;
+ title->bottom = 3 * infoPtr->height_increment / 2;
+ title->left = 0;
+ title->right = infoPtr->width_increment * xdiv;
/* set the dimensions of the next and previous buttons and center */
/* the month text vertically */
prev->top = next->top = title->top + 4;
prev->bottom = next->bottom = title->bottom - 4;
prev->left = title->left + 4;
- prev->right = prev->left + (title->bottom - title->top) ;
+ prev->right = prev->left + (title->bottom - title->top);
next->right = title->right - 4;
next->left = next->right - (title->bottom - title->top);
@@ -1751,24 +2235,47 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
/* setup the dimensions of the rectangle we draw the names of the */
/* days of the week in */
- weeknumrect->left = left_offset;
+ weeknumrect->left = 0;
+
if(infoPtr->dwStyle & MCS_WEEKNUMBERS)
- weeknumrect->right=prev->right;
+ weeknumrect->right = prev->right;
else
- weeknumrect->right=weeknumrect->left;
+ weeknumrect->right = weeknumrect->left;
+
wdays->left = days->left = weeknumrect->right;
wdays->right = days->right = wdays->left + 7 * infoPtr->width_increment;
- wdays->top = title->bottom ;
+ wdays->top = title->bottom;
wdays->bottom = wdays->top + infoPtr->height_increment;
- days->top = weeknumrect->top = wdays->bottom ;
+ days->top = weeknumrect->top = wdays->bottom;
days->bottom = weeknumrect->bottom = days->top + 6 * infoPtr->height_increment;
- todayrect->left = rcClient.left;
- todayrect->right = rcClient.right;
+ todayrect->left = 0;
+ todayrect->right = title->right;
todayrect->top = days->bottom;
todayrect->bottom = days->bottom + infoPtr->height_increment;
+ /* offset all rectangles to center in client area */
+ dx = (rcClient.right - title->right) / 2;
+ dy = (rcClient.bottom - todayrect->bottom) / 2;
+
+ /* if calendar doesn't fit client area show it at left/top bounds */
+ if (title->left + dx < 0) dx = 0;
+ if (title->top + dy < 0) dy = 0;
+
+ if (dx != 0 || dy != 0)
+ {
+ OffsetRect(title, dx, dy);
+ OffsetRect(prev, dx, dy);
+ OffsetRect(next, dx, dy);
+ OffsetRect(titlemonth, dx, dy);
+ OffsetRect(titleyear, dx, dy);
+ OffsetRect(wdays, dx, dy);
+ OffsetRect(weeknumrect, dx, dy);
+ OffsetRect(days, dx, dy);
+ OffsetRect(todayrect, dx, dy);
+ }
+
TRACE("dx=%d dy=%d client[%s] title[%s] wdays[%s] days[%s] today[%s]\n",
infoPtr->width_increment,infoPtr->height_increment,
wine_dbgstr_rect(&rcClient),
@@ -1841,6 +2348,28 @@ static INT MONTHCAL_StyleChanged(MONTHCAL_INFO *infoPtr, WPARAM wStyleType,
infoPtr->dwStyle = lpss->styleNew;
+ /* make room for week numbers */
+ if ((lpss->styleNew ^ lpss->styleOld) & MCS_WEEKNUMBERS)
+ MONTHCAL_UpdateSize(infoPtr);
+
+ return 0;
+}
+
+static INT MONTHCAL_StyleChanging(MONTHCAL_INFO *infoPtr, WPARAM wStyleType,
+ STYLESTRUCT *lpss)
+{
+ TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
+ wStyleType, lpss->styleOld, lpss->styleNew);
+
+ /* block MCS_MULTISELECT change */
+ if ((lpss->styleNew ^ lpss->styleOld) & MCS_MULTISELECT)
+ {
+ if (lpss->styleOld & MCS_MULTISELECT)
+ lpss->styleNew |= MCS_MULTISELECT;
+ else
+ lpss->styleNew &= ~MCS_MULTISELECT;
+ }
+
return 0;
}
@@ -1869,33 +2398,30 @@ MONTHCAL_Create(HWND hwnd, LPCREATESTRUCTW lpcs)
/* FIXME: calculate systemtime ->> localtime(substract timezoneinfo) */
GetLocalTime(&infoPtr->todaysDate);
- infoPtr->firstDayHighWord = FALSE;
MONTHCAL_SetFirstDayOfWeek(infoPtr, -1);
- infoPtr->currentMonth = infoPtr->todaysDate.wMonth;
- infoPtr->currentYear = infoPtr->todaysDate.wYear;
- MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->minDate);
- MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxDate);
- infoPtr->maxDate.wYear=2050;
- infoPtr->minDate.wYear=1950;
- infoPtr->maxSelCount = 7;
- infoPtr->monthRange = 3;
- infoPtr->monthdayState = Alloc
- (infoPtr->monthRange * sizeof(MONTHDAYSTATE));
- infoPtr->titlebk = comctl32_color.clrActiveCaption;
- infoPtr->titletxt = comctl32_color.clrWindow;
- infoPtr->monthbk = comctl32_color.clrWindow;
- infoPtr->trailingtxt = comctl32_color.clrGrayText;
- infoPtr->bk = comctl32_color.clrWindow;
- infoPtr->txt = comctl32_color.clrWindowText;
- /* set the current day for highlighing */
- infoPtr->minSel.wDay = infoPtr->todaysDate.wDay;
- infoPtr->maxSel.wDay = infoPtr->todaysDate.wDay;
+ infoPtr->maxSelCount = (infoPtr->dwStyle & MCS_MULTISELECT) ? 7 : 1;
+ infoPtr->monthRange = 3;
+ infoPtr->monthdayState = Alloc(infoPtr->monthRange * sizeof(MONTHDAYSTATE));
+ infoPtr->titlebk = comctl32_color.clrActiveCaption;
+ infoPtr->titletxt = comctl32_color.clrWindow;
+ infoPtr->monthbk = comctl32_color.clrWindow;
+ infoPtr->trailingtxt = comctl32_color.clrGrayText;
+ infoPtr->bk = comctl32_color.clrWindow;
+ infoPtr->txt = comctl32_color.clrWindowText;
+
+ infoPtr->minSel = infoPtr->todaysDate;
+ infoPtr->maxSel = infoPtr->todaysDate;
+ infoPtr->curSel = infoPtr->todaysDate;
+ infoPtr->isUnicode = TRUE;
/* call MONTHCAL_UpdateSize to set all of the dimensions */
/* of the control */
MONTHCAL_UpdateSize(infoPtr);
-
+
+ /* today auto update timer, to be freed only on control destruction */
+ SetTimer(infoPtr->hwndSelf, MC_TODAYUPDATETIMER, MC_TODAYUPDATEDELAY, 0);
+
OpenThemeData (infoPtr->hwndSelf, themeClass);
return 0;
@@ -1915,6 +2441,45 @@ MONTHCAL_Destroy(MONTHCAL_INFO *infoPtr)
return 0;
}
+/*
+ * Handler for WM_NOTIFY messages
+ */
+static LRESULT
+MONTHCAL_Notify(MONTHCAL_INFO *infoPtr, NMHDR *hdr)
+{
+ /* notification from year edit updown */
+ if (hdr->code == UDN_DELTAPOS)
+ {
+ NMUPDOWN *nmud = (NMUPDOWN*)hdr;
+
+ if (hdr->hwndFrom == infoPtr->hWndYearUpDown)
+ {
+ /* year value limits are set up explicitly after updown creation */
+ if ((nmud->iDelta + nmud->iPos) != infoPtr->curSel.wYear)
+ {
+ SYSTEMTIME new_date = infoPtr->curSel;
+
+ new_date.wYear = nmud->iDelta + nmud->iPos;
+ MONTHCAL_SetCurSel(infoPtr, &new_date);
+ }
+ }
+ }
+ return 0;
+}
+
+static inline BOOL
+MONTHCAL_SetUnicodeFormat(MONTHCAL_INFO *infoPtr, BOOL isUnicode)
+{
+ BOOL prev = infoPtr->isUnicode;
+ infoPtr->isUnicode = isUnicode;
+ return prev;
+}
+
+static inline BOOL
+MONTHCAL_GetUnicodeFormat(const MONTHCAL_INFO *infoPtr)
+{
+ return infoPtr->isUnicode;
+}
static LRESULT WINAPI
MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
@@ -1947,7 +2512,7 @@ MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return MONTHCAL_SetSelRange(infoPtr, (LPSYSTEMTIME)lParam);
case MCM_GETMONTHRANGE:
- return MONTHCAL_GetMonthRange(infoPtr);
+ return MONTHCAL_GetMonthRange(infoPtr, wParam, (SYSTEMTIME*)lParam);
case MCM_SETDAYSTATE:
return MONTHCAL_SetDayState(infoPtr, (INT)wParam, (LPMONTHDAYSTATE)lParam);
@@ -1991,14 +2556,17 @@ MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case MCM_GETMAXTODAYWIDTH:
return MONTHCAL_GetMaxTodayWidth(infoPtr);
+ case MCM_SETUNICODEFORMAT:
+ return MONTHCAL_SetUnicodeFormat(infoPtr, (BOOL)wParam);
+
+ case MCM_GETUNICODEFORMAT:
+ return MONTHCAL_GetUnicodeFormat(infoPtr);
+
case WM_GETDLGCODE:
return DLGC_WANTARROWS | DLGC_WANTCHARS;
- case WM_KILLFOCUS:
- return MONTHCAL_KillFocus(infoPtr, (HWND)wParam);
-
- case WM_RBUTTONDOWN:
- return MONTHCAL_RButtonDown(infoPtr, lParam);
+ case WM_RBUTTONUP:
+ return MONTHCAL_RButtonUp(infoPtr, lParam);
case WM_LBUTTONDOWN:
return MONTHCAL_LButtonDown(infoPtr, lParam);
@@ -2009,16 +2577,24 @@ MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_LBUTTONUP:
return MONTHCAL_LButtonUp(infoPtr, lParam);
- case WM_PRINTCLIENT:
case WM_PAINT:
return MONTHCAL_Paint(infoPtr, (HDC)wParam);
+ case WM_PRINTCLIENT:
+ return MONTHCAL_PrintClient(infoPtr, (HDC)wParam, (DWORD)lParam);
+
+ case WM_ERASEBKGND:
+ return MONTHCAL_EraseBkgnd(infoPtr, (HDC)wParam);
+
case WM_SETFOCUS:
return MONTHCAL_SetFocus(infoPtr);
case WM_SIZE:
return MONTHCAL_Size(infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
+ case WM_NOTIFY:
+ return MONTHCAL_Notify(infoPtr, (NMHDR*)lParam);
+
case WM_CREATE:
return MONTHCAL_Create(hwnd, (LPCREATESTRUCTW)lParam);
@@ -2044,6 +2620,9 @@ MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_STYLECHANGED:
return MONTHCAL_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
+ case WM_STYLECHANGING:
+ return MONTHCAL_StyleChanging(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
+
default:
if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
ERR( "unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);