|
|
/*****************************************************************************
* * diqvint.c * * VList plug-in that does integers. * *****************************************************************************/
#include "diquick.h"
#pragma BEGIN_CONST_DATA
/*****************************************************************************
* * VLISTINT * * INT-specific goo. * *****************************************************************************/
typedef struct VLISTINT {
VLISTITEM item;
DIPROPDWORD dipdw; int iMin; int iMax; int iRadix;
/*
* If non-NULL, then this is a read/write control. */ PROPUPDATEPROC Update; PV pvRef1; PV pvRef2;
} VLISTINT, *PVLISTINT;
#ifndef UDM_SETRANGE32
#define UDM_SETRANGE32 (WM_USER + 111)
#define UDM_GETRANGE32 (WM_USER + 112)
#endif
/*****************************************************************************
* * Some helper functions for UpDown controls since they're kind * of broken. * *****************************************************************************/
/*****************************************************************************
* * UpDown_SetRange * * This is an evil hack to set the range of an UpDown control to a * 32-bit value, because older versions didn't support * UDM_SETRANGE32. * *****************************************************************************/
void EXTERNAL UpDown_SetRange(HWND hwndUD, int min, int max) { int iTest;
/*
* We detect whether UDM_SETRANGE32 is supported by first sending it, * then using UDM_GETRANGE32 to see if it worked. */ SendMessage(hwndUD, UDM_SETRANGE32, (WPARAM)min, (LPARAM)max);
iTest = max + 1; /* Make sure it's different */ SendMessage(hwndUD, UDM_GETRANGE32, 0, (LPARAM)&iTest);
/*
* If UDM_GETRANGE32 failed to return the correct value, * then try it the old way, but first pin the pin/max values. */ if (iTest != max) { if (max > UD_MAXVAL) max = UD_MAXVAL; if (min < UD_MINVAL) min = UD_MINVAL;
SendMessage(hwndUD, UDM_SETRANGE, 0, MAKELPARAM(max, min)); }
}
/*****************************************************************************
* * UpDown_SetPos * * Set the value in the edit control part of the sub-dialog. * We have to do it ourselves because there is no UDM_SETPOS32 * message. * *****************************************************************************/
void EXTERNAL UpDown_SetPos(HWND hwndUD, int iRadix, int iValue) { TCHAR tsz[128];
SendMessage(hwndUD, UDM_SETBASE, iRadix, 0L);
/*
* Bug in UDM_SETPOS means that we cannot use it on values * greater than 65535. */ if (iRadix == 10) { wsprintf(tsz, TEXT("%d") , iValue); } else { wsprintf(tsz, TEXT("0x%08x"), iValue); }
SetWindowText(GetWindow(hwndUD, GW_HWNDPREV), tsz); }
/*****************************************************************************
* * VInt_AToI * * Convert a string to an integer, allowing decimal or hex. * *****************************************************************************/
BOOL INTERNAL VInt_AToI(LPCTSTR ptsz, PINT pi) { int iVal; BOOL fSign = FALSE; UINT uiRadix;
/*
* Skip leading whitespace. */ while (*ptsz == TEXT(' ')) { ptsz++; }
/*
* See if there is a leading negative sign. */ if (*ptsz == TEXT('-')) { fSign = TRUE; ptsz++; }
iVal = 0;
if (ptsz[0] == TEXT('0') && (ptsz[1] == TEXT('x') || ptsz[1] == TEXT('X'))) { uiRadix = 16; ptsz += 2; } else { uiRadix = 10; }
for (;;) { UINT uiVal; if ((UINT)(*ptsz - TEXT('0')) < 10) { uiVal = (UINT)(*ptsz - TEXT('0')); } else if ((UINT)(*ptsz - TEXT('A')) < 6) { uiVal = (UINT)(*ptsz - TEXT('A')) + 10; } else if ((UINT)(*ptsz - TEXT('a')) < 6) { uiVal = (UINT)(*ptsz - TEXT('a')) + 10; } else if (*ptsz == TEXT(' ') || *ptsz == TEXT(',')) { continue; /* Ignore spaces and commas */ } else if (*ptsz == TEXT('\0')) { *pi = fSign ? -iVal : iVal; return TRUE; } else { return FALSE; } if (uiVal < uiRadix) { iVal = iVal * uiRadix + uiVal; } else { return FALSE; } ptsz++; } }
/*****************************************************************************
* * UpDown_GetPos * * Get the value in the edit control part of the sub-dialog. * We have to do it ourselves because there is no UDM_GETPOS32 * message. * *****************************************************************************/
BOOL EXTERNAL UpDown_GetPos(HWND hwndUD, LPINT pi) { TCHAR tsz[CCHMAXINT];
GetWindowText(GetWindow(hwndUD, GW_HWNDPREV), tsz, cA(tsz)); return VInt_AToI(tsz, pi); }
/*****************************************************************************
* * VInt_PreDisplay * * Set the edit control text and let the dialog know who it is in * charge of. * *****************************************************************************/
void INTERNAL VInt_PreDisplay(HWND hdlg, PV pv) { PVLISTINT pvint = pv; HWND hwndUD = GetDlgItem(hdlg, IDC_VINT_UD); HWND hwndEdit;
ShowWindow(hwndUD, pvint->Update ? SW_SHOW : SW_HIDE); ShowWindow(GetDlgItem(hdlg, IDC_VINT_APPLY), pvint->Update ? SW_SHOW : SW_HIDE);
UpDown_SetRange(hwndUD, pvint->iMin, pvint->iMax);
UpDown_SetPos(hwndUD, pvint->iRadix, pvint->dipdw.dwData);
hwndEdit = GetDlgItem(hdlg, IDC_VINT_EDIT); Edit_SetReadOnly(hwndEdit, !pvint->Update);
CheckRadioButton(hdlg, IDC_VINT_DEC, IDC_VINT_HEX, pvint->iRadix == 10 ? IDC_VINT_DEC : IDC_VINT_HEX);
SetDialogPtr(hdlg, pvint);
}
/*****************************************************************************
* * VInt_Destroy * * Nothing to clean up. * *****************************************************************************/
void INTERNAL VInt_Destroy(PV pv) { PVLISTINT pvint = pv; }
/*****************************************************************************
* * VInt_OnInitDialog * * Limit the strings to CCHMAXINT characters. * *****************************************************************************/
BOOL INTERNAL VInt_OnInitDialog(HWND hdlg) { HWND hwndEdit = GetDlgItem(hdlg, IDC_VINT_EDIT); Edit_LimitText(hwndEdit, CCHMAXINT); return TRUE; }
/*****************************************************************************
* * VInt_OnApply * * Let the owner know. * *****************************************************************************/
void INTERNAL VInt_OnApply(HWND hdlg, PVLISTINT pvint) { HRESULT hres;
hres = pvint->Update(&pvint->dipdw.diph, pvint->pvRef1, pvint->pvRef2);
if (FAILED(hres)) { MessageBoxV(hdlg, IDS_ERR_HRESULT, hres); } }
/*****************************************************************************
* * VInt_SetRadix * * Set a new radix by reading the old value, changing the radix, * and writing out the new value. * *****************************************************************************/
void INTERNAL VInt_SetRadix(HWND hwndUD, PVLISTINT pvint, int iRadix) { UpDown_GetPos(hwndUD, &pvint->dipdw.dwData); pvint->iRadix = iRadix; UpDown_SetPos(hwndUD, pvint->iRadix, pvint->dipdw.dwData); }
/*****************************************************************************
* * VInt_OnCommand * * If they changed the radix, then change it. * * If they pressed Apply, then apply it. * *****************************************************************************/
BOOL INTERNAL VInt_OnCommand(HWND hdlg, int id, UINT codeNotify) { PVLISTINT pvint = GetDialogPtr(hdlg); HWND hwndUD = GetDlgItem(hdlg, IDC_VINT_UD);
switch (id) {
case IDC_VINT_DEC: VInt_SetRadix(hwndUD, pvint, 10); return TRUE;
case IDC_VINT_HEX: VInt_SetRadix(hwndUD, pvint, 16); return TRUE;
case IDC_VINT_APPLY: UpDown_GetPos(hwndUD, &pvint->dipdw.dwData); VInt_OnApply(hdlg, pvint); return TRUE; } return FALSE; }
/*****************************************************************************
* * VInt_DlgProc * * Nothing really happens here. The real work is done externally. * *****************************************************************************/
INT_PTR CALLBACK VInt_DlgProc(HWND hdlg, UINT wm, WPARAM wp, LPARAM lp) { switch (wm) { case WM_INITDIALOG: return VInt_OnInitDialog(hdlg);
case WM_COMMAND: return VInt_OnCommand(hdlg, (int)GET_WM_COMMAND_ID(wp, lp), (UINT)GET_WM_COMMAND_CMD(wp, lp)); }
return FALSE; }
/*****************************************************************************
* * c_vvtblInt * * Our vtbl. * *****************************************************************************/
const VLISTVTBL c_vvtblInt = { VInt_PreDisplay, VInt_Destroy, IDD_VAL_INT, VInt_DlgProc, };
/*****************************************************************************
* * VInt_Create * * Make a vlist item that tracks an integer. * * The LPDIPROPDWORD gets copied and handed to the Update procedure. * The Update procedure can use the non-dwData fields of the * DIPROPDWORD to stash extra reference data. * *****************************************************************************/
PVLISTITEM EXTERNAL VInt_Create(LPDIPROPDWORD pdipdw, int iMin, int iMax, int iRadix, PROPUPDATEPROC Update, PV pvRef1, PV pvRef2) { PVLISTINT pvint = LocalAlloc(LPTR, cbX(VLISTINT));
if (pvint) { pvint->item.pvtbl = &c_vvtblInt; pvint->dipdw = *pdipdw; pvint->iMin = iMin; pvint->iMax = iMax; pvint->iRadix = iRadix; pvint->Update = Update; pvint->pvRef1 = pvRef1; pvint->pvRef2 = pvRef2; }
return (PV)pvint; }
|