diff --git a/dlls/comctl32/ipaddress.c b/dlls/comctl32/ipaddress.c index dc97321562d..fab4ffd34ce 100644 --- a/dlls/comctl32/ipaddress.c +++ b/dlls/comctl32/ipaddress.c @@ -1,8 +1,9 @@ /* * IP Address control * - * Copyright 1999 Chris Morgan and - * James Abbatiello + * Copyright 2002 Dimitrie O. Paun + * Copyright 1999 Chris Morgan + * Copyright 1999 James Abbatiello * Copyright 1998, 1999 Eric Kohl * Copyright 1998 Alex Priem * @@ -20,19 +21,6 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * NOTES - * - * TODO: - * -Edit control doesn't support the ES_CENTER style which prevents - * this ipaddress control from having centered text look like the - * windows ipaddress control - * -Check all notifications/behavior. - * -Optimization: - * -include lpipsi in IPADDRESS_INFO. - * -CurrentFocus: field that has focus at moment of processing. - * -connect Rect32 rcClient. - * -check ipaddress.cpp for missing features. - * -refresh: draw '.' instead of setpixel. */ #include @@ -40,6 +28,7 @@ #include #include +#include "ntddk.h" #include "winbase.h" #include "commctrl.h" #include "wine/debug.h" @@ -48,637 +37,505 @@ WINE_DEFAULT_DEBUG_CHANNEL(ipaddress); typedef struct { - BYTE LowerLimit[4]; - BYTE UpperLimit[4]; - - RECT rcClient; - INT uFocus; -} IPADDRESS_INFO; + HWND EditHwnd; + INT LowerLimit; + INT UpperLimit; + WNDPROC OrigProc; +} IPPART_INFO; typedef struct { - WNDPROC wpOrigProc[4]; - HWND hwndIP[4]; - IPADDRESS_INFO *infoPtr; - HWND hwnd; - UINT uRefCount; -} IP_SUBCLASS_INFO, *LPIP_SUBCLASS_INFO; + HWND Self; + IPPART_INFO Part[4]; +} IPADDRESS_INFO; -#define IPADDRESS_GetInfoPtr(hwnd) ((IPADDRESS_INFO *)GetWindowLongA (hwnd, 0)) +#define POS_DEFAULT 0 +#define POS_LEFT 1 +#define POS_RIGHT 2 +#define POS_SELALL 3 -static BOOL -IPADDRESS_SendNotify (HWND hwnd, UINT command); -static BOOL -IPADDRESS_SendIPAddressNotify (HWND hwnd, UINT field, BYTE newValue); - -/* property name of tooltip window handle */ #define IP_SUBCLASS_PROP "CCIP32SubclassInfo" +#define IPADDRESS_GetInfoPtr(hwnd) ((IPADDRESS_INFO *)GetWindowLongW (hwnd, 0)) static LRESULT CALLBACK IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - -static VOID -IPADDRESS_Refresh (HWND hwnd, HDC hdc) +static LRESULT IPADDRESS_Notify (IPADDRESS_INFO *infoPtr, UINT command) { - RECT rcClient; - HBRUSH hbr; - COLORREF clr=GetSysColor (COLOR_3DDKSHADOW); - int i,x,fieldsize; + HWND hwnd = infoPtr->Self; + + TRACE("(command=%x)\n", command); + + return SendMessageW (GetParent (hwnd), WM_COMMAND, + MAKEWPARAM (GetWindowLongW (hwnd, GWL_ID), command), (LPARAM)hwnd); +} - GetClientRect (hwnd, &rcClient); - hbr = CreateSolidBrush (RGB(255,255,255)); - DrawEdge (hdc, &rcClient, EDGE_SUNKEN, BF_RECT | BF_ADJUST); - FillRect (hdc, &rcClient, hbr); - DeleteObject (hbr); +static INT IPADDRESS_IPNotify (IPADDRESS_INFO *infoPtr, INT field, INT value) +{ + NMIPADDRESS nmip; - x=rcClient.left; - fieldsize=(rcClient.right-rcClient.left) / 4; + TRACE("(field=%x, value=%d)\n", field, value); + + nmip.hdr.hwndFrom = infoPtr->Self; + nmip.hdr.idFrom = GetWindowLongW (infoPtr->Self, GWL_ID); + nmip.hdr.code = IPN_FIELDCHANGED; - for (i=0; i<3; i++) { /* Should draw text "." here */ - x+=fieldsize; - SetPixel (hdc, x, 13, clr); - SetPixel (hdc, x, 14, clr); - SetPixel (hdc, x+1, 13, clr); - SetPixel (hdc, x+1, 14, clr); - } + nmip.iField = field; + nmip.iValue = value; + + SendMessageW (GetParent (infoPtr->Self), WM_NOTIFY, + (WPARAM)nmip.hdr.idFrom, (LPARAM)&nmip); + + TRACE("<-- %d\n", nmip.iValue); + + return nmip.iValue; } -static LRESULT -IPADDRESS_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) +static int IPADDRESS_GetPartIndex(IPADDRESS_INFO *infoPtr, HWND hwnd) { - IPADDRESS_INFO *infoPtr; - RECT rcClient, edit; - int i,fieldsize; - LPIP_SUBCLASS_INFO lpipsi; - - - infoPtr = (IPADDRESS_INFO *)COMCTL32_Alloc (sizeof(IPADDRESS_INFO)); - SetWindowLongA (hwnd, 0, (DWORD)infoPtr); - - GetClientRect (hwnd, &rcClient); - - fieldsize=(rcClient.right-rcClient.left) /4; - - edit.top =rcClient.top+2; - edit.bottom=rcClient.bottom-2; - - lpipsi=(LPIP_SUBCLASS_INFO) GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP); - if (lpipsi == NULL) { - lpipsi = (LPIP_SUBCLASS_INFO) COMCTL32_Alloc (sizeof(IP_SUBCLASS_INFO)); - lpipsi->hwnd = hwnd; - lpipsi->uRefCount++; - SetPropA ((HWND)hwnd, IP_SUBCLASS_PROP, (HANDLE)lpipsi); -/* infoPtr->lpipsi= lpipsi; */ - } else - WARN("IP-create called twice\n"); - - for (i=0; i<=3; i++) - { - infoPtr->LowerLimit[i]=0; - infoPtr->UpperLimit[i]=255; - edit.left=rcClient.left+i*fieldsize+6; - edit.right=rcClient.left+(i+1)*fieldsize-2; - lpipsi->hwndIP[i]= CreateWindowA ("edit", NULL, - WS_CHILD | WS_VISIBLE | ES_CENTER, - edit.left, edit.top, edit.right-edit.left, edit.bottom-edit.top, - hwnd, (HMENU) 1, GetWindowLongA (hwnd, GWL_HINSTANCE), NULL); - lpipsi->wpOrigProc[i]= (WNDPROC) - SetWindowLongA (lpipsi->hwndIP[i],GWL_WNDPROC, (LONG) - IPADDRESS_SubclassProc); - SetPropA ((HWND)lpipsi->hwndIP[i], IP_SUBCLASS_PROP, (HANDLE)lpipsi); - } - - lpipsi->infoPtr= infoPtr; - - return 0; + int i; + + TRACE("(hwnd=%x)\n", hwnd); + + for (i = 0; i < 4; i++) + if (infoPtr->Part[i].EditHwnd == hwnd) return i; + + ERR("We subclassed the wrong window! (hwnd=%x)\n", hwnd); + return -1; } -static LRESULT -IPADDRESS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) +static LRESULT IPADDRESS_Draw (IPADDRESS_INFO *infoPtr, HDC hdc) { - int i; - IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); - LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) - GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP); + RECT rect, rcPart; + POINT pt; + int i; - for (i=0; i<=3; i++) { - SetWindowLongA ((HWND)lpipsi->hwndIP[i], GWL_WNDPROC, - (LONG)lpipsi->wpOrigProc[i]); - } - - COMCTL32_Free (infoPtr); - SetWindowLongA (hwnd, 0, 0); - return 0; -} - - -static LRESULT -IPADDRESS_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HDC hdc; - - TRACE("\n"); - hdc = GetDC (hwnd); - IPADDRESS_Refresh (hwnd, hdc); - ReleaseDC (hwnd, hdc); - - IPADDRESS_SendIPAddressNotify (hwnd, 0, 0); /* FIXME: should use -1 */ - IPADDRESS_SendNotify (hwnd, EN_KILLFOCUS); - InvalidateRect (hwnd, NULL, TRUE); - - return 0; -} - - -static LRESULT -IPADDRESS_Paint (HWND hwnd, WPARAM wParam) -{ - HDC hdc; - PAINTSTRUCT ps; - - hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam; - IPADDRESS_Refresh (hwnd, hdc); - if(!wParam) - EndPaint (hwnd, &ps); - return 0; -} - - -static LRESULT -IPADDRESS_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HDC hdc; - - TRACE("\n"); - - hdc = GetDC (hwnd); - IPADDRESS_Refresh (hwnd, hdc); - ReleaseDC (hwnd, hdc); - - return 0; -} - - -static LRESULT -IPADDRESS_Size (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */ - TRACE("\n"); - return 0; -} - - -static BOOL -IPADDRESS_SendNotify (HWND hwnd, UINT command) -{ - TRACE("%x\n",command); - return (BOOL)SendMessageA (GetParent (hwnd), WM_COMMAND, - MAKEWPARAM (GetWindowLongA (hwnd, GWL_ID),command), (LPARAM)hwnd); -} - - -static BOOL -IPADDRESS_SendIPAddressNotify (HWND hwnd, UINT field, BYTE newValue) -{ - NMIPADDRESS nmip; - - TRACE("%x %x\n",field,newValue); - nmip.hdr.hwndFrom = hwnd; - nmip.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID); - nmip.hdr.code = IPN_FIELDCHANGED; - - nmip.iField=field; - nmip.iValue=newValue; - - return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY, - (WPARAM)nmip.hdr.idFrom, (LPARAM)&nmip); -} - - -static LRESULT -IPADDRESS_ClearAddress (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - int i; - HDC hdc; - char buf[1]; - LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) - GetPropA ((HWND)hwnd,IP_SUBCLASS_PROP); - - TRACE("\n"); - - buf[0]=0; - for (i=0; i<=3; i++) - SetWindowTextA (lpipsi->hwndIP[i],buf); - - hdc = GetDC (hwnd); - IPADDRESS_Refresh (hwnd, hdc); - ReleaseDC (hwnd, hdc); - - return 0; -} - - -static LRESULT -IPADDRESS_IsBlank (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - int i; - char buf[20]; - LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) - GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP); - - TRACE("\n"); - - for (i=0; i<=3; i++) { - GetWindowTextA (lpipsi->hwndIP[i],buf,5); - if (buf[0]) - return 0; - } - - return 1; -} - - -static LRESULT -IPADDRESS_GetAddress (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - char field[20]; - int i,valid,fieldvalue; - DWORD ip_addr; - IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); - LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) - GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP); - - TRACE("\n"); - - valid=0; - ip_addr=0; - for (i=0; i<=3; i++) { - GetWindowTextA (lpipsi->hwndIP[i],field,4); - ip_addr*=256; - if (field[0]) { - field[3]=0; - fieldvalue=atoi(field); - if (fieldvalueLowerLimit[i]) - fieldvalue=infoPtr->LowerLimit[i]; - if (fieldvalue>infoPtr->UpperLimit[i]) - fieldvalue=infoPtr->UpperLimit[i]; - ip_addr+=fieldvalue; - valid++; - } - } - - *(LPDWORD) lParam=ip_addr; - - return valid; -} - - -static LRESULT -IPADDRESS_SetRange (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); - INT index; - - TRACE("\n"); - - index=(INT) wParam; - if ((index<0) || (index>3)) return 0; - - infoPtr->LowerLimit[index]=lParam & 0xff; - infoPtr->UpperLimit[index]=(lParam >>8) & 0xff; - return 1; -} - - -static LRESULT -IPADDRESS_SetAddress (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); - HDC hdc; - LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) - GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP); - int i,value; - DWORD ip_address; - char buf[20]; - - TRACE("\n"); - ip_address=(DWORD) lParam; - - for (i=3; i>=0; i--) { - value=ip_address & 0xff; - if ((value>=infoPtr->LowerLimit[i]) && (value<=infoPtr->UpperLimit[i])) - { - sprintf (buf,"%d",value); - SetWindowTextA (lpipsi->hwndIP[i],buf); - IPADDRESS_SendNotify (hwnd, EN_CHANGE); - } - ip_address= ip_address >> 8; - } - - hdc = GetDC (hwnd); /* & send notifications */ - IPADDRESS_Refresh (hwnd, hdc); - ReleaseDC (hwnd, hdc); - - return TRUE; -} - - -static LRESULT -IPADDRESS_SetFocusToField (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */ - LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) GetPropA ((HWND)hwnd, - IP_SUBCLASS_PROP); - INT index; - - index=(INT) wParam; - TRACE(" %d\n", index); - if ((index<0) || (index>3)) return 0; - - SetFocus (lpipsi->hwndIP[index]); - - return 1; -} - - -static LRESULT -IPADDRESS_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TRACE("\n"); - - SetFocus (hwnd); - IPADDRESS_SendNotify (hwnd, EN_SETFOCUS); - IPADDRESS_SetFocusToField (hwnd, 0, 0); - - return TRUE; -} - - -static INT -IPADDRESS_CheckField (LPIP_SUBCLASS_INFO lpipsi, int currentfield) -{ - int newField,fieldvalue; - char field[20]; - IPADDRESS_INFO *infoPtr=lpipsi->infoPtr; - - if(currentfield >= 0 && currentfield < 4) - { TRACE("\n"); - GetWindowTextA (lpipsi->hwndIP[currentfield],field,4); - if (field[0]) - { - field[3]=0; - newField=-1; - fieldvalue=atoi(field); - if (fieldvalue < infoPtr->LowerLimit[currentfield]) - newField=infoPtr->LowerLimit[currentfield]; - - if (fieldvalue > infoPtr->UpperLimit[currentfield]) - newField=infoPtr->UpperLimit[currentfield]; - - if (newField >= 0) - { - sprintf (field,"%d",newField); - SetWindowTextA (lpipsi->hwndIP[currentfield], field); - return TRUE; - } + GetClientRect (infoPtr->Self, &rect); + DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + + for (i = 0; i < 3; i++) { + GetWindowRect (infoPtr->Part[i].EditHwnd, &rcPart); + pt.x = rcPart.right; + ScreenToClient(infoPtr->Self, &pt); + rect.left = pt.x; + GetWindowRect (infoPtr->Part[i+1].EditHwnd, &rcPart); + pt.x = rcPart.left; + ScreenToClient(infoPtr->Self, &pt); + rect.right = pt.x; + DrawTextA(hdc, ".", 1, &rect, DT_SINGLELINE | DT_CENTER | DT_BOTTOM); } - } - return FALSE; + + return 0; } -static INT -IPADDRESS_GotoNextField (LPIP_SUBCLASS_INFO lpipsi, int currentfield) +static LRESULT IPADDRESS_Create (HWND hwnd) { - if(currentfield >= -1 && currentfield < 4) - { - IPADDRESS_CheckField(lpipsi, currentfield); /* check the fields value */ + IPADDRESS_INFO *infoPtr; + RECT rcClient, edit; + int i, fieldsize; + WCHAR EDIT[] = { 'E', 'd', 'i', 't', 0 }; - if(currentfield < 3) - { - SetFocus (lpipsi->hwndIP[currentfield+1]); - return TRUE; + TRACE("\n"); + + SetWindowLongW (hwnd, GWL_STYLE, + GetWindowLongW(hwnd, GWL_STYLE) & ~WS_BORDER); + + infoPtr = (IPADDRESS_INFO *)COMCTL32_Alloc (sizeof(IPADDRESS_INFO)); + if (!infoPtr) return -1; + SetWindowLongW (hwnd, 0, (DWORD)infoPtr); + + GetClientRect (hwnd, &rcClient); + + fieldsize = (rcClient.right - rcClient.left) / 4; + + edit.top = rcClient.top + 2; + edit.bottom = rcClient.bottom - 2; + + infoPtr->Self = hwnd; + + for (i = 0; i < 4; i++) { + IPPART_INFO* part = &infoPtr->Part[i]; + + part->LowerLimit = 0; + part->UpperLimit = 255; + 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, + edit.left, edit.top, edit.right - edit.left, + edit.bottom - edit.top, hwnd, (HMENU) 1, + GetWindowLongW (hwnd, GWL_HINSTANCE), NULL); + SetPropA(part->EditHwnd, IP_SUBCLASS_PROP, hwnd); + part->OrigProc = (WNDPROC) + SetWindowLongW (part->EditHwnd, GWL_WNDPROC, + (LONG)IPADDRESS_SubclassProc); } - } - return FALSE; + + return 0; } -/* period: move and select the text in the next field to the right if */ -/* the current field is not empty(l!=0), we are not in the */ -/* left most position, and nothing is selected(startsel==endsel) */ +static LRESULT IPADDRESS_Destroy (IPADDRESS_INFO *infoPtr) +{ + int i; -/* spacebar: same behavior as period */ + TRACE("\n"); + + for (i = 0; i < 4; i++) { + IPPART_INFO* part = &infoPtr->Part[i]; + SetWindowLongW (part->EditHwnd, GWL_WNDPROC, (LONG)part->OrigProc); + } -/* alpha characters: completely ignored */ - -/* digits: accepted when field text length < 2 ignored otherwise. */ -/* when 3 numbers have been entered into the field the value */ -/* of the field is checked, if the field value exceeds the */ -/* maximum value and is changed the field remains the current */ -/* field, otherwise focus moves to the field to the right */ - -/* tab: change focus from the current ipaddress control to the next */ -/* control in the tab order */ - -/* right arrow: move to the field on the right to the left most */ -/* position in that field if no text is selected, */ -/* we are in the right most position in the field, */ -/* we are not in the right most field */ - -/* left arrow: move to the field on the left to the right most */ -/* position in that field if no text is selected, */ -/* we are in the left most position in the current field */ -/* and we are not in the left most field */ - -/* backspace: delete the character to the left of the cursor position, */ -/* if none are present move to the field on the left if */ -/* we are not in the left most field and delete the right */ -/* most digit in that field while keeping the cursor */ -/* on the right side of the field */ + SetWindowLongW (infoPtr->Self, 0, 0); + COMCTL32_Free (infoPtr); + return 0; +} +static LRESULT IPADDRESS_Paint (IPADDRESS_INFO *infoPtr, HDC hdc) +{ + PAINTSTRUCT ps; + + TRACE("\n"); + + if (hdc) return IPADDRESS_Draw (infoPtr, hdc); + + hdc = BeginPaint (infoPtr->Self, &ps); + IPADDRESS_Draw (infoPtr, hdc); + EndPaint (infoPtr->Self, &ps); + return 0; +} + + +static BOOL IPADDRESS_IsBlank (IPADDRESS_INFO *infoPtr) +{ + int i; + + TRACE("\n"); + + for (i = 0; i < 4; i++) + if (GetWindowTextLengthW (infoPtr->Part[i].EditHwnd)) return FALSE; + + return TRUE; +} + + +static int IPADDRESS_GetAddress (IPADDRESS_INFO *infoPtr, LPDWORD ip_address) +{ + WCHAR field[5]; + int i, invalid = 0; + DWORD ip_addr = 0; + + TRACE("\n"); + + for (i = 0; i < 4; i++) { + ip_addr *= 256; + if (GetWindowTextW (infoPtr->Part[i].EditHwnd, field, 4)) + ip_addr += wcstol(field, 0, 10); + else + invalid++; + } + *ip_address = ip_addr; + + return 4 - invalid; +} + + +static BOOL IPADDRESS_SetRange (IPADDRESS_INFO *infoPtr, int index, WORD range) +{ + TRACE("\n"); + + if ( (index < 0) || (index > 3) ) return FALSE; + + infoPtr->Part[index].LowerLimit = range & 0xFF; + infoPtr->Part[index].UpperLimit = (range >> 8) & 0xFF; + + return TRUE; +} + + +static void IPADDRESS_ClearAddress (IPADDRESS_INFO *infoPtr) +{ + WCHAR nil[0] = { 0 }; + int i; + + TRACE("\n"); + + for (i = 0; i < 4; i++) + SetWindowTextW (infoPtr->Part[i].EditHwnd, nil); +} + + +static LRESULT IPADDRESS_SetAddress (IPADDRESS_INFO *infoPtr, DWORD ip_address) +{ + WCHAR buf[20], fmt[] = { '%', 'd', 0 }; + int i; + + TRACE("\n"); + + for (i = 3; i >= 0; i--) { + IPPART_INFO* part = &infoPtr->Part[i]; + int value = ip_address & 0xff; + if ( (value >= part->LowerLimit) && (value <= part->UpperLimit) ) { + swprintf (buf, fmt, value); + SetWindowTextW (part->EditHwnd, buf); + IPADDRESS_Notify (infoPtr, EN_CHANGE); + } + ip_address >>= 8; + } + + return TRUE; +} + + +static void IPADDRESS_SetFocusToField (IPADDRESS_INFO *infoPtr, INT index) +{ + TRACE("(index=%d)\n", index); + + if (index > 3) { + for (index = 0; index < 4; index++) + if (!GetWindowTextLengthW(infoPtr->Part[index].EditHwnd)) break; + } + if (index < 9 || index > 3) index = 0; + + SetFocus (infoPtr->Part[index].EditHwnd); +} + + +static BOOL IPADDRESS_ConstrainField (IPADDRESS_INFO *infoPtr, int currentfield) +{ + IPPART_INFO *part = &infoPtr->Part[currentfield]; + WCHAR field[10], fmt[] = { '%', 'd', 0 }; + int curValue, newValue; + + TRACE("(currentfield=%d)\n", currentfield); + + if (currentfield < 0 || currentfield > 3) return FALSE; + + if (!GetWindowTextW (part->EditHwnd, field, 4)) return FALSE; + + curValue = wcstol(field, 0, 10); + TRACE(" curValue=%d\n", curValue); + + newValue = IPADDRESS_IPNotify(infoPtr, currentfield, curValue); + TRACE(" newValue=%d\n", newValue); + + if (newValue < part->LowerLimit) newValue = part->LowerLimit; + if (newValue > part->UpperLimit) newValue = part->UpperLimit; + + if (newValue == curValue) return FALSE; + + swprintf (field, fmt, newValue); + TRACE(" field='%s'\n", debugstr_w(field)); + return SetWindowTextW (part->EditHwnd, field); +} + + +static BOOL IPADDRESS_GotoNextField (IPADDRESS_INFO *infoPtr, int cur, int sel) +{ + TRACE("\n"); + + if(cur >= -1 && cur < 4) { + IPADDRESS_ConstrainField(infoPtr, cur); + + if(cur < 3) { + IPPART_INFO *next = &infoPtr->Part[cur + 1]; + int start = 0, end = 0; + SetFocus (next->EditHwnd); + if (sel != POS_DEFAULT) { + if (sel == POS_RIGHT) + start = end = GetWindowTextLengthW(next->EditHwnd); + else if (sel == POS_SELALL) + end = -1; + SendMessageW(next->EditHwnd, EM_SETSEL, start, end); + } + return TRUE; + } + + } + return FALSE; +} + + +/* + * period: move and select the text in the next field to the right if + * the current field is not empty(l!=0), we are not in the + * left most position, and nothing is selected(startsel==endsel) + * + * spacebar: same behavior as period + * + * alpha characters: completely ignored + * + * digits: accepted when field text length < 2 ignored otherwise. + * when 3 numbers have been entered into the field the value + * of the field is checked, if the field value exceeds the + * maximum value and is changed the field remains the current + * field, otherwise focus moves to the field to the right + * + * tab: change focus from the current ipaddress control to the next + * control in the tab order + * + * right arrow: move to the field on the right to the left most + * position in that field if no text is selected, + * we are in the right most position in the field, + * we are not in the right most field + * + * left arrow: move to the field on the left to the right most + * position in that field if no text is selected, + * we are in the left most position in the current field + * and we are not in the left most field + * + * backspace: delete the character to the left of the cursor position, + * if none are present move to the field on the left if + * we are not in the left most field and delete the right + * most digit in that field while keeping the cursor + * on the right side of the field + */ LRESULT CALLBACK IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - IPADDRESS_INFO *infoPtr; - LPIP_SUBCLASS_INFO lpipsi = (LPIP_SUBCLASS_INFO) GetPropA - ((HWND)hwnd,IP_SUBCLASS_PROP); - CHAR c = (CHAR)wParam; - INT i, l, index, startsel, endsel; + HWND Self = (HWND)GetPropA (hwnd, IP_SUBCLASS_PROP); + IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (Self); + CHAR c = (CHAR)wParam; + INT index, len = 0, startsel, endsel; + IPPART_INFO *part; - infoPtr = lpipsi->infoPtr; - index=0; /* FIXME */ - for (i=0; i<=3; i++) - if (lpipsi->hwndIP[i]==hwnd) index=i; + TRACE("(hwnd=0x%x msg=0x%x wparam=0x%x lparam=0x%lx)\n", hwnd, uMsg, wParam, lParam); - switch (uMsg) { - case WM_CHAR: - if(isdigit(c)) /* process all digits */ - { - int return_val; - SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); - l = GetWindowTextLengthA (lpipsi->hwndIP[index]); - if(l==2 && startsel==endsel) /* field is full after this key is processed */ - { - /* process the digit press before we check the field */ - return_val = CallWindowProcA (lpipsi->wpOrigProc[index], hwnd, uMsg, wParam, lParam); - - /* if the field value was changed stay at the current field */ - if(!IPADDRESS_CheckField(lpipsi, index)) - IPADDRESS_GotoNextField (lpipsi,index); + if ( (index = IPADDRESS_GetPartIndex(infoPtr, hwnd)) < 0) return 0; + part = &infoPtr->Part[index]; - return return_val; - } - - if(l > 2) /* field is full, stop key messages */ - { - lParam = 0; - wParam = 0; - } - break; + if (uMsg == WM_CHAR || uMsg == WM_KEYDOWN) { + len = GetWindowTextLengthW (hwnd); + SendMessageW(hwnd, EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); } - - if(c == '.') /* VK_PERIOD */ - { - l = GetWindowTextLengthA(lpipsi->hwndIP[index]); - SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); - if(l != 0 && startsel==endsel && startsel != 0) - { - IPADDRESS_GotoNextField(lpipsi, index); - SendMessageA(lpipsi->hwndIP[index+1], EM_SETSEL, (WPARAM)0, (LPARAM)3); - } - } + switch (uMsg) { + case WM_CHAR: + if(isdigit(c)) { + if(len == 2 && startsel==endsel && endsel==len) { + /* process the digit press before we check the field */ + int return_val = CallWindowProcW (part->OrigProc, hwnd, uMsg, wParam, lParam); + + /* if the field value was changed stay at the current field */ + if(!IPADDRESS_ConstrainField(infoPtr, index)) + IPADDRESS_GotoNextField (infoPtr, index, POS_DEFAULT); + + return return_val; + } else if (len == 3 && startsel==endsel && endsel==len) + IPADDRESS_GotoNextField (infoPtr, index, POS_SELALL); + else if (len < 3) break; + } else if(c == '.' || c == ' ') { + if(len && startsel==endsel && startsel != 0) { + IPADDRESS_GotoNextField(infoPtr, index, POS_SELALL); + } + } else if (c == VK_BACK) break; + return 0; - /* stop all other characters */ - wParam = 0; - lParam = 0; - break; - - case WM_KEYDOWN: - if(c == VK_SPACE) - { - l = GetWindowTextLengthA(lpipsi->hwndIP[index]); - SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); - if(l != 0 && startsel==endsel && startsel != 0) - { - IPADDRESS_GotoNextField(lpipsi, index); - SendMessageA(lpipsi->hwndIP[index+1], EM_SETSEL, (WPARAM)0, (LPARAM)3); - } + case WM_KEYDOWN: + switch(c) { + case VK_RIGHT: + if(startsel==endsel && startsel==len) { + IPADDRESS_GotoNextField(infoPtr, index, POS_LEFT); + return 0; + } + break; + case VK_LEFT: + if(startsel==0 && startsel==endsel && index > 0) { + IPADDRESS_GotoNextField(infoPtr, index - 2, POS_RIGHT); + return 0; + } + break; + case VK_BACK: + if(startsel==endsel && startsel==0 && index > 0) { + IPPART_INFO *prev = &infoPtr->Part[index-1]; + WCHAR val[10]; + + if(GetWindowTextW(prev->EditHwnd, val, 5)) { + val[lstrlenW(val) - 1] = 0; + SetWindowTextW(prev->EditHwnd, val); + } + + IPADDRESS_GotoNextField(infoPtr, index - 2, POS_RIGHT); + return 0; + } + break; + } + break; + case WM_KILLFOCUS: + if (IPADDRESS_GetPartIndex(infoPtr, (HWND)wParam) < 0) + IPADDRESS_Notify(infoPtr, EN_KILLFOCUS); + break; + case WM_SETFOCUS: + if (IPADDRESS_GetPartIndex(infoPtr, (HWND)wParam) < 0) + IPADDRESS_Notify(infoPtr, EN_SETFOCUS); + break; } - - if(c == VK_RIGHT) - { - SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); - l = GetWindowTextLengthA (lpipsi->hwndIP[index]); - - if(startsel==endsel && startsel==l) - { - IPADDRESS_GotoNextField(lpipsi, index); - SendMessageA(lpipsi->hwndIP[index+1], EM_SETSEL, (WPARAM)0,(LPARAM)0); - } - } - - if(c == VK_LEFT) - { - SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); - if(startsel==0 && startsel==endsel && index > 0) - { - IPADDRESS_GotoNextField(lpipsi, index - 2); - l = GetWindowTextLengthA(lpipsi->hwndIP[index-1]); - SendMessageA(lpipsi->hwndIP[index-1], EM_SETSEL, (WPARAM)l,(LPARAM)l); - } - } - - if(c == VK_BACK) /* VK_BACKSPACE */ - { - CHAR buf[4]; - - SendMessageA(lpipsi->hwndIP[index], EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); - l = GetWindowTextLengthA (lpipsi->hwndIP[index]); - if(startsel==endsel && startsel==0 && index > 0) - { - l = GetWindowTextLengthA(lpipsi->hwndIP[index-1]); - if(l!=0) - { - GetWindowTextA (lpipsi->hwndIP[index-1],buf,4); - buf[l-1] = '\0'; - SetWindowTextA(lpipsi->hwndIP[index-1], buf); - SendMessageA(lpipsi->hwndIP[index-1], EM_SETSEL, (WPARAM)l,(LPARAM)l); - } - IPADDRESS_GotoNextField(lpipsi, index - 2); - } - } - break; - - default: - break; - } - return CallWindowProcA (lpipsi->wpOrigProc[index], hwnd, uMsg, wParam, lParam); + return CallWindowProcW (part->OrigProc, hwnd, uMsg, wParam, lParam); } static LRESULT WINAPI IPADDRESS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - TRACE("hwnd=%x msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam); - if (!IPADDRESS_GetInfoPtr (hwnd) && (uMsg != WM_CREATE)) - return DefWindowProcA (hwnd, uMsg, wParam, lParam); - switch (uMsg) - { - case IPM_CLEARADDRESS: - return IPADDRESS_ClearAddress (hwnd, wParam, lParam); + IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); + + TRACE("(hwnd=0x%x msg=0x%x wparam=0x%x lparam=0x%lx)\n", hwnd, uMsg, wParam, lParam); + + if (!infoPtr && (uMsg != WM_CREATE)) + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case WM_CREATE: + return IPADDRESS_Create (hwnd); - case IPM_SETADDRESS: - return IPADDRESS_SetAddress (hwnd, wParam, lParam); + case WM_DESTROY: + return IPADDRESS_Destroy (infoPtr); - case IPM_GETADDRESS: - return IPADDRESS_GetAddress (hwnd, wParam, lParam); + case WM_PAINT: + return IPADDRESS_Paint (infoPtr, (HDC)wParam); - case IPM_SETRANGE: - return IPADDRESS_SetRange (hwnd, wParam, lParam); + case WM_COMMAND: + switch(wParam >> 16) { + case EN_CHANGE: + IPADDRESS_Notify(infoPtr, EN_CHANGE); + break; + case EN_KILLFOCUS: + IPADDRESS_ConstrainField(infoPtr, IPADDRESS_GetPartIndex(infoPtr, (HWND)lParam)); + break; + } + break; - case IPM_SETFOCUS: - return IPADDRESS_SetFocusToField (hwnd, wParam, lParam); + case IPM_CLEARADDRESS: + IPADDRESS_ClearAddress (infoPtr); + break; - case IPM_ISBLANK: - return IPADDRESS_IsBlank (hwnd, wParam, lParam); + case IPM_SETADDRESS: + return IPADDRESS_SetAddress (infoPtr, (DWORD)lParam); - case WM_CREATE: - return IPADDRESS_Create (hwnd, wParam, lParam); + case IPM_GETADDRESS: + return IPADDRESS_GetAddress (infoPtr, (LPDWORD)lParam); - case WM_DESTROY: - return IPADDRESS_Destroy (hwnd, wParam, lParam); + case IPM_SETRANGE: + return IPADDRESS_SetRange (infoPtr, (int)wParam, (WORD)lParam); - case WM_GETDLGCODE: - return DLGC_WANTARROWS | DLGC_WANTCHARS; + case IPM_SETFOCUS: + IPADDRESS_SetFocusToField (infoPtr, (int)wParam); + break; - case WM_KILLFOCUS: - return IPADDRESS_KillFocus (hwnd, wParam, lParam); + case IPM_ISBLANK: + return IPADDRESS_IsBlank (infoPtr); - case WM_LBUTTONDOWN: - return IPADDRESS_LButtonDown (hwnd, wParam, lParam); - - case WM_PAINT: - return IPADDRESS_Paint (hwnd, wParam); - - case WM_SETFOCUS: - return IPADDRESS_SetFocus (hwnd, wParam, lParam); - - case WM_SIZE: - return IPADDRESS_Size (hwnd, wParam, lParam); - - default: - if (uMsg >= WM_USER) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", - uMsg, wParam, lParam); - return DefWindowProcA (hwnd, uMsg, wParam, lParam); + default: + if (uMsg >= WM_USER) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); } return 0; } @@ -686,22 +543,22 @@ IPADDRESS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) void IPADDRESS_Register (void) { - WNDCLASSA wndClass; + WNDCLASSW wndClass; - ZeroMemory (&wndClass, sizeof(WNDCLASSA)); - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = (WNDPROC)IPADDRESS_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(IPADDRESS_INFO *); - wndClass.hCursor = LoadCursorA (0, IDC_ARROWA); - wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - wndClass.lpszClassName = WC_IPADDRESSA; + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS; + wndClass.lpfnWndProc = (WNDPROC)IPADDRESS_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(IPADDRESS_INFO *); + wndClass.hCursor = LoadCursorW (0, IDC_IBEAMW); + wndClass.hbrBackground = GetStockObject(WHITE_BRUSH); + wndClass.lpszClassName = WC_IPADDRESSW; - RegisterClassA (&wndClass); + RegisterClassW (&wndClass); } -VOID IPADDRESS_Unregister (void) +void IPADDRESS_Unregister (void) { - UnregisterClassA (WC_IPADDRESSA, (HINSTANCE)NULL); + UnregisterClassW (WC_IPADDRESSW, (HINSTANCE)NULL); }