| /* |
| * IP Address control |
| * |
| * Copyright 1998, 1999 Eric Kohl |
| * Copyright 1998 Alex Priem <alexp@sci.kun.nl> |
| * |
| * NOTES |
| |
| * |
| * TODO: |
| * -Check ranges when changing field-focus. |
| * -Check all notifications/behavior. |
| * -Optimization: include lpipsi in IPADDRESS_INFO. |
| * -CurrentFocus: field that has focus at moment of processing. |
| * -connect Rect32 rcClient. |
| * -handle right and left arrows correctly. Boring. |
| * -split GotoNextField in CheckField and GotoNextField. |
| * -check ipaddress.cpp for missing features. |
| * -refresh: draw '.' instead of setpixel. |
| * -handle VK_ESCAPE. |
| */ |
| |
| #include <ctype.h> |
| #include <stdlib.h> |
| |
| #include "winbase.h" |
| #include "commctrl.h" |
| #include "ipaddress.h" |
| #include "heap.h" |
| #include "debug.h" |
| |
| DEFAULT_DEBUG_CHANNEL(ipaddress) |
| |
| |
| #define IPADDRESS_GetInfoPtr(hwnd) ((IPADDRESS_INFO *)GetWindowLongA (hwnd, 0)) |
| |
| |
| 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" |
| |
| |
| static LRESULT CALLBACK |
| IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); |
| |
| |
| |
| |
| static VOID |
| IPADDRESS_Refresh (HWND hwnd, HDC hdc) |
| { |
| RECT rcClient; |
| HBRUSH hbr; |
| COLORREF clr=GetSysColor (COLOR_3DDKSHADOW); |
| int i,x,fieldsize; |
| |
| GetClientRect (hwnd, &rcClient); |
| hbr = CreateSolidBrush (RGB(255,255,255)); |
| DrawEdge (hdc, &rcClient, EDGE_SUNKEN, BF_RECT | BF_ADJUST); |
| FillRect (hdc, &rcClient, hbr); |
| DeleteObject (hbr); |
| |
| x=rcClient.left; |
| fieldsize=(rcClient.right-rcClient.left) /4; |
| |
| 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); |
| |
| } |
| |
| } |
| |
| |
| |
| |
| |
| static LRESULT |
| IPADDRESS_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) |
| { |
| 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 (ipaddress,"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+3; |
| edit.right=rcClient.left+(i+1)*fieldsize-2; |
| lpipsi->hwndIP[i]= CreateWindowA ("edit", NULL, |
| WS_CHILD | WS_VISIBLE | ES_LEFT, |
| 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; |
| } |
| |
| |
| static LRESULT |
| IPADDRESS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) |
| { |
| int i; |
| IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); |
| LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) |
| GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP); |
| |
| for (i=0; i<=3; i++) { |
| SetWindowLongA ((HWND)lpipsi->hwndIP[i], GWL_WNDPROC, |
| (LONG)lpipsi->wpOrigProc[i]); |
| } |
| |
| COMCTL32_Free (infoPtr); |
| return 0; |
| } |
| |
| |
| static LRESULT |
| IPADDRESS_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam) |
| { |
| HDC hdc; |
| |
| TRACE (ipaddress,"\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 (ipaddress,"\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 (ipaddress,"\n"); |
| return 0; |
| } |
| |
| |
| static BOOL |
| IPADDRESS_SendNotify (HWND hwnd, UINT command) |
| |
| { |
| TRACE (ipaddress, "%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 (ipaddress, "%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 (ipaddress,"\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 (ipaddress,"\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 (ipaddress,"\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 (fieldvalue<infoPtr->LowerLimit[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 (ipaddress,"\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,ip_address,value; |
| char buf[20]; |
| |
| TRACE (ipaddress,"\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/=256; |
| } |
| |
| 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 (ipaddress," %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 (ipaddress, "\n"); |
| |
| SetFocus (hwnd); |
| IPADDRESS_SendNotify (hwnd, EN_SETFOCUS); |
| IPADDRESS_SetFocusToField (hwnd, 0, 0); |
| |
| return TRUE; |
| } |
| |
| |
| |
| /* tab/shift-tab: IPN_FIELDCHANGED, lose focus. |
| dot, space,right arrow: set focus to next child edit. |
| numerics (0..9), control characters: forward to default edit control |
| other characters: dropped |
| */ |
| |
| |
| |
| |
| static int |
| IPADDRESS_GotoNextField (LPIP_SUBCLASS_INFO lpipsi, int currentfield) |
| { |
| int newField,fieldvalue; |
| char field[20]; |
| IPADDRESS_INFO *infoPtr=lpipsi->infoPtr; |
| |
| TRACE (ipaddress,"\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 1; |
| } |
| } |
| |
| if (currentfield<3) |
| SetFocus (lpipsi->hwndIP[currentfield+1]); |
| return 0; |
| } |
| |
| |
| LRESULT CALLBACK |
| IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) |
| { |
| int i,l,index; |
| IPADDRESS_INFO *infoPtr; |
| LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) |
| GetPropA ((HWND)hwnd,IP_SUBCLASS_PROP); |
| |
| infoPtr = lpipsi->infoPtr; |
| index=0; /* FIXME */ |
| for (i=0; i<=3; i++) |
| if (lpipsi->hwndIP[i]==hwnd) index=i; |
| |
| switch (uMsg) { |
| case WM_CHAR: break; |
| case WM_KEYDOWN: { |
| char c=(char) wParam; |
| if (c==VK_TAB) { |
| HWND pwnd; |
| int shift; |
| shift = GetKeyState(VK_SHIFT) & 0x8000; |
| if (shift) |
| pwnd=GetNextDlgTabItem (GetParent (hwnd), 0, TRUE); |
| else |
| pwnd=GetNextDlgTabItem (GetParent (hwnd), 0, FALSE); |
| if (pwnd) SetFocus (pwnd); |
| break; |
| } |
| |
| if ((c==' ') || (c=='.') || (c==VK_RIGHT)) { |
| IPADDRESS_GotoNextField (lpipsi,index); |
| wParam=0; |
| lParam=0; |
| break; |
| } |
| if (c==VK_LEFT) { |
| |
| } |
| if (c==VK_RETURN) { |
| } |
| if (((c>='0') && (c<='9')) || (iscntrl(c))) { |
| l=GetWindowTextLengthA (lpipsi->hwndIP[index]); |
| if (l==3) |
| if (IPADDRESS_GotoNextField (lpipsi,index)) { |
| wParam=0; |
| lParam=0; |
| } |
| break; |
| } |
| |
| wParam=0; |
| lParam=0; |
| break; |
| } |
| } |
| |
| return CallWindowProcA (lpipsi->wpOrigProc[index], hwnd, uMsg, wParam, lParam); |
| } |
| |
| LRESULT WINAPI |
| IPADDRESS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) |
| { |
| switch (uMsg) |
| { |
| case IPM_CLEARADDRESS: |
| return IPADDRESS_ClearAddress (hwnd, wParam, lParam); |
| |
| case IPM_SETADDRESS: |
| return IPADDRESS_SetAddress (hwnd, wParam, lParam); |
| |
| case IPM_GETADDRESS: |
| return IPADDRESS_GetAddress (hwnd, wParam, lParam); |
| |
| case IPM_SETRANGE: |
| return IPADDRESS_SetRange (hwnd, wParam, lParam); |
| |
| case IPM_SETFOCUS: |
| return IPADDRESS_SetFocusToField (hwnd, wParam, lParam); |
| |
| case IPM_ISBLANK: |
| return IPADDRESS_IsBlank (hwnd, wParam, lParam); |
| |
| case WM_CREATE: |
| return IPADDRESS_Create (hwnd, wParam, lParam); |
| |
| case WM_DESTROY: |
| return IPADDRESS_Destroy (hwnd, wParam, lParam); |
| |
| case WM_GETDLGCODE: |
| return DLGC_WANTARROWS | DLGC_WANTCHARS; |
| |
| case WM_KILLFOCUS: |
| return IPADDRESS_KillFocus (hwnd, wParam, lParam); |
| |
| 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 (ipaddress, "unknown msg %04x wp=%08x lp=%08lx\n", |
| uMsg, wParam, lParam); |
| return DefWindowProcA (hwnd, uMsg, wParam, lParam); |
| } |
| return 0; |
| } |
| |
| |
| void |
| IPADDRESS_Register (void) |
| { |
| WNDCLASSA wndClass; |
| |
| if (GlobalFindAtomA (WC_IPADDRESSA)) return; |
| |
| 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; |
| |
| RegisterClassA (&wndClass); |
| } |
| |
| VOID |
| IPADDRESS_Unregister (VOID) |
| { |
| if (GlobalFindAtomA (WC_IPADDRESSA)) |
| UnregisterClassA (WC_IPADDRESSA, (HINSTANCE)NULL); |
| } |
| |