完成常规设置项编码

This commit is contained in:
gb 2022-06-21 17:23:26 +08:00
parent 9ce97e3061
commit 64c671b6b7
5 changed files with 749 additions and 63 deletions

View File

@ -5,6 +5,15 @@
#include "resource.h"
#include "scanned_img.h" // for local_trans
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
#define FLOAT_FORMAT L"%.2f"
#define IS_STR_EQUAL(s1, s2) (wcscmp(s1, s2) == 0)
#define IS_EDIT(cls) IS_STR_EQUAL(cls, WC_EDITW)
#define IS_COMBOX(cls) IS_STR_EQUAL(cls, WC_COMBOBOXW)
#define IS_TRACKBAR(cls) IS_STR_EQUAL(cls, TRACKBAR_CLASSW)
#define IS_UPDOWN_ARROW(cls) IS_STR_EQUAL(cls, UPDOWN_CLASSW)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// dlg_base 对话框
extern HMODULE g_my_inst;
@ -122,86 +131,635 @@ HFONT dlg_base::get_font(void)
{
return (HFONT)SendMessage(hwnd_, WM_GETFONT, 0, 0);
}
int dlg_base::get_string_width(const wchar_t* str)
{
HDC hdc = GetWindowDC(hwnd_);
SIZE size = { 0 };
GetTextExtentPointW(hdc, str, lstrlenW(str), &size);
ReleaseDC(hwnd_, hdc);
return size.cx;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// dlg_page 对话框
std::wstring dlg_page::property_type = L"option_type";
std::wstring dlg_page::property_host = L"option_host_wnd";
std::wstring dlg_page::property_size = L"option_size";
UINT dlg_page::dyn_id_base = 3000;
int dlg_page::gap_x = 20;
int dlg_page::gap_y = 12;
int dlg_page::gap_y = 15;
int dlg_page::spin_w = 8;
dlg_page::dlg_page(HWND parent, const wchar_t* name) : dlg_base(parent, IDD_PAGE), name_(name ? name : L""), ctrl_id_(0)
dlg_page::dlg_page(HWND parent, const wchar_t* name
, LPSANEAPI api, SANE_Handle dev)
: dlg_base(parent, IDD_PAGE), name_(name ? name : L""), ctrl_id_(0)
, sane_(*api), dev_(dev), done_(false)
{
size_.cx = size_.cy = 0;
pos_.x = 12;
pos_.y = 8;
create();
refresh_font();
}
dlg_page::~dlg_page()
{}
{
for (auto& v : ctrls_)
DestroyWindow(v);
}
BOOL dlg_page::handle_message(UINT msg, WPARAM wp, LPARAM lp)
{
return FALSE;
BOOL ret = TRUE;
switch (msg)
{
case WM_MOUSEWHEEL:
ret = on_mouse_wheel(LOWORD(wp), HIWORD(wp), LOWORD(lp), HIWORD(lp));
break;
case WM_NOTIFY:
ret = on_notify((int)wp, (LPNMHDR)lp);
break;
case WM_COMMAND:
handle_command(HIWORD(wp), LOWORD(wp), (HWND)lp);
break;
default:
ret = FALSE;
}
return ret;
}
void dlg_page::on_font_changed(void)
{
refresh_font();
}
void dlg_page::refresh_font(void)
{
HFONT font = get_font();
LOGFONTW lf = { 0 };
GetObjectW(font, sizeof(lf), &lf);
font_size_.cx = lf.lfWidth;
font_size_.cy = lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight;
}
bool dlg_page::create_control_bool(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
{
std::wstring title(local_trans::a2u(desc->title, CP_UTF8));
bool ret = true;
bool now = *(SANE_Bool*)cur_val == SANE_TRUE ? true : false;
int w = title.length() * font_size_.cx + 18,
h = font_size_.cy;
HWND wnd = CreateWindowW(L"Button", L"check", WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX, pos_.x, pos_.y, w, h, hwnd(), NULL, g_my_inst, NULL);
pos_.y += h + dlg_page::gap_y;
if (size_.cx < w)
size_.cx = w;
if (size_.cy < pos_.y)
size_.cy = pos_.y;
if (desc->cap & SANE_CAP_INACTIVE)
EnableWindow(wnd, FALSE);
HWND dlg_page::create_label(int sn, const wchar_t* title, int x, int y, SIZE size)
{
HWND wnd = CreateWindowW(WC_STATICW, title, WS_CHILD | WS_VISIBLE, x, y, size.cx, size.cy, hwnd(), NULL, g_my_inst, NULL);
ShowWindow(wnd, SW_SHOW);
SendMessage(wnd, WM_SETFONT, (WPARAM)get_font(), 1);
SetWindowLong(wnd, GWL_ID, dlg_page::dyn_id_base + sn);
ctrls_.push_back(wnd);
return wnd;
}
HWND dlg_page::create_slider(int sn, int x, int y, double lower, double upper, double step, double pos, LPSIZE size, bool is_double)
{
// lower slider upper
HWND wnd = NULL;
wchar_t limit[20] = { 0 };
const wchar_t *fmt = is_double ? FLOAT_FORMAT : L"%d";
int w = x, ticks_limit = is_double ? 500 : 5;
DWORD style = WS_CHILD | WS_VISIBLE | TBS_HORZ;
if (IS_DOUBLE_EQUAL(step, 0))
step = 1.0f;
if(is_double)
swprintf_s(limit, _countof(limit) - 1, fmt, lower);
else
swprintf_s(limit, _countof(limit) - 1, fmt, (int)lower);
size->cx = get_string_width(limit);
create_label(sn, limit, x, y, *size);
x += size->cx;
size->cx = (upper - lower + step - 1) / step;
size->cx += 100;
size->cx /= 200;
size->cx *= 100;
if (size->cx < 100)
size->cx = 100;
if (size->cx > 300)
size->cx = 300;
if (upper > lower && size->cx / (upper - lower) < ticks_limit)
style |= TBS_NOTICKS;
else
style |= TBS_AUTOTICKS;
wnd = CreateWindowW(TRACKBAR_CLASSW, L"", style, x, y, size->cx, size->cy, hwnd(), NULL, g_my_inst, NULL);
if (is_double)
{
SendMessage(wnd, TBM_SETRANGEMIN, 1, (LPARAM)int(lower * 100.0f + .5f));
SendMessage(wnd, TBM_SETRANGEMAX, 1, (LPARAM)int(upper * 100.0f + .5f));
SendMessage(wnd, TBM_SETPOS, TRUE, (LPARAM)int(pos * 100.0f + .5f));
}
else
{
SendMessage(wnd, TBM_SETRANGEMIN, 1, (LPARAM)int(lower * 1.0f + .5f));
SendMessage(wnd, TBM_SETRANGEMAX, 1, (LPARAM)int(upper * 1.0f + .5f));
SendMessage(wnd, TBM_SETPOS, TRUE, (LPARAM)int(pos * 1.0f + .5f));
}
SetWindowLong(wnd, GWL_ID, dlg_page::dyn_id_base + sn);
ShowWindow(wnd, SW_SHOW);
ctrls_.push_back(wnd);
x += size->cx;
if(is_double)
swprintf_s(limit, _countof(limit) - 1, fmt, upper);
else
swprintf_s(limit, _countof(limit) - 1, fmt, (int)upper);
size->cx = get_string_width(limit);
create_label(sn, limit, x, y, *size);
size->cx = x + size->cx - w;
return wnd;
}
HWND dlg_page::create_edit(int sn, int x, int y, int h, int w)
{
HWND edit = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, L"", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, x, y, w, h, hwnd(), NULL, g_my_inst, NULL);
SetWindowLong(edit, GWL_ID, dlg_page::dyn_id_base + sn);
SendMessage(edit, WM_SETFONT, (WPARAM)get_font(), 1);
ShowWindow(edit, SW_SHOW);
ctrls_.push_back(edit);
return edit;
}
HWND dlg_page::create_combox(int sn, int x, int y, std::vector<std::wstring>& vals, const wchar_t* cur_val, LPSIZE size)
{
int h = vals.size() * 2 * size->cy;
HWND wnd = NULL;
for (int i = 0; i < vals.size(); ++i)
{
if (size->cx < get_string_width(vals[i].c_str()))
size->cx = get_string_width(vals[i].c_str());
}
size->cx + 20;
wnd = CreateWindowW(WC_COMBOBOXW, L"", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL, x, y, size->cx, h, hwnd(), NULL, g_my_inst, NULL);
SendMessage(wnd, CB_SETDROPPEDWIDTH, size->cx, 0);
for (int i = 0; i < vals.size(); ++i)
{
SendMessageW(wnd, CB_ADDSTRING, 0, (LPARAM)vals[i].c_str());
if (vals[i] == cur_val)
SendMessageW(wnd, CB_SETCURSEL, i, 0);
}
SetWindowLong(wnd, GWL_ID, dlg_page::dyn_id_base + sn);
SendMessage(wnd, WM_SETFONT, (WPARAM)get_font(), 1);
ShowWindow(wnd, SW_SHOW);
ctrls_.push_back(wnd);
return wnd;
}
HWND dlg_page::create_spin(int sn, HWND edit, double pos, double lower, double upper, bool is_double)
{
RECT r = { 0 };
HWND wnd = NULL;
GetWindowRect(edit, &r);
screen_2_client(&r);
wnd = CreateWindowW(UPDOWN_CLASSW, L"", WS_CHILD | WS_VISIBLE | UDS_SETBUDDYINT, r.right - 1, r.top, dlg_page::spin_w, r.bottom - r.top, hwnd(), NULL, g_my_inst, NULL);
SetWindowLong(wnd, GWL_ID, dlg_page::dyn_id_base + sn);
SendMessage(wnd, WM_SETFONT, (WPARAM)get_font(), 1);
if (is_double)
{
SendMessage(wnd, UDM_SETRANGE32, WPARAM(lower * 100.f + .5f), LPARAM(upper * 100.0f + .5f));
SendMessage(wnd, UDM_SETPOS32, 0, LPARAM(pos * 100.0f + .5f));
}
else
{
SendMessage(wnd, UDM_SETRANGE32, (WPARAM)(int)lower, (LPARAM)(int)upper);
SendMessage(wnd, UDM_SETPOS32, 0, (LPARAM)(int)pos);
}
ShowWindow(wnd, SW_SHOW);
ctrls_.push_back(wnd);
SetPropW(wnd, dlg_page::property_host.c_str(), edit);
if(!is_double)
SendMessage(wnd, UDM_SETBUDDY, (WPARAM)edit, 0);
return wnd;
}
HWND dlg_page::create_control_bool(int sn, const SANE_Option_Descriptor* desc, void* cur_val, const wchar_t* title, LPSIZE text_size)
{
bool now = *(SANE_Bool*)cur_val == SANE_TRUE ? true : false;
HWND wnd = NULL;
text_size->cx += 18 + dlg_page::gap_x;
wnd = CreateWindowW(WC_BUTTONW, title, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, pos_.x, pos_.y, text_size->cx, text_size->cy, hwnd(), NULL, g_my_inst, NULL);
SetWindowLong(wnd, GWL_ID, dlg_page::dyn_id_base + sn);
SendMessage(wnd, WM_SETFONT, (WPARAM)get_font(), 1);
ShowWindow(wnd, SW_SHOW);
ctrls_.push_back(wnd);
if (now)
SendMessage(wnd, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
return ret;
return wnd;
}
bool dlg_page::create_control_int(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
HWND dlg_page::create_control_int(int sn, const SANE_Option_Descriptor* desc, void* cur_val, const wchar_t* title, LPSIZE text_size)
{
bool ret = true;
// title: combox
// title: [slider] edit spin
HWND label = create_label(sn, title, pos_.x, pos_.y, *text_size), slider = NULL, wnd = NULL, spin = NULL;
int now = *(SANE_Int*)cur_val,
x = pos_.x,
w = 50;
SIZE size(*text_size);
wchar_t text[20] = { 0 };
x += text_size->cx + dlg_page::gap_x;
swprintf_s(text, _countof(text) - 1, L"%d", now);
if (desc->constraint_type == SANE_CONSTRAINT_WORD_LIST)
{
const SANE_Word *v = desc->constraint.word_list;
std::vector<std::wstring> vals;
for (int i = 0; i < v[0]; ++i)
{
swprintf_s(text, _countof(text) - 1, L"%d", v[i + 1]);
vals.push_back(text);
}
swprintf_s(text, _countof(text) - 1, L"%d", now);
wnd = create_combox(sn, x, pos_.y, vals, text, &size);
x += size.cx;
}
else
{
int lower = 0, upper = 100;
if (desc->constraint_type == SANE_CONSTRAINT_RANGE)
{
lower = desc->constraint.range->min;
upper = desc->constraint.range->max;
slider = create_slider(sn, x, pos_.y, lower, upper, desc->constraint.range->quant, now, &size, false);
x += size.cx + dlg_page::gap_x;
}
wnd = create_edit(sn, x, pos_.y - 2, text_size->cy, w);
x += w;
SetWindowTextW(wnd, text);
if (IsWindow(slider))
SetPropW(slider, dlg_page::property_host.c_str(), wnd);
spin = create_spin(sn, wnd, now, lower, upper, false);
x += dlg_page::spin_w;
}
text_size->cx = x + dlg_page::gap_x;
return wnd;
}
HWND dlg_page::create_control_float(int sn, const SANE_Option_Descriptor* desc, void* cur_val, const wchar_t* title, LPSIZE text_size)
{
// title: combox
// title: [slider] edit spin
HWND label = create_label(sn, title, pos_.x, pos_.y, *text_size), slider = NULL, wnd = NULL, spin = NULL;
int now = *(SANE_Int*)cur_val,
x = pos_.x,
w = 50;
SIZE size(*text_size);
wchar_t text[20] = { 0 };
x += text_size->cx + dlg_page::gap_x;
swprintf_s(text, _countof(text) - 1, FLOAT_FORMAT, SANE_UNFIX(*(SANE_Word*)cur_val));
if (desc->constraint_type == SANE_CONSTRAINT_WORD_LIST)
{
const SANE_Word *v = desc->constraint.word_list;
std::vector<std::wstring> vals;
wchar_t cur[40] = { 0 };
for (int i = 0; i < v[0]; ++i)
{
swprintf_s(text, _countof(text) - 1, FLOAT_FORMAT, SANE_UNFIX(v[i + 1]));
vals.push_back(text);
if (v[i + 1] == *(SANE_Word*)cur_val)
wcscpy_s(cur, _countof(cur) - 1, text);
}
wnd = create_combox(sn, x, pos_.y, vals, cur, &size);
x += size.cx;
}
else
{
double lower = .0f, upper = 100.0f;
if (desc->constraint_type == SANE_CONSTRAINT_RANGE)
{
lower = SANE_UNFIX(desc->constraint.range->min);
upper = SANE_UNFIX(desc->constraint.range->max);
slider = create_slider(sn, x, pos_.y, lower, upper, SANE_UNFIX(desc->constraint.range->quant), SANE_UNFIX(*(SANE_Word*)cur_val), &size, true);
x += size.cx + dlg_page::gap_x;
}
wnd = create_edit(sn, x, pos_.y - 2, text_size->cy, w);
x += w;
SetWindowTextW(wnd, text);
if (IsWindow(slider))
SetPropW(slider, dlg_page::property_host.c_str(), wnd);
spin = create_spin(sn, wnd, SANE_UNFIX(*(SANE_Word*)cur_val), lower, upper, true);
x += dlg_page::spin_w;
}
text_size->cx = x + dlg_page::gap_x;
return wnd;
}
HWND dlg_page::create_control_string(int sn, const SANE_Option_Descriptor* desc, void* cur_val, const wchar_t* title, LPSIZE text_size)
{
HWND wnd = NULL;
int x = pos_.x;
std::wstring now(local_trans::a2u((char*)cur_val, CP_UTF8));
create_label(sn, title, x, pos_.y, *text_size);
x += text_size->cx + dlg_page::gap_x;
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
{
std::vector<std::wstring> vals;
const SANE_String_Const *str = desc->constraint.string_list;
SIZE size(*text_size);
for (int i = 0; str[i]; ++i)
{
std::wstring text(local_trans::a2u(str[i], CP_UTF8));
vals.push_back(text);
}
wnd = create_combox(sn, x, pos_.y, vals, now.c_str(), &size);
x += size.cx;
}
else
{
wnd = create_edit(sn, x, pos_.y, text_size->cy, 200);
SetWindowTextW(wnd, now.c_str());
x += 200;
}
text_size->cx = x + dlg_page::gap_x;
return wnd;
}
HWND dlg_page::create_control_button(int sn, const SANE_Option_Descriptor* desc, void* cur_val, const wchar_t* title, LPSIZE text_size)
{
HWND wnd = NULL;
return wnd;
}
void dlg_page::handle_command(WORD code, WORD id, HANDLE ctrl)
{
wchar_t cls[128] = { 0 };
GetClassNameW((HWND)ctrl, cls, _countof(cls) - 1);
if (IS_EDIT(cls) && code != EN_CHANGE ||
IS_COMBOX(cls) && code != CBN_SELCHANGE)
{
return;
}
control_action((HWND)ctrl);
}
BOOL dlg_page::on_notify(int ctrl_id, LPNMHDR pnmh)
{
wchar_t cls[128] = { 0 };
GetClassNameW((HWND)pnmh->hwndFrom, cls, _countof(cls) - 1);
if (IS_TRACKBAR(cls))
{
if (pnmh->code != NM_RELEASEDCAPTURE &&
pnmh->code != NM_CUSTOMDRAW)
return FALSE;
}
else if (IS_UPDOWN_ARROW(cls))
{
HWND host = (HWND)GetPropW(pnmh->hwndFrom, dlg_page::property_host.c_str());
if(IsWindow(host) && (int)GetPropW(host, dlg_page::property_type.c_str()) == SANE_TYPE_INT)
return FALSE;
}
control_action(pnmh->hwndFrom);
return TRUE;
}
void* dlg_page::value_from_ctrl(HWND ctrl, SANE_Value_Type* type)
{
void* ret = NULL;
HWND host = (HWND)GetPropW(ctrl, dlg_page::property_host.c_str());
wchar_t cls[40] = { 0 };
SANE_Value_Type tp = SANE_TYPE_INT;
int(__cdecl * cmpstr)(const wchar_t*, const wchar_t*) = wcscmp;
if (!IsWindow(host))
host = ctrl;
tp = (SANE_Value_Type)(DWORD)GetPropW(host, dlg_page::property_type.c_str());
if (type)
*type = tp;
GetClassNameW(ctrl, cls, _countof(cls) - 1);
if (cmpstr(cls, WC_BUTTONW) == 0)
{
if (tp == SANE_TYPE_BOOL)
{
ret = new char[sizeof(SANE_Bool)];
*(SANE_Bool*)ret = SendMessage(ctrl, BM_GETCHECK, 0, 0) == BST_CHECKED ? SANE_TRUE : SANE_FALSE;
}
}
else if (cmpstr(cls, TRACKBAR_CLASSW) == 0)
{
if (tp == SANE_TYPE_INT)
{
ret = new char[sizeof(SANE_Int)];
*(SANE_Int*)ret = SendMessage(ctrl, TBM_GETPOS, 0, 0);
}
else if (tp == SANE_TYPE_FIXED)
{
double pos = (double)SendMessage(ctrl, TBM_GETPOS, 0, 0);
ret = new char[sizeof(SANE_Fixed)];
*(SANE_Fixed*)ret = SANE_FIX(pos / 100.0f);
}
}
else if (cmpstr(cls, WC_EDITW) == 0 || cmpstr(cls, WC_COMBOBOXW) == 0)
{
int len = (int)GetPropW(host, dlg_page::property_size.c_str());
wchar_t* buf = new wchar_t[len + 2];
GetWindowTextW(ctrl, buf, len);
buf[len] = 0;
if (tp == SANE_TYPE_INT)
{
ret = new char[sizeof(SANE_Int)];
*(SANE_Int*)ret = _wtoi(buf);
}
else if (tp == SANE_TYPE_FIXED)
{
ret = new char[sizeof(SANE_Fixed)];
*(SANE_Fixed*)ret = SANE_FIX(_wtof(buf));
}
else if (tp == SANE_TYPE_STRING)
{
std::string utf8(local_trans::u2a(buf, CP_UTF8));
ret = new char[len + 2];
if (utf8.length() > len)
utf8.erase(len);
strcpy((char*)ret, utf8.c_str());
((char*)ret)[len] = 0;
}
delete[] buf;
}
else if (cmpstr(cls, UPDOWN_CLASSW) == 0)
{
if (tp == SANE_TYPE_INT)
{
ret = new char[sizeof(SANE_Int)];
*(SANE_Int*)ret = (int)SendMessage(ctrl, UDM_GETPOS, 0, 0);
}
else if (tp == SANE_TYPE_FIXED)
{
double pos = (double)(int)SendMessage(ctrl, UDM_GETPOS32, 0, 0);
ret = new char[sizeof(SANE_Fixed)];
*(SANE_Fixed*)ret = SANE_FIX(pos / 100.0f);
}
}
return ret;
}
bool dlg_page::create_control_float(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
void dlg_page::set_ctrl_value(HWND ctrl, SANE_Value_Type type, void* val, bool only_me, bool skip_ctrl)
{
bool ret = true;
if (only_me)
{
bool finish = done_;
wchar_t cls[128] = { 0 };
int(__cdecl * cmpstr)(const wchar_t*, const wchar_t*) = wcscmp;
return ret;
GetClassNameW(ctrl, cls, _countof(cls) - 1);
done_ = false;
if (cmpstr(cls, WC_BUTTONW) == 0)
{
if (type == SANE_TYPE_BOOL)
SendMessage(ctrl, BM_SETCHECK, *(SANE_Bool*)val == SANE_TRUE ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0);
}
else if (cmpstr(cls, TRACKBAR_CLASSW) == 0)
{
if (type == SANE_TYPE_INT)
SendMessage(ctrl, TBM_SETPOS, 1, (LPARAM)*(SANE_Int*)val);
else if (type == SANE_TYPE_FIXED)
{
double pos = SANE_UNFIX(*(SANE_Fixed*)val);
SendMessage(ctrl, TBM_SETPOS, TRUE, (LPARAM)int(pos * 100.0f + .5f));
}
}
else if (cmpstr(cls, WC_EDITW) == 0 || cmpstr(cls, WC_COMBOBOXW) == 0)
{
wchar_t buf[40] = { 0 };
std::wstring text(L"");
if (type == SANE_TYPE_INT)
{
swprintf_s(buf, _countof(buf) - 1, L"%d", *(SANE_Int*)val);
text = buf;
}
else if (type == SANE_TYPE_FIXED)
{
swprintf_s(buf, _countof(buf) - 1, FLOAT_FORMAT, SANE_UNFIX(*(SANE_Fixed*)val));
text = buf;
}
else if (type == SANE_TYPE_STRING)
{
text = local_trans::a2u((char*)val, CP_UTF8);
}
if (IS_EDIT(cls))
SetWindowTextW(ctrl, text.c_str());
else
SendMessageW(ctrl, CB_SELECTSTRING, 0, (LPARAM)text.c_str());
}
else if (cmpstr(cls, UPDOWN_CLASSW) == 0)
{
if (type == SANE_TYPE_INT)
{
SendMessage(ctrl, UDM_SETPOS32, 0, *(SANE_Int*)val);
}
else if (type == SANE_TYPE_FIXED)
{
double pos = SANE_UNFIX(*(SANE_Fixed*)val);
}
}
done_ = finish;
}
else
{
int id = GetWindowLong(ctrl, GWL_ID);
int ind = 0;
for (; ind < ctrls_.size(); ++ind)
{
if (GetWindowLong(ctrls_[ind], GWL_ID) == id)
break;
}
for (; ind < ctrls_.size(); ++ind)
{
if (GetWindowLong(ctrls_[ind], GWL_ID) != id)
break;
if (skip_ctrl && ctrl == ctrls_[ind])
continue;
set_ctrl_value(ctrls_[ind], type, val, true);
}
}
}
bool dlg_page::create_control_string(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
void dlg_page::free_ctrl_value(void* val)
{
bool ret = true;
return ret;
if (val)
{
char* v = (char*)val;
delete[] v;
}
}
bool dlg_page::create_control_button(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
int dlg_page::find_control_ind(HWND wnd)
{
bool ret = true;
int ind = -1;
return ret;
for (int i = 0; i < ctrls_.size(); ++i)
{
if (ctrls_[i] == wnd)
{
ind = i;
break;
}
}
return ind;
}
void dlg_page::control_action(HWND wnd)
{
if (done_)
{
SANE_Value_Type type = (SANE_Value_Type)-1;
int id = GetWindowLong(wnd, GWL_ID);
void* val = value_from_ctrl(wnd, &type);
if (val)
{
SANE_Int after = 0;
SANE_Status statu = sane_.sane_control_option_api(dev_, id - dlg_page::dyn_id_base, SANE_ACTION_SET_VALUE, val, &after);
done_ = false;
set_ctrl_value(wnd, type, val, false, !(after || statu));
done_ = true;
if (after || statu)
PostMessage(parent_, WM_REFRESH_OPTION, id - dlg_page::dyn_id_base, 0);
free_ctrl_value(val);
}
}
}
BOOL dlg_page::on_mouse_wheel(WORD vkey, short delta, short x, short y)
{
POINT pt = { x, y };
HWND wnd = WindowFromPoint(pt);
BOOL handled = FALSE;
if (IsWindow(wnd))
{
wchar_t cls[128] = { 0 };
GetClassNameW(wnd, cls, _countof(cls) - 1);
if (IS_EDIT(cls))
{
SANE_Value_Type type = (SANE_Value_Type)(DWORD)GetPropW(wnd, dlg_page::property_type.c_str());
if (type == SANE_TYPE_INT || type == SANE_TYPE_FIXED)
{
int s = delta < 0 ? -1 : 1;
GetWindowTextW(wnd, cls, _countof(cls) - 1);
handled = TRUE;
if (type == SANE_TYPE_INT)
swprintf_s(cls, _countof(cls) - 1, L"%d", _wtoi(cls) + 1 * s);
else
swprintf_s(cls, _countof(cls) - 1, FLOAT_FORMAT, _wtof(cls) + .01f * s);
SetWindowTextW(wnd, cls);
}
}
}
return handled;
}
bool dlg_page::add_control(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
@ -211,7 +769,7 @@ bool dlg_page::add_control(int sn, const SANE_Option_Descriptor* desc, void* cur
struct
{
int sane_type;
bool(dlg_page::* func)(int, const SANE_Option_Descriptor*, void*);
HWND(dlg_page::* func)(int, const SANE_Option_Descriptor*, void*, const wchar_t*, LPSIZE);
}creat[] = { {SANE_TYPE_BOOL, &dlg_page::create_control_bool}
, {SANE_TYPE_INT, &dlg_page::create_control_int}
, {SANE_TYPE_FIXED, &dlg_page::create_control_float}
@ -222,13 +780,40 @@ bool dlg_page::add_control(int sn, const SANE_Option_Descriptor* desc, void* cur
{
if (creat[i].sane_type == desc->type)
{
ret = (this->*creat[i].func)(sn, desc, cur_val);
std::wstring title(local_trans::a2u(desc->title, CP_UTF8));
HDC hdc = GetWindowDC(hwnd());
SIZE text = { 0 };
HWND wnd = NULL;
int pos = ctrls_.size();
GetTextExtentPointW(hdc, title.c_str(), title.length(), &text);
ReleaseDC(hwnd(), hdc);
wnd = (this->*creat[i].func)(sn, desc, cur_val, title.c_str(), &text);
ret = IsWindow(wnd);
if (ret)
{
SetPropW(wnd, dlg_page::property_type.c_str(), (HANDLE)creat[i].sane_type);
SetPropW(wnd, dlg_page::property_size.c_str(), (HANDLE)desc->size);
if (desc->cap & SANE_CAP_INACTIVE)
{
for (; pos < ctrls_.size(); ++pos)
EnableWindow(ctrls_[pos], FALSE);
}
if (size_.cx < pos_.x + text.cx)
size_.cx = pos_.x + text.cx;
pos_.y += text.cy + dlg_page::gap_y;
}
break;
}
}
size_.cy = pos_.y;
return ret;
}
void dlg_page::add_control_done(void)
{
done_ = true;
}
SIZE dlg_page::desired_size(void)
{
return size_;
@ -241,6 +826,32 @@ void dlg_page::hide(void)
{
ShowWindow(hwnd_, SW_HIDE);
}
bool dlg_page::refresh(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
{
bool found = false;
int ind = 0;
sn += dlg_page::dyn_id_base;
for (; ind < ctrls_.size(); ++ind)
{
if (GetWindowLong(ctrls_[ind], GWL_ID) == sn)
{
found = true;
break;
}
}
done_ = false;
for (; ind < ctrls_.size(); ++ind)
{
if (GetWindowLong(ctrls_[ind], GWL_ID) != sn)
break;
set_ctrl_value(ctrls_[ind], desc->type, cur_val, true);
EnableWindow(ctrls_[ind], (desc->cap & SANE_CAP_INACTIVE) != SANE_CAP_INACTIVE);
}
done_ = true;
return found;
}
const wchar_t* dlg_page::name(void)
{
return name_.c_str();

View File

@ -40,37 +40,63 @@ public:
HWND get_item(UINT id);
BOOL set_font(HFONT font);
HFONT get_font(void);
int get_string_width(const wchar_t* str);
};
class dlg_page : public dlg_base
{
std::wstring name_;
SIZE size_;
SIZE font_size_;
UINT ctrl_id_;
POINT pos_;
SANEAPI sane_;
SANE_Handle dev_;
bool done_;
std::vector<HWND> ctrls_;
static std::wstring property_type;
static std::wstring property_host;
static std::wstring property_size;
static UINT dyn_id_base;
static int gap_x;
static int gap_y;
static int spin_w;
BOOL handle_message(UINT msg, WPARAM wp, LPARAM lp) override;
void on_font_changed(void) override;
void refresh_font(void);
bool create_control_bool(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
bool create_control_int(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
bool create_control_float(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
bool create_control_string(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
bool create_control_button(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
HWND create_label(int sn, const wchar_t* title, int x, int y, SIZE size);
HWND create_slider(int sn, int x, int y, double lower, double upper, double step, double pos, LPSIZE size, bool is_double);
HWND create_edit(int sn, int x, int y, int h, int w = 50);
HWND create_combox(int sn, int x, int y, std::vector<std::wstring>& vals, const wchar_t* cur_val, LPSIZE size);
HWND create_spin(int sn, HWND edit, double pos, double lower, double upper, bool is_double);
HWND create_control_bool(int sn, const SANE_Option_Descriptor* desc, void* cur_val, const wchar_t* title, LPSIZE text_size);
HWND create_control_int(int sn, const SANE_Option_Descriptor* desc, void* cur_val, const wchar_t* title, LPSIZE text_size);
HWND create_control_float(int sn, const SANE_Option_Descriptor* desc, void* cur_val, const wchar_t* title, LPSIZE text_size);
HWND create_control_string(int sn, const SANE_Option_Descriptor* desc, void* cur_val, const wchar_t* title, LPSIZE text_size);
HWND create_control_button(int sn, const SANE_Option_Descriptor* desc, void* cur_val, const wchar_t* title, LPSIZE text_size);
void handle_command(WORD code, WORD id, HANDLE ctrl);
BOOL on_notify(int ctrl_id, LPNMHDR pnmh);
void* value_from_ctrl(HWND ctrl, SANE_Value_Type* type); // call free_ctrl_value to free the returned value, data according to SANE-standard
void set_ctrl_value(HWND ctrl, SANE_Value_Type type, void* val, bool only_me, bool skip_ctrl = false);
void free_ctrl_value(void* val);
int find_control_ind(HWND wnd);
void control_action(HWND wnd);
BOOL on_mouse_wheel(WORD vkey, short delta, short x, short y);
public:
dlg_page(HWND parent, const wchar_t* name);
dlg_page(HWND parent, const wchar_t* name, LPSANEAPI api, SANE_Handle dev);
~dlg_page();
public:
bool add_control(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
void add_control_done(void);
SIZE desired_size(void);
void show(void);
void hide(void);
bool refresh(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
const wchar_t* name(void);
};

View File

@ -53,7 +53,7 @@ BOOL dlg_setting::handle_message(UINT msg, WPARAM wp, LPARAM lp)
handle_command(HIWORD(wp), LOWORD(wp), (HWND)lp);
break;
case WM_NOTIFY:
on_notify((int)wp, (LPNMHDR)lp);
ret = on_notify((int)wp, (LPNMHDR)lp);
break;
case WM_REFRESH_OPTION:
refresh_controls((int)wp);
@ -73,11 +73,14 @@ void dlg_setting::handle_command(WORD code, WORD id, HANDLE ctrl)
}
else if (id == IDC_BUTTON_HELP)
{
SANE_Int after = 0;
SANE_Status statu = sane_api_.sane_control_option_api(sane_dev_, id_help_, SANE_ACTION_SET_VALUE, &after, &after);
}
else if (id == IDC_BUTTON_RESTORE)
{
SANE_Int after = 0;
SANE_Status statu = sane_api_.sane_control_option_api(sane_dev_, id_restore_, SANE_ACTION_SET_VALUE, &after, &after);
refresh_controls(id_restore_);
}
}
void dlg_setting::notify_over(void)
@ -99,7 +102,10 @@ void dlg_setting::on_init_dialog(void)
if (desc->type == SANE_TYPE_GROUP)
{
if (page)
{
dlg_base::get_max_size(size, page->desired_size());
page->add_control_done();
}
page = add_tab(desc->title);
}
else if (page)
@ -115,14 +121,23 @@ void dlg_setting::on_init_dialog(void)
else if(desc->type == SANE_TYPE_BUTTON)
{
if (cmp_sane_opt(OPTION_TITLE_BZ, desc->title))
{
ShowWindow(GetDlgItem(hwnd_, IDC_BUTTON_HELP), SW_SHOW);
if (cmp_sane_opt(OPTION_TITLE_HFMRSZ, desc->title))
id_help_ = sn - 1;
}
else if (cmp_sane_opt(OPTION_TITLE_HFMRSZ, desc->title))
{
ShowWindow(GetDlgItem(hwnd_, IDC_BUTTON_RESTORE), SW_SHOW);
id_restore_ = sn - 1;
}
}
desc = sane_api_.sane_get_option_descriptor_api(sane_dev_, sn++);
}
if (page)
{
dlg_base::get_max_size(size, page->desired_size());
page->add_control_done();
}
if (size.cx || size.cy || IsWindow(tab_))
{
@ -136,7 +151,7 @@ void dlg_setting::on_init_dialog(void)
GetWindowRect(tab_, &r);
y = r.bottom - r.top;
size.cy += y;
r.right = r.left + rme.right - rme.left;
r.right = r.left + size.cx;
screen_2_client(&r);
MoveWindow(tab_, r.left, r.top, r.right - r.left, y, TRUE);
}
@ -174,9 +189,19 @@ void dlg_setting::on_init_dialog(void)
select_page(0);
UpdateWindow(hwnd());
}
void dlg_setting::on_notify(int ctrl_id, LPNMHDR pnmh)
BOOL dlg_setting::on_notify(int ctrl_id, LPNMHDR pnmh)
{
BOOL ret = TRUE;
if (pnmh->hwndFrom == tab_)
{
if (pnmh->code == TCN_SELCHANGING)
ret = FALSE;
else if (pnmh->code == TCN_SELCHANGE)
select_page(TabCtrl_GetCurSel(tab_));
}
return ret;
}
int dlg_setting::get_tab_count(void)
{
@ -190,7 +215,7 @@ int dlg_setting::get_tab_count(void)
dlg_page* dlg_setting::add_tab(const char* utf8_title)
{
std::wstring title(local_trans::a2u(utf8_title, CP_UTF8));
dlg_page *page = new dlg_page(hwnd(), title.c_str());
dlg_page *page = new dlg_page(hwnd(), title.c_str(), &sane_api_, sane_dev_);
HFONT font = (HFONT)SendMessage(get_item(IDOK), WM_GETFONT, 0, 0);
LOGFONTW lf = { 0 };
@ -198,7 +223,12 @@ dlg_page* dlg_setting::add_tab(const char* utf8_title)
page->set_font(font);
if (!IsWindow(tab_))
{
tab_ = CreateWindowW(L"SysTabControl32", L"pages", WS_CHILD | WS_VISIBLE, 0, 0, 100, lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight, hwnd(), NULL, g_my_inst, NULL);
HDC hdc = GetWindowDC(hwnd());
SIZE text = { 0 };
GetTextExtentPointW(hdc, title.c_str(), title.length(), &text);
ReleaseDC(hwnd(), hdc);
tab_ = CreateWindowW(L"SysTabControl32", L"pages", WS_CHILD | WS_VISIBLE, 0, 0, 100, text.cy + 6, hwnd(), NULL, g_my_inst, NULL);
SendMessage(tab_, WM_SETFONT, (WPARAM)SendMessage(get_item(IDOK), WM_GETFONT, 0, 0), 1);
SetWindowLong(tab_, GWL_ID, 1234);
ShowWindow(tab_, SW_SHOW);
@ -271,7 +301,24 @@ dlg_page* dlg_setting::select_page(int index)
}
void dlg_setting::refresh_controls(int src_sn)
{
int sn = 1;
const SANE_Option_Descriptor* desc = sane_api_.sane_get_option_descriptor_api(sane_dev_, sn++);
while (desc)
{
char* buf = new char[desc->size + 8];
SANE_Int info = 0;
dlg_page* page = NULL;
memset(buf, 0, desc->size + 8);
sane_api_.sane_control_option_api(sane_dev_, sn - 1, SANE_ACTION_GET_VALUE, buf, &info);
for (int i = 0; page = get_page(i); ++i)
{
if (page->refresh(sn - 1, desc, buf))
break;
}
delete[] buf;
desc = sane_api_.sane_get_option_descriptor_api(sane_dev_, sn++);
}
}
void dlg_setting::set_quit_notify(void(__stdcall* notify)(bool, void*), void* param)

View File

@ -23,6 +23,8 @@ class dlg_setting : public dlg_base
unsigned int papers_;
unsigned int images_;
bool err_;
int id_help_;
int id_restore_;
HWND tab_;
@ -36,7 +38,7 @@ class dlg_setting : public dlg_base
void handle_command(WORD code, WORD id, HANDLE ctrl);
void notify_over(void);
void on_init_dialog(void);
void on_notify(int ctrl_id, LPNMHDR pnmh);
BOOL on_notify(int ctrl_id, LPNMHDR pnmh);
int get_tab_count(void);
dlg_page* add_tab(const char* utf8_title);
dlg_page* get_page(int index);

View File

@ -74,7 +74,7 @@ BEGIN
PUSHBUTTON "°ïÖú",IDC_BUTTON_HELP,167,7,48,14,NOT WS_VISIBLE
END
IDD_PAGE DIALOGEX 0, 0, 257, 133
IDD_PAGE DIALOGEX 0, 0, 258, 133
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
@ -108,7 +108,7 @@ BEGIN
IDD_PAGE, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 250
RIGHTMARGIN, 251
TOPMARGIN, 7
BOTTOMMARGIN, 126
END