// DlgIndicator.cpp: 实现文件 // #include "DlgSetting.h" #include "resource.h" #include "scanned_img.h" // for local_trans #include "DlgPage.h" #include "gb_json.h" #include "../../sdk/include/lang/app_language.h" // CDlgIndicator 对话框 #include "DlgCfgMgr.h" #include "DlgInput.h" #include "DlgSaveScheme.h" #define MENU_CMD_0 ((unsigned short)0x8888) static IMPLEMENT_OPTION_STRING_COMPARE(cmp_sane_opt); dlg_setting::dlg_setting(HWND parent, LPSANEAPI api, SANE_Handle dev, bool with_scan, const wchar_t* name) : dlg_base(parent, IDD_SETTING) , sane_api_(*api), sane_dev_(dev), with_scan_(with_scan) , papers_(0), images_(0), err_(false), tab_(NULL), cfg_(NULL), cfg_file_(L""), twain_set_(nullptr), twain_schm_(nullptr) , schm_from_empty_(false) { std::wstring setting(local_trans::lang_trans_between_hz936(CONST_STRING_SETTING)); create(); SetWindowTextW(hwnd(), (std::wstring(name) + L" " + setting).c_str()); cfg_menu_ = CreatePopupMenu(); InsertMenuW(cfg_menu_, 0, MF_BYPOSITION, MENU_CMD_0, local_trans::lang_trans_between_hz936(CONST_STRING_SAVE_CUR_CFG_AS).c_str()); InsertMenuA(cfg_menu_, 1, MF_BYPOSITION | MF_SEPARATOR, MENU_CMD_0 + 1, ""); } dlg_setting::~dlg_setting() { if (IsWindow(tab_)) { for (int i = 0; i < get_tab_count(); ++i) { TCITEMW item = { 0 }; item.mask = TCIF_PARAM; TabCtrl_GetItem(tab_, i, &item); if (item.lParam) delete (dlg_page*)item.lParam; } DestroyWindow(tab_); } if (twain_schm_) twain_schm_->release(); cfg_->save(local_trans::u2a(cfg_file_.c_str()).c_str()); DestroyMenu(cfg_menu_); } BOOL dlg_setting::handle_message(UINT msg, WPARAM wp, LPARAM lp) { wchar_t text[40] = { 0 }; BOOL ret = TRUE; switch (msg) { case WM_INITDIALOG: on_init_dialog(); break; case WM_COMMAND: handle_command(HIWORD(wp), LOWORD(wp), (HWND)lp); break; case WM_NOTIFY: ret = on_notify((int)wp, (LPNMHDR)lp); break; case WM_REFRESH_OPTION: refresh_controls((int)wp); break; case WM_GET_CONFIG_OBJ: { gb::sane_config_schm* schm = twain_schm_ ? twain_schm_ : cfg_->get_scheme(); if (twain_schm_) twain_schm_->add_ref(); if (wp) { if (!schm && *(bool*)wp) { schm = cfg_->create_empty_scheme(true); if (schm) schm->begin_setting(); schm_from_empty_ = true; log_info(L"Create a new config scheme for recording user settings.\r\n", 0); } else *(bool*)wp = false; } *((gb::sane_config_schm**)lp) = schm; { std::wstring name(schm ? local_trans::a2u(schm->get_scheme_name().c_str(), CP_UTF8) : L"default"); name.insert(0, L"Return scheme '"); name += L"' to user.\r\n"; log_info(name.c_str(), 0); } } break; default: ret = FALSE; break; } return ret; } void dlg_setting::handle_command(WORD code, WORD id, HANDLE ctrl) { if (ctrl == NULL) { // menu command ... if (id == MENU_CMD_0) { // save current scheme as ... bool new_scheme = false; gb::sane_config_schm* s = twain_schm_ ? twain_schm_ : cfg_->get_scheme(); if (!s) { s = cfg_->copy_scheme(nullptr); new_scheme = true; } if (twain_schm_) { s->add_ref(); twain_schm_->release(); twain_schm_ = nullptr; new_scheme = true; } if (s) { std::vector all(get_stored_scheme_names()); std::wstring cur(local_trans::a2u(s->get_scheme_name().c_str(), CP_UTF8)); dlg_input dlg(hwnd(), cur.c_str()); dlg.set_no_repeats(all); if (dlg.do_modal(hwnd()) == IDOK) { std::string name(local_trans::u2a(dlg.get_value().c_str(), CP_UTF8)); gb::sane_config_schm* n = s; if (new_scheme) { n->add_ref(); n->end_setting(false); } else { n = s->copy(); s->end_setting(true); n->end_setting(false); } if (cfg_->add_scheme(n, name.c_str())) { cfg_->select_scheme(name.c_str()); n->begin_setting(); } n->release(); } s->release(); } } else if(id > MENU_CMD_0 + 1) { // config scheme changed ... std::string schm(local_trans::u2a(dlg_base::get_menu_text(cfg_menu_, id - MENU_CMD_0).c_str(), CP_UTF8)); log_info((L"Select scheme '" + local_trans::a2u(schm.c_str(), CP_UTF8) + L"' on scheme menu.\r\n").c_str(), 0); save_changes_to_cur_scheme(SAVE_REASON_SWITCH_SCHEME); // if (cfg_->get_current_scheme_name() != schm) { gb::sane_config_schm* s = nullptr; if (cfg_->select_scheme(schm.c_str())) { s = cfg_->get_scheme(); apply_scheme_(s, apply_param_); if (s) { s->begin_setting(); s->release(); } refresh_controls(-1); // cfg_->save(); } } } } else if (id == IDOK) { save_changes_to_cur_scheme(SAVE_REASON_QUIT_UI); notify_over(); } 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) { log_info(L"Press 'Restore' button to restore settings\r\n", 0); save_changes_to_cur_scheme(SAVE_REASON_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_); cfg_->select_scheme(nullptr); } else if (id == IDC_BUTTON_SCAN) { // enable(false); save_changes_to_cur_scheme(SAVE_REASON_QUIT_UI); notify_ui_event(SANE_EVENT_UI_SCAN_COMMAND); } else if (id == IDC_BUTTON_CONFIG_MGR) { dlg_cfg_mgr dlg(cfg_, hwnd()); gb::sane_config_schm* prev = cfg_->get_scheme(), * after = nullptr; dlg.do_modal(hwnd()); after = cfg_->get_scheme(); if (prev != after) // refresh settings and UI { { std::wstring info(L"Current scheme has changed from '"); if (prev) info += local_trans::a2u(prev->get_scheme_name().c_str(), CP_UTF8) + L"' to '"; else info += L"default' to '"; if (after) info += local_trans::a2u(after->get_scheme_name().c_str(), CP_UTF8) + L"' in management UI\r\n"; else info += L"default' in management UI\r\n"; log_info(info.c_str(), 0); } apply_scheme_(after, apply_param_); refresh_controls(-1); } if (prev) prev->release(); if (after) after->release(); } else if (id == IDC_BUTTON_CONFIG_MENU) { HMENU sub = cfg_menu_; // GetSubMenu(cfg_menu_, 0); int ind = 2; // 0 - save as ...; 1 - separator std::vector schemes; while (DeleteMenu(sub, 2, MF_BYPOSITION)); cfg_->get_all_schemes(schemes); for (auto& v : schemes) { UINT flag = MF_BYPOSITION; if (twain_set_ && *twain_set_ == false && v == cfg_->get_current_scheme_name()) flag |= MF_CHECKED; InsertMenuW(sub, ind, flag, MENU_CMD_0 + ind, local_trans::a2u(v.c_str(), CP_UTF8).c_str()); ind++; } RECT r = { 0 }; GetWindowRect(get_item(IDC_BUTTON_CONFIG_MENU), &r); TrackPopupMenu(cfg_menu_, TPM_LEFTALIGN | TPM_BOTTOMALIGN, r.left, r.top, 0, hwnd(), NULL); } } void dlg_setting::notify_over(void) { notify_ui_event(SANE_EVENT_UI_CLOSE_SETTING); } void dlg_setting::on_init_dialog(void) { dlg_page* page = NULL; SANE_Int sn = 1; SIZE size = { 0 }; RECT r = { 0 }, rme = { 0 }; int y = 0; const SANE_Option_Descriptor* desc = sane_api_.sane_get_option_descriptor_api(sane_dev_, sn++); while (desc) { if (desc->type == SANE_TYPE_GROUP) { if (page) { page->add_control_done(); dlg_base::get_max_size(size, page->desired_size()); } page = add_tab(desc->title); } else if (page) { char* buf = new char[desc->size + 4]; SANE_Int info = 0; memset(buf, 0, desc->size + 4); sane_api_.sane_control_option_api(sane_dev_, sn - 1, SANE_ACTION_GET_VALUE, buf, &info); page->add_control(sn - 1, desc, buf); delete[] buf; } else if(desc->type == SANE_TYPE_BUTTON) { if (strcmp(SANE_STD_OPT_NAME_HELP, desc->name) == 0) { ShowWindow(GetDlgItem(hwnd_, IDC_BUTTON_HELP), SW_SHOW); id_help_ = sn - 1; } else if (strcmp(SANE_STD_OPT_NAME_RESTORE, desc->name) == 0) { 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) { page->add_control_done(); dlg_base::get_max_size(size, page->desired_size()); } if (size.cx || size.cy || IsWindow(tab_)) { // resize ... GetClientRect(hwnd(), &rme); if (size.cx < rme.right - rme.left) size.cx = rme.right - rme.left; if (IsWindow(tab_)) { GetWindowRect(tab_, &r); y = r.bottom - r.top; size.cy += y; r.right = r.left + size.cx; screen_2_client(&r); MoveWindow(tab_, r.left, r.top, r.right - r.left, y, TRUE); } RECT desk = { 0 }; int diff = 0; GetClientRect(GetDesktopWindow(), &desk); GetWindowRect(hwnd(), &r); r.right += size.cx - (rme.right - rme.left); r.bottom += size.cy; if (r.bottom - r.top > desk.bottom - desk.top) { diff = (r.bottom - r.top) - (desk.bottom - desk.top) + 100; r.top = desk.top; r.bottom = desk.bottom - 100; } MoveWindow(hwnd(), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE); size.cy -= diff; for (int i = 0; page = get_page(i); ++i) { MoveWindow(page->hwnd(), 0, y, size.cx, size.cy - y, TRUE); page->set_view_size(size); } offset_item(IDC_BUTTON_SCAN, 0, size.cy); offset_item(IDC_BUTTON_CONFIG_MGR, size.cx - RECT_W(rme), size.cy); offset_item(IDC_BUTTON_CONFIG_MENU, size.cx - RECT_W(rme), size.cy); offset_item(IDC_BUTTON_HELP, size.cx - RECT_W(rme), size.cy); offset_item(IDC_BUTTON_RESTORE, size.cx - RECT_W(rme), size.cy); offset_item(IDOK, size.cx - RECT_W(rme), size.cy); ShowWindow(get_item(IDC_BUTTON_CONFIG_MGR), SW_SHOW); ShowWindow(get_item(IDC_BUTTON_CONFIG_MENU), SW_SHOW); } if (with_scan_) ShowWindow(get_item(IDC_BUTTON_SCAN), SW_SHOW); if (!dlg_base::is_language_pack_default_code_page()) { std::wstring title(local_trans::lang_trans_between_hz936(CONST_STRING_CFG_MANAGER)); ::SetDlgItemTextW(hwnd(), IDC_BUTTON_CONFIG_MGR, title.c_str()); y = set_item_fit_to_text(IDC_BUTTON_CONFIG_MGR); if (y) offset_item(IDC_BUTTON_CONFIG_MGR, -y, 0); ::SetDlgItemTextW(hwnd(), IDC_BUTTON_SCAN, local_trans::lang_trans_between_hz936(CONST_STRING_SCAN).c_str()); ::SetDlgItemTextW(hwnd(), IDC_BUTTON_RESTORE, local_trans::lang_trans_between_hz936(CONST_STRING_RESTORE).c_str()); ::SetDlgItemTextW(hwnd(), IDC_BUTTON_HELP, local_trans::lang_trans_between_hz936(CONST_STRING_HELP).c_str()); ::SetDlgItemTextW(hwnd(), IDOK, local_trans::lang_trans_between_hz936(CONST_STRING_OK).c_str()); } select_page(0); UpdateWindow(hwnd()); } 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) { int count = 0; if (IsWindow(tab_)) count = TabCtrl_GetItemCount(tab_); return count; } 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(), &sane_api_, sane_dev_); HFONT font = (HFONT)SendMessage(get_item(IDOK), WM_GETFONT, 0, 0); LOGFONTW lf = { 0 }; GetObjectW(font, sizeof(lf), &lf); page->set_font(font); if (!IsWindow(tab_)) { 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); } TC_ITEMW item = { 0 }; item.mask = TCIF_PARAM | TCIF_TEXT; item.lParam = (LPARAM)page; item.pszText = &title[0]; TabCtrl_InsertItem(tab_, get_tab_count(), &item); page->hide(); return page; } dlg_page* dlg_setting::get_page(int index) { dlg_page* page = NULL; if (IsWindow(tab_) && index >= 0 && index < get_tab_count()) { TCITEMW item = { 0 }; item.mask = TCIF_PARAM; TabCtrl_GetItem(tab_, index, &item); page = (dlg_page*)item.lParam; } return page; } dlg_page* dlg_setting::get_page(const char* utf8_title) { dlg_page* page = NULL; std::wstring unic(local_trans::a2u(utf8_title, CP_UTF8)); for (int i = 0; i < get_tab_count(); ++i) { TCITEMW item = { 0 }; wchar_t buf[80] = { 0 }; item.mask = TCIF_TEXT | TCIF_PARAM; item.pszText = buf; item.cchTextMax = _countof(buf) - 1; TabCtrl_GetItem(tab_, i, &item); if (unic == buf) { page = (dlg_page*)item.lParam; break; } } return page; } dlg_page* dlg_setting::select_page(int index) { dlg_page* ret = NULL, *cur = NULL; for (int i = 0; cur = get_page(i); ++i) { if (i == index) { ret = cur; cur->show(); } else cur->hide(); } return ret; } 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::save_changes_to_cur_scheme(int reason) { // discard, overwrite, new int items = 0; bool changed = false; std::vector now(get_stored_scheme_names()); if (!cfg_) return; if (twain_set_ && reason != SAVE_REASON_QUIT_UI) *twain_set_ = false; if (twain_schm_) { changed = twain_schm_->has_changed(&items); if (changed) { dlg_save_scheme dlg(hwnd()); std::wstring sug(L""); sug = local_trans::a2u(twain_schm_->auto_gen_scheme_name(local_trans::lang_trans_between_hz936, nullptr, false).c_str(), CP_UTF8); dlg.set_info(local_trans::a2u(twain_schm_->get_scheme_name().c_str(), CP_UTF8).c_str(), now , SAVE_METHOD_MASK(SAVE_DISCARD) | SAVE_METHOD_MASK(SAVE_NEW), sug.c_str()); dlg.do_modal(hwnd()); if(dlg.get_dispose() == SAVE_NEW) { std::string name(local_trans::u2a(dlg.get_name().c_str(), CP_UTF8)); if (cfg_->add_scheme(twain_schm_, name.c_str()) && reason == SAVE_REASON_QUIT_UI) { cfg_->select_scheme(name.c_str()); if (twain_set_) *twain_set_ = false; } } } twain_schm_->release(); twain_schm_ = nullptr; } else { gb::sane_config_schm* schm = cfg_->get_scheme(); if (schm) { changed = schm->has_changed(&items); if (changed) { if (schm_from_empty_) schm->end_setting(false); else { dlg_save_scheme dlg(hwnd()); std::wstring name(local_trans::a2u(schm->get_scheme_name().c_str(), CP_UTF8)), suggest(local_trans::a2u(schm->auto_gen_scheme_name(local_trans::lang_trans_between_hz936, nullptr, false).c_str(), CP_UTF8)); dlg.set_info(name.c_str(), now, SAVE_METHOD_MASK(SAVE_DISCARD) | SAVE_METHOD_MASK(SAVE_OVERWRITE) | SAVE_METHOD_MASK(SAVE_NEW) , suggest.c_str()); dlg.do_modal(hwnd()); int dispose = dlg.get_dispose(); if (dispose == SAVE_NEW) { std::string uname(local_trans::u2a(dlg.get_name().c_str(), CP_UTF8)); gb::sane_config_schm* s = schm->copy(); schm->end_setting(true); s->end_setting(false); cfg_->add_scheme(s, uname.c_str()); s->release(); if (reason == SAVE_REASON_QUIT_UI) cfg_->select_scheme(uname.c_str()); } else { schm->end_setting(dispose == SAVE_DISCARD); if (dispose == SAVE_DISCARD && reason == SAVE_REASON_QUIT_UI && twain_set_) { std::wstring info(local_trans::a2u(schm->get_scheme_name().c_str(), CP_UTF8)); info.insert(0, L"User discard the changes on scheme '"); info += L"' and will quit UI, set temporary scheme flag!\r\n"; log_info(info.c_str(), 0); *twain_set_ = true; } } } } schm->release(); } } schm_from_empty_ = false; } void dlg_setting::set_config(gb::scanner_cfg* cfg, const wchar_t* file, void(__stdcall* apply)(gb::sane_config_schm*, void*), void* param, bool* twain_set) { cfg_ = cfg; cfg_file_ = file; apply_scheme_ = apply; apply_param_ = param; twain_set_ = twain_set; if (twain_set && *twain_set && cfg_) { // create a temporary scheme because of APP has changed the setting after we applied the store scheme ... twain_schm_ = new gb::sane_config_schm(cfg_); int sn = 1; const SANE_Option_Descriptor* desc = sane_api_.sane_get_option_descriptor_api(sane_dev_, sn++); while (desc) { if (desc->type != SANE_TYPE_BUTTON && desc->type != SANE_TYPE_GROUP) { 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); if (desc->type == SANE_TYPE_STRING) { std::string defl(to_default_language(buf, nullptr)); twain_schm_->config_changed(sn - 1, defl.c_str(), defl.length()); } else { int len = desc->size; switch (desc->type) { case SANE_TYPE_BOOL: len = sizeof(SANE_Bool); break; case SANE_TYPE_INT: len = sizeof(SANE_Int); break; case SANE_TYPE_FIXED: len = sizeof(SANE_Fixed); break; } twain_schm_->config_changed(sn - 1, buf, len); } delete[] buf; } desc = sane_api_.sane_get_option_descriptor_api(sane_dev_, sn++); } twain_schm_->has_changed(&sn); twain_schm_->auto_gen_scheme_name(local_trans::lang_trans_between_hz936, nullptr); twain_schm_->begin_setting(); if(sn) { std::wstring name(local_trans::a2u(cfg_->get_current_scheme_name().c_str(), CP_UTF8)); name.insert(0, L"TWAIN-app has changed " + std::to_wstring(sn) + L" setting(s) after we applied stored scheme '"); name += L"'\r\n"; log_info(name.c_str(), 0); } } else if(cfg_) { gb::sane_config_schm* schm = cfg_->get_scheme(); if (schm) { schm->begin_setting(); schm->release(); } } } HWND dlg_setting::window(void) { return hwnd_; } HWND dlg_setting::parent(void) { return parent_; } //void dlg_setting::show(void) //{ // RECT rp, r, desk; // // if (IsWindow(parent_)) // GetWindowRect(parent_, &rp); // else // GetWindowRect(GetDesktopWindow(), &rp); // GetWindowRect(hwnd_, &r); // GetWindowRect(GetDesktopWindow(), &desk); // // rp.left += (rp.right - rp.left - (r.right - r.left)) / 2; // rp.top += (rp.bottom - rp.top - (r.bottom - r.top)) / 2; // if (rp.top > desk.bottom) // rp.top = desk.bottom - (r.bottom - r.top); // if (rp.top < desk.top) // rp.top = desk.top; // if (rp.left > desk.right) // rp.left = desk.right - (rp.right - rp.left); // if (rp.left < desk.left) // rp.left = desk.left; // SetWindowPos(hwnd_, HWND_TOPMOST, rp.left, rp.top, r.right - r.left, r.bottom - r.top, SWP_NOSIZE | SWP_SHOWWINDOW); // UpdateWindow(hwnd_); //} void dlg_setting::hide(void) { ShowWindow(hwnd_, SW_HIDE); } void dlg_setting::notify_scan_over(void) { enable(true); } std::vector dlg_setting::get_stored_scheme_names(void) { std::vector now; std::vector wnow; if (cfg_) { cfg_->get_all_schemes(now); for (auto& v : now) wnow.push_back(local_trans::a2u(v.c_str(), CP_UTF8)); } return std::move(wnow); } // CDlgIndicator 消息处理程序