408 lines
10 KiB
C
408 lines
10 KiB
C
|
/*****************************************************************************
|
||
|
*
|
||
|
* 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;
|
||
|
}
|