diff --git a/sane/DlgIndicator.cpp b/sane/DlgIndicator.cpp index 66be786..10eb7d1 100644 --- a/sane/DlgIndicator.cpp +++ b/sane/DlgIndicator.cpp @@ -10,96 +10,19 @@ #define WM_IMAGE_RECEIVED WM_USER + 2 #define WM_SCAN_FINISHED WM_USER + 3 // WPARAM: std::string* msg; LPARAM: boo err -ATOM dlg_indicator::indicator_class_atom = 0; -std::wstring dlg_indicator::handle_name = L"dlg_indicator_prop_handle"; -std::wstring dlg_indicator::indicator_class_name = L"dlg_indicator_class"; -extern HMODULE g_my_inst; -dlg_indicator::dlg_indicator() : hwnd_(NULL), papers_(0), images_(0), notify_(NULL), notify_param_(NULL), parent_(NULL), err_(false) +dlg_indicator::dlg_indicator(HWND parent) : dlg_base(parent, IDD_INDICATOR) + , papers_(0), images_(0), notify_(NULL), notify_param_(NULL), err_(false) { - HANDLE wait = CreateEvent(NULL, TRUE, FALSE, NULL); -#ifdef USE_SOLE_WIN_THREAD - thread_.reset(new std::thread(&dlg_indicator::create, this, wait)); -#else - create(wait); -#endif - WaitForSingleObject(wait, INFINITE); - CloseHandle(wait); + create(); + SetWindowLongW(GetDlgItem(hwnd_, IDC_STATIC_ERR), GWL_STYLE, GetWindowLong(GetDlgItem(hwnd_, IDC_STATIC_ERR), GWL_STYLE) | SS_OWNERDRAW); } dlg_indicator::~dlg_indicator() { -#ifdef USE_SOLE_WIN_THREAD - if (IsWindow(hwnd_)) - PostMessage(hwnd_, WM_QUIT, 0, 0); - - if (thread_.get() && thread_->joinable()) - thread_->join(); - thread_.reset(); -#else - if (IsWindow(hwnd_)) - DestroyWindow(hwnd_); -#endif } -BOOL CALLBACK dlg_indicator::dlg_indicator_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) -{ - if (msg == WM_INITDIALOG) - { - dlg_indicator *obj = (dlg_indicator*)lp; - SetPropW(hwnd, dlg_indicator::handle_name.c_str(), (HANDLE)obj); - } - - dlg_indicator* obj = (dlg_indicator*)GetPropW(hwnd, dlg_indicator::handle_name.c_str()); - BOOL handled = FALSE, ret = FALSE; - - if (obj) - ret = obj->handle_msg(msg, wp, lp); - - return ret; -} -ATOM dlg_indicator::register_indicator_class(void) -{ - WNDCLASSEXW wcex; - - wcex.cbSize = sizeof(WNDCLASSEXW); - wcex.style = WS_POPUP; - wcex.lpfnWndProc = (WNDPROC)dlg_indicator::dlg_indicator_proc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = g_my_inst; - wcex.hIcon = NULL; - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = NULL; - wcex.lpszClassName = dlg_indicator::indicator_class_name.c_str(); - wcex.hIconSm = NULL; - - return RegisterClassExW(&wcex); -} - -void dlg_indicator::create(HANDLE wait) -{ - MSG msg = { 0 }; - BOOL ret = TRUE; - - hwnd_ = CreateDialogParamW(g_my_inst, MAKEINTRESOURCE(IDD_INDICATOR), NULL, &dlg_indicator::dlg_indicator_proc, (LPARAM)this); - SetWindowLongW(GetDlgItem(hwnd_, IDC_STATIC_ERR), GWL_STYLE, GetWindowLong(GetDlgItem(hwnd_, IDC_STATIC_ERR), GWL_STYLE) | SS_OWNERDRAW); - SetEvent(wait); - -#ifdef USE_SOLE_WIN_THREAD - while ((ret = GetMessage(&msg, NULL, 0, 0))) - { - if (ret == -1) - break; - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - DestroyWindow(hwnd_); -#endif -} -BOOL dlg_indicator::handle_msg(UINT msg, WPARAM wp, LPARAM lp) +BOOL dlg_indicator::handle_message(UINT msg, WPARAM wp, LPARAM lp) { wchar_t text[40] = { 0 }; BOOL ret = TRUE; @@ -110,6 +33,7 @@ BOOL dlg_indicator::handle_msg(UINT msg, WPARAM wp, LPARAM lp) swprintf_s(text, _countof(text) - 1, L"%u", papers_); SetDlgItemTextW(hwnd_, IDC_EDIT_IMAGE, text); SetDlgItemTextW(hwnd_, IDC_EDIT_PAPER, text); + UpdateWindow(hwnd_); break; case WM_USB_PACKET_RECEIVED: papers_++; @@ -206,17 +130,16 @@ HWND dlg_indicator::parent(void) { return parent_; } -void dlg_indicator::show(HWND parent) +void dlg_indicator::show() { RECT rp, r; - if (IsWindow(parent)) - GetWindowRect(parent, &rp); + if (IsWindow(parent_)) + GetWindowRect(parent_, &rp); else GetWindowRect(GetDesktopWindow(), &rp); GetWindowRect(hwnd_, &r); - parent_ = parent; rp.left += (rp.right - rp.left - (r.right - r.left)) / 2; rp.top += (rp.bottom - rp.top - (r.bottom - r.top)) / 2; SetWindowPos(hwnd_, HWND_TOPMOST, rp.left, rp.top, r.right - r.left, r.bottom - r.top, SWP_NOSIZE | SWP_SHOWWINDOW); diff --git a/sane/DlgIndicator.h b/sane/DlgIndicator.h index 616849b..c42c3e7 100644 --- a/sane/DlgIndicator.h +++ b/sane/DlgIndicator.h @@ -3,47 +3,31 @@ #include #include +#include "DlgPage.h" + // CDlgIndicator 对话框 -//#define USE_SOLE_WIN_THREAD -#ifdef USE_SOLE_WIN_THREAD -#include -#include -#endif - -class dlg_indicator +class dlg_indicator : public dlg_base { - HWND hwnd_; - HWND parent_; - unsigned int papers_; - unsigned int images_; - bool err_; -#ifdef USE_SOLE_WIN_THREAD - std::unique_ptr thread_; -#endif + unsigned int papers_; + unsigned int images_; + bool err_; void(__stdcall* notify_)(bool, void*); - void* notify_param_; + void* notify_param_; - static ATOM indicator_class_atom; - static std::wstring handle_name; - static std::wstring indicator_class_name; - static BOOL CALLBACK dlg_indicator_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); - static ATOM register_indicator_class(void); - - void create(HANDLE wait); - BOOL handle_msg(UINT msg, WPARAM wp, LPARAM lp); + BOOL handle_message(UINT msg, WPARAM wp, LPARAM lp) override; void handle_command(WORD code, WORD id, HANDLE ctrl); void notify_over(void); public: - dlg_indicator(); + dlg_indicator(HWND parent); ~dlg_indicator(); public: void set_quit_notify(void(__stdcall* notify)(bool cancel, void*), void* param); HWND window(void); HWND parent(void); - void show(HWND parent); + void show(void); void hide(void); void notify_data_arrived(bool image); void notify_scan_over(const char* msg, bool err); diff --git a/sane/DlgPage.cpp b/sane/DlgPage.cpp new file mode 100644 index 0000000..1d3fd56 --- /dev/null +++ b/sane/DlgPage.cpp @@ -0,0 +1,247 @@ +// DlgIndicator.cpp: 实现文件 +// + +#include "DlgPage.h" +#include "resource.h" +#include "scanned_img.h" // for local_trans + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// 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); +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// dlg_page 对话框 +UINT dlg_page::dyn_id_base = 3000; +int dlg_page::gap_x = 20; +int dlg_page::gap_y = 12; + +dlg_page::dlg_page(HWND parent, const wchar_t* name) : dlg_base(parent, IDD_PAGE), name_(name ? name : L""), ctrl_id_(0) +{ + size_.cx = size_.cy = 0; + create(); + refresh_font(); +} +dlg_page::~dlg_page() +{} + +BOOL dlg_page::handle_message(UINT msg, WPARAM wp, LPARAM lp) +{ + return FALSE; +} +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); + ShowWindow(wnd, SW_SHOW); + if (now) + SendMessage(wnd, BM_SETCHECK, (WPARAM)BST_CHECKED, 0); + + return ret; +} +bool dlg_page::create_control_int(int sn, const SANE_Option_Descriptor* desc, void* cur_val) +{ + bool ret = true; + + return ret; +} +bool dlg_page::create_control_float(int sn, const SANE_Option_Descriptor* desc, void* cur_val) +{ + bool ret = true; + + return ret; +} +bool dlg_page::create_control_string(int sn, const SANE_Option_Descriptor* desc, void* cur_val) +{ + bool ret = true; + + return ret; +} +bool dlg_page::create_control_button(int sn, const SANE_Option_Descriptor* desc, void* cur_val) +{ + bool ret = true; + + return ret; +} + +bool dlg_page::add_control(int sn, const SANE_Option_Descriptor* desc, void* cur_val) +{ + bool ret = false; + + struct + { + int sane_type; + bool(dlg_page::* func)(int, const SANE_Option_Descriptor*, void*); + }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} + }; + for (int i = 0; i < _countof(creat); ++i) + { + if (creat[i].sane_type == desc->type) + { + ret = (this->*creat[i].func)(sn, desc, cur_val); + break; + } + } + + return ret; +} +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); +} +const wchar_t* dlg_page::name(void) +{ + return name_.c_str(); +} diff --git a/sane/DlgPage.h b/sane/DlgPage.h new file mode 100644 index 0000000..1a9a82e --- /dev/null +++ b/sane/DlgPage.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +// CDlgIndicator 对话框 +#define WM_REFRESH_OPTION WM_USER + 111 // WPARAM: source option SN, LPARAM: unused now + +extern HMODULE g_my_inst; + +class dlg_base +{ +protected: + HWND hwnd_; + HWND parent_; + UINT idd_; + + static std::wstring prop_name; + static BOOL CALLBACK dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); + + virtual BOOL handle_message(UINT msg, WPARAM wp, LPARAM lp); + virtual void on_font_changed(void); + void create(void); + +public: + dlg_base(HWND parent, UINT idd); + virtual ~dlg_base(); + + static bool get_max_size(SIZE& dst, const SIZE& src); // return whether changed dst + static bool get_max_size(SIZE& dst, int cx, int cy); // return whether changed dst + +public: + HWND hwnd(void); + void screen_2_client(LPRECT r); + void client_2_screen(LPRECT r); + HWND get_item(UINT id); + BOOL set_font(HFONT font); + HFONT get_font(void); +}; + +class dlg_page : public dlg_base +{ + std::wstring name_; + SIZE size_; + SIZE font_size_; + UINT ctrl_id_; + POINT pos_; + + static UINT dyn_id_base; + static int gap_x; + static int gap_y; + + 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); + +public: + dlg_page(HWND parent, const wchar_t* name); + ~dlg_page(); + +public: + bool add_control(int sn, const SANE_Option_Descriptor* desc, void* cur_val); + SIZE desired_size(void); + void show(void); + void hide(void); + const wchar_t* name(void); +}; diff --git a/sane/DlgSetting.cpp b/sane/DlgSetting.cpp new file mode 100644 index 0000000..4b4db74 --- /dev/null +++ b/sane/DlgSetting.cpp @@ -0,0 +1,324 @@ +// DlgIndicator.cpp: 实现文件 +// + +#include "DlgSetting.h" +#include "resource.h" +#include "scanned_img.h" // for local_trans +#include "DlgPage.h" + +// CDlgIndicator 对话框 +#define WM_USB_PACKET_RECEIVED WM_USER + 1 +#define WM_IMAGE_RECEIVED WM_USER + 2 +#define WM_SCAN_FINISHED WM_USER + 3 // WPARAM: std::string* msg; LPARAM: boo err + + +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), notify_(NULL), notify_param_(NULL), err_(false), tab_(NULL) +{ + create(); + SetWindowTextW(hwnd(), (std::wstring(name) + L" \u8bbe\u7f6e").c_str()); +} +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_); + } +} + +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: + on_notify((int)wp, (LPNMHDR)lp); + break; + case WM_REFRESH_OPTION: + refresh_controls((int)wp); + break; + default: + ret = FALSE; + break; + } + + return ret; +} +void dlg_setting::handle_command(WORD code, WORD id, HANDLE ctrl) +{ + if (id == IDOK) + { + notify_over(); + } + else if (id == IDC_BUTTON_HELP) + { + + } + else if (id == IDC_BUTTON_RESTORE) + { + + } +} +void dlg_setting::notify_over(void) +{ + if (notify_) + notify_(true, notify_param_); +} +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) + 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 (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)) + ShowWindow(GetDlgItem(hwnd_, IDC_BUTTON_RESTORE), SW_SHOW); + } + desc = sane_api_.sane_get_option_descriptor_api(sane_dev_, sn++); + } + if (page) + 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 + rme.right - rme.left; + screen_2_client(&r); + MoveWindow(tab_, r.left, r.top, r.right - r.left, y, TRUE); + } + + GetWindowRect(hwnd(), &r); + r.right += size.cx - (rme.right - rme.left); + r.bottom += size.cy; + MoveWindow(hwnd(), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE); + + for (int i = 0; page = get_page(i); ++i) + { + MoveWindow(page->hwnd(), 0, y, size.cx, size.cy - y, TRUE); + } + + GetWindowRect(get_item(IDC_BUTTON_SCAN), &r); + OffsetRect(&r, 0, size.cy); + screen_2_client(&r); + MoveWindow(get_item(IDC_BUTTON_SCAN), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE); + + GetWindowRect(get_item(IDC_BUTTON_HELP), &r); + OffsetRect(&r, size.cx - (rme.right - rme.left), size.cy); + screen_2_client(&r); + MoveWindow(get_item(IDC_BUTTON_HELP), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE); + + GetWindowRect(get_item(IDC_BUTTON_RESTORE), &r); + OffsetRect(&r, size.cx - (rme.right - rme.left), size.cy); + screen_2_client(&r); + MoveWindow(get_item(IDC_BUTTON_RESTORE), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE); + + GetWindowRect(get_item(IDOK), &r); + OffsetRect(&r, size.cx - (rme.right - rme.left), size.cy); + screen_2_client(&r); + MoveWindow(get_item(IDOK), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE); + } + select_page(0); + UpdateWindow(hwnd()); +} +void dlg_setting::on_notify(int ctrl_id, LPNMHDR pnmh) +{ + +} +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()); + 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_)) + { + 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); + 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) +{ + +} + +void dlg_setting::set_quit_notify(void(__stdcall* notify)(bool, void*), void* param) +{ + notify_ = notify; + notify_param_ = param; +} +HWND dlg_setting::window(void) +{ + return hwnd_; +} +HWND dlg_setting::parent(void) +{ + return parent_; +} +void dlg_setting::show(void) +{ + RECT rp, r; + + if (IsWindow(parent_)) + GetWindowRect(parent_, &rp); + else + GetWindowRect(GetDesktopWindow(), &rp); + GetWindowRect(hwnd_, &r); + + rp.left += (rp.right - rp.left - (r.right - r.left)) / 2; + rp.top += (rp.bottom - rp.top - (r.bottom - r.top)) / 2; + 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_data_arrived(bool image) +{ + PostMessage(hwnd_, image ? WM_IMAGE_RECEIVED : WM_USB_PACKET_RECEIVED, 0, 0); +} +void dlg_setting::notify_scan_over(const char* msg, bool err) +{ + std::string* mstr(new std::string(msg ? msg : "")); + + err_ = err; + if (!PostMessage(hwnd_, WM_SCAN_FINISHED, (WPARAM)mstr, (LPARAM)err)) + { + delete mstr; + notify_over(); + } +} +// CDlgIndicator 消息处理程序 diff --git a/sane/DlgSetting.h b/sane/DlgSetting.h new file mode 100644 index 0000000..dab540d --- /dev/null +++ b/sane/DlgSetting.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include +#include + +#include "DlgPage.h" + +// CDlgIndicator 对话框 +//#define USE_SOLE_WIN_THREAD + +#ifdef USE_SOLE_WIN_THREAD +#include +#include +#endif + +class dlg_setting : public dlg_base +{ + SANEAPI sane_api_; + SANE_Handle sane_dev_; + bool with_scan_; + unsigned int papers_; + unsigned int images_; + bool err_; + + HWND tab_; + +#ifdef USE_SOLE_WIN_THREAD + std::unique_ptr thread_; +#endif + void(__stdcall* notify_)(bool, void*); + void* notify_param_; + + BOOL handle_message(UINT msg, WPARAM wp, LPARAM lp) override; + 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); + int get_tab_count(void); + dlg_page* add_tab(const char* utf8_title); + dlg_page* get_page(int index); + dlg_page* get_page(const char* utf8_title); + dlg_page* select_page(int index); + void refresh_controls(int src_sn); + +public: + dlg_setting(HWND parent, LPSANEAPI api, SANE_Handle dev, bool with_scan, const wchar_t* name); + ~dlg_setting(); + +public: + void set_quit_notify(void(__stdcall* notify)(bool cancel, void*), void* param); + HWND window(void); + HWND parent(void); + void show(void); + void hide(void); + void notify_data_arrived(bool image); + void notify_scan_over(const char* msg, bool err); +}; diff --git a/sane/resource.h b/sane/resource.h index c0b8a1d..9ce941c 100644 --- a/sane/resource.h +++ b/sane/resource.h @@ -3,19 +3,25 @@ // sane.rc ʹ // #define IDD_INDICATOR 101 +#define IDD_SETTING 103 +#define IDD_PAGE 105 #define IDC_EDIT_PAPER 1001 #define IDC_EDIT_IMAGE 1002 #define IDC_STATIC_PAPER 1003 #define IDC_STATIC_IMAGE 1004 #define IDC_STATIC_ERR 1005 +#define IDC_BUTTON_SCAN 1007 +#define IDC_BUTTON_RESTORE 1008 +#define IDC_BUTTON3 1009 +#define IDC_BUTTON_HELP 1009 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_RESOURCE_VALUE 107 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1006 +#define _APS_NEXT_CONTROL_VALUE 1008 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/sane/sane.def b/sane/sane.def index deda82a..fd91092 100644 --- a/sane/sane.def +++ b/sane/sane.def @@ -4,3 +4,19 @@ EXPORTS open_scanner is_scanner_online uninitialize + sane_hgsane_init + sane_hgsane_exit + sane_hgsane_get_devices + sane_hgsane_open + sane_hgsane_close + sane_hgsane_get_option_descriptor + sane_hgsane_control_option + sane_hgsane_get_parameters + sane_hgsane_start + sane_hgsane_read + sane_hgsane_cancel + sane_hgsane_set_io_mode + sane_hgsane_get_select_fd + sane_hgsane_strstatus + sane_hgsane_init_ex + sane_hgsane_io_control diff --git a/sane/sane.rc b/sane/sane.rc index 53c3c9b..dab6080 100644 --- a/sane/sane.rc +++ b/sane/sane.rc @@ -63,6 +63,23 @@ BEGIN LTEXT "",IDC_STATIC_ERR,7,7,131,9,NOT WS_VISIBLE END +IDD_SETTING DIALOGEX 0, 0, 263, 28 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "ȷ",IDOK,223,8,33,13 + PUSHBUTTON "ɨ",IDC_BUTTON_SCAN,7,7,39,14,NOT WS_VISIBLE + PUSHBUTTON "ָĬֵ",IDC_BUTTON_RESTORE,113,7,48,14,NOT WS_VISIBLE + PUSHBUTTON "",IDC_BUTTON_HELP,167,7,48,14,NOT WS_VISIBLE +END + +IDD_PAGE DIALOGEX 0, 0, 257, 133 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN +END + ///////////////////////////////////////////////////////////////////////////// // @@ -79,6 +96,22 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 31 END + + IDD_SETTING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 256 + TOPMARGIN, 7 + BOTTOMMARGIN, 21 + END + + IDD_PAGE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 250 + TOPMARGIN, 7 + BOTTOMMARGIN, 126 + END END #endif // APSTUDIO_INVOKED @@ -93,6 +126,16 @@ BEGIN 0 END +IDD_SETTING AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PAGE AFX_DIALOG_LAYOUT +BEGIN + 0 +END + #endif // (壬й) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/sane/sane.vcxproj b/sane/sane.vcxproj index e107004..72b577b 100644 --- a/sane/sane.vcxproj +++ b/sane/sane.vcxproj @@ -103,7 +103,7 @@ Level3 true - BACKEND_NAME=sane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + BACKEND_NAME=hgsane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 4996 @@ -128,7 +128,7 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$ true true true - BACKEND_NAME=sane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + BACKEND_NAME=hgsane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 4996 @@ -198,6 +198,8 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$ + + @@ -216,6 +218,8 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$ + + diff --git a/sane/sane.vcxproj.filters b/sane/sane.vcxproj.filters index b850f0e..bcd0e34 100644 --- a/sane/sane.vcxproj.filters +++ b/sane/sane.vcxproj.filters @@ -16,6 +16,9 @@ {8ae15a45-410d-4611-b852-f82b64bb1fcc} + + {5c86255e-570e-4921-9c62-c98d05edcab4} + @@ -43,7 +46,13 @@ sane2twain - 源文件 + sane2twain\UI + + + sane2twain\UI + + + sane2twain\UI @@ -99,7 +108,13 @@ 头文件 - 头文件 + sane2twain\UI + + + sane2twain\UI + + + sane2twain\UI diff --git a/sane/scanner.cpp b/sane/scanner.cpp index 5b62da0..8782faa 100644 --- a/sane/scanner.cpp +++ b/sane/scanner.cpp @@ -8,6 +8,7 @@ #include #include #include "DlgIndicator.h" +#include "DlgSetting.h" static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt); @@ -24,6 +25,27 @@ static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // callback +extern "C" +{ + extern SANE_Status inner_sane_init(SANE_Int* version_code, SANE_Auth_Callback authorize); + extern void inner_sane_exit(void); + extern SANE_Status inner_sane_get_devices(const SANE_Device*** device_list, SANE_Bool local_only); + extern SANE_Status inner_sane_open(SANE_String_Const devicename, SANE_Handle* handle); + extern void inner_sane_close(SANE_Handle handle); + extern const SANE_Option_Descriptor* inner_sane_get_option_descriptor(SANE_Handle handle, SANE_Int option); + extern SANE_Status inner_sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info); + extern SANE_Status inner_sane_get_parameters(SANE_Handle handle, SANE_Parameters* params); + extern SANE_Status inner_sane_start(SANE_Handle handle); + extern SANE_Status inner_sane_read(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length); + extern void inner_sane_cancel(SANE_Handle handle); + extern SANE_Status inner_sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking); + extern SANE_Status inner_sane_get_select_fd(SANE_Handle handle, SANE_Int* fd); + extern SANE_String_Const inner_sane_strstatus(SANE_Status status); + + extern SANE_Status inner_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param); + extern SANE_Status inner_sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len); +} + namespace callback { static std::mutex cb_lock_; @@ -87,7 +109,7 @@ namespace callback // class scanner scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BASE), prev_start_result_(SCANNER_ERR_NOT_START) , dpi_(200), tmp_path_(L""), img_ind_(0), cb_invoker_(NULL), cb_param_(NULL), working_(false) - , ui_quit_(true) + , ui_quit_(true), scanner_name_(L"") { tmp_path_ = local_trans::a2u(hg_sane_middleware::sane_path().c_str()); tmp_path_ += L"imgs"; @@ -190,12 +212,14 @@ int scanner::open(void) int ret = close(); std::string name(scanner::get_scanner_name(id_)); + scanner_name_ = L""; if (name.empty()) return SCANNER_ERR_DEVICE_NOT_FOUND; ret = hg_sane_middleware::instance()->open_device(name.c_str(), &handle_); if (ret == SANE_STATUS_GOOD) { + scanner_name_ = local_trans::a2u(name.c_str(), CP_UTF8); callback::reg_callback(handle_, this); ret = init_options_id(); } @@ -1818,18 +1842,34 @@ COM_API_IMPLEMENT(scanner, bool, ui_show_main(HWND parent)) } COM_API_IMPLEMENT(scanner, bool, ui_show_setting(HWND parent, bool with_scan)) { - indicator_.reset(new dlg_indicator()); - indicator_->set_quit_notify(&scanner::ui_callback, this); - indicator_->show(parent); + SANEAPI api = { NULL }; + + api.sane_cancel_api = inner_sane_cancel; + api.sane_close_api = inner_sane_close; + api.sane_control_option_api = inner_sane_control_option; + api.sane_get_devices_api = inner_sane_get_devices; + api.sane_get_option_descriptor_api = inner_sane_get_option_descriptor; + api.sane_get_parameters_api = inner_sane_get_parameters; + api.sane_get_select_fd_api = inner_sane_get_select_fd; + api.sane_io_control_api = inner_sane_io_control; + api.sane_open_api = inner_sane_open; + api.sane_read_api = inner_sane_read; + api.sane_set_io_mode_api = inner_sane_set_io_mode; + api.sane_start_api = inner_sane_start; + api.sane_strstatus_api = inner_sane_strstatus; + + setting_.reset(new dlg_setting(parent, &api, handle_, with_scan, scanner_name_.c_str())); + setting_->set_quit_notify(&scanner::ui_callback, this); + setting_->show(); ui_quit_ = false; return true; } COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent)) { - indicator_.reset(new dlg_indicator()); + indicator_.reset(new dlg_indicator(parent)); indicator_->set_quit_notify(&scanner::ui_callback, this); - indicator_->show(parent); + indicator_->show(); ui_quit_ = false; return true; @@ -1838,6 +1878,8 @@ COM_API_IMPLEMENT(scanner, void, ui_hide(void)) { if (indicator_.get()) indicator_.reset(); + if (setting_.get()) + setting_.reset(); } COM_API_IMPLEMENT(scanner, bool, ui_is_ok(void)) { diff --git a/sane/scanner.h b/sane/scanner.h index 525a0dd..0306c86 100644 --- a/sane/scanner.h +++ b/sane/scanner.h @@ -23,6 +23,8 @@ class dlg_indicator; +class dlg_setting; + class scanner : public ISaneInvoker, virtual public refer { SANE_Handle handle_; @@ -34,6 +36,7 @@ class scanner : public ISaneInvoker, virtual public refer int prev_start_result_; int dpi_; unsigned int img_ind_; + std::wstring scanner_name_; std::wstring tmp_path_; std::string scan_msg_; bool scan_err_; @@ -43,6 +46,7 @@ class scanner : public ISaneInvoker, virtual public refer bool ui_quit_; SANE_FinalImgFormat img_fmt_; std::unique_ptr indicator_; + std::unique_ptr setting_; void on_ui_quit(bool cancel); int open(void);