// DlgIndicator.cpp: 实现文件 // #include "DlgPage.h" #include "resource.h" #include "scanned_img.h" // for local_trans #include "DlgArea.h" ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // #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_BUTTON(cls) IS_STR_EQUAL(cls, WC_BUTTONW) #define IS_TRACKBAR(cls) IS_STR_EQUAL(cls, TRACKBAR_CLASSW) #define IS_UPDOWN_ARROW(cls) IS_STR_EQUAL(cls, UPDOWN_CLASSW) static IMPLEMENT_OPTION_STRING_COMPARE(is_sane_opt); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // dlg_base 对话框 extern HMODULE g_my_inst; std::wstring dlg_base::prop_name = L"dlg_base_object_prop_name"; dlg_base::dlg_base(HWND parent, UINT idd) : parent_(parent), hwnd_(NULL), idd_(idd) { } dlg_base::~dlg_base() { if(IsWindow(hwnd_)) DestroyWindow(hwnd_); } BOOL CALLBACK dlg_base::dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { if (msg == WM_INITDIALOG) { dlg_base* obj = (dlg_base*)lp; SetPropW(hwnd, dlg_base::prop_name.c_str(), (HANDLE)obj); obj->hwnd_ = hwnd; } dlg_base *obj = (dlg_base*)GetPropW(hwnd, dlg_base::prop_name.c_str()); BOOL ret = FALSE; if (obj) ret = obj->handle_message(msg, wp, lp); return ret; } bool dlg_base::get_max_size(SIZE& dst, const SIZE& src) { bool changed = false; if (dst.cx < src.cx) { dst.cx = src.cx; changed = true; } if (dst.cy < src.cy) { dst.cy = src.cy; changed = true; } return changed; } bool dlg_base::get_max_size(SIZE& dst, int cx, int cy) { bool changed = false; if (dst.cx < cx) { dst.cx = cx; changed = true; } if (dst.cy < cy) { dst.cy = cy; changed = true; } return changed; } BOOL dlg_base::handle_message(UINT msg, WPARAM wp, LPARAM lp) { return FALSE; } void dlg_base::on_font_changed(void) { } void dlg_base::create(void) { hwnd_ = CreateDialogParamW(g_my_inst, MAKEINTRESOURCE(idd_), parent_, &dlg_base::dlg_proc, (LPARAM)this); } HWND dlg_base::hwnd(void) { return hwnd_; } void dlg_base::screen_2_client(LPRECT r) { POINT pt = { r->left, r->top }; ScreenToClient(hwnd_, &pt); OffsetRect(r, pt.x - r->left, pt.y - r->top); } void dlg_base::client_2_screen(LPRECT r) { POINT pt = { r->left, r->top }; ClientToScreen(hwnd_, &pt); OffsetRect(r, pt.x - r->left, pt.y - r->top); } HWND dlg_base::get_item(UINT id) { return GetDlgItem(hwnd_, id); } BOOL dlg_base::set_font(HFONT font) { BOOL ret = SendMessage(hwnd_, WM_SETFONT, (WPARAM)font, 1) == 0; if (ret) on_font_changed(); return ret; } 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 = 15; int dlg_page::spin_w = 8; 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) , id_custom_area_(-1), id_custom_left_(-1), id_custom_right_(-1), id_custom_top_(-1), id_custom_bottom_(-1) , id_custom_gamma_(-1), id_paper_(-1), paper_(L"A4"), id_dpi_(-1), dpi_(200) { size_.cx = size_.cy = 0; pos_.x = 12; pos_.y = 8; create(); } dlg_page::~dlg_page() { for (auto& v : ctrls_) DestroyWindow(v); } BOOL dlg_page::handle_message(UINT msg, WPARAM wp, LPARAM lp) { 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) { HFONT font = get_font(); LOGFONTW lf = { 0 }; } 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& 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 wnd; } HWND dlg_page::create_control_int(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, L"%d", now); if (desc->constraint_type == SANE_CONSTRAINT_WORD_LIST) { const SANE_Word *v = desc->constraint.word_list; std::vector 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 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 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; } if (IS_BUTTON(cls)) { HWND host = (HWND)GetPropW((HWND)ctrl, dlg_page::property_host.c_str()); if (IsWindow(host)) { if (id == dlg_page::dyn_id_base + id_custom_area_) { unsigned int size = 0; std::string utf8(local_trans::u2a(paper_.c_str(), CP_UTF8)); dlg_area dlg(hwnd()); sane_.sane_io_control_api(dev_, IO_CTRL_CODE_GET_PAPER_SIZE, &utf8[0], &size); dlg.set_paper(paper_.c_str(), (float)(size & 0x0ffff), float(size >> 16), dpi_); if (dlg.do_modal(hwnd()) == IDOK) { SANE_Fixed val = SANE_FIX(dlg.x_in_mm()); SANE_Int after = 0; sane_.sane_control_option_api(dev_, id_custom_left_, SANE_ACTION_SET_VALUE, &val, &after); val = SANE_FIX(dlg.y_in_mm()); sane_.sane_control_option_api(dev_, id_custom_top_, SANE_ACTION_SET_VALUE, &val, &after); val = SANE_FIX(dlg.x_in_mm() + dlg.w_in_mm()); sane_.sane_control_option_api(dev_, id_custom_right_, SANE_ACTION_SET_VALUE, &val, &after); val = SANE_FIX(dlg.y_in_mm() + dlg.h_in_mm()); sane_.sane_control_option_api(dev_, id_custom_bottom_, SANE_ACTION_SET_VALUE, &val, &after); } return; } else if (id == dlg_page::dyn_id_base + id_custom_gamma_) { 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; } void dlg_page::set_ctrl_value(HWND ctrl, SANE_Value_Type type, void* val, bool only_me, bool skip_ctrl) { if (only_me) { bool finish = done_; wchar_t cls[128] = { 0 }; GetClassNameW(ctrl, cls, _countof(cls) - 1); done_ = false; if (IS_BUTTON(cls)) { if (type == SANE_TYPE_BOOL) { DWORD id = GetWindowLong(ctrl, GWL_ID); HWND host = (HWND)GetPropW(ctrl, dlg_page::property_host.c_str()); if (IsWindow(host) && (id == id_custom_area_ || id == id_custom_gamma_)) EnableWindow(ctrl, *(SANE_Bool*)val == SANE_TRUE); else SendMessage(ctrl, BM_SETCHECK, *(SANE_Bool*)val == SANE_TRUE ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0); } } else if (IS_TRACKBAR(cls)) { 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 (IS_EDIT(cls) || IS_COMBOX(cls)) { 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 (IS_UPDOWN_ARROW(cls)) { 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); } } } void dlg_page::free_ctrl_value(void* val) { if (val) { char* v = (char*)val; delete[] v; } } int dlg_page::find_control_ind(HWND wnd) { int ind = -1; 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 (id == dlg_page::dyn_id_base + id_dpi_) { if (type == SANE_TYPE_FIXED) dpi_ = SANE_UNFIX(*(SANE_Fixed*)val); else dpi_ = (float)(int)*(SANE_Int*)val; } else if (id == dlg_page::dyn_id_base + id_paper_) paper_ = local_trans::a2u((char*)val, CP_UTF8); 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) { bool ret = false; struct { int sane_type; 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} , {SANE_TYPE_STRING, &dlg_page::create_control_string} , {SANE_TYPE_BUTTON, &dlg_page::create_control_button} }; if (is_sane_opt(OPTION_TITLE_SMQYZCmm, desc->title)) id_custom_left_ = sn; else if (is_sane_opt(OPTION_TITLE_SMQYSCmm, desc->title)) id_custom_top_ = sn; else if (is_sane_opt(OPTION_TITLE_SMQYXCmm, desc->title)) id_custom_bottom_ = sn; else if (is_sane_opt(OPTION_TITLE_SMQYYCmm, desc->title)) id_custom_right_ = sn; else { for (int i = 0; i < _countof(creat); ++i) { if (creat[i].sane_type == desc->type) { 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 (is_sane_opt(OPTION_TITLE_ZDYSMQY, desc->title)) { // custom area ... int w = 69; HWND host = wnd; id_custom_area_ = sn; wnd = CreateWindowW(WC_BUTTONW, L"\u8bbe\u7f6e\u533a\u57df", WS_CHILD | WS_VISIBLE, pos_.x + text.cx, pos_.y - 1, w, text.cy + 3, hwnd(), NULL, g_my_inst, NULL); text.cx += w + dlg_page::gap_x; EnableWindow(wnd, (desc->cap & SANE_CAP_INACTIVE) == 0 && *(SANE_Bool*)cur_val == SANE_TRUE); SetWindowLong(wnd, GWL_ID, dlg_page::dyn_id_base + sn); SendMessage(wnd, WM_SETFONT, (WPARAM)get_font(), 1); SetPropW(wnd, dlg_page::property_host.c_str(), host); ctrls_.push_back(wnd); } else if (is_sane_opt(OPTION_TITLE_ZZCC, desc->title)) { paper_ = local_trans::a2u((char*)cur_val, CP_UTF8); id_paper_ = sn; } else if (is_sane_opt(OPTION_TITLE_FBL, desc->title)) { if (desc->type == SANE_TYPE_FIXED) dpi_ = SANE_UNFIX(*(SANE_Fixed*)cur_val); else dpi_ = (float)(int)*(SANE_Int*)cur_val; id_dpi_ = sn; } else if (is_sane_opt(OPTION_TITLE_QYSDQX, desc->title)) { // custom gamma control ... } 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_; } void dlg_page::show(void) { ShowWindow(hwnd_, SW_SHOW); } 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); HWND host = (HWND)GetPropW(ctrls_[ind], dlg_page::property_host.c_str()); if (IsWindow(host)) { BOOL checked = SendMessage(host, BM_GETCHECK, 0, 0) == BST_CHECKED; checked &= (desc->cap & SANE_CAP_INACTIVE) != SANE_CAP_INACTIVE; if (sn - dlg_page::dyn_id_base == id_custom_area_) { EnableWindow(ctrls_[ind], checked); } else if (sn - dlg_page::dyn_id_base == id_custom_gamma_) { EnableWindow(ctrls_[ind], checked); } } } done_ = true; return found; } const wchar_t* dlg_page::name(void) { return name_.c_str(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // compatible_dc compatible_dc::compatible_dc(HDC src) : src_(src), old_(NULL) { HWND hwnd = WindowFromDC(src); RECT r = { 0 }; if (!IsWindow(hwnd)) hwnd = GetDesktopWindow(); GetWindowRect(hwnd, &r); size_.cx = r.right - r.left; size_.cy = r.bottom - r.top; bmp_ = CreateCompatibleBitmap(src, size_.cx, size_.cy); hdc_ = CreateCompatibleDC(src); old_ = (HBITMAP)SelectObject(hdc_, bmp_); BitBlt(hdc_, 0, 0, size_.cx, size_.cy, src, 0, 0, SRCCOPY); } compatible_dc::~compatible_dc() { BitBlt(src_, 0, 0, size_.cx, size_.cy, hdc_, 0, 0, SRCCOPY); SelectObject(hdc_, old_); DeleteObject(bmp_); DeleteDC(hdc_); } HDC compatible_dc::get_dc() { return hdc_; }