- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
[wine] / dlls / comctl32 / ipaddress.c
1 /* IP Address control
2  *
3  * Copyright 1998 Eric Kohl
4  * Copyright 1998 Alex Priem <alexp@sci.kun.nl>
5  *
6  * NOTES
7
8  *
9  * TODO:
10  *    -Check ranges when changing field-focus.
11  *        -Check all notifications/behavior.
12  *    -Optimization: include lpipsi in IPADDRESS_INFO.
13  *        -CurrentFocus: field that has focus at moment of processing.
14  *        -connect Rect32 rcClient.
15  *        -handle right and left arrows correctly. Boring.
16  *        -split GotoNextField in CheckField and GotoNextField.
17  *        -check ipaddress.cpp for missing features.
18  *    -refresh: draw '.' instead of setpixel.
19  *        -handle VK_ESCAPE.
20  */
21
22 #include <ctype.h>
23 #include <stdlib.h>
24
25 #include "win.h"
26 #include "commctrl.h"
27 #include "ipaddress.h"
28 #include "heap.h"
29 #include "debug.h"
30
31
32 #define IPADDRESS_GetInfoPtr(wndPtr) ((IPADDRESS_INFO *)wndPtr->wExtra[0])
33
34
35 static BOOL32 
36 IPADDRESS_SendNotify (WND *wndPtr, UINT32 command);
37 static BOOL32 
38 IPADDRESS_SendIPAddressNotify (WND *wndPtr, UINT32 field, BYTE newValue);
39
40
41 /* property name of tooltip window handle */
42 #define IP_SUBCLASS_PROP "CCIP32SubclassInfo"
43
44
45 static LRESULT CALLBACK
46 IPADDRESS_SubclassProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam);
47
48
49
50
51 static VOID
52 IPADDRESS_Refresh (WND *wndPtr, HDC32 hdc)
53 {
54         RECT32 rcClient;
55         HBRUSH32 hbr;
56         COLORREF clr=GetSysColor32 (COLOR_3DDKSHADOW);
57     int i,x,fieldsize;
58
59     GetClientRect32 (wndPtr->hwndSelf, &rcClient);
60         hbr =  CreateSolidBrush32 (RGB(255,255,255));
61     DrawEdge32 (hdc, &rcClient, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
62         FillRect32 (hdc, &rcClient, hbr);
63     DeleteObject32 (hbr);
64
65         x=rcClient.left;
66         fieldsize=(rcClient.right-rcClient.left) /4;
67
68         for (i=0; i<3; i++) {           /* Should draw text "." here */
69                 x+=fieldsize;
70                 SetPixel32 (hdc, x,   13, clr);
71                 SetPixel32 (hdc, x,   14, clr);
72                 SetPixel32 (hdc, x+1, 13, clr);
73                 SetPixel32 (hdc, x+1, 14, clr);
74
75         }
76
77 }
78
79
80
81
82
83 static LRESULT
84 IPADDRESS_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
85 {
86     IPADDRESS_INFO *infoPtr;
87         RECT32 rcClient, edit;
88         int i,fieldsize;
89         LPIP_SUBCLASS_INFO lpipsi;
90         
91
92     infoPtr = (IPADDRESS_INFO *)COMCTL32_Alloc (sizeof(IPADDRESS_INFO));
93     wndPtr->wExtra[0] = (DWORD)infoPtr;
94
95         if (infoPtr == NULL) {
96         ERR (ipaddress, "could not allocate info memory!\n");
97         return 0;
98     }
99
100     GetClientRect32 (wndPtr->hwndSelf, &rcClient);
101
102         fieldsize=(rcClient.right-rcClient.left) /4;
103
104         edit.top   =rcClient.top+2;
105         edit.bottom=rcClient.bottom-2;
106
107         lpipsi=(LPIP_SUBCLASS_INFO)
108                         GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP);
109         if (lpipsi == NULL)  {
110                 lpipsi= (LPIP_SUBCLASS_INFO) COMCTL32_Alloc (sizeof(IP_SUBCLASS_INFO));
111                 lpipsi->wndPtr=wndPtr;
112                 lpipsi->uRefCount++;
113                 SetProp32A ((HWND32)wndPtr->hwndSelf, IP_SUBCLASS_PROP,
114                                         (HANDLE32)lpipsi);
115 /*              infoPtr->lpipsi= lpipsi; */
116         } else 
117                 WARN (ipaddress,"IP-create called twice\n");
118         
119         for (i=0; i<=3; i++) {
120                 infoPtr->LowerLimit[i]=0;
121                 infoPtr->UpperLimit[i]=255;
122                 edit.left=rcClient.left+i*fieldsize+3;
123                 edit.right=rcClient.left+(i+1)*fieldsize-2;
124                 lpipsi->hwndIP[i]= CreateWindow32A ("edit", NULL, 
125                                 WS_CHILD | WS_VISIBLE | ES_LEFT,
126                                 edit.left, edit.top, edit.right-edit.left, edit.bottom-edit.top,
127                                 wndPtr->hwndSelf, (HMENU32) 1, wndPtr->hInstance, NULL);
128                 lpipsi->wpOrigProc[i]= (WNDPROC32)
129                                         SetWindowLong32A (lpipsi->hwndIP[i],GWL_WNDPROC, (LONG)
130                                         IPADDRESS_SubclassProc);
131                 SetProp32A ((HWND32)lpipsi->hwndIP[i], IP_SUBCLASS_PROP,
132                                         (HANDLE32)lpipsi);
133         }
134
135         lpipsi->infoPtr= infoPtr;
136
137     return 0;
138 }
139
140
141 static LRESULT
142 IPADDRESS_Destroy (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
143 {
144         int i;
145     IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr);
146         LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
147             GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP);
148
149         for (i=0; i<=3; i++) {
150                 SetWindowLong32A ((HWND32)lpipsi->hwndIP[i], GWL_WNDPROC,
151                   (LONG)lpipsi->wpOrigProc[i]);
152         }
153
154     COMCTL32_Free (infoPtr);
155     return 0;
156 }
157
158
159 static LRESULT
160 IPADDRESS_KillFocus (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
161 {
162     HDC32 hdc;
163
164         TRACE (ipaddress,"\n");
165     hdc = GetDC32 (wndPtr->hwndSelf);
166     IPADDRESS_Refresh (wndPtr, hdc);
167     ReleaseDC32 (wndPtr->hwndSelf, hdc);
168
169         IPADDRESS_SendIPAddressNotify (wndPtr, 0, 0);  /* FIXME: should use -1 */
170         IPADDRESS_SendNotify (wndPtr, EN_KILLFOCUS);       
171     InvalidateRect32 (wndPtr->hwndSelf, NULL, TRUE);
172
173     return 0;
174 }
175
176
177 static LRESULT
178 IPADDRESS_Paint (WND *wndPtr, WPARAM32 wParam)
179 {
180     HDC32 hdc;
181     PAINTSTRUCT32 ps;
182
183     hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
184     IPADDRESS_Refresh (wndPtr, hdc);
185     if(!wParam)
186         EndPaint32 (wndPtr->hwndSelf, &ps);
187     return 0;
188 }
189
190
191 static LRESULT
192 IPADDRESS_SetFocus (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
193 {
194     HDC32 hdc;
195
196         TRACE (ipaddress,"\n");
197
198     hdc = GetDC32 (wndPtr->hwndSelf);
199     IPADDRESS_Refresh (wndPtr, hdc);
200     ReleaseDC32 (wndPtr->hwndSelf, hdc);
201
202     return 0;
203 }
204
205
206 static LRESULT
207 IPADDRESS_Size (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
208 {
209     /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr); */
210         TRACE (ipaddress,"\n");
211     return 0;
212 }
213
214
215 static BOOL32
216 IPADDRESS_SendNotify (WND *wndPtr, UINT32 command)
217
218 {
219     TRACE (ipaddress, "%x\n",command);
220     return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_COMMAND,
221               MAKEWPARAM (wndPtr->wIDmenu,command), (LPARAM) wndPtr->hwndSelf);
222 }
223
224
225 static BOOL32
226 IPADDRESS_SendIPAddressNotify (WND *wndPtr, UINT32 field, BYTE newValue)
227
228 {
229         NMIPADDRESS nmip;
230
231     TRACE (ipaddress, "%x %x\n",field,newValue);
232     nmip.hdr.hwndFrom = wndPtr->hwndSelf;
233     nmip.hdr.idFrom   = wndPtr->wIDmenu;
234     nmip.hdr.code     = IPN_FIELDCHANGED;
235
236         nmip.iField=field;
237         nmip.iValue=newValue;
238
239     return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
240                                    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmip);
241 }
242
243
244
245
246 static LRESULT
247 IPADDRESS_ClearAddress (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
248 {
249         int i;
250         HDC32 hdc;
251         char buf[1];
252         LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
253             GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP);
254
255         TRACE (ipaddress,"\n");
256
257         buf[0]=0;
258         for (i=0; i<=3; i++) 
259                 SetWindowText32A (lpipsi->hwndIP[i],buf);
260         
261         hdc = GetDC32 (wndPtr->hwndSelf);
262     IPADDRESS_Refresh (wndPtr, hdc);
263     ReleaseDC32 (wndPtr->hwndSelf, hdc);
264         return 0;
265 }
266
267 static LRESULT
268 IPADDRESS_IsBlank (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
269 {
270  int i;
271  char buf[20];
272  LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
273             GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP);
274
275  TRACE (ipaddress,"\n");
276
277  for (i=0; i<=3; i++) {
278                 GetWindowText32A (lpipsi->hwndIP[i],buf,5);
279                 if (buf[0]) return 0;
280         }
281
282  return 1;
283 }
284
285 static LRESULT
286 IPADDRESS_GetAddress (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
287 {
288  char field[20];
289  int i,valid,fieldvalue;
290  DWORD ip_addr;
291  IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr);
292  LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
293             GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP);
294
295  TRACE (ipaddress,"\n");
296
297  valid=0;
298  ip_addr=0;
299  for (i=0; i<=3; i++) {
300                 GetWindowText32A (lpipsi->hwndIP[i],field,4);
301                 ip_addr*=256;
302                 if (field[0]) {
303                         field[3]=0;
304                         fieldvalue=atoi(field);
305                         if (fieldvalue<infoPtr->LowerLimit[i]) 
306                                 fieldvalue=infoPtr->LowerLimit[i];
307                         if (fieldvalue>infoPtr->UpperLimit[i]) 
308                                 fieldvalue=infoPtr->UpperLimit[i];
309                         ip_addr+=fieldvalue;
310                         valid++;
311                 }
312  }
313
314  *(LPDWORD) lParam=ip_addr;
315
316  return valid;
317 }
318
319 static LRESULT
320 IPADDRESS_SetRange (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
321
322 {
323     IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr);
324         INT32 index;
325         
326         TRACE (ipaddress,"\n");
327
328         index=(INT32) wParam;
329         if ((index<0) || (index>3)) return 0;
330
331         infoPtr->LowerLimit[index]=lParam & 0xff;
332         infoPtr->UpperLimit[index]=(lParam >>8)  & 0xff;
333         return 1;
334 }
335
336 static LRESULT
337 IPADDRESS_SetAddress (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
338 {
339         HDC32 hdc;
340     IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr);
341         LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
342             GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP);
343         int i,ip_address,value;
344     char buf[20];
345
346         TRACE (ipaddress,"\n");
347         ip_address=(DWORD) lParam;
348
349         for (i=3; i>=0; i--) {
350                 value=ip_address & 0xff;
351                 if ((value>=infoPtr->LowerLimit[i]) && (value<=infoPtr->UpperLimit[i])) 
352                         {
353                          sprintf (buf,"%d",value);
354                          SetWindowText32A (lpipsi->hwndIP[i],buf);
355                          IPADDRESS_SendNotify (wndPtr, EN_CHANGE);
356                 }
357                 ip_address/=256;
358         }
359
360         hdc = GetDC32 (wndPtr->hwndSelf);               /* & send notifications */
361     IPADDRESS_Refresh (wndPtr, hdc);
362     ReleaseDC32 (wndPtr->hwndSelf, hdc);
363
364  return TRUE;
365 }
366
367
368
369
370 static LRESULT
371 IPADDRESS_SetFocusToField (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
372 {
373     /* IPADDRESS_INFO *infoPtr = IPADDRESS_GetInfoPtr(wndPtr); */
374         LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
375             GetProp32A ((HWND32)wndPtr->hwndSelf,IP_SUBCLASS_PROP);
376         INT32 index;
377
378         index=(INT32) wParam;
379         TRACE (ipaddress," %d\n", index);
380         if ((index<0) || (index>3)) return 0;
381         
382         SetFocus32 (lpipsi->hwndIP[index]);
383         
384     return 1;
385 }
386
387
388 static LRESULT
389 IPADDRESS_LButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
390 {
391     TRACE (ipaddress, "\n");
392
393         SetFocus32 (wndPtr->hwndSelf);
394         IPADDRESS_SendNotify (wndPtr, EN_SETFOCUS);
395         IPADDRESS_SetFocusToField (wndPtr, 0, 0);
396
397         return TRUE;
398 }
399
400
401
402 /* tab/shift-tab: IPN_FIELDCHANGED, lose focus.
403    dot, space,right arrow:      set focus to next child edit.
404    numerics (0..9), control characters: forward to default edit control 
405    other characters: dropped
406 */
407    
408
409
410
411 static int
412 IPADDRESS_GotoNextField (LPIP_SUBCLASS_INFO lpipsi, int currentfield)
413 {
414  int newField,fieldvalue;
415  char field[20];
416  IPADDRESS_INFO *infoPtr=lpipsi->infoPtr;
417
418  TRACE (ipaddress,"\n");
419  GetWindowText32A (lpipsi->hwndIP[currentfield],field,4);
420  if (field[0]) {
421         field[3]=0;     
422         newField=-1;
423         fieldvalue=atoi(field);
424         if (fieldvalue<infoPtr->LowerLimit[currentfield]) 
425                 newField=infoPtr->LowerLimit[currentfield];
426         if (fieldvalue>infoPtr->UpperLimit[currentfield])
427                 newField=infoPtr->UpperLimit[currentfield];
428         if (newField>=0) {
429                 sprintf (field,"%d",newField);
430                 SetWindowText32A (lpipsi->hwndIP[currentfield], field);
431                 return 1;
432         }
433  }
434
435  if (currentfield<3) 
436                 SetFocus32 (lpipsi->hwndIP[currentfield+1]);
437  return 0;
438 }
439
440
441 LRESULT CALLBACK
442 IPADDRESS_SubclassProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
443 {
444  int i,l,index;
445  IPADDRESS_INFO *infoPtr;
446  LPIP_SUBCLASS_INFO lpipsi=(LPIP_SUBCLASS_INFO)
447             GetProp32A ((HWND32)hwnd,IP_SUBCLASS_PROP); 
448
449  infoPtr = lpipsi->infoPtr;
450  index=0;             /* FIXME */
451  for (i=0; i<=3; i++) 
452                 if (lpipsi->hwndIP[i]==hwnd) index=i;
453
454  switch (uMsg) {
455         case WM_CHAR: break;
456         case WM_KEYDOWN: {
457                         char c=(char) wParam;
458                         if (c==VK_TAB) {
459                                 HWND32 pwnd;
460                                 int shift;
461                                 shift = GetKeyState32(VK_SHIFT) & 0x8000;
462                                 if (shift)
463                                         pwnd=GetNextDlgTabItem32 (GetParent32 (hwnd), 0, TRUE);
464                                 else
465                                         pwnd=GetNextDlgTabItem32 (GetParent32 (hwnd), 0, FALSE);
466                                 if (pwnd) SetFocus32 (pwnd);
467                                 break;
468                         }
469                         
470                         if ((c==' ') || (c=='.') || (c==VK_RIGHT)) {
471                                 IPADDRESS_GotoNextField (lpipsi,index);
472                                 wParam=0;
473                                 lParam=0;
474                                 break;
475                         }
476                         if (c==VK_LEFT) {
477                                 
478                         }
479                         if (c==VK_RETURN) {
480                         }
481                         if (((c>='0') && (c<='9')) || (iscntrl(c))) {
482                                 l=GetWindowTextLength32A (lpipsi->hwndIP[index]);
483                                 if (l==3) 
484                                         if (IPADDRESS_GotoNextField (lpipsi,index)) {
485                                                 wParam=0;
486                                                 lParam=0;
487                                         }
488                                 break;
489                         }
490         
491                         wParam=0;
492                         lParam=0;
493                         break;
494                 }
495  }
496
497  return CallWindowProc32A (lpipsi->wpOrigProc[index], hwnd, uMsg, wParam, lParam);
498 }
499
500 LRESULT WINAPI
501 IPADDRESS_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
502 {
503     WND *wndPtr = WIN_FindWndPtr(hwnd);
504
505     switch (uMsg)
506     {
507         case IPM_CLEARADDRESS:
508                 return IPADDRESS_ClearAddress (wndPtr, wParam, lParam);
509
510         case IPM_SETADDRESS:
511             return IPADDRESS_SetAddress (wndPtr, wParam, lParam);
512
513         case IPM_GETADDRESS:
514             return IPADDRESS_GetAddress (wndPtr, wParam, lParam);
515
516         case IPM_SETRANGE:
517             return IPADDRESS_SetRange (wndPtr, wParam, lParam);
518
519         case IPM_SETFOCUS:
520             return IPADDRESS_SetFocusToField (wndPtr, wParam, lParam);
521
522         case IPM_ISBLANK:
523                 return IPADDRESS_IsBlank (wndPtr, wParam, lParam);
524
525         case WM_CREATE:
526             return IPADDRESS_Create (wndPtr, wParam, lParam);
527
528         case WM_DESTROY:
529             return IPADDRESS_Destroy (wndPtr, wParam, lParam);
530
531         case WM_GETDLGCODE:
532             return DLGC_WANTARROWS | DLGC_WANTCHARS;
533
534         case WM_KILLFOCUS:
535             return IPADDRESS_KillFocus (wndPtr, wParam, lParam);
536
537         case WM_LBUTTONDOWN:
538         return IPADDRESS_LButtonDown (wndPtr, wParam, lParam);
539
540         case WM_PAINT:
541             return IPADDRESS_Paint (wndPtr, wParam);
542
543         case WM_SETFOCUS:
544             return IPADDRESS_SetFocus (wndPtr, wParam, lParam);
545
546         case WM_SIZE:
547             return IPADDRESS_Size (wndPtr, wParam, lParam);
548
549         default:
550             if (uMsg >= WM_USER)
551                 ERR (ipaddress, "unknown msg %04x wp=%08x lp=%08lx\n",
552                      uMsg, wParam, lParam);
553             return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
554     }
555     return 0;
556 }
557
558
559 void
560 IPADDRESS_Register (void)
561 {
562     WNDCLASS32A wndClass;
563
564     if (GlobalFindAtom32A (WC_IPADDRESS32A)) return;
565
566     ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
567     wndClass.style         = CS_GLOBALCLASS;
568     wndClass.lpfnWndProc   = (WNDPROC32)IPADDRESS_WindowProc;
569     wndClass.cbClsExtra    = 0;
570     wndClass.cbWndExtra    = sizeof(IPADDRESS_INFO *);
571     wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
572     wndClass.hbrBackground = (HBRUSH32)(COLOR_3DFACE + 1);
573     wndClass.lpszClassName = WC_IPADDRESS32A;
574  
575     RegisterClass32A (&wndClass);
576 }
577
578 VOID
579 IPADDRESS_Unregister (VOID)
580 {
581     if (GlobalFindAtom32A (WC_IPADDRESS32A))
582     UnregisterClass32A (WC_IPADDRESS32A, (HINSTANCE32)NULL);
583 }
584