/* IP Address control * * Copyright 1998 Eric Kohl * Copyright 1998 Alex Priem * * 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 #include #include "windows.h" #include "win.h" #include "commctrl.h" #include "ipaddress.h" #include "heap.h" #include "debug.h" #define IPADDRESS_GetInfoPtr(wndPtr) ((IPADDRESS_INFO *)wndPtr->wExtra[0]) static BOOL32 IPADDRESS_SendNotify (WND *wndPtr, UINT32 command); static BOOL32 IPADDRESS_SendIPAddressNotify (WND *wndPtr, UINT32 field, BYTE newValue); /* property name of tooltip window handle */ #define IP_SUBCLASS_PROP "CCIP32SubclassInfo" static LRESULT CALLBACK IPADDRESS_SubclassProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam); static VOID IPADDRESS_Refresh (WND *wndPtr, HDC32 hdc) { RECT32 rcClient; HBRUSH32 hbr; COLORREF clr=GetSysColor32 (COLOR_3DDKSHADOW); int i,x,fieldsize; GetClientRect32 (wndPtr->hwndSelf, &rcClient); hbr = CreateSolidBrush32 (RGB(255,255,255)); DrawEdge32 (hdc, &rcClient, EDGE_SUNKEN, BF_RECT | BF_ADJUST); FillRect32 (hdc, &rcClient, hbr); DeleteObject32 (hbr); x=rcClient.left; fieldsize=(rcClient.right-rcClient.left) /4; for (i=0; i<3; i++) { /* Should draw text "." here */ x+=fieldsize; SetPixel32 (hdc, x, 13, clr); SetPixel32 (hdc, x, 14, clr); SetPixel32 (hdc, x+1, 13, clr); SetPixel32 (hdc, x+1, 14, clr); } } static LRESULT IPADDRESS_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { IPADDRESS_INFO *infoPtr; RECT32 rcClient, edit; int i,fieldsize; LPIP_SUBCLASS_INFO lpipsi; infoPtr = (IPADDRESS_INFO *)COMCTL32_Alloc (sizeof(IPADDRESS_INFO)); wndPtr->wExtra[0] = (DWORD)infoPtr; if (infoPtr == NULL) { ERR (ipaddress, "could not allocate info memory!\n"); return 0; } GetClientRect32 (wndPtr->hwndSelf, &rcClient); fieldsize=(rcClient.right-rcClient.left) /4; edit.top =rcClient.top+2; edit.bottom=rcClient.bottom-2; lpipsi=(LPIP_SUBCLASS_INFO) GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP); if (lpipsi == NULL) { lpipsi= (LPIP_SUBCLASS_INFO) COMCTL32_Alloc (sizeof(IP_SUBCLASS_INFO)); lpipsi->wndPtr=wndPtr; lpipsi->uRefCount++; SetProp32A ((HWND32)wndPtr->hwndSelf, IP_SUBCLASS_PROP, (HANDLE32)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]= CreateWindow32A ("edit", NULL, WS_CHILD | WS_VISIBLE | ES_LEFT, edit.left, edit.top, edit.right-edit.left, edit.bottom-edit.top, wndPtr->hwndSelf, (HMENU32) 1, wndPtr->hInstance, NULL); lpipsi->wpOrigProc[i]= (WNDPROC32) SetWindowLong32A (lpipsi->hwndIP[i],GWL_WNDPROC, (LONG) IPADDRESS_SubclassProc); SetProp32A ((HWND32)lpipsi->hwndIP[i], IP_SUBCLASS_PROP, (HANDLE32)lpipsi); } lpipsi->infoPtr= infoPtr; return 0; } static LRESULT IPADDRESS_Destroy (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { int i; IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr); LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP); for (i=0; i<=3; i++) { SetWindowLong32A ((HWND32)lpipsi->hwndIP[i], GWL_WNDPROC, (LONG)lpipsi->wpOrigProc[i]); } COMCTL32_Free (infoPtr); return 0; } static LRESULT IPADDRESS_KillFocus (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { HDC32 hdc; TRACE (ipaddress,"\n"); hdc = GetDC32 (wndPtr->hwndSelf); IPADDRESS_Refresh (wndPtr, hdc); ReleaseDC32 (wndPtr->hwndSelf, hdc); IPADDRESS_SendIPAddressNotify (wndPtr, 0, 0); /* FIXME: should use -1 */ IPADDRESS_SendNotify (wndPtr, EN_KILLFOCUS); InvalidateRect32 (wndPtr->hwndSelf, NULL, TRUE); return 0; } static LRESULT IPADDRESS_Paint (WND *wndPtr, WPARAM32 wParam) { HDC32 hdc; PAINTSTRUCT32 ps; hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam; IPADDRESS_Refresh (wndPtr, hdc); if(!wParam) EndPaint32 (wndPtr->hwndSelf, &ps); return 0; } static LRESULT IPADDRESS_SetFocus (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { HDC32 hdc; TRACE (ipaddress,"\n"); hdc = GetDC32 (wndPtr->hwndSelf); IPADDRESS_Refresh (wndPtr, hdc); ReleaseDC32 (wndPtr->hwndSelf, hdc); return 0; } static LRESULT IPADDRESS_Size (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr); */ TRACE (ipaddress,"\n"); return 0; } static BOOL32 IPADDRESS_SendNotify (WND *wndPtr, UINT32 command) { TRACE (ipaddress, "%x\n",command); return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_COMMAND, MAKEWPARAM (wndPtr->wIDmenu,command), (LPARAM) wndPtr->hwndSelf); } static BOOL32 IPADDRESS_SendIPAddressNotify (WND *wndPtr, UINT32 field, BYTE newValue) { NMIPADDRESS nmip; TRACE (ipaddress, "%x %x\n",field,newValue); nmip.hdr.hwndFrom = wndPtr->hwndSelf; nmip.hdr.idFrom = wndPtr->wIDmenu; nmip.hdr.code = IPN_FIELDCHANGED; nmip.iField=field; nmip.iValue=newValue; return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY, (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmip); } static LRESULT IPADDRESS_ClearAddress (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { int i; HDC32 hdc; char buf[1]; LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP); TRACE (ipaddress,"\n"); buf[0]=0; for (i=0; i<=3; i++) SetWindowText32A (lpipsi->hwndIP[i],buf); hdc = GetDC32 (wndPtr->hwndSelf); IPADDRESS_Refresh (wndPtr, hdc); ReleaseDC32 (wndPtr->hwndSelf, hdc); return 0; } static LRESULT IPADDRESS_IsBlank (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { int i; char buf[20]; LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP); TRACE (ipaddress,"\n"); for (i=0; i<=3; i++) { GetWindowText32A (lpipsi->hwndIP[i],buf,5); if (buf[0]) return 0; } return 1; } static LRESULT IPADDRESS_GetAddress (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { char field[20]; int i,valid,fieldvalue; DWORD ip_addr; IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr); LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP); TRACE (ipaddress,"\n"); valid=0; ip_addr=0; for (i=0; i<=3; i++) { GetWindowText32A (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 (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr); INT32 index; TRACE (ipaddress,"\n"); index=(INT32) 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 (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { HDC32 hdc; IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr); LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) GetProp32A ((HWND32)wndPtr->hwndSelf,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); SetWindowText32A (lpipsi->hwndIP[i],buf); IPADDRESS_SendNotify (wndPtr, EN_CHANGE); } ip_address/=256; } hdc = GetDC32 (wndPtr->hwndSelf); /* & send notifications */ IPADDRESS_Refresh (wndPtr, hdc); ReleaseDC32 (wndPtr->hwndSelf, hdc); return TRUE; } static LRESULT IPADDRESS_SetFocusToField (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr); */ LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP); INT32 index; index=(INT32) wParam; TRACE (ipaddress," %d\n", index); if ((index<0) || (index>3)) return 0; SetFocus32 (lpipsi->hwndIP[index]); return 1; } static LRESULT IPADDRESS_LButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) { TRACE (ipaddress, "\n"); SetFocus32 (wndPtr->hwndSelf); IPADDRESS_SendNotify (wndPtr, EN_SETFOCUS); IPADDRESS_SetFocusToField (wndPtr, 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"); GetWindowText32A (lpipsi->hwndIP[currentfield],field,4); if (field[0]) { field[3]=0; newField=-1; fieldvalue=atoi(field); if (fieldvalueLowerLimit[currentfield]) newField=infoPtr->LowerLimit[currentfield]; if (fieldvalue>infoPtr->UpperLimit[currentfield]) newField=infoPtr->UpperLimit[currentfield]; if (newField>=0) { sprintf (field,"%d",newField); SetWindowText32A (lpipsi->hwndIP[currentfield], field); return 1; } } if (currentfield<3) SetFocus32 (lpipsi->hwndIP[currentfield+1]); return 0; } LRESULT CALLBACK IPADDRESS_SubclassProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam) { int i,l,index; IPADDRESS_INFO *infoPtr; LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO) GetProp32A ((HWND32)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) { HWND32 pwnd; int shift; shift = GetKeyState32(VK_SHIFT) & 0x8000; if (shift) pwnd=GetNextDlgTabItem32 (GetParent32 (hwnd), 0, TRUE); else pwnd=GetNextDlgTabItem32 (GetParent32 (hwnd), 0, FALSE); if (pwnd) SetFocus32 (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=GetWindowTextLength32A (lpipsi->hwndIP[index]); if (l==3) if (IPADDRESS_GotoNextField (lpipsi,index)) { wParam=0; lParam=0; } break; } wParam=0; lParam=0; break; } } return CallWindowProc32A (lpipsi->wpOrigProc[index], hwnd, uMsg, wParam, lParam); } LRESULT WINAPI IPADDRESS_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam) { WND *wndPtr = WIN_FindWndPtr(hwnd); switch (uMsg) { case IPM_CLEARADDRESS: return IPADDRESS_ClearAddress (wndPtr, wParam, lParam); case IPM_SETADDRESS: return IPADDRESS_SetAddress (wndPtr, wParam, lParam); case IPM_GETADDRESS: return IPADDRESS_GetAddress (wndPtr, wParam, lParam); case IPM_SETRANGE: return IPADDRESS_SetRange (wndPtr, wParam, lParam); case IPM_SETFOCUS: return IPADDRESS_SetFocusToField (wndPtr, wParam, lParam); case IPM_ISBLANK: return IPADDRESS_IsBlank (wndPtr, wParam, lParam); case WM_CREATE: return IPADDRESS_Create (wndPtr, wParam, lParam); case WM_DESTROY: return IPADDRESS_Destroy (wndPtr, wParam, lParam); case WM_GETDLGCODE: return DLGC_WANTARROWS | DLGC_WANTCHARS; case WM_KILLFOCUS: return IPADDRESS_KillFocus (wndPtr, wParam, lParam); case WM_LBUTTONDOWN: return IPADDRESS_LButtonDown (wndPtr, wParam, lParam); case WM_PAINT: return IPADDRESS_Paint (wndPtr, wParam); case WM_SETFOCUS: return IPADDRESS_SetFocus (wndPtr, wParam, lParam); case WM_SIZE: return IPADDRESS_Size (wndPtr, wParam, lParam); default: if (uMsg >= WM_USER) ERR (ipaddress, "unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); return DefWindowProc32A (hwnd, uMsg, wParam, lParam); } return 0; } void IPADDRESS_Register (void) { WNDCLASS32A wndClass; if (GlobalFindAtom32A (WC_IPADDRESS32A)) return; ZeroMemory (&wndClass, sizeof(WNDCLASS32A)); wndClass.style = CS_GLOBALCLASS; wndClass.lpfnWndProc = (WNDPROC32)IPADDRESS_WindowProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = sizeof(IPADDRESS_INFO *); wndClass.hCursor = LoadCursor32A (0, IDC_ARROW32A); wndClass.hbrBackground = (HBRUSH32)(COLOR_3DFACE + 1); wndClass.lpszClassName = WC_IPADDRESS32A; RegisterClass32A (&wndClass); } VOID IPADDRESS_Unregister (VOID) { if (GlobalFindAtom32A (WC_IPADDRESS32A)) UnregisterClass32A (WC_IPADDRESS32A, (HINSTANCE32)NULL); }