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);