4 * Copyright 1999 Chris Morgan<cmorgan@wpi.edu> and
5 * James Abbatiello<abbeyj@wpi.edu>
6 * Copyright 1998, 1999 Eric Kohl
7 * Copyright 1998 Alex Priem <alexp@sci.kun.nl>
12 * -Edit control doesn't support the ES_CENTER style which prevents
13 * this ipaddress control from having centered text look like the
14 * windows ipaddress control
15 * -Check all notifications/behavior.
17 * -include lpipsi in IPADDRESS_INFO.
18 * -CurrentFocus: field that has focus at moment of processing.
19 * -connect Rect32 rcClient.
20 * -check ipaddress.cpp for missing features.
21 * -refresh: draw '.' instead of setpixel.
30 #include "ipaddress.h"
32 #include "debugtools.h"
34 DEFAULT_DEBUG_CHANNEL(ipaddress
);
36 #define IPADDRESS_GetInfoPtr(hwnd) ((IPADDRESS_INFO *)GetWindowLongA (hwnd, 0))
39 IPADDRESS_SendNotify (HWND hwnd
, UINT command
);
41 IPADDRESS_SendIPAddressNotify (HWND hwnd
, UINT field
, BYTE newValue
);
43 /* property name of tooltip window handle */
44 #define IP_SUBCLASS_PROP "CCIP32SubclassInfo"
47 static LRESULT CALLBACK
48 IPADDRESS_SubclassProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
52 IPADDRESS_Refresh (HWND hwnd
, HDC hdc
)
56 COLORREF clr
=GetSysColor (COLOR_3DDKSHADOW
);
59 GetClientRect (hwnd
, &rcClient
);
60 hbr
= CreateSolidBrush (RGB(255,255,255));
61 DrawEdge (hdc
, &rcClient
, EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
);
62 FillRect (hdc
, &rcClient
, hbr
);
66 fieldsize
=(rcClient
.right
-rcClient
.left
) / 4;
68 for (i
=0; i
<3; i
++) { /* Should draw text "." here */
70 SetPixel (hdc
, x
, 13, clr
);
71 SetPixel (hdc
, x
, 14, clr
);
72 SetPixel (hdc
, x
+1, 13, clr
);
73 SetPixel (hdc
, x
+1, 14, clr
);
79 IPADDRESS_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
81 IPADDRESS_INFO
*infoPtr
;
84 LPIP_SUBCLASS_INFO lpipsi
;
87 infoPtr
= (IPADDRESS_INFO
*)COMCTL32_Alloc (sizeof(IPADDRESS_INFO
));
88 SetWindowLongA (hwnd
, 0, (DWORD
)infoPtr
);
90 GetClientRect (hwnd
, &rcClient
);
92 fieldsize
=(rcClient
.right
-rcClient
.left
) /4;
94 edit
.top
=rcClient
.top
+2;
95 edit
.bottom
=rcClient
.bottom
-2;
97 lpipsi
=(LPIP_SUBCLASS_INFO
) GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
99 lpipsi
= (LPIP_SUBCLASS_INFO
) COMCTL32_Alloc (sizeof(IP_SUBCLASS_INFO
));
102 SetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
, (HANDLE
)lpipsi
);
103 /* infoPtr->lpipsi= lpipsi; */
105 WARN("IP-create called twice\n");
109 infoPtr
->LowerLimit
[i
]=0;
110 infoPtr
->UpperLimit
[i
]=255;
111 edit
.left
=rcClient
.left
+i
*fieldsize
+6;
112 edit
.right
=rcClient
.left
+(i
+1)*fieldsize
-2;
113 lpipsi
->hwndIP
[i
]= CreateWindowA ("edit", NULL
,
114 WS_CHILD
| WS_VISIBLE
| ES_CENTER
,
115 edit
.left
, edit
.top
, edit
.right
-edit
.left
, edit
.bottom
-edit
.top
,
116 hwnd
, (HMENU
) 1, GetWindowLongA (hwnd
, GWL_HINSTANCE
), NULL
);
117 lpipsi
->wpOrigProc
[i
]= (WNDPROC
)
118 SetWindowLongA (lpipsi
->hwndIP
[i
],GWL_WNDPROC
, (LONG
)
119 IPADDRESS_SubclassProc
);
120 SetPropA ((HWND
)lpipsi
->hwndIP
[i
], IP_SUBCLASS_PROP
, (HANDLE
)lpipsi
);
123 lpipsi
->infoPtr
= infoPtr
;
130 IPADDRESS_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
133 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
134 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
135 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
137 for (i
=0; i
<=3; i
++) {
138 SetWindowLongA ((HWND
)lpipsi
->hwndIP
[i
], GWL_WNDPROC
,
139 (LONG
)lpipsi
->wpOrigProc
[i
]);
142 COMCTL32_Free (infoPtr
);
143 SetWindowLongA (hwnd
, 0, 0);
149 IPADDRESS_KillFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
155 IPADDRESS_Refresh (hwnd
, hdc
);
156 ReleaseDC (hwnd
, hdc
);
158 IPADDRESS_SendIPAddressNotify (hwnd
, 0, 0); /* FIXME: should use -1 */
159 IPADDRESS_SendNotify (hwnd
, EN_KILLFOCUS
);
160 InvalidateRect (hwnd
, NULL
, TRUE
);
167 IPADDRESS_Paint (HWND hwnd
, WPARAM wParam
)
172 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
173 IPADDRESS_Refresh (hwnd
, hdc
);
175 EndPaint (hwnd
, &ps
);
181 IPADDRESS_SetFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
188 IPADDRESS_Refresh (hwnd
, hdc
);
189 ReleaseDC (hwnd
, hdc
);
196 IPADDRESS_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
198 /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
205 IPADDRESS_SendNotify (HWND hwnd
, UINT command
)
207 TRACE("%x\n",command
);
208 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_COMMAND
,
209 MAKEWPARAM (GetWindowLongA (hwnd
, GWL_ID
),command
), (LPARAM
)hwnd
);
214 IPADDRESS_SendIPAddressNotify (HWND hwnd
, UINT field
, BYTE newValue
)
218 TRACE("%x %x\n",field
,newValue
);
219 nmip
.hdr
.hwndFrom
= hwnd
;
220 nmip
.hdr
.idFrom
= GetWindowLongA (hwnd
, GWL_ID
);
221 nmip
.hdr
.code
= IPN_FIELDCHANGED
;
224 nmip
.iValue
=newValue
;
226 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
227 (WPARAM
)nmip
.hdr
.idFrom
, (LPARAM
)&nmip
);
232 IPADDRESS_ClearAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
237 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
238 GetPropA ((HWND
)hwnd
,IP_SUBCLASS_PROP
);
244 SetWindowTextA (lpipsi
->hwndIP
[i
],buf
);
247 IPADDRESS_Refresh (hwnd
, hdc
);
248 ReleaseDC (hwnd
, hdc
);
255 IPADDRESS_IsBlank (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
259 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
260 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
264 for (i
=0; i
<=3; i
++) {
265 GetWindowTextA (lpipsi
->hwndIP
[i
],buf
,5);
275 IPADDRESS_GetAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
278 int i
,valid
,fieldvalue
;
280 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
281 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
282 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
288 for (i
=0; i
<=3; i
++) {
289 GetWindowTextA (lpipsi
->hwndIP
[i
],field
,4);
293 fieldvalue
=atoi(field
);
294 if (fieldvalue
<infoPtr
->LowerLimit
[i
])
295 fieldvalue
=infoPtr
->LowerLimit
[i
];
296 if (fieldvalue
>infoPtr
->UpperLimit
[i
])
297 fieldvalue
=infoPtr
->UpperLimit
[i
];
303 *(LPDWORD
) lParam
=ip_addr
;
310 IPADDRESS_SetRange (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
312 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
318 if ((index
<0) || (index
>3)) return 0;
320 infoPtr
->LowerLimit
[index
]=lParam
& 0xff;
321 infoPtr
->UpperLimit
[index
]=(lParam
>>8) & 0xff;
327 IPADDRESS_SetAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
329 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
331 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
332 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
333 int i
,ip_address
,value
;
337 ip_address
=(DWORD
) lParam
;
339 for (i
=3; i
>=0; i
--) {
340 value
=ip_address
& 0xff;
341 if ((value
>=infoPtr
->LowerLimit
[i
]) && (value
<=infoPtr
->UpperLimit
[i
]))
343 sprintf (buf
,"%d",value
);
344 SetWindowTextA (lpipsi
->hwndIP
[i
],buf
);
345 IPADDRESS_SendNotify (hwnd
, EN_CHANGE
);
350 hdc
= GetDC (hwnd
); /* & send notifications */
351 IPADDRESS_Refresh (hwnd
, hdc
);
352 ReleaseDC (hwnd
, hdc
);
359 IPADDRESS_SetFocusToField (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
361 /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
362 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
) GetPropA ((HWND
)hwnd
,
367 TRACE(" %d\n", index
);
368 if ((index
<0) || (index
>3)) return 0;
370 SetFocus (lpipsi
->hwndIP
[index
]);
377 IPADDRESS_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
382 IPADDRESS_SendNotify (hwnd
, EN_SETFOCUS
);
383 IPADDRESS_SetFocusToField (hwnd
, 0, 0);
390 IPADDRESS_CheckField (LPIP_SUBCLASS_INFO lpipsi
, int currentfield
)
392 int newField
,fieldvalue
;
394 IPADDRESS_INFO
*infoPtr
=lpipsi
->infoPtr
;
396 if(currentfield
>= 0 && currentfield
< 4)
399 GetWindowTextA (lpipsi
->hwndIP
[currentfield
],field
,4);
404 fieldvalue
=atoi(field
);
406 if (fieldvalue
< infoPtr
->LowerLimit
[currentfield
])
407 newField
=infoPtr
->LowerLimit
[currentfield
];
409 if (fieldvalue
> infoPtr
->UpperLimit
[currentfield
])
410 newField
=infoPtr
->UpperLimit
[currentfield
];
414 sprintf (field
,"%d",newField
);
415 SetWindowTextA (lpipsi
->hwndIP
[currentfield
], field
);
425 IPADDRESS_GotoNextField (LPIP_SUBCLASS_INFO lpipsi
, int currentfield
)
427 if(currentfield
>= -1 && currentfield
< 4)
429 IPADDRESS_CheckField(lpipsi
, currentfield
); /* check the fields value */
433 SetFocus (lpipsi
->hwndIP
[currentfield
+1]);
441 /* period: move and select the text in the next field to the right if */
442 /* the current field is not empty(l!=0), we are not in the */
443 /* left most position, and nothing is selected(startsel==endsel) */
445 /* spacebar: same behavior as period */
447 /* alpha characters: completely ignored */
449 /* digits: accepted when field text length < 2 ignored otherwise. */
450 /* when 3 numbers have been entered into the field the value */
451 /* of the field is checked, if the field value exceeds the */
452 /* maximum value and is changed the field remains the current */
453 /* field, otherwise focus moves to the field to the right */
455 /* tab: change focus from the current ipaddress control to the next */
456 /* control in the tab order */
458 /* right arrow: move to the field on the right to the left most */
459 /* position in that field if no text is selected, */
460 /* we are in the right most position in the field, */
461 /* we are not in the right most field */
463 /* left arrow: move to the field on the left to the right most */
464 /* position in that field if no text is selected, */
465 /* we are in the left most position in the current field */
466 /* and we are not in the left most field */
468 /* backspace: delete the character to the left of the cursor position, */
469 /* if none are present move to the field on the left if */
470 /* we are not in the left most field and delete the right */
471 /* most digit in that field while keeping the cursor */
472 /* on the right side of the field */
476 IPADDRESS_SubclassProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
478 IPADDRESS_INFO
*infoPtr
;
479 LPIP_SUBCLASS_INFO lpipsi
= (LPIP_SUBCLASS_INFO
) GetPropA
480 ((HWND
)hwnd
,IP_SUBCLASS_PROP
);
481 CHAR c
= (CHAR
)wParam
;
482 INT i
, l
, index
, startsel
, endsel
;
484 infoPtr
= lpipsi
->infoPtr
;
487 if (lpipsi
->hwndIP
[i
]==hwnd
) index
=i
;
491 if(isdigit(c
)) /* process all digits */
494 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
495 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
496 if(l
==2 && startsel
==endsel
) /* field is full after this key is processed */
498 /* process the digit press before we check the field */
499 return_val
= CallWindowProcA (lpipsi
->wpOrigProc
[index
], hwnd
, uMsg
, wParam
, lParam
);
501 /* if the field value was changed stay at the current field */
502 if(!IPADDRESS_CheckField(lpipsi
, index
))
503 IPADDRESS_GotoNextField (lpipsi
,index
);
508 if(l
> 2) /* field is full, stop key messages */
516 if(c
== '.') /* VK_PERIOD */
518 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
]);
519 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
520 if(l
!= 0 && startsel
==endsel
&& startsel
!= 0)
522 IPADDRESS_GotoNextField(lpipsi
, index
);
523 SendMessageA(lpipsi
->hwndIP
[index
+1], EM_SETSEL
, (WPARAM
)0, (LPARAM
)3);
527 /* stop all other characters */
535 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
]);
536 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
537 if(l
!= 0 && startsel
==endsel
&& startsel
!= 0)
539 IPADDRESS_GotoNextField(lpipsi
, index
);
540 SendMessageA(lpipsi
->hwndIP
[index
+1], EM_SETSEL
, (WPARAM
)0, (LPARAM
)3);
546 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
547 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
549 if(startsel
==endsel
&& startsel
==l
)
551 IPADDRESS_GotoNextField(lpipsi
, index
);
552 SendMessageA(lpipsi
->hwndIP
[index
+1], EM_SETSEL
, (WPARAM
)0,(LPARAM
)0);
558 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
559 if(startsel
==0 && startsel
==endsel
&& index
> 0)
561 IPADDRESS_GotoNextField(lpipsi
, index
- 2);
562 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
-1]);
563 SendMessageA(lpipsi
->hwndIP
[index
-1], EM_SETSEL
, (WPARAM
)l
,(LPARAM
)l
);
567 if(c
== VK_BACK
) /* VK_BACKSPACE */
571 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
572 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
573 if(startsel
==endsel
&& startsel
==0 && index
> 0)
575 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
-1]);
578 GetWindowTextA (lpipsi
->hwndIP
[index
-1],buf
,4);
580 SetWindowTextA(lpipsi
->hwndIP
[index
-1], buf
);
581 SendMessageA(lpipsi
->hwndIP
[index
-1], EM_SETSEL
, (WPARAM
)l
,(LPARAM
)l
);
583 IPADDRESS_GotoNextField(lpipsi
, index
- 2);
591 return CallWindowProcA (lpipsi
->wpOrigProc
[index
], hwnd
, uMsg
, wParam
, lParam
);
595 static LRESULT WINAPI
596 IPADDRESS_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
598 TRACE("hwnd=%x msg=%x wparam=%x lparam=%lx\n", hwnd
, uMsg
, wParam
, lParam
);
599 if (!IPADDRESS_GetInfoPtr (hwnd
) && (uMsg
!= WM_CREATE
))
600 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
603 case IPM_CLEARADDRESS
:
604 return IPADDRESS_ClearAddress (hwnd
, wParam
, lParam
);
607 return IPADDRESS_SetAddress (hwnd
, wParam
, lParam
);
610 return IPADDRESS_GetAddress (hwnd
, wParam
, lParam
);
613 return IPADDRESS_SetRange (hwnd
, wParam
, lParam
);
616 return IPADDRESS_SetFocusToField (hwnd
, wParam
, lParam
);
619 return IPADDRESS_IsBlank (hwnd
, wParam
, lParam
);
622 return IPADDRESS_Create (hwnd
, wParam
, lParam
);
625 return IPADDRESS_Destroy (hwnd
, wParam
, lParam
);
628 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
631 return IPADDRESS_KillFocus (hwnd
, wParam
, lParam
);
634 return IPADDRESS_LButtonDown (hwnd
, wParam
, lParam
);
637 return IPADDRESS_Paint (hwnd
, wParam
);
640 return IPADDRESS_SetFocus (hwnd
, wParam
, lParam
);
643 return IPADDRESS_Size (hwnd
, wParam
, lParam
);
647 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
648 uMsg
, wParam
, lParam
);
649 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
655 void IPADDRESS_Register (void)
659 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
660 wndClass
.style
= CS_GLOBALCLASS
;
661 wndClass
.lpfnWndProc
= (WNDPROC
)IPADDRESS_WindowProc
;
662 wndClass
.cbClsExtra
= 0;
663 wndClass
.cbWndExtra
= sizeof(IPADDRESS_INFO
*);
664 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
665 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+ 1);
666 wndClass
.lpszClassName
= WC_IPADDRESSA
;
668 RegisterClassA (&wndClass
);
672 VOID
IPADDRESS_Unregister (void)
674 UnregisterClassA (WC_IPADDRESSA
, (HINSTANCE
)NULL
);