Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / WINNT / afsapplib / ctl_spinner.cpp
blob6d71acec06f59ce063a5b996e250a535dc644cf8
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
15 #include <windows.h>
16 #include <windowsx.h>
17 #include <commctrl.h>
18 #include <WINNT/dialog.h>
19 #include <WINNT/subclass.h>
20 #include <WINNT/ctl_spinner.h>
21 #include <WINNT/TaLocale.h>
23 #ifndef cchRESOURCE
24 #define cchRESOURCE 256
25 #endif
29 * MISCELLANEOUS ______________________________________________________________
33 #define ishexdigit(_ch) ( (((_ch) >= 'a') && ((_ch) <= 'f')) || \
34 (((_ch) >= 'A') && ((_ch) <= 'F')) )
36 #define digitval(_ch) (isdigit(_ch) \
37 ? ((DWORD)(_ch) - (DWORD)TEXT('0')) \
38 : (((_ch) >= 'a') && ((_ch) <= 'f')) \
39 ? ((DWORD)(_ch) - (DWORD)TEXT('a') + 10) \
40 : (((_ch) >= 'A') && ((_ch) <= 'F')) \
41 ? ((DWORD)(_ch) - (DWORD)TEXT('A') + 10) \
42 : 0)
44 #ifndef REALLOC
45 #define REALLOC(_a,_c,_r,_i) SpinnerReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
46 BOOL SpinnerReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
48 LPVOID pNew;
49 size_t cNew;
51 if (cReq <= *pcTarget)
52 return TRUE;
54 if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
55 return FALSE;
57 if ((pNew = (LPVOID)Allocate (cbElement * cNew)) == NULL)
58 return FALSE;
59 memset (pNew, 0x00, cbElement * cNew);
61 if (*pcTarget != 0)
63 memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
64 Free (*ppTarget);
67 *ppTarget = pNew;
68 *pcTarget = cNew;
69 return TRUE;
71 #endif
75 * SPINNERS ___________________________________________________________________
79 typedef struct
81 HWND hSpinner;
82 HWND hBuddy;
83 RECT rReq;
85 DWORD dwMin;
86 DWORD dwMax;
87 WORD wBase;
88 BOOL fSigned;
89 DWORD dwPos;
91 BOOL fNewText;
92 BOOL fCallingBack;
93 BOOL fCanCallBack;
94 LPTSTR pszFormat;
95 } SpinnerInfo;
97 static CRITICAL_SECTION csSpinners;
98 static SpinnerInfo *aSpinners = NULL;
99 static size_t cSpinners = 0;
100 static LONG oldSpinnerProc = 0;
102 #define cszSPINNERCLASS TEXT("Spinner")
104 HRESULT CALLBACK SpinnerProc (HWND hSpin, UINT msg, WPARAM wp, LPARAM lp);
105 HRESULT CALLBACK SpinnerDialogProc (HWND hSpin, UINT msg, WPARAM wp, LPARAM lp);
106 HRESULT CALLBACK SpinnerBuddyProc (HWND hBuddy, UINT msg, WPARAM wp, LPARAM lp);
108 void SpinnerSendCallback (SpinnerInfo *psi, WORD spm, LPARAM lp);
110 void Spinner_OnCreate (SpinnerInfo *psi);
111 BOOL Spinner_OnGetRange (SpinnerInfo *psi, WPARAM wp, LPARAM lp);
112 BOOL Spinner_OnSetRange (SpinnerInfo *psi, WPARAM wp, LPARAM lp);
113 BOOL Spinner_OnGetPos (SpinnerInfo *psi, WPARAM wp, LPARAM lp);
114 BOOL Spinner_OnSetPos (SpinnerInfo *psi, WPARAM wp, LPARAM lp);
115 BOOL Spinner_OnGetBase (SpinnerInfo *psi, WPARAM wp, LPARAM lp);
116 BOOL Spinner_OnSetBase (SpinnerInfo *psi, WPARAM wp, LPARAM lp);
117 BOOL Spinner_OnReattach (SpinnerInfo *psi, WPARAM wp, LPARAM lp);
118 BOOL Spinner_OnSetRect (SpinnerInfo *psi, WPARAM wp, LPARAM lp);
119 BOOL Spinner_OnGetSpinner (SpinnerInfo *psi, WPARAM wp, LPARAM lp);
120 BOOL Spinner_OnSetFormat (SpinnerInfo *psi, WPARAM wp, LPARAM lp);
121 BOOL Spinner_OnSetBuddy (SpinnerInfo *psi, WPARAM wp, LPARAM lp);
123 void Spinner_GetNewText (SpinnerInfo *psi);
124 void Spinner_SetNewText (SpinnerInfo *psi, BOOL fCallback);
127 BOOL RegisterSpinnerClass (void)
129 static BOOL fRegistered = FALSE;
131 if (!fRegistered)
133 WNDCLASS wc;
135 InitializeCriticalSection (&csSpinners);
137 if (GetClassInfo (THIS_HINST, TEXT("scrollbar"), &wc))
139 oldSpinnerProc = (LONG)(LONG_PTR)wc.lpfnWndProc;
141 wc.lpfnWndProc = (WNDPROC)SpinnerProc;
142 wc.style = CS_GLOBALCLASS;
143 wc.hInstance = THIS_HINST;
144 wc.lpszClassName = cszSPINNERCLASS;
146 if (RegisterClass (&wc))
147 fRegistered = TRUE;
151 return fRegistered;
155 SpinnerInfo *Spinner_FindSpinnerInfo (HWND hSpinner, HWND hBuddy)
157 SpinnerInfo *psi = NULL;
159 EnterCriticalSection (&csSpinners);
161 for (size_t ii = 0; ii < cSpinners; ++ii)
163 if ( (hSpinner && (aSpinners[ ii ].hSpinner == hSpinner)) ||
164 (hBuddy && (aSpinners[ ii ].hBuddy == hBuddy)) )
166 psi = &aSpinners[ ii ];
167 break;
171 LeaveCriticalSection (&csSpinners);
172 return psi;
176 BOOL CreateSpinner (HWND hBuddy,
177 WORD wBase, BOOL fSigned,
178 DWORD dwMin, DWORD dwPos, DWORD dwMax,
179 LPRECT prTarget)
181 if (!RegisterSpinnerClass())
182 return FALSE;
184 EnterCriticalSection (&csSpinners);
186 size_t ii;
187 for (ii = 0; ii < cSpinners; ++ii)
189 if (!aSpinners[ ii ].hSpinner)
190 break;
192 if (ii >= cSpinners)
194 if (!REALLOC (aSpinners, cSpinners, 1+ii, 4))
196 LeaveCriticalSection (&csSpinners);
197 return FALSE;
201 memset (&aSpinners[ ii ], 0x00, sizeof(SpinnerInfo));
203 aSpinners[ ii ].hBuddy = hBuddy;
204 aSpinners[ ii ].dwMin = dwMin;
205 aSpinners[ ii ].dwMax = dwMax;
206 aSpinners[ ii ].wBase = wBase;
207 aSpinners[ ii ].fSigned = fSigned;
208 aSpinners[ ii ].dwPos = dwPos;
210 if (prTarget != NULL)
211 aSpinners[ ii ].rReq = *prTarget;
213 aSpinners[ ii ].hSpinner = CreateWindowEx (
214 0, // extended window style
215 cszSPINNERCLASS, // pointer to registered class name
216 TEXT(""), // pointer to window name
217 WS_CHILD | SBS_VERT, // window style
218 0, 0, 1, 1, // spinner moves/resizes itself
219 GetParent(hBuddy), // handle to parent or owner window
220 (HMENU)-1, // handle to menu, or child-window identifier
221 THIS_HINST, // handle to application instance
222 (LPVOID)ii); // pointer to window-creation data
224 LeaveCriticalSection (&csSpinners);
226 if (aSpinners[ ii ].hSpinner == NULL)
227 return FALSE;
229 ShowWindow (aSpinners[ ii ].hSpinner, SW_SHOW);
231 if (!IsWindowEnabled (aSpinners[ ii ].hBuddy))
232 EnableWindow (aSpinners[ ii ].hSpinner, FALSE);
234 return TRUE;
238 BOOL fHasSpinner (HWND hBuddy)
240 if (!RegisterSpinnerClass())
241 return FALSE;
243 return (Spinner_FindSpinnerInfo (NULL, hBuddy) == NULL) ? FALSE : TRUE;
247 void Spinner_OnDestroy (SpinnerInfo *psi)
249 Subclass_RemoveHook (GetParent (psi->hSpinner), SpinnerDialogProc);
250 Subclass_RemoveHook (psi->hBuddy, SpinnerBuddyProc);
252 if (psi->pszFormat)
254 Free (psi->pszFormat);
255 psi->pszFormat = NULL;
257 psi->hSpinner = NULL;
258 psi->hBuddy = NULL;
262 HRESULT CALLBACK SpinnerProc (HWND hSpinner, UINT msg, WPARAM wp, LPARAM lp)
264 EnterCriticalSection (&csSpinners);
266 if (msg == WM_CREATE)
268 aSpinners[ (int)(INT_PTR)((LPCREATESTRUCT)lp)->lpCreateParams ].hSpinner = hSpinner;
271 SpinnerInfo *psi = Spinner_FindSpinnerInfo (hSpinner, NULL);
273 LeaveCriticalSection (&csSpinners);
275 if (psi != NULL)
277 switch (msg)
279 case WM_CREATE:
280 Spinner_OnCreate (psi);
281 break;
283 case WM_SETFOCUS:
284 PostMessage (GetParent(psi->hSpinner), WM_NEXTDLGCTL, (WPARAM)psi->hBuddy, TRUE);
285 break;
287 case WM_DESTROY:
288 Spinner_OnDestroy (psi);
289 break;
291 case WM_SYSCHAR:
292 case WM_CHAR:
293 switch (wp)
295 case VK_UP:
296 PostMessage (GetParent(psi->hSpinner), WM_VSCROLL, SB_LINEUP, (LPARAM)psi->hSpinner);
297 break;
299 case VK_DOWN:
300 PostMessage (GetParent(psi->hSpinner), WM_VSCROLL, SB_LINEDOWN, (LPARAM)psi->hSpinner);
301 break;
303 case VK_PRIOR:
304 PostMessage (GetParent(psi->hSpinner), WM_VSCROLL, SB_PAGEUP, (LPARAM)psi->hSpinner);
305 break;
307 case VK_NEXT:
308 PostMessage (GetParent(psi->hSpinner), WM_VSCROLL, SB_PAGEDOWN, (LPARAM)psi->hSpinner);
309 break;
311 case VK_HOME:
312 PostMessage (GetParent(psi->hSpinner), WM_VSCROLL, SB_TOP, (LPARAM)psi->hSpinner);
313 break;
315 case VK_END:
316 PostMessage (GetParent(psi->hSpinner), WM_VSCROLL, SB_BOTTOM, (LPARAM)psi->hSpinner);
317 break;
319 break;
323 if (oldSpinnerProc == 0)
324 return DefWindowProc (hSpinner, msg, wp, lp);
325 else
326 return CallWindowProc ((WNDPROC)(LONG_PTR)oldSpinnerProc, hSpinner, msg, wp, lp);
330 HRESULT CALLBACK SpinnerDialogProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
332 PVOID oldProc = Subclass_FindNextHook (hDlg, SpinnerDialogProc);
333 SpinnerInfo *psi;
335 switch (msg)
337 case WM_COMMAND:
338 if ((psi = Spinner_FindSpinnerInfo (NULL, (HWND)lp)) != NULL)
340 switch (HIWORD(wp))
342 // case CBN_SELCHANGE: --same value as LBN_SELCHANGE
343 case LBN_SELCHANGE:
344 case EN_UPDATE:
345 Spinner_GetNewText (psi);
347 if (psi->fCanCallBack == TRUE)
348 SpinnerSendCallback (psi, SPN_UPDATE, (LPARAM)psi->dwPos);
349 else
350 oldProc = NULL; // don't forward this notification message
351 break;
353 default:
354 oldProc = NULL; // don't forward this notification message
355 break;
358 break;
360 case WM_VSCROLL:
361 if ((psi = Spinner_FindSpinnerInfo ((HWND)lp, NULL)) != NULL)
363 if (psi->fNewText)
365 WORD wBaseOld = psi->wBase;
366 Spinner_GetNewText (psi);
367 if ((wBaseOld != psi->wBase) && !(psi->pszFormat))
368 Spinner_OnSetBase (psi, psi->wBase, psi->fSigned);
371 switch (LOWORD(wp))
373 case SB_LINEUP:
375 DWORD dw = psi->dwPos;
376 SpinnerSendCallback (psi, SPN_CHANGE_UP, (LPARAM)&dw);
377 if (dw == psi->dwPos)
378 psi->dwPos ++;
379 else if (dw != SPVAL_UNCHANGED)
380 psi->dwPos = dw;
382 if (psi->wBase == 10 && psi->fSigned)
383 psi->dwPos = (DWORD)limit ((signed long)psi->dwMin, (signed long)psi->dwPos, (signed long)psi->dwMax);
384 else
385 psi->dwPos = (DWORD)limit (psi->dwMin, psi->dwPos, psi->dwMax);
387 Spinner_SetNewText (psi, TRUE);
388 PostMessage (GetParent(psi->hSpinner), WM_NEXTDLGCTL, (WPARAM)psi->hBuddy, TRUE);
389 break;
392 case SB_LINEDOWN:
394 DWORD dw = psi->dwPos;
395 SpinnerSendCallback (psi, SPN_CHANGE_DOWN, (LPARAM)&dw);
396 if (dw == psi->dwPos)
398 if ((psi->dwPos > 0) || (psi->wBase == 10 && psi->fSigned))
399 psi->dwPos --;
401 else if (dw != SPVAL_UNCHANGED)
402 psi->dwPos = dw;
404 if (psi->wBase == 10 && psi->fSigned)
405 psi->dwPos = (DWORD)limit ((signed long)psi->dwMin, (signed long)psi->dwPos, (signed long)psi->dwMax);
406 else
407 psi->dwPos = (DWORD)limit (psi->dwMin, psi->dwPos, psi->dwMax);
409 Spinner_SetNewText (psi, TRUE);
410 PostMessage (GetParent(psi->hSpinner), WM_NEXTDLGCTL, (WPARAM)psi->hBuddy, TRUE);
411 break;
415 break;
418 if (oldProc == 0)
419 return DefWindowProc (hDlg, msg, wp, lp);
420 else
421 return CallWindowProc ((WNDPROC)oldProc, hDlg, msg, wp, lp);
426 HRESULT CALLBACK SpinnerBuddyProc (HWND hBuddy, UINT msg, WPARAM wp, LPARAM lp)
428 PVOID oldProc = Subclass_FindNextHook (hBuddy, SpinnerBuddyProc);
430 SpinnerInfo *psi;
431 if ((psi = Spinner_FindSpinnerInfo (NULL, hBuddy)) != NULL)
433 switch (msg)
435 case WM_KEYDOWN:
436 case WM_KEYUP:
437 switch (wp)
439 case VK_HOME:
440 case VK_END:
441 case VK_PRIOR:
442 case VK_NEXT:
443 case VK_UP:
444 case VK_DOWN:
445 SendMessage (psi->hSpinner, msg, wp, lp);
446 return FALSE;
448 break;
450 case WM_CHAR:
451 psi->fNewText = TRUE;
452 break;
454 case WM_MOVE:
455 case WM_SIZE:
456 PostMessage (hBuddy, SPM_REATTACH, 0, 0);
457 break;
459 case WM_ENABLE:
460 EnableWindow (psi->hSpinner, (BOOL)wp);
461 break;
463 case WM_KILLFOCUS:
464 Spinner_GetNewText (psi);
465 Spinner_OnSetBase (psi, psi->wBase, psi->fSigned);
466 break;
468 case SPM_GETRANGE:
469 return Spinner_OnGetRange (psi, wp, lp);
471 case SPM_SETRANGE:
472 return Spinner_OnSetRange (psi, wp, lp);
474 case SPM_GETPOS:
475 return Spinner_OnGetPos (psi, wp, lp);
477 case SPM_SETPOS:
478 return Spinner_OnSetPos (psi, wp, lp);
480 case SPM_GETBASE:
481 return Spinner_OnGetBase (psi, wp, lp);
483 case SPM_SETBASE:
484 return Spinner_OnSetBase (psi, wp, lp);
486 case SPM_REATTACH:
487 return Spinner_OnReattach (psi, wp, lp);
489 case SPM_SETRECT:
490 return Spinner_OnSetRect (psi, wp, lp);
492 case SPM_GETSPINNER:
493 return Spinner_OnGetSpinner (psi, wp, lp);
495 case SPM_SETFORMAT:
496 return Spinner_OnSetFormat (psi, wp, lp);
498 case SPM_SETBUDDY:
499 return Spinner_OnSetBuddy (psi, wp, lp);
503 if (oldProc)
504 return CallWindowProc ((WNDPROC)oldProc, hBuddy, msg, wp, lp);
505 else
506 return DefWindowProc (hBuddy, msg, wp, lp);
510 void SpinnerSendCallback (SpinnerInfo *psi, WORD spm, LPARAM lp)
512 if ((psi->fCanCallBack == TRUE) && !psi->fCallingBack)
514 psi->fCallingBack = TRUE;
516 SendMessage (GetParent (psi->hSpinner),
517 WM_COMMAND,
518 MAKELONG ((WORD)GetWindowLong (psi->hBuddy, GWL_ID), spm),
519 lp);
521 psi->fCallingBack = FALSE;
526 void Spinner_OnCreate (SpinnerInfo *psi)
528 Subclass_AddHook (GetParent(psi->hSpinner), SpinnerDialogProc);
529 Subclass_AddHook (psi->hBuddy, SpinnerBuddyProc);
531 Spinner_OnReattach (psi, 0, 0);
532 Spinner_SetNewText (psi, FALSE);
534 psi->fCanCallBack = TRUE;
538 BOOL Spinner_OnGetRange (SpinnerInfo *psi, WPARAM wp, LPARAM lp)
540 if (wp != 0)
541 *(LPDWORD)wp = psi->dwMin;
542 if (lp != 0)
543 *(LPDWORD)lp = psi->dwMax;
544 return TRUE;
547 BOOL Spinner_OnSetRange (SpinnerInfo *psi, WPARAM wp, LPARAM lp)
549 psi->dwMin = (DWORD)wp;
550 psi->dwMax = (DWORD)lp;
551 Spinner_SetNewText (psi, FALSE);
552 return TRUE;
555 BOOL Spinner_OnGetPos (SpinnerInfo *psi, WPARAM wp, LPARAM lp)
557 if (psi->fNewText)
559 Spinner_GetNewText (psi);
560 Spinner_OnSetBase (psi, psi->wBase, psi->fSigned);
562 return (BOOL)psi->dwPos;
565 BOOL Spinner_OnSetPos (SpinnerInfo *psi, WPARAM wp, LPARAM lp)
567 psi->dwPos = (DWORD)lp;
568 Spinner_SetNewText (psi, FALSE);
569 return TRUE;
572 BOOL Spinner_OnGetBase (SpinnerInfo *psi, WPARAM wp, LPARAM lp)
574 if (psi->fNewText)
576 Spinner_GetNewText (psi);
577 Spinner_OnSetBase (psi, psi->wBase, psi->fSigned);
580 if (wp != 0)
581 *(WORD *)wp = psi->wBase;
582 if (lp != 0)
583 *(BOOL *)lp = psi->fSigned;
584 return TRUE;
587 BOOL Spinner_OnSetBase (SpinnerInfo *psi, WPARAM wp, LPARAM lp)
589 if (psi->fNewText)
590 Spinner_GetNewText (psi);
592 switch ((WORD)wp)
594 case 2:
595 case 8:
596 case 10:
597 case 16:
598 psi->wBase = (WORD)wp;
599 break;
601 default:
602 psi->wBase = 10;
603 break;
606 if (psi->wBase != 10)
607 psi->fSigned = FALSE;
608 else
609 psi->fSigned = (BOOL)lp;
611 Spinner_SetNewText (psi, FALSE);
612 return TRUE;
616 BOOL Spinner_OnReattach (SpinnerInfo *psi, WPARAM wp, LPARAM lp)
618 RECT rSpinner;
619 if (psi->rReq.right != 0)
621 rSpinner = psi->rReq;
623 else
625 RECT rBuddyInParent;
626 POINT pt = { 0, 0 };
628 ClientToScreen (GetParent (psi->hBuddy), &pt);
630 GetWindowRect (psi->hBuddy, &rBuddyInParent);
631 rBuddyInParent.left -= pt.x;
632 rBuddyInParent.right -= pt.x;
633 rBuddyInParent.top -= pt.y;
634 rBuddyInParent.bottom -= pt.y;
636 rSpinner.top = rBuddyInParent.top;
637 rSpinner.bottom = rBuddyInParent.bottom -2; // just like Win95 does
638 rSpinner.left = rBuddyInParent.right;
639 rSpinner.right = rBuddyInParent.right +GetSystemMetrics (SM_CXVSCROLL);
642 SetWindowPos (psi->hSpinner, NULL,
643 rSpinner.left, rSpinner.top,
644 rSpinner.right-rSpinner.left,
645 rSpinner.bottom-rSpinner.top,
646 SWP_NOACTIVATE | SWP_NOZORDER);
647 return TRUE;
651 BOOL Spinner_OnSetRect (SpinnerInfo *psi, WPARAM wp, LPARAM lp)
653 LPRECT prTarget;
654 if ((prTarget = (LPRECT)lp) == NULL)
655 SetRectEmpty (&psi->rReq);
656 else
657 psi->rReq = *prTarget;
659 Spinner_OnReattach (psi, 0, 0);
660 return TRUE;
664 BOOL Spinner_OnGetSpinner (SpinnerInfo *psi, WPARAM wp, LPARAM lp)
666 return (BOOL)(INT_PTR)psi->hSpinner;
670 BOOL Spinner_OnSetFormat (SpinnerInfo *psi, WPARAM wp, LPARAM lp)
672 if (psi->pszFormat)
674 Free (psi->pszFormat);
675 psi->pszFormat = NULL;
677 if (lp != 0)
679 psi->pszFormat = (LPTSTR)Allocate (sizeof(TCHAR) * (1+lstrlen((LPTSTR)lp)));
680 lstrcpy (psi->pszFormat, (LPTSTR)lp);
682 Spinner_SetNewText (psi, FALSE);
683 return TRUE;
687 BOOL Spinner_OnSetBuddy (SpinnerInfo *psi, WPARAM wp, LPARAM lp)
689 HWND hBuddyNew = (HWND)wp;
690 BOOL fMove = (BOOL)lp;
692 // First un-subclass our buddy.
693 // Then subclass the new buddy.
695 Subclass_RemoveHook (psi->hBuddy, SpinnerBuddyProc);
696 psi->hBuddy = hBuddyNew;
697 Subclass_AddHook (psi->hBuddy, SpinnerBuddyProc);
699 // Update our SpinnerInfo structure, and move if requested.
701 Spinner_GetNewText (psi);
703 if (fMove)
705 SetRectEmpty (&psi->rReq);
706 Spinner_OnReattach (psi, 0, 0);
709 return TRUE;
713 void Spinner_GetNewText (SpinnerInfo *psi)
715 // First find out what kind of buddy we have.
716 // That will determine what we do here.
718 TCHAR szBuddyClass[256];
719 GetClassName (psi->hBuddy, szBuddyClass, 256);
721 // For comboboxes and listboxes, the dwPos value is actually
722 // the selected item's index.
724 if (!lstrcmpi (szBuddyClass, TEXT("listbox")))
726 psi->dwPos = (DWORD)LB_GetSelected (psi->hBuddy);
729 if (!lstrcmpi (szBuddyClass, TEXT("combobox")))
731 psi->dwPos = (DWORD)CB_GetSelected (psi->hBuddy);
734 // For edit controls, the dwPos value is actually
735 // the control's text's value.
737 if (!lstrcmpi (szBuddyClass, TEXT("edit")))
739 TCHAR szText[256];
740 LPTSTR pszText = szText;
741 BOOL fNegative = FALSE;
743 psi->fNewText = FALSE;
744 psi->dwPos = 0;
745 psi->wBase = 10;
747 GetWindowText (psi->hBuddy, szText, 256);
749 while (*pszText == TEXT(' ') || *pszText == TEXT('\t'))
750 ++pszText;
752 if (*pszText == TEXT('0'))
754 if ((*(1+pszText) == 'x') || (*(1+pszText) == 'X'))
756 psi->wBase = 16;
757 ++pszText;
758 ++pszText;
760 else if ((*(1+pszText) == 'b') || (*(1+pszText) == 'B') || (*(1+pszText) == '!'))
762 psi->wBase = 2;
763 ++pszText;
764 ++pszText;
766 else if (*(1+pszText) != '\0')
768 // psi->wBase = 8; // ignore octal--time controls use "4:08" etc
769 ++pszText;
773 for ( ; *pszText == TEXT('-'); ++pszText)
775 fNegative = !fNegative;
778 for ( ; *pszText; ++pszText)
780 if (!isdigit( *pszText ) &&
781 !(psi->wBase == 16 && ishexdigit( *pszText )))
783 break;
786 psi->dwPos *= psi->wBase;
788 if ((DWORD)digitval(*pszText) < (DWORD)psi->wBase)
789 psi->dwPos += digitval( *pszText );
792 if (fNegative && psi->wBase == 10 && psi->fSigned)
794 psi->dwPos = (DWORD)(0 - (signed long)psi->dwPos);
798 if (psi->wBase == 10 && psi->fSigned)
799 psi->dwPos = (DWORD)limit ((signed long)psi->dwMin, (signed long)psi->dwPos, (signed long)psi->dwMax);
800 else
801 psi->dwPos = (DWORD)limit (psi->dwMin, psi->dwPos, psi->dwMax);
805 void Spinner_SetNewText (SpinnerInfo *psi, BOOL fCallBack)
807 TCHAR szText[256];
809 // First find out what kind of buddy we have.
810 // That will determine what we do here.
812 TCHAR szBuddyClass[256];
813 GetClassName (psi->hBuddy, szBuddyClass, 256);
815 // Be sure to notify the parent window that the selection may be changing.
817 if (fCallBack)
819 DWORD dw = psi->dwPos;
820 SpinnerSendCallback (psi, SPN_CHANGE, (LPARAM)&dw);
821 if (dw != SPVAL_UNCHANGED)
822 psi->dwPos = dw;
825 if (psi->wBase == 10 && psi->fSigned)
826 psi->dwPos = (DWORD)limit ((signed long)psi->dwMin, (signed long)psi->dwPos, (signed long)psi->dwMax);
827 else
828 psi->dwPos = (DWORD)limit (psi->dwMin, psi->dwPos, psi->dwMax);
830 if (!fCallBack)
831 psi->fCanCallBack --;
833 // For comboboxes and listboxes, select the item specified by the
834 // given index.
836 if (!lstrcmpi (szBuddyClass, TEXT("listbox")))
838 LB_SetSelected (psi->hBuddy, psi->dwPos);
841 if (!lstrcmpi (szBuddyClass, TEXT("combobox")))
843 CB_SetSelected (psi->hBuddy, psi->dwPos);
846 // For edit controls, fill in the new value as text--expressed in the
847 // requested base, using the requested format.
849 if (!lstrcmpi (szBuddyClass, TEXT("edit")))
851 switch (psi->wBase)
853 case 10:
854 if (psi->pszFormat)
855 wsprintf (szText, psi->pszFormat, (unsigned long)psi->dwPos);
856 else if (psi->fSigned)
857 wsprintf (szText, TEXT("%ld"), (signed long)psi->dwPos);
858 else
859 wsprintf (szText, TEXT("%lu"), (unsigned long)psi->dwPos);
860 break;
862 case 16:
863 wsprintf (szText, TEXT("0x%lX"), (unsigned long)psi->dwPos);
864 break;
866 default:
867 TCHAR szTemp[256];
868 LPTSTR pszTemp = szTemp;
869 LPTSTR pszText = szText;
871 if (psi->dwPos == 0)
872 *pszTemp++ = TEXT('0');
873 else
875 for (DWORD dwRemainder = psi->dwPos; dwRemainder != 0; dwRemainder /= (DWORD)psi->wBase)
877 DWORD dw = (dwRemainder % (DWORD)psi->wBase);
878 *pszTemp++ = TEXT('0') + (TCHAR)dw;
882 if (psi->wBase == 8)
884 *pszText++ = TEXT('0');
886 else if (psi->wBase == 2)
888 *pszText++ = TEXT('0');
889 *pszText++ = TEXT('b');
892 for (--pszTemp; pszTemp >= szTemp; )
894 *pszText++ = *pszTemp--;
896 *pszText = TEXT('\0');
897 break;
900 SetWindowText (psi->hBuddy, szText);
903 if (!fCallBack)
904 psi->fCanCallBack ++;
905 else
906 SpinnerSendCallback (psi, SPN_UPDATE, (LPARAM)psi->dwPos);