Fixed a silly VGA-emulation palette bug.
[wine/multimedia.git] / dlls / comctl32 / ipaddress.c
blob85a0893cdd63b479b0e24bf1e1d156c3a19c640c
1 /*
2 * IP Address control
4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1998 Alex Priem <alexp@sci.kun.nl>
7 * NOTES
10 * TODO:
11 * -Check ranges when changing field-focus.
12 * -Check all notifications/behavior.
13 * -Optimization: include lpipsi in IPADDRESS_INFO.
14 * -CurrentFocus: field that has focus at moment of processing.
15 * -connect Rect32 rcClient.
16 * -handle right and left arrows correctly. Boring.
17 * -split GotoNextField in CheckField and GotoNextField.
18 * -check ipaddress.cpp for missing features.
19 * -refresh: draw '.' instead of setpixel.
20 * -handle VK_ESCAPE.
23 #include <ctype.h>
24 #include <stdlib.h>
26 #include "win.h"
27 #include "commctrl.h"
28 #include "ipaddress.h"
29 #include "heap.h"
30 #include "debug.h"
33 #define IPADDRESS_GetInfoPtr(hwnd) ((IPADDRESS_INFO *)GetWindowLongA (hwnd, 0))
36 static BOOL
37 IPADDRESS_SendNotify (HWND hwnd, UINT command);
38 static BOOL
39 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);
52 static VOID
53 IPADDRESS_Refresh (HWND hwnd, HDC hdc)
55 RECT rcClient;
56 HBRUSH hbr;
57 COLORREF clr=GetSysColor (COLOR_3DDKSHADOW);
58 int i,x,fieldsize;
60 GetClientRect (hwnd, &rcClient);
61 hbr = CreateSolidBrush (RGB(255,255,255));
62 DrawEdge (hdc, &rcClient, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
63 FillRect (hdc, &rcClient, hbr);
64 DeleteObject (hbr);
66 x=rcClient.left;
67 fieldsize=(rcClient.right-rcClient.left) /4;
69 for (i=0; i<3; i++) { /* Should draw text "." here */
70 x+=fieldsize;
71 SetPixel (hdc, x, 13, clr);
72 SetPixel (hdc, x, 14, clr);
73 SetPixel (hdc, x+1, 13, clr);
74 SetPixel (hdc, x+1, 14, clr);
84 static LRESULT
85 IPADDRESS_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
87 IPADDRESS_INFO *infoPtr;
88 RECT rcClient, edit;
89 int i,fieldsize;
90 LPIP_SUBCLASS_INFO lpipsi;
93 infoPtr = (IPADDRESS_INFO *)COMCTL32_Alloc (sizeof(IPADDRESS_INFO));
94 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
96 GetClientRect (hwnd, &rcClient);
98 fieldsize=(rcClient.right-rcClient.left) /4;
100 edit.top =rcClient.top+2;
101 edit.bottom=rcClient.bottom-2;
103 lpipsi=(LPIP_SUBCLASS_INFO)
104 GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
105 if (lpipsi == NULL) {
106 lpipsi= (LPIP_SUBCLASS_INFO) COMCTL32_Alloc (sizeof(IP_SUBCLASS_INFO));
107 lpipsi->hwnd = hwnd;
108 lpipsi->uRefCount++;
109 SetPropA ((HWND)hwnd, IP_SUBCLASS_PROP,
110 (HANDLE)lpipsi);
111 /* infoPtr->lpipsi= lpipsi; */
112 } else
113 WARN (ipaddress,"IP-create called twice\n");
115 for (i=0; i<=3; i++) {
116 infoPtr->LowerLimit[i]=0;
117 infoPtr->UpperLimit[i]=255;
118 edit.left=rcClient.left+i*fieldsize+3;
119 edit.right=rcClient.left+(i+1)*fieldsize-2;
120 lpipsi->hwndIP[i]= CreateWindowA ("edit", NULL,
121 WS_CHILD | WS_VISIBLE | ES_LEFT,
122 edit.left, edit.top, edit.right-edit.left, edit.bottom-edit.top,
123 hwnd, (HMENU) 1, GetWindowLongA (hwnd, GWL_HINSTANCE), NULL);
124 lpipsi->wpOrigProc[i]= (WNDPROC)
125 SetWindowLongA (lpipsi->hwndIP[i],GWL_WNDPROC, (LONG)
126 IPADDRESS_SubclassProc);
127 SetPropA ((HWND)lpipsi->hwndIP[i], IP_SUBCLASS_PROP,
128 (HANDLE)lpipsi);
131 lpipsi->infoPtr= infoPtr;
133 return 0;
137 static LRESULT
138 IPADDRESS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
140 int i;
141 IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
142 LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
143 GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
145 for (i=0; i<=3; i++) {
146 SetWindowLongA ((HWND)lpipsi->hwndIP[i], GWL_WNDPROC,
147 (LONG)lpipsi->wpOrigProc[i]);
150 COMCTL32_Free (infoPtr);
151 return 0;
155 static LRESULT
156 IPADDRESS_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
158 HDC hdc;
160 TRACE (ipaddress,"\n");
161 hdc = GetDC (hwnd);
162 IPADDRESS_Refresh (hwnd, hdc);
163 ReleaseDC (hwnd, hdc);
165 IPADDRESS_SendIPAddressNotify (hwnd, 0, 0); /* FIXME: should use -1 */
166 IPADDRESS_SendNotify (hwnd, EN_KILLFOCUS);
167 InvalidateRect (hwnd, NULL, TRUE);
169 return 0;
173 static LRESULT
174 IPADDRESS_Paint (HWND hwnd, WPARAM wParam)
176 HDC hdc;
177 PAINTSTRUCT ps;
179 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
180 IPADDRESS_Refresh (hwnd, hdc);
181 if(!wParam)
182 EndPaint (hwnd, &ps);
183 return 0;
187 static LRESULT
188 IPADDRESS_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
190 HDC hdc;
192 TRACE (ipaddress,"\n");
194 hdc = GetDC (hwnd);
195 IPADDRESS_Refresh (hwnd, hdc);
196 ReleaseDC (hwnd, hdc);
198 return 0;
202 static LRESULT
203 IPADDRESS_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
205 /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
206 TRACE (ipaddress,"\n");
207 return 0;
211 static BOOL
212 IPADDRESS_SendNotify (HWND hwnd, UINT command)
215 TRACE (ipaddress, "%x\n",command);
216 return (BOOL)SendMessageA (GetParent (hwnd), WM_COMMAND,
217 MAKEWPARAM (GetWindowLongA (hwnd, GWL_ID),command), (LPARAM)hwnd);
221 static BOOL
222 IPADDRESS_SendIPAddressNotify (HWND hwnd, UINT field, BYTE newValue)
224 NMIPADDRESS nmip;
226 TRACE (ipaddress, "%x %x\n",field,newValue);
227 nmip.hdr.hwndFrom = hwnd;
228 nmip.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
229 nmip.hdr.code = IPN_FIELDCHANGED;
231 nmip.iField=field;
232 nmip.iValue=newValue;
234 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
235 (WPARAM)nmip.hdr.idFrom, (LPARAM)&nmip);
241 static LRESULT
242 IPADDRESS_ClearAddress (HWND hwnd, WPARAM wParam, LPARAM lParam)
244 int i;
245 HDC hdc;
246 char buf[1];
247 LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
248 GetPropA ((HWND)hwnd,IP_SUBCLASS_PROP);
250 TRACE (ipaddress,"\n");
252 buf[0]=0;
253 for (i=0; i<=3; i++)
254 SetWindowTextA (lpipsi->hwndIP[i],buf);
256 hdc = GetDC (hwnd);
257 IPADDRESS_Refresh (hwnd, hdc);
258 ReleaseDC (hwnd, hdc);
260 return 0;
263 static LRESULT
264 IPADDRESS_IsBlank (HWND hwnd, WPARAM wParam, LPARAM lParam)
266 int i;
267 char buf[20];
268 LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
269 GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
271 TRACE (ipaddress,"\n");
273 for (i=0; i<=3; i++) {
274 GetWindowTextA (lpipsi->hwndIP[i],buf,5);
275 if (buf[0])
276 return 0;
279 return 1;
282 static LRESULT
283 IPADDRESS_GetAddress (HWND hwnd, WPARAM wParam, LPARAM lParam)
285 char field[20];
286 int i,valid,fieldvalue;
287 DWORD ip_addr;
288 IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
289 LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
290 GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
292 TRACE (ipaddress,"\n");
294 valid=0;
295 ip_addr=0;
296 for (i=0; i<=3; i++) {
297 GetWindowTextA (lpipsi->hwndIP[i],field,4);
298 ip_addr*=256;
299 if (field[0]) {
300 field[3]=0;
301 fieldvalue=atoi(field);
302 if (fieldvalue<infoPtr->LowerLimit[i])
303 fieldvalue=infoPtr->LowerLimit[i];
304 if (fieldvalue>infoPtr->UpperLimit[i])
305 fieldvalue=infoPtr->UpperLimit[i];
306 ip_addr+=fieldvalue;
307 valid++;
311 *(LPDWORD) lParam=ip_addr;
313 return valid;
317 static LRESULT
318 IPADDRESS_SetRange (HWND hwnd, WPARAM wParam, LPARAM lParam)
320 IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
321 INT index;
323 TRACE (ipaddress,"\n");
325 index=(INT) wParam;
326 if ((index<0) || (index>3)) return 0;
328 infoPtr->LowerLimit[index]=lParam & 0xff;
329 infoPtr->UpperLimit[index]=(lParam >>8) & 0xff;
330 return 1;
333 static LRESULT
334 IPADDRESS_SetAddress (HWND hwnd, WPARAM wParam, LPARAM lParam)
336 IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd);
337 HDC hdc;
338 LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
339 GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
340 int i,ip_address,value;
341 char buf[20];
343 TRACE (ipaddress,"\n");
344 ip_address=(DWORD) lParam;
346 for (i=3; i>=0; i--) {
347 value=ip_address & 0xff;
348 if ((value>=infoPtr->LowerLimit[i]) && (value<=infoPtr->UpperLimit[i]))
350 sprintf (buf,"%d",value);
351 SetWindowTextA (lpipsi->hwndIP[i],buf);
352 IPADDRESS_SendNotify (hwnd, EN_CHANGE);
354 ip_address/=256;
357 hdc = GetDC (hwnd); /* & send notifications */
358 IPADDRESS_Refresh (hwnd, hdc);
359 ReleaseDC (hwnd, hdc);
361 return TRUE;
367 static LRESULT
368 IPADDRESS_SetFocusToField (HWND hwnd, WPARAM wParam, LPARAM lParam)
370 /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr (hwnd); */
371 LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
372 GetPropA ((HWND)hwnd, IP_SUBCLASS_PROP);
373 INT index;
375 index=(INT) wParam;
376 TRACE (ipaddress," %d\n", index);
377 if ((index<0) || (index>3)) return 0;
379 SetFocus (lpipsi->hwndIP[index]);
381 return 1;
385 static LRESULT
386 IPADDRESS_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
388 TRACE (ipaddress, "\n");
390 SetFocus (hwnd);
391 IPADDRESS_SendNotify (hwnd, EN_SETFOCUS);
392 IPADDRESS_SetFocusToField (hwnd, 0, 0);
394 return TRUE;
399 /* tab/shift-tab: IPN_FIELDCHANGED, lose focus.
400 dot, space,right arrow: set focus to next child edit.
401 numerics (0..9), control characters: forward to default edit control
402 other characters: dropped
408 static int
409 IPADDRESS_GotoNextField (LPIP_SUBCLASS_INFO lpipsi, int currentfield)
411 int newField,fieldvalue;
412 char field[20];
413 IPADDRESS_INFO *infoPtr=lpipsi->infoPtr;
415 TRACE (ipaddress,"\n");
416 GetWindowTextA (lpipsi->hwndIP[currentfield],field,4);
417 if (field[0]) {
418 field[3]=0;
419 newField=-1;
420 fieldvalue=atoi(field);
421 if (fieldvalue<infoPtr->LowerLimit[currentfield])
422 newField=infoPtr->LowerLimit[currentfield];
423 if (fieldvalue>infoPtr->UpperLimit[currentfield])
424 newField=infoPtr->UpperLimit[currentfield];
425 if (newField>=0) {
426 sprintf (field,"%d",newField);
427 SetWindowTextA (lpipsi->hwndIP[currentfield], field);
428 return 1;
432 if (currentfield<3)
433 SetFocus (lpipsi->hwndIP[currentfield+1]);
434 return 0;
438 LRESULT CALLBACK
439 IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
441 int i,l,index;
442 IPADDRESS_INFO *infoPtr;
443 LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
444 GetPropA ((HWND)hwnd,IP_SUBCLASS_PROP);
446 infoPtr = lpipsi->infoPtr;
447 index=0; /* FIXME */
448 for (i=0; i<=3; i++)
449 if (lpipsi->hwndIP[i]==hwnd) index=i;
451 switch (uMsg) {
452 case WM_CHAR: break;
453 case WM_KEYDOWN: {
454 char c=(char) wParam;
455 if (c==VK_TAB) {
456 HWND pwnd;
457 int shift;
458 shift = GetKeyState(VK_SHIFT) & 0x8000;
459 if (shift)
460 pwnd=GetNextDlgTabItem (GetParent (hwnd), 0, TRUE);
461 else
462 pwnd=GetNextDlgTabItem (GetParent (hwnd), 0, FALSE);
463 if (pwnd) SetFocus (pwnd);
464 break;
467 if ((c==' ') || (c=='.') || (c==VK_RIGHT)) {
468 IPADDRESS_GotoNextField (lpipsi,index);
469 wParam=0;
470 lParam=0;
471 break;
473 if (c==VK_LEFT) {
476 if (c==VK_RETURN) {
478 if (((c>='0') && (c<='9')) || (iscntrl(c))) {
479 l=GetWindowTextLengthA (lpipsi->hwndIP[index]);
480 if (l==3)
481 if (IPADDRESS_GotoNextField (lpipsi,index)) {
482 wParam=0;
483 lParam=0;
485 break;
488 wParam=0;
489 lParam=0;
490 break;
494 return CallWindowProcA (lpipsi->wpOrigProc[index], hwnd, uMsg, wParam, lParam);
497 LRESULT WINAPI
498 IPADDRESS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
500 switch (uMsg)
502 case IPM_CLEARADDRESS:
503 return IPADDRESS_ClearAddress (hwnd, wParam, lParam);
505 case IPM_SETADDRESS:
506 return IPADDRESS_SetAddress (hwnd, wParam, lParam);
508 case IPM_GETADDRESS:
509 return IPADDRESS_GetAddress (hwnd, wParam, lParam);
511 case IPM_SETRANGE:
512 return IPADDRESS_SetRange (hwnd, wParam, lParam);
514 case IPM_SETFOCUS:
515 return IPADDRESS_SetFocusToField (hwnd, wParam, lParam);
517 case IPM_ISBLANK:
518 return IPADDRESS_IsBlank (hwnd, wParam, lParam);
520 case WM_CREATE:
521 return IPADDRESS_Create (hwnd, wParam, lParam);
523 case WM_DESTROY:
524 return IPADDRESS_Destroy (hwnd, wParam, lParam);
526 case WM_GETDLGCODE:
527 return DLGC_WANTARROWS | DLGC_WANTCHARS;
529 case WM_KILLFOCUS:
530 return IPADDRESS_KillFocus (hwnd, wParam, lParam);
532 case WM_LBUTTONDOWN:
533 return IPADDRESS_LButtonDown (hwnd, wParam, lParam);
535 case WM_PAINT:
536 return IPADDRESS_Paint (hwnd, wParam);
538 case WM_SETFOCUS:
539 return IPADDRESS_SetFocus (hwnd, wParam, lParam);
541 case WM_SIZE:
542 return IPADDRESS_Size (hwnd, wParam, lParam);
544 default:
545 if (uMsg >= WM_USER)
546 ERR (ipaddress, "unknown msg %04x wp=%08x lp=%08lx\n",
547 uMsg, wParam, lParam);
548 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
550 return 0;
554 void
555 IPADDRESS_Register (void)
557 WNDCLASSA wndClass;
559 if (GlobalFindAtomA (WC_IPADDRESSA)) return;
561 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
562 wndClass.style = CS_GLOBALCLASS;
563 wndClass.lpfnWndProc = (WNDPROC)IPADDRESS_WindowProc;
564 wndClass.cbClsExtra = 0;
565 wndClass.cbWndExtra = sizeof(IPADDRESS_INFO *);
566 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
567 wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
568 wndClass.lpszClassName = WC_IPADDRESSA;
570 RegisterClassA (&wndClass);
573 VOID
574 IPADDRESS_Unregister (VOID)
576 if (GlobalFindAtomA (WC_IPADDRESSA))
577 UnregisterClassA (WC_IPADDRESSA, (HINSTANCE)NULL);