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
);
148 IPADDRESS_KillFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
154 IPADDRESS_Refresh (hwnd
, hdc
);
155 ReleaseDC (hwnd
, hdc
);
157 IPADDRESS_SendIPAddressNotify (hwnd
, 0, 0); /* FIXME: should use -1 */
158 IPADDRESS_SendNotify (hwnd
, EN_KILLFOCUS
);
159 InvalidateRect (hwnd
, NULL
, TRUE
);
166 IPADDRESS_Paint (HWND hwnd
, WPARAM wParam
)
171 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
172 IPADDRESS_Refresh (hwnd
, hdc
);
174 EndPaint (hwnd
, &ps
);
180 IPADDRESS_SetFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
187 IPADDRESS_Refresh (hwnd
, hdc
);
188 ReleaseDC (hwnd
, hdc
);
195 IPADDRESS_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
197 /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
204 IPADDRESS_SendNotify (HWND hwnd
, UINT command
)
206 TRACE("%x\n",command
);
207 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_COMMAND
,
208 MAKEWPARAM (GetWindowLongA (hwnd
, GWL_ID
),command
), (LPARAM
)hwnd
);
213 IPADDRESS_SendIPAddressNotify (HWND hwnd
, UINT field
, BYTE newValue
)
217 TRACE("%x %x\n",field
,newValue
);
218 nmip
.hdr
.hwndFrom
= hwnd
;
219 nmip
.hdr
.idFrom
= GetWindowLongA (hwnd
, GWL_ID
);
220 nmip
.hdr
.code
= IPN_FIELDCHANGED
;
223 nmip
.iValue
=newValue
;
225 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
226 (WPARAM
)nmip
.hdr
.idFrom
, (LPARAM
)&nmip
);
231 IPADDRESS_ClearAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
236 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
237 GetPropA ((HWND
)hwnd
,IP_SUBCLASS_PROP
);
243 SetWindowTextA (lpipsi
->hwndIP
[i
],buf
);
246 IPADDRESS_Refresh (hwnd
, hdc
);
247 ReleaseDC (hwnd
, hdc
);
254 IPADDRESS_IsBlank (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
258 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
259 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
263 for (i
=0; i
<=3; i
++) {
264 GetWindowTextA (lpipsi
->hwndIP
[i
],buf
,5);
274 IPADDRESS_GetAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
277 int i
,valid
,fieldvalue
;
279 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
280 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
281 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
287 for (i
=0; i
<=3; i
++) {
288 GetWindowTextA (lpipsi
->hwndIP
[i
],field
,4);
292 fieldvalue
=atoi(field
);
293 if (fieldvalue
<infoPtr
->LowerLimit
[i
])
294 fieldvalue
=infoPtr
->LowerLimit
[i
];
295 if (fieldvalue
>infoPtr
->UpperLimit
[i
])
296 fieldvalue
=infoPtr
->UpperLimit
[i
];
302 *(LPDWORD
) lParam
=ip_addr
;
309 IPADDRESS_SetRange (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
311 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
317 if ((index
<0) || (index
>3)) return 0;
319 infoPtr
->LowerLimit
[index
]=lParam
& 0xff;
320 infoPtr
->UpperLimit
[index
]=(lParam
>>8) & 0xff;
326 IPADDRESS_SetAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
328 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
330 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
331 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
332 int i
,ip_address
,value
;
336 ip_address
=(DWORD
) lParam
;
338 for (i
=3; i
>=0; i
--) {
339 value
=ip_address
& 0xff;
340 if ((value
>=infoPtr
->LowerLimit
[i
]) && (value
<=infoPtr
->UpperLimit
[i
]))
342 sprintf (buf
,"%d",value
);
343 SetWindowTextA (lpipsi
->hwndIP
[i
],buf
);
344 IPADDRESS_SendNotify (hwnd
, EN_CHANGE
);
349 hdc
= GetDC (hwnd
); /* & send notifications */
350 IPADDRESS_Refresh (hwnd
, hdc
);
351 ReleaseDC (hwnd
, hdc
);
358 IPADDRESS_SetFocusToField (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
360 /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
361 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
) GetPropA ((HWND
)hwnd
,
366 TRACE(" %d\n", index
);
367 if ((index
<0) || (index
>3)) return 0;
369 SetFocus (lpipsi
->hwndIP
[index
]);
376 IPADDRESS_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
381 IPADDRESS_SendNotify (hwnd
, EN_SETFOCUS
);
382 IPADDRESS_SetFocusToField (hwnd
, 0, 0);
389 IPADDRESS_CheckField (LPIP_SUBCLASS_INFO lpipsi
, int currentfield
)
391 int newField
,fieldvalue
;
393 IPADDRESS_INFO
*infoPtr
=lpipsi
->infoPtr
;
395 if(currentfield
>= 0 && currentfield
< 4)
398 GetWindowTextA (lpipsi
->hwndIP
[currentfield
],field
,4);
403 fieldvalue
=atoi(field
);
405 if (fieldvalue
< infoPtr
->LowerLimit
[currentfield
])
406 newField
=infoPtr
->LowerLimit
[currentfield
];
408 if (fieldvalue
> infoPtr
->UpperLimit
[currentfield
])
409 newField
=infoPtr
->UpperLimit
[currentfield
];
413 sprintf (field
,"%d",newField
);
414 SetWindowTextA (lpipsi
->hwndIP
[currentfield
], field
);
424 IPADDRESS_GotoNextField (LPIP_SUBCLASS_INFO lpipsi
, int currentfield
)
426 if(currentfield
>= -1 && currentfield
< 4)
428 IPADDRESS_CheckField(lpipsi
, currentfield
); /* check the fields value */
432 SetFocus (lpipsi
->hwndIP
[currentfield
+1]);
440 /* period: move and select the text in the next field to the right if */
441 /* the current field is not empty(l!=0), we are not in the */
442 /* left most position, and nothing is selected(startsel==endsel) */
444 /* spacebar: same behavior as period */
446 /* alpha characters: completely ignored */
448 /* digits: accepted when field text length < 2 ignored otherwise. */
449 /* when 3 numbers have been entered into the field the value */
450 /* of the field is checked, if the field value exceeds the */
451 /* maximum value and is changed the field remains the current */
452 /* field, otherwise focus moves to the field to the right */
454 /* tab: change focus from the current ipaddress control to the next */
455 /* control in the tab order */
457 /* right arrow: move to the field on the right to the left most */
458 /* position in that field if no text is selected, */
459 /* we are in the right most position in the field, */
460 /* we are not in the right most field */
462 /* left arrow: move to the field on the left to the right most */
463 /* position in that field if no text is selected, */
464 /* we are in the left most position in the current field */
465 /* and we are not in the left most field */
467 /* backspace: delete the character to the left of the cursor position, */
468 /* if none are present move to the field on the left if */
469 /* we are not in the left most field and delete the right */
470 /* most digit in that field while keeping the cursor */
471 /* on the right side of the field */
475 IPADDRESS_SubclassProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
477 IPADDRESS_INFO
*infoPtr
;
478 LPIP_SUBCLASS_INFO lpipsi
= (LPIP_SUBCLASS_INFO
) GetPropA
479 ((HWND
)hwnd
,IP_SUBCLASS_PROP
);
480 CHAR c
= (CHAR
)wParam
;
481 INT i
, l
, index
, startsel
, endsel
;
483 infoPtr
= lpipsi
->infoPtr
;
486 if (lpipsi
->hwndIP
[i
]==hwnd
) index
=i
;
490 if(isdigit(c
)) /* process all digits */
493 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
494 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
495 if(l
==2 && startsel
==endsel
) /* field is full after this key is processed */
497 /* process the digit press before we check the field */
498 return_val
= CallWindowProcA (lpipsi
->wpOrigProc
[index
], hwnd
, uMsg
, wParam
, lParam
);
500 /* if the field value was changed stay at the current field */
501 if(!IPADDRESS_CheckField(lpipsi
, index
))
502 IPADDRESS_GotoNextField (lpipsi
,index
);
507 if(l
> 2) /* field is full, stop key messages */
515 if(c
== '.') /* VK_PERIOD */
517 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
]);
518 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
519 if(l
!= 0 && startsel
==endsel
&& startsel
!= 0)
521 IPADDRESS_GotoNextField(lpipsi
, index
);
522 SendMessageA(lpipsi
->hwndIP
[index
+1], EM_SETSEL
, (WPARAM
)0, (LPARAM
)3);
526 /* stop all other characters */
534 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
]);
535 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
536 if(l
!= 0 && startsel
==endsel
&& startsel
!= 0)
538 IPADDRESS_GotoNextField(lpipsi
, index
);
539 SendMessageA(lpipsi
->hwndIP
[index
+1], EM_SETSEL
, (WPARAM
)0, (LPARAM
)3);
545 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
546 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
548 if(startsel
==endsel
&& startsel
==l
)
550 IPADDRESS_GotoNextField(lpipsi
, index
);
551 SendMessageA(lpipsi
->hwndIP
[index
+1], EM_SETSEL
, (WPARAM
)0,(LPARAM
)0);
557 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
558 if(startsel
==0 && startsel
==endsel
&& index
> 0)
560 IPADDRESS_GotoNextField(lpipsi
, index
- 2);
561 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
-1]);
562 SendMessageA(lpipsi
->hwndIP
[index
-1], EM_SETSEL
, (WPARAM
)l
,(LPARAM
)l
);
566 if(c
== VK_BACK
) /* VK_BACKSPACE */
570 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
571 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
572 if(startsel
==endsel
&& startsel
==0 && index
> 0)
574 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
-1]);
577 GetWindowTextA (lpipsi
->hwndIP
[index
-1],buf
,4);
579 SetWindowTextA(lpipsi
->hwndIP
[index
-1], buf
);
580 SendMessageA(lpipsi
->hwndIP
[index
-1], EM_SETSEL
, (WPARAM
)l
,(LPARAM
)l
);
582 IPADDRESS_GotoNextField(lpipsi
, index
- 2);
590 return CallWindowProcA (lpipsi
->wpOrigProc
[index
], hwnd
, uMsg
, wParam
, lParam
);
594 static LRESULT WINAPI
595 IPADDRESS_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
599 case IPM_CLEARADDRESS
:
600 return IPADDRESS_ClearAddress (hwnd
, wParam
, lParam
);
603 return IPADDRESS_SetAddress (hwnd
, wParam
, lParam
);
606 return IPADDRESS_GetAddress (hwnd
, wParam
, lParam
);
609 return IPADDRESS_SetRange (hwnd
, wParam
, lParam
);
612 return IPADDRESS_SetFocusToField (hwnd
, wParam
, lParam
);
615 return IPADDRESS_IsBlank (hwnd
, wParam
, lParam
);
618 return IPADDRESS_Create (hwnd
, wParam
, lParam
);
621 return IPADDRESS_Destroy (hwnd
, wParam
, lParam
);
624 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
627 return IPADDRESS_KillFocus (hwnd
, wParam
, lParam
);
630 return IPADDRESS_LButtonDown (hwnd
, wParam
, lParam
);
633 return IPADDRESS_Paint (hwnd
, wParam
);
636 return IPADDRESS_SetFocus (hwnd
, wParam
, lParam
);
639 return IPADDRESS_Size (hwnd
, wParam
, lParam
);
643 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
644 uMsg
, wParam
, lParam
);
645 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
651 void IPADDRESS_Register (void)
655 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
656 wndClass
.style
= CS_GLOBALCLASS
;
657 wndClass
.lpfnWndProc
= (WNDPROC
)IPADDRESS_WindowProc
;
658 wndClass
.cbClsExtra
= 0;
659 wndClass
.cbWndExtra
= sizeof(IPADDRESS_INFO
*);
660 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
661 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+ 1);
662 wndClass
.lpszClassName
= WC_IPADDRESSA
;
664 RegisterClassA (&wndClass
);
668 VOID
IPADDRESS_Unregister (void)
670 UnregisterClassA (WC_IPADDRESSA
, (HINSTANCE
)NULL
);