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.
31 #include "debugtools.h"
33 DEFAULT_DEBUG_CHANNEL(ipaddress
);
46 WNDPROC wpOrigProc
[4];
48 IPADDRESS_INFO
*infoPtr
;
51 } IP_SUBCLASS_INFO
, *LPIP_SUBCLASS_INFO
;
53 #define IPADDRESS_GetInfoPtr(hwnd) ((IPADDRESS_INFO *)GetWindowLongA (hwnd, 0))
56 IPADDRESS_SendNotify (HWND hwnd
, UINT command
);
58 IPADDRESS_SendIPAddressNotify (HWND hwnd
, UINT field
, BYTE newValue
);
60 /* property name of tooltip window handle */
61 #define IP_SUBCLASS_PROP "CCIP32SubclassInfo"
64 static LRESULT CALLBACK
65 IPADDRESS_SubclassProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
69 IPADDRESS_Refresh (HWND hwnd
, HDC hdc
)
73 COLORREF clr
=GetSysColor (COLOR_3DDKSHADOW
);
76 GetClientRect (hwnd
, &rcClient
);
77 hbr
= CreateSolidBrush (RGB(255,255,255));
78 DrawEdge (hdc
, &rcClient
, EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
);
79 FillRect (hdc
, &rcClient
, hbr
);
83 fieldsize
=(rcClient
.right
-rcClient
.left
) / 4;
85 for (i
=0; i
<3; i
++) { /* Should draw text "." here */
87 SetPixel (hdc
, x
, 13, clr
);
88 SetPixel (hdc
, x
, 14, clr
);
89 SetPixel (hdc
, x
+1, 13, clr
);
90 SetPixel (hdc
, x
+1, 14, clr
);
96 IPADDRESS_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
98 IPADDRESS_INFO
*infoPtr
;
101 LPIP_SUBCLASS_INFO lpipsi
;
104 infoPtr
= (IPADDRESS_INFO
*)COMCTL32_Alloc (sizeof(IPADDRESS_INFO
));
105 SetWindowLongA (hwnd
, 0, (DWORD
)infoPtr
);
107 GetClientRect (hwnd
, &rcClient
);
109 fieldsize
=(rcClient
.right
-rcClient
.left
) /4;
111 edit
.top
=rcClient
.top
+2;
112 edit
.bottom
=rcClient
.bottom
-2;
114 lpipsi
=(LPIP_SUBCLASS_INFO
) GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
115 if (lpipsi
== NULL
) {
116 lpipsi
= (LPIP_SUBCLASS_INFO
) COMCTL32_Alloc (sizeof(IP_SUBCLASS_INFO
));
119 SetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
, (HANDLE
)lpipsi
);
120 /* infoPtr->lpipsi= lpipsi; */
122 WARN("IP-create called twice\n");
126 infoPtr
->LowerLimit
[i
]=0;
127 infoPtr
->UpperLimit
[i
]=255;
128 edit
.left
=rcClient
.left
+i
*fieldsize
+6;
129 edit
.right
=rcClient
.left
+(i
+1)*fieldsize
-2;
130 lpipsi
->hwndIP
[i
]= CreateWindowA ("edit", NULL
,
131 WS_CHILD
| WS_VISIBLE
| ES_CENTER
,
132 edit
.left
, edit
.top
, edit
.right
-edit
.left
, edit
.bottom
-edit
.top
,
133 hwnd
, (HMENU
) 1, GetWindowLongA (hwnd
, GWL_HINSTANCE
), NULL
);
134 lpipsi
->wpOrigProc
[i
]= (WNDPROC
)
135 SetWindowLongA (lpipsi
->hwndIP
[i
],GWL_WNDPROC
, (LONG
)
136 IPADDRESS_SubclassProc
);
137 SetPropA ((HWND
)lpipsi
->hwndIP
[i
], IP_SUBCLASS_PROP
, (HANDLE
)lpipsi
);
140 lpipsi
->infoPtr
= infoPtr
;
147 IPADDRESS_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
150 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
151 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
152 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
154 for (i
=0; i
<=3; i
++) {
155 SetWindowLongA ((HWND
)lpipsi
->hwndIP
[i
], GWL_WNDPROC
,
156 (LONG
)lpipsi
->wpOrigProc
[i
]);
159 COMCTL32_Free (infoPtr
);
160 SetWindowLongA (hwnd
, 0, 0);
166 IPADDRESS_KillFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
172 IPADDRESS_Refresh (hwnd
, hdc
);
173 ReleaseDC (hwnd
, hdc
);
175 IPADDRESS_SendIPAddressNotify (hwnd
, 0, 0); /* FIXME: should use -1 */
176 IPADDRESS_SendNotify (hwnd
, EN_KILLFOCUS
);
177 InvalidateRect (hwnd
, NULL
, TRUE
);
184 IPADDRESS_Paint (HWND hwnd
, WPARAM wParam
)
189 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
190 IPADDRESS_Refresh (hwnd
, hdc
);
192 EndPaint (hwnd
, &ps
);
198 IPADDRESS_SetFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
205 IPADDRESS_Refresh (hwnd
, hdc
);
206 ReleaseDC (hwnd
, hdc
);
213 IPADDRESS_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
215 /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
222 IPADDRESS_SendNotify (HWND hwnd
, UINT command
)
224 TRACE("%x\n",command
);
225 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_COMMAND
,
226 MAKEWPARAM (GetWindowLongA (hwnd
, GWL_ID
),command
), (LPARAM
)hwnd
);
231 IPADDRESS_SendIPAddressNotify (HWND hwnd
, UINT field
, BYTE newValue
)
235 TRACE("%x %x\n",field
,newValue
);
236 nmip
.hdr
.hwndFrom
= hwnd
;
237 nmip
.hdr
.idFrom
= GetWindowLongA (hwnd
, GWL_ID
);
238 nmip
.hdr
.code
= IPN_FIELDCHANGED
;
241 nmip
.iValue
=newValue
;
243 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
244 (WPARAM
)nmip
.hdr
.idFrom
, (LPARAM
)&nmip
);
249 IPADDRESS_ClearAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
254 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
255 GetPropA ((HWND
)hwnd
,IP_SUBCLASS_PROP
);
261 SetWindowTextA (lpipsi
->hwndIP
[i
],buf
);
264 IPADDRESS_Refresh (hwnd
, hdc
);
265 ReleaseDC (hwnd
, hdc
);
272 IPADDRESS_IsBlank (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
276 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
277 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
281 for (i
=0; i
<=3; i
++) {
282 GetWindowTextA (lpipsi
->hwndIP
[i
],buf
,5);
292 IPADDRESS_GetAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
295 int i
,valid
,fieldvalue
;
297 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
298 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
299 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
305 for (i
=0; i
<=3; i
++) {
306 GetWindowTextA (lpipsi
->hwndIP
[i
],field
,4);
310 fieldvalue
=atoi(field
);
311 if (fieldvalue
<infoPtr
->LowerLimit
[i
])
312 fieldvalue
=infoPtr
->LowerLimit
[i
];
313 if (fieldvalue
>infoPtr
->UpperLimit
[i
])
314 fieldvalue
=infoPtr
->UpperLimit
[i
];
320 *(LPDWORD
) lParam
=ip_addr
;
327 IPADDRESS_SetRange (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
329 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
335 if ((index
<0) || (index
>3)) return 0;
337 infoPtr
->LowerLimit
[index
]=lParam
& 0xff;
338 infoPtr
->UpperLimit
[index
]=(lParam
>>8) & 0xff;
344 IPADDRESS_SetAddress (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
346 IPADDRESS_INFO
*infoPtr
= IPADDRESS_GetInfoPtr (hwnd
);
348 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
)
349 GetPropA ((HWND
)hwnd
, IP_SUBCLASS_PROP
);
350 int i
,ip_address
,value
;
354 ip_address
=(DWORD
) lParam
;
356 for (i
=3; i
>=0; i
--) {
357 value
=ip_address
& 0xff;
358 if ((value
>=infoPtr
->LowerLimit
[i
]) && (value
<=infoPtr
->UpperLimit
[i
]))
360 sprintf (buf
,"%d",value
);
361 SetWindowTextA (lpipsi
->hwndIP
[i
],buf
);
362 IPADDRESS_SendNotify (hwnd
, EN_CHANGE
);
367 hdc
= GetDC (hwnd
); /* & send notifications */
368 IPADDRESS_Refresh (hwnd
, hdc
);
369 ReleaseDC (hwnd
, hdc
);
376 IPADDRESS_SetFocusToField (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
378 /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
379 LPIP_SUBCLASS_INFO lpipsi
=(LPIP_SUBCLASS_INFO
) GetPropA ((HWND
)hwnd
,
384 TRACE(" %d\n", index
);
385 if ((index
<0) || (index
>3)) return 0;
387 SetFocus (lpipsi
->hwndIP
[index
]);
394 IPADDRESS_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
399 IPADDRESS_SendNotify (hwnd
, EN_SETFOCUS
);
400 IPADDRESS_SetFocusToField (hwnd
, 0, 0);
407 IPADDRESS_CheckField (LPIP_SUBCLASS_INFO lpipsi
, int currentfield
)
409 int newField
,fieldvalue
;
411 IPADDRESS_INFO
*infoPtr
=lpipsi
->infoPtr
;
413 if(currentfield
>= 0 && currentfield
< 4)
416 GetWindowTextA (lpipsi
->hwndIP
[currentfield
],field
,4);
421 fieldvalue
=atoi(field
);
423 if (fieldvalue
< infoPtr
->LowerLimit
[currentfield
])
424 newField
=infoPtr
->LowerLimit
[currentfield
];
426 if (fieldvalue
> infoPtr
->UpperLimit
[currentfield
])
427 newField
=infoPtr
->UpperLimit
[currentfield
];
431 sprintf (field
,"%d",newField
);
432 SetWindowTextA (lpipsi
->hwndIP
[currentfield
], field
);
442 IPADDRESS_GotoNextField (LPIP_SUBCLASS_INFO lpipsi
, int currentfield
)
444 if(currentfield
>= -1 && currentfield
< 4)
446 IPADDRESS_CheckField(lpipsi
, currentfield
); /* check the fields value */
450 SetFocus (lpipsi
->hwndIP
[currentfield
+1]);
458 /* period: move and select the text in the next field to the right if */
459 /* the current field is not empty(l!=0), we are not in the */
460 /* left most position, and nothing is selected(startsel==endsel) */
462 /* spacebar: same behavior as period */
464 /* alpha characters: completely ignored */
466 /* digits: accepted when field text length < 2 ignored otherwise. */
467 /* when 3 numbers have been entered into the field the value */
468 /* of the field is checked, if the field value exceeds the */
469 /* maximum value and is changed the field remains the current */
470 /* field, otherwise focus moves to the field to the right */
472 /* tab: change focus from the current ipaddress control to the next */
473 /* control in the tab order */
475 /* right arrow: move to the field on the right to the left most */
476 /* position in that field if no text is selected, */
477 /* we are in the right most position in the field, */
478 /* we are not in the right most field */
480 /* left arrow: move to the field on the left to the right most */
481 /* position in that field if no text is selected, */
482 /* we are in the left most position in the current field */
483 /* and we are not in the left most field */
485 /* backspace: delete the character to the left of the cursor position, */
486 /* if none are present move to the field on the left if */
487 /* we are not in the left most field and delete the right */
488 /* most digit in that field while keeping the cursor */
489 /* on the right side of the field */
493 IPADDRESS_SubclassProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
495 IPADDRESS_INFO
*infoPtr
;
496 LPIP_SUBCLASS_INFO lpipsi
= (LPIP_SUBCLASS_INFO
) GetPropA
497 ((HWND
)hwnd
,IP_SUBCLASS_PROP
);
498 CHAR c
= (CHAR
)wParam
;
499 INT i
, l
, index
, startsel
, endsel
;
501 infoPtr
= lpipsi
->infoPtr
;
504 if (lpipsi
->hwndIP
[i
]==hwnd
) index
=i
;
508 if(isdigit(c
)) /* process all digits */
511 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
512 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
513 if(l
==2 && startsel
==endsel
) /* field is full after this key is processed */
515 /* process the digit press before we check the field */
516 return_val
= CallWindowProcA (lpipsi
->wpOrigProc
[index
], hwnd
, uMsg
, wParam
, lParam
);
518 /* if the field value was changed stay at the current field */
519 if(!IPADDRESS_CheckField(lpipsi
, index
))
520 IPADDRESS_GotoNextField (lpipsi
,index
);
525 if(l
> 2) /* field is full, stop key messages */
533 if(c
== '.') /* VK_PERIOD */
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);
544 /* stop all other characters */
552 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
]);
553 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
554 if(l
!= 0 && startsel
==endsel
&& startsel
!= 0)
556 IPADDRESS_GotoNextField(lpipsi
, index
);
557 SendMessageA(lpipsi
->hwndIP
[index
+1], EM_SETSEL
, (WPARAM
)0, (LPARAM
)3);
563 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
564 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
566 if(startsel
==endsel
&& startsel
==l
)
568 IPADDRESS_GotoNextField(lpipsi
, index
);
569 SendMessageA(lpipsi
->hwndIP
[index
+1], EM_SETSEL
, (WPARAM
)0,(LPARAM
)0);
575 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
576 if(startsel
==0 && startsel
==endsel
&& index
> 0)
578 IPADDRESS_GotoNextField(lpipsi
, index
- 2);
579 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
-1]);
580 SendMessageA(lpipsi
->hwndIP
[index
-1], EM_SETSEL
, (WPARAM
)l
,(LPARAM
)l
);
584 if(c
== VK_BACK
) /* VK_BACKSPACE */
588 SendMessageA(lpipsi
->hwndIP
[index
], EM_GETSEL
, (WPARAM
)&startsel
, (LPARAM
)&endsel
);
589 l
= GetWindowTextLengthA (lpipsi
->hwndIP
[index
]);
590 if(startsel
==endsel
&& startsel
==0 && index
> 0)
592 l
= GetWindowTextLengthA(lpipsi
->hwndIP
[index
-1]);
595 GetWindowTextA (lpipsi
->hwndIP
[index
-1],buf
,4);
597 SetWindowTextA(lpipsi
->hwndIP
[index
-1], buf
);
598 SendMessageA(lpipsi
->hwndIP
[index
-1], EM_SETSEL
, (WPARAM
)l
,(LPARAM
)l
);
600 IPADDRESS_GotoNextField(lpipsi
, index
- 2);
608 return CallWindowProcA (lpipsi
->wpOrigProc
[index
], hwnd
, uMsg
, wParam
, lParam
);
612 static LRESULT WINAPI
613 IPADDRESS_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
615 TRACE("hwnd=%x msg=%x wparam=%x lparam=%lx\n", hwnd
, uMsg
, wParam
, lParam
);
616 if (!IPADDRESS_GetInfoPtr (hwnd
) && (uMsg
!= WM_CREATE
))
617 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
620 case IPM_CLEARADDRESS
:
621 return IPADDRESS_ClearAddress (hwnd
, wParam
, lParam
);
624 return IPADDRESS_SetAddress (hwnd
, wParam
, lParam
);
627 return IPADDRESS_GetAddress (hwnd
, wParam
, lParam
);
630 return IPADDRESS_SetRange (hwnd
, wParam
, lParam
);
633 return IPADDRESS_SetFocusToField (hwnd
, wParam
, lParam
);
636 return IPADDRESS_IsBlank (hwnd
, wParam
, lParam
);
639 return IPADDRESS_Create (hwnd
, wParam
, lParam
);
642 return IPADDRESS_Destroy (hwnd
, wParam
, lParam
);
645 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
648 return IPADDRESS_KillFocus (hwnd
, wParam
, lParam
);
651 return IPADDRESS_LButtonDown (hwnd
, wParam
, lParam
);
654 return IPADDRESS_Paint (hwnd
, wParam
);
657 return IPADDRESS_SetFocus (hwnd
, wParam
, lParam
);
660 return IPADDRESS_Size (hwnd
, wParam
, lParam
);
664 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
665 uMsg
, wParam
, lParam
);
666 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
672 void IPADDRESS_Register (void)
676 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
677 wndClass
.style
= CS_GLOBALCLASS
;
678 wndClass
.lpfnWndProc
= (WNDPROC
)IPADDRESS_WindowProc
;
679 wndClass
.cbClsExtra
= 0;
680 wndClass
.cbWndExtra
= sizeof(IPADDRESS_INFO
*);
681 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
682 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+ 1);
683 wndClass
.lpszClassName
= WC_IPADDRESSA
;
685 RegisterClassA (&wndClass
);
689 VOID
IPADDRESS_Unregister (void)
691 UnregisterClassA (WC_IPADDRESSA
, (HINSTANCE
)NULL
);