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.
29 #include "ipaddress.h"
31 #include "debugtools.h"
33 DEFAULT_DEBUG_CHANNEL(ipaddress
)
35 #define IPADDRESS_GetInfoPtr(hwnd) ((IPADDRESS_INFO *)GetWindowLongA (hwnd, 0))
38 IPADDRESS_SendNotify (HWND hwnd
, UINT command
);
40 IPADDRESS_SendIPAddressNotify (HWND hwnd
, UINT field
, BYTE newValue
);
42 /* property name of tooltip window handle */
43 #define IP_SUBCLASS_PROP "CCIP32SubclassInfo"
46 static LRESULT CALLBACK
47 IPADDRESS_SubclassProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
51 IPADDRESS_Refresh (HWND hwnd
, HDC hdc
)
55 COLORREF clr
=GetSysColor (COLOR_3DDKSHADOW
);
58 GetClientRect (hwnd
, &rcClient
);
59 hbr
= CreateSolidBrush (RGB(255,255,255));
60 DrawEdge (hdc
, &rcClient
, EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
);
61 FillRect (hdc
, &rcClient
, hbr
);
65 fieldsize
=(rcClient
.right
-rcClient
.left
) / 4;
67 for (i
=0; i
<3; i
++) { /* Should draw text "." here */
69 SetPixel (hdc
, x
, 13, clr
);
70 SetPixel (hdc
, x
, 14, clr
);
71 SetPixel (hdc
, x
+1, 13, clr
);
72 SetPixel (hdc
, x
+1, 14, clr
);
78 IPADDRESS_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
80 IPADDRESS_INFO
*infoPtr
;
83 LPIP_SUBCLASS_INFO lpipsi
;
86 infoPtr
= (IPADDRESS_INFO
*)COMCTL32_Alloc (sizeof(IPADDRESS_INFO
));
87 SetWindowLongA (hwnd
, 0, (DWORD
)infoPtr
);
89 GetClientRect (hwnd
, &rcClient
);
91 fieldsize
=(rcClient
.right
-rcClient
.left
) /4;
93 edit
.top
=rcClient
.top
+2;
94 edit
.bottom
=rcClient
.bottom
-2;
96 lpipsi
=(LPIP_SUBCLASS_INFO
) GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
98 lpipsi
= (LPIP_SUBCLASS_INFO
) COMCTL32_Alloc (sizeof(IP_SUBCLASS_INFO
));
101 SetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
, (HANDLE
)lpipsi
);
102 /* infoPtr->lpipsi= lpipsi; */
104 WARN("IP-create called twice\n");
108 infoPtr
->LowerLimit
[i
]=0;
109 infoPtr
->UpperLimit
[i
]=255;
110 edit
.left
=rcClient
.left
+i
*fieldsize
+6;
111 edit
.right
=rcClient
.left
+(i
+1)*fieldsize
-2;
112 lpipsi
->hwndIP
[i
]= CreateWindowA ("edit", NULL
,
113 WS_CHILD
| WS_VISIBLE
| ES_CENTER
,
114 edit
.left
, edit
.top
, edit
.right
-edit
.left
, edit
.bottom
-edit
.top
,
115 hwnd
, (HMENU
) 1, GetWindowLongA (hwnd
, GWL_HINSTANCE
), NULL
);
116 lpipsi
->wpOrigProc
[i
]= (WNDPROC
)
117 SetWindowLongA (lpipsi
->hwndIP
[i
],GWL_WNDPROC
, (LONG
)
118 IPADDRESS_SubclassProc
);
119 SetPropA ((HWND
)lpipsi
->hwndIP
[i
], IP_SUBCLASS_PROP
, (HANDLE
)lpipsi
);
122 lpipsi
->infoPtr
= infoPtr
;
129 IPADDRESS_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
132 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
133 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
134 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
136 for (i
=0; i
<=3; i
++) {
137 SetWindowLongA ((HWND
)lpipsi
->hwndIP
[i
], GWL_WNDPROC
,
138 (LONG
)lpipsi
->wpOrigProc
[i
]);
141 COMCTL32_Free (infoPtr
);
147 IPADDRESS_KillFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
153 IPADDRESS_Refresh (hwnd
, hdc
);
154 ReleaseDC (hwnd
, hdc
);
156 IPADDRESS_SendIPAddressNotify (hwnd
, 0, 0); /* FIXME: should use -1 */
157 IPADDRESS_SendNotify (hwnd
, EN_KILLFOCUS
);
158 InvalidateRect (hwnd
, NULL
, TRUE
);
165 IPADDRESS_Paint (HWND hwnd
, WPARAM wParam
)
170 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
171 IPADDRESS_Refresh (hwnd
, hdc
);
173 EndPaint (hwnd
, &ps
);
179 IPADDRESS_SetFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
186 IPADDRESS_Refresh (hwnd
, hdc
);
187 ReleaseDC (hwnd
, hdc
);
194 IPADDRESS_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
196 /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
203 IPADDRESS_SendNotify (HWND hwnd
, UINT command
)
205 TRACE("%x\n",command
);
206 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_COMMAND
,
207 MAKEWPARAM (GetWindowLongA (hwnd
, GWL_ID
),command
), (LPARAM
)hwnd
);
212 IPADDRESS_SendIPAddressNotify (HWND hwnd
, UINT field
, BYTE newValue
)
216 TRACE("%x %x\n",field
,newValue
);
217 nmip
.hdr
.hwndFrom
= hwnd
;
218 nmip
.hdr
.idFrom
= GetWindowLongA (hwnd
, GWL_ID
);
219 nmip
.hdr
.code
= IPN_FIELDCHANGED
;
222 nmip
.iValue
=newValue
;
224 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
225 (WPARAM
)nmip
.hdr
.idFrom
, (LPARAM
)&nmip
);
230 IPADDRESS_ClearAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
235 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
236 GetPropA ((HWND
)hwnd
,IP_SUBCLASS_PROP
);
242 SetWindowTextA (lpipsi
->hwndIP
[i
],buf
);
245 IPADDRESS_Refresh (hwnd
, hdc
);
246 ReleaseDC (hwnd
, hdc
);
253 IPADDRESS_IsBlank (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
257 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
258 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
262 for (i
=0; i
<=3; i
++) {
263 GetWindowTextA (lpipsi
->hwndIP
[i
],buf
,5);
273 IPADDRESS_GetAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
276 int i
,valid
,fieldvalue
;
278 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
279 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
280 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
286 for (i
=0; i
<=3; i
++) {
287 GetWindowTextA (lpipsi
->hwndIP
[i
],field
,4);
291 fieldvalue
=atoi(field
);
292 if (fieldvalue
<infoPtr
->LowerLimit
[i
])
293 fieldvalue
=infoPtr
->LowerLimit
[i
];
294 if (fieldvalue
>infoPtr
->UpperLimit
[i
])
295 fieldvalue
=infoPtr
->UpperLimit
[i
];
301 *(LPDWORD
) lParam
=ip_addr
;
308 IPADDRESS_SetRange (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
310 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
316 if ((index
<0) || (index
>3)) return 0;
318 infoPtr
->LowerLimit
[index
]=lParam
& 0xff;
319 infoPtr
->UpperLimit
[index
]=(lParam
>>8) & 0xff;
325 IPADDRESS_SetAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
327 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
329 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
330 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
331 int i
,ip_address
,value
;
335 ip_address
=(DWORD
) lParam
;
337 for (i
=3; i
>=0; i
--) {
338 value
=ip_address
& 0xff;
339 if ((value
>=infoPtr
->LowerLimit
[i
]) && (value
<=infoPtr
->UpperLimit
[i
]))
341 sprintf (buf
,"%d",value
);
342 SetWindowTextA (lpipsi
->hwndIP
[i
],buf
);
343 IPADDRESS_SendNotify (hwnd
, EN_CHANGE
);
348 hdc
= GetDC (hwnd
); /* & send notifications */
349 IPADDRESS_Refresh (hwnd
, hdc
);
350 ReleaseDC (hwnd
, hdc
);
357 IPADDRESS_SetFocusToField (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
359 /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
360 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
) GetPropA ((HWND
)hwnd
,
365 TRACE(" %d\n", index
);
366 if ((index
<0) || (index
>3)) return 0;
368 SetFocus (lpipsi
->hwndIP
[index
]);
375 IPADDRESS_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
380 IPADDRESS_SendNotify (hwnd
, EN_SETFOCUS
);
381 IPADDRESS_SetFocusToField (hwnd
, 0, 0);
388 IPADDRESS_CheckField (LPIP_SUBCLASS_INFO lpipsi
, int currentfield
)
390 int newField
,fieldvalue
;
392 IPADDRESS_INFO
*infoPtr
=lpipsi
->infoPtr
;
394 if(currentfield
>= 0 && currentfield
< 4)
397 GetWindowTextA (lpipsi
->hwndIP
[currentfield
],field
,4);
402 fieldvalue
=atoi(field
);
404 if (fieldvalue
< infoPtr
->LowerLimit
[currentfield
])
405 newField
=infoPtr
->LowerLimit
[currentfield
];
407 if (fieldvalue
> infoPtr
->UpperLimit
[currentfield
])
408 newField
=infoPtr
->UpperLimit
[currentfield
];
412 sprintf (field
,"%d",newField
);
413 SetWindowTextA (lpipsi
->hwndIP
[currentfield
], field
);
423 IPADDRESS_GotoNextField (LPIP_SUBCLASS_INFO lpipsi
, int currentfield
)
425 if(currentfield
>= -1 && currentfield
< 4)
427 IPADDRESS_CheckField(lpipsi
, currentfield
); /* check the fields value */
431 SetFocus (lpipsi
->hwndIP
[currentfield
+1]);
439 /* period: move and select the text in the next field to the right if */
440 /* the current field is not empty(l!=0), we are not in the */
441 /* left most position, and nothing is selected(startsel==endsel) */
443 /* spacebar: same behavior as period */
445 /* alpha characters: completely ignored */
447 /* digits: accepted when field text length < 2 ignored otherwise. */
448 /* when 3 numbers have been entered into the field the value */
449 /* of the field is checked, if the field value exceeds the */
450 /* maximum value and is changed the field remains the current */
451 /* field, otherwise focus moves to the field to the right */
453 /* tab: change focus from the current ipaddress control to the next */
454 /* control in the tab order */
456 /* right arrow: move to the field on the right to the left most */
457 /* position in that field if no text is selected, */
458 /* we are in the right most position in the field, */
459 /* we are not in the right most field */
461 /* left arrow: move to the field on the left to the right most */
462 /* position in that field if no text is selected, */
463 /* we are in the left most position in the current field */
464 /* and we are not in the left most field */
466 /* backspace: delete the character to the left of the cursor position, */
467 /* if none are present move to the field on the left if */
468 /* we are not in the left most field and delete the right */
469 /* most digit in that field while keeping the cursor */
470 /* on the right side of the field */
474 IPADDRESS_SubclassProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
476 IPADDRESS_INFO
*infoPtr
;
477 LPIP_SUBCLASS_INFO lpipsi
= (LPIP_SUBCLASS_INFO
) GetPropA
478 ((HWND
)hwnd
,IP_SUBCLASS_PROP
);
479 CHAR c
= (CHAR
)wParam
;
480 INT i
, l
, index
, startsel
, endsel
;
482 infoPtr
= lpipsi
->infoPtr
;
485 if (lpipsi
->hwndIP
[i
]==hwnd
) index
=i
;
489 if(isdigit(c
)) /* process all digits */
492 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
493 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
494 if(l
==2 && startsel
==endsel
) /* field is full after this key is processed */
496 /* process the digit press before we check the field */
497 return_val
= CallWindowProcA (lpipsi
->wpOrigProc
[index
], hwnd
, uMsg
, wParam
, lParam
);
499 /* if the field value was changed stay at the current field */
500 if(!IPADDRESS_CheckField(lpipsi
, index
))
501 IPADDRESS_GotoNextField (lpipsi
,index
);
506 if(l
> 2) /* field is full, stop key messages */
514 if(c
== '.') /* VK_PERIOD */
516 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
]);
517 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
518 if(l
!= 0 && startsel
==endsel
&& startsel
!= 0)
520 IPADDRESS_GotoNextField(lpipsi
, index
);
521 SendMessageA(lpipsi
->hwndIP
[index
+1], EM_SETSEL
, (WPARAM
)0, (LPARAM
)3);
525 /* stop all other characters */
533 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
]);
534 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
535 if(l
!= 0 && startsel
==endsel
&& startsel
!= 0)
537 IPADDRESS_GotoNextField(lpipsi
, index
);
538 SendMessageA(lpipsi
->hwndIP
[index
+1], EM_SETSEL
, (WPARAM
)0, (LPARAM
)3);
544 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
545 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
547 if(startsel
==endsel
&& startsel
==l
)
549 IPADDRESS_GotoNextField(lpipsi
, index
);
550 SendMessageA(lpipsi
->hwndIP
[index
+1], EM_SETSEL
, (WPARAM
)0,(LPARAM
)0);
556 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
557 if(startsel
==0 && startsel
==endsel
&& index
> 0)
559 IPADDRESS_GotoNextField(lpipsi
, index
- 2);
560 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
-1]);
561 SendMessageA(lpipsi
->hwndIP
[index
-1], EM_SETSEL
, (WPARAM
)l
,(LPARAM
)l
);
565 if(c
== VK_BACK
) /* VK_BACKSPACE */
569 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
570 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
571 if(startsel
==endsel
&& startsel
==0 && index
> 0)
573 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
-1]);
576 GetWindowTextA (lpipsi
->hwndIP
[index
-1],buf
,4);
578 SetWindowTextA(lpipsi
->hwndIP
[index
-1], buf
);
579 SendMessageA(lpipsi
->hwndIP
[index
-1], EM_SETSEL
, (WPARAM
)l
,(LPARAM
)l
);
581 IPADDRESS_GotoNextField(lpipsi
, index
- 2);
589 return CallWindowProcA (lpipsi
->wpOrigProc
[index
], hwnd
, uMsg
, wParam
, lParam
);
594 IPADDRESS_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
598 case IPM_CLEARADDRESS
:
599 return IPADDRESS_ClearAddress (hwnd
, wParam
, lParam
);
602 return IPADDRESS_SetAddress (hwnd
, wParam
, lParam
);
605 return IPADDRESS_GetAddress (hwnd
, wParam
, lParam
);
608 return IPADDRESS_SetRange (hwnd
, wParam
, lParam
);
611 return IPADDRESS_SetFocusToField (hwnd
, wParam
, lParam
);
614 return IPADDRESS_IsBlank (hwnd
, wParam
, lParam
);
617 return IPADDRESS_Create (hwnd
, wParam
, lParam
);
620 return IPADDRESS_Destroy (hwnd
, wParam
, lParam
);
623 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
626 return IPADDRESS_KillFocus (hwnd
, wParam
, lParam
);
629 return IPADDRESS_LButtonDown (hwnd
, wParam
, lParam
);
632 return IPADDRESS_Paint (hwnd
, wParam
);
635 return IPADDRESS_SetFocus (hwnd
, wParam
, lParam
);
638 return IPADDRESS_Size (hwnd
, wParam
, lParam
);
642 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
643 uMsg
, wParam
, lParam
);
644 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
650 void IPADDRESS_Register (void)
654 if (GlobalFindAtomA (WC_IPADDRESSA
)) return;
656 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
657 wndClass
.style
= CS_GLOBALCLASS
;
658 wndClass
.lpfnWndProc
= (WNDPROC
)IPADDRESS_WindowProc
;
659 wndClass
.cbClsExtra
= 0;
660 wndClass
.cbWndExtra
= sizeof(IPADDRESS_INFO
*);
661 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
662 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+ 1);
663 wndClass
.lpszClassName
= WC_IPADDRESSA
;
665 RegisterClassA (&wndClass
);
669 VOID
IPADDRESS_Unregister (void)
671 if (GlobalFindAtomA (WC_IPADDRESSA
))
672 UnregisterClassA (WC_IPADDRESSA
, (HINSTANCE
)NULL
);