code_app/modules/saneui/device_menu.h

524 lines
20 KiB
C
Raw Normal View History

2023-06-03 09:25:56 +00:00
#ifndef DEVICE_MENU_H
#define DEVICE_MENU_H
#include <QMenu>
#include <mutex>
#include "sane/sane_ex.h"
#include "sane/sane_option_definitions.h"
#include "../../../sdk/include/huagao/hgscanner_error.h"
#include "cfg/gb_json.h"
#include "lang/app_language.h"
typedef struct _scanner
{
std::string name;
std::string model;
bool online;
gb::scanner_cfg *cfg;
}SCANNER;
class dev_que
{
std::vector<SCANNER> que_;
std::string root_dir_;
std::string opened_scanner_;
std::string applied_scheme_;
SANE_Handle handle_;
static void trans_number(const char* name, std::string& val, void* param)
{
if (strcmp(name, "tl-x") == 0
|| strcmp(name, "br-x") == 0
|| strcmp(name, "tl-y") == 0
|| strcmp(name, "br-y") == 0
|| strcmp(name, "gamma") == 0
|| strcmp(name, "search-hole-range-l") == 0
|| strcmp(name, "search-hole-range-r") == 0
|| strcmp(name, "search-hole-range-t") == 0
|| strcmp(name, "search-hole-range-b") == 0
|| strcmp(name, "feed-strength-value") == 0
)
{
float v = atof(val.c_str());
SANE_Fixed f = SANE_FIX(v);
val = std::string((char*)&f, sizeof(f));
}
else if (strcmp(name, "binary-threshold") == 0
|| strcmp(name, "bkg-color-range") == 0
|| strcmp(name, "noise-size") == 0
|| strcmp(name, "blank-sensitivity") == 0
|| strcmp(name, "resolution") == 0
|| strcmp(name, "brightness") == 0
|| strcmp(name, "contrast") == 0
|| strcmp(name, "threshold") == 0
|| strcmp(name, "anti-noise-level") == 0
|| strcmp(name, "margin") == 0
|| strcmp(name, "scan-count") == 0
|| strcmp(name, "askew-range") == 0
|| strcmp(name, "dog-ear-size") == 0
)
{
SANE_Int v = atoi(val.c_str());
val = std::string((char*)&v, sizeof(v));
}
else if (strcmp(val.c_str(), "true") == 0)
{
SANE_Bool b = SANE_TRUE;
val = std::string((char*)&b, sizeof(b));
}
else if (strcmp(val.c_str(), "false") == 0)
{
SANE_Bool b = SANE_FALSE;
val = std::string((char*)&b, sizeof(b));
}
}
static const char* title_2_name(const char* title, void* param)
{
struct
{
const char* name;
const char* title;
}g_opts[] = { {SANE_STD_OPT_NAME_RESTORE , OPTION_TITLE_HFMRSZ}
, {SANE_STD_OPT_NAME_HELP , OPTION_TITLE_BZ}
, {SANE_STD_OPT_NAME_IS_MULTI_OUT , OPTION_TITLE_DLSC}
, {SANE_STD_OPT_NAME_MULTI_OUT_TYPE , OPTION_TITLE_DLSCLX}
, {SANE_STD_OPT_NAME_COLOR_MODE , OPTION_TITLE_YSMS}
, {SANE_STD_OPT_NAME_BINARY_THRESHOLD , OPTION_TITLE_HBTXYZ}
, {SANE_STD_OPT_NAME_REVERSE_01 , OPTION_TITLE_HBTXFSSC}
, {SANE_STD_OPT_NAME_FILTER , OPTION_TITLE_HDHHBTX_CSYZQ}
, {SANE_STD_OPT_NAME_RID_MULTIOUT_RED , OPTION_TITLE_24WCSTX_DLSCCH}
, {SANE_STD_OPT_NAME_RID_ANSWER_SHEET_RED , OPTION_TITLE_24WCSTX_DTKCH}
, {SANE_STD_OPT_NAME_ERASE_BACKGROUND , OPTION_TITLE_BJYC}
, {SANE_STD_OPT_NAME_BKG_COLOR_RANGE , OPTION_TITLE_BJSCFDFW}
, {SANE_STD_OPT_NAME_SHARPEN , OPTION_TITLE_RHYMH}
, {SANE_STD_OPT_NAME_RID_MORR , OPTION_TITLE_QCMW}
, {SANE_STD_OPT_NAME_RID_GRID , OPTION_TITLE_CWW}
, {SANE_STD_OPT_NAME_ERROR_EXTENSION , OPTION_TITLE_CWKS}
, {SANE_STD_OPT_NAME_NOISE_OPTIMIZE , OPTION_TITLE_HBTXZDYH}
, {SANE_STD_OPT_NAME_NOISE_SIZE , OPTION_TITLE_ZDYHCC}
, {SANE_STD_OPT_NAME_PAPER , OPTION_TITLE_ZZCC}
, {SANE_STD_OPT_NAME_CUSTOM_AREA , OPTION_TITLE_ZDYSMQY}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT , OPTION_TITLE_SMQYZCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT , OPTION_TITLE_SMQYYCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_TOP , OPTION_TITLE_SMQYSCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM , OPTION_TITLE_SMQYXCmm}
, {SANE_STD_OPT_NAME_SIZE_CHECK , OPTION_TITLE_CCJC}
, {SANE_STD_OPT_NAME_PAGE , OPTION_TITLE_SMYM}
, {SANE_STD_OPT_NAME_DISCARD_BLANK_SENS , OPTION_TITLE_TGKBYLMD}
, {SANE_STD_OPT_NAME_RESOLUTION , OPTION_TITLE_FBL}
, {SANE_STD_OPT_NAME_TIME_TO_SLEEP , OPTION_TITLE_XMSJ}
, {SANE_STD_OPT_NAME_IMAGE_QUALITY , OPTION_TITLE_HZ}
, {SANE_STD_OPT_NAME_EXCHANGE ,OPTION_TITLE_JHZFM}
, {SANE_STD_OPT_NAME_SPLIT ,OPTION_TITLE_TXCF }
, {SANE_STD_OPT_NAME_ANTI_SKEW , OPTION_TITLE_ZDJP}
, {SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA , OPTION_TITLE_QYSDQX}
, {SANE_STD_OPT_NAME_GAMMA , OPTION_TITLE_JMZ}
, {SANE_STD_OPT_NAME_BRIGHTNESS , OPTION_TITLE_LDZ}
, {SANE_STD_OPT_NAME_CONTRAST , OPTION_TITLE_DBD}
, {SANE_STD_OPT_NAME_IS_PHOTO_MODE , OPTION_TITLE_ZPMS}
, {SANE_STD_OPT_NAME_ERASE_BLACK_FRAME , OPTION_TITLE_XCHK}
, {SANE_STD_OPT_NAME_DARK_SAMPLE , OPTION_TITLE_SSYZ}
, {SANE_STD_OPT_NAME_THRESHOLD , OPTION_TITLE_YZ}
, {SANE_STD_OPT_NAME_ANTI_NOISE_LEVEL , OPTION_TITLE_BJKZDJ}
, {SANE_STD_OPT_NAME_MARGIN , OPTION_TITLE_BYSJ}
, {SANE_STD_OPT_NAME_FILL_BKG_MODE , OPTION_TITLE_BJTCFS}
, {SANE_STD_OPT_NAME_IS_ANTI_PERMEATE , OPTION_TITLE_FZST}
, {SANE_STD_OPT_NAME_ANTI_PERMEATE_LEVEL , OPTION_TITLE_FZSTDJ}
, {SANE_STD_OPT_NAME_RID_HOLE_L , OPTION_TITLE_CKYCZC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_L , OPTION_TITLE_ZCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_R , OPTION_TITLE_CKYCYC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_R , OPTION_TITLE_YCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_T , OPTION_TITLE_CKYCSC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_T , OPTION_TITLE_SCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_B , OPTION_TITLE_CKYCXC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_B , OPTION_TITLE_XCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_IS_FILL_COLOR , OPTION_TITLE_SCTC}
, {SANE_STD_OPT_NAME_IS_ULTROSONIC_CHECK , OPTION_TITLE_CSBJC}
, {SANE_STD_OPT_NAME_DOUBLE_FEED_HANDLE , OPTION_TITLE_SZTPCL}
, {SANE_STD_OPT_NAME_IS_CHECK_STAPLE , OPTION_TITLE_ZDJC}
, {SANE_STD_OPT_NAME_SCAN_MODE , OPTION_TITLE_SMZS}
, {SANE_STD_OPT_NAME_SCAN_COUNT , OPTION_TITLE_SMSL}
, {SANE_STD_OPT_NAME_TEXT_DIRECTION , OPTION_TITLE_WGFX}
, {SANE_STD_OPT_NAME_IS_ROTATE_BKG_180 , OPTION_TITLE_BMXZ180}
, {SANE_STD_OPT_NAME_IS_CHECK_DOG_EAR , OPTION_TITLE_ZJJC}
, {SANE_STD_OPT_NAME_DOG_EAR_SIZE , OPTION_TITLE_ZJDX}
, {SANE_STD_OPT_NAME_IS_CHECK_ASKEW , OPTION_TITLE_WXJC}
, {SANE_STD_OPT_NAME_ASKEW_RANGE , OPTION_TITLE_WXRRD}
, {SANE_STD_OPT_NAME_FEED_STRENGTH , OPTION_TITLE_FZQD}
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , OPTION_TITLE_ZDFZQD}
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , OPTION_TITLE_JZSBL}
, {SANE_STD_OPT_NAME_WAIT_TO_SCAN , OPTION_TITLE_DZSM}
, {SANE_STD_OPT_NAME_FOLD_TYPE , OPTION_TITLE_DZMS}
},
g_discard[] = { {SANE_STD_OPT_NAME_REVERSE_01 , "\351\273\221\347\231\275\345\233\276\345\203\217\345\217\215\350\211\262\350\276\223\345\207\272\357\274\210\346\255\243\345\270\270\351\242\234\350\211\262\344\270\272\357\274\2320-\351\273\221\350\211\262\357\274\2331-\347\231\275\350\211\262\357\274\211"} // 黑白图像反色输出正常颜色为0-黑色1-白色)
, {SANE_STD_OPT_NAME_FILTER , "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262"} // 灰度或黑白图像 - 除色
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , "\350\207\252\345\212\250\346\220\223\347\272\270\345\274\272\345\272\246"} // 自动搓纸强度
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , "\346\220\223\347\272\270\351\230\210\345\200\274"} // " 搓纸阈值"
};
while (*title == ' ')
title++;
for (size_t i = 0; i < _countof(g_opts); ++i)
{
if (strcmp(title, g_opts[i].title) == 0)
return g_opts[i].name;
}
for (size_t i = 0; i < _countof(g_discard); ++i)
{
if (strcmp(title, g_discard[i].title) == 0)
return g_discard[i].name;
}
return title;
}
public:
dev_que() : handle_(nullptr)
{}
~dev_que()
{
close_scanner();
for(auto& v : que_)
v.cfg->release();
}
static void update_old_cfg(const char* conf)
{
gb::scanner_cfg::UDF func;
func.func_param = nullptr;
func.title2name = &dev_que::title_2_name;
func.trans_number = &dev_que::trans_number;
gb::scanner_cfg::update(conf, &func);
}
static SANE_Status restore_settings(const SANEAPI* saneApi, SANE_Handle h)
{
SANE_Int dev_options = 0;
saneApi->sane_control_option_api(h, 0, SANE_ACTION_GET_VALUE, &dev_options, nullptr);
for(int i = 1; i < dev_options; ++i)
{
const SANE_Option_Descriptor* opt = saneApi->sane_get_option_descriptor_api(h, i);
if(!opt)
2023-05-29 10:45:15 +00:00
continue;
2023-06-03 09:25:56 +00:00
if (opt->type == SANE_TYPE_BUTTON || opt->type == SANE_TYPE_GROUP)
continue;
saneApi->sane_control_option_api(h, i, SANE_ACTION_SET_AUTO, NULL, NULL);
}
return SANE_STATUS_GOOD;
}
static SANE_Status get_default_value(const SANEAPI* saneApi, SANE_Handle h, int i, void* def)
{
2023-06-03 09:25:56 +00:00
return saneApi->sane_control_option_api(h, i, (SANE_Action)100, def, NULL);
}
static SANE_Status set_custom_gamma(const SANEAPI* saneApi, SANE_Handle h, SANE_Gamma *gamma)
{
return saneApi->sane_control_option_api(h, 0x885A, SANE_ACTION_SET_VALUE, gamma, NULL);
}
static void apply_scheme(const SANEAPI* saneApi, SANE_Handle h, gb::sane_config_schm* schm)
{
SANE_Int count = 0, none = 0;
std::string name(""), val("");
none = restore_settings(saneApi, h);
if(schm && schm->id_from_name(SANE_STD_OPT_NAME_COLOR_MODE) == -1)
{
SANE_Int dev_options = 0;
saneApi->sane_control_option_api(h, 0, SANE_ACTION_GET_VALUE, &dev_options, nullptr);
for(int i = 1; i < dev_options; ++i)
{
const SANE_Option_Descriptor* opt = saneApi->sane_get_option_descriptor_api(h, i);
2023-06-03 09:25:56 +00:00
if(!opt || opt->type == SANE_TYPE_BUTTON || opt->type == SANE_TYPE_GROUP)
continue;
unsigned int n = i;
if(opt->type == SANE_TYPE_BOOL)
{
SANE_Bool v = SANE_TRUE;
get_default_value(saneApi, h, n, &v);
schm->set_default_value(i, opt->name, (char*)&v, sizeof(v));
}
else if (opt->type == SANE_TYPE_INT) {
SANE_Int v = 0;
get_default_value(saneApi, h, n, &v);
schm->set_default_value(i, opt->name, (char*)&v, sizeof(v));
}
else if(opt->type == SANE_TYPE_FIXED)
{
SANE_Fixed v = 0;
get_default_value(saneApi, h, n, &v);
schm->set_default_value(i, opt->name, (char*)&v, sizeof(v));
}
else {
char *buf = new char[opt->size + 4];
memset(buf, 0, opt->size + 4);
get_default_value(saneApi, h, n, buf);
std::string langCN(to_default_language(buf, nullptr));
schm->set_default_value(i, opt->name, &langCN[0], langCN.length());
delete[] buf;
}
}
}
if(schm && schm->first_config(name, val))
{
do
{
int id = schm->id_from_name(name.c_str());
if(id == -1)
{
if(gb::sane_config_schm::is_option_data(name))
{
if(name == SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA && val.length() == sizeof(SANE_Gamma))
{
set_custom_gamma(saneApi, h, (SANE_Gamma*)&val[0]);
}
}
}
else {
const SANE_Option_Descriptor* opt = reinterpret_cast<const SANE_Option_Descriptor*>(saneApi->sane_get_option_descriptor_api(h, id));
if(opt)
{
if(opt->type == SANE_TYPE_STRING)
{
char *buf = new char[opt->size + 4];
memset(buf, 0, opt->size + 4);
strcpy(buf, val.c_str());
std::string langCN(from_default_language(buf, nullptr));
saneApi->sane_control_option_api(h, id, SANE_ACTION_SET_VALUE, &langCN[0], &none);
delete[] buf;
}
else {
saneApi->sane_control_option_api(h, id, SANE_ACTION_SET_VALUE, &val[0], &none);
}
}
}
}while(schm->next_config(name, val));
}
}
public:
void set_root_dir(const char* root)
{
root_dir_ = std::string(root) + PATH_SYMBOL;
}
void add_scanner(const char* sane_name)
{
2023-06-03 09:25:56 +00:00
std::string devName = sane_name;
bool found = false;
for(auto& v: que_)
{
2023-06-03 09:25:56 +00:00
if(v.name == devName)
{
found = true;
break;
}
}
if(!found)
{
SCANNER s;
size_t pos = 0;
2023-06-03 09:25:56 +00:00
s.model = s.name = devName;
s.cfg = nullptr;
pos = s.model.find(" - ");
if(pos != std::string::npos)
{
pos = s.model.find(" - ", pos + 3);
if(pos != std::string::npos)
s.model.erase(pos);
}
for(auto& v: que_)
{
if(v.model == s.model)
{
s.cfg = v.cfg;
s.cfg->add_ref();
break;
}
}
if(!s.cfg)
{
s.cfg = new gb::scanner_cfg();
s.cfg->load_file((root_dir_ + s.model + ".cfg").c_str());
}
s.online = true;
que_.push_back(s);
}
}
void get_schemes(const char* scanner_name, std::vector<std::string>& schemes)
{
schemes.clear();
for(auto& v : que_)
{
if(v.name == scanner_name)
{
v.cfg->get_all_schemes(schemes);
break;
}
}
}
SANE_Handle handle(void)
{
return handle_;
}
std::string opened_scanner_name(void)
{
return opened_scanner_;
}
std::string applied_scheme(void)
{
return applied_scheme_;
}
2023-06-03 09:25:56 +00:00
int open_scanner(const SANEAPI* saneAPI, SANE_Handle handle, const char* scanner_name, bool apply, const char* scheme = nullptr)
{
handle_ = handle;
opened_scanner_ = scanner_name;
2023-06-03 09:25:56 +00:00
if (apply)
apply_scheme(saneAPI, scheme);
return SANE_STATUS_GOOD;
}
int close_scanner(void)
{
handle_ = nullptr;
opened_scanner_ = "";
applied_scheme_ = "";
return SANE_STATUS_GOOD;
}
int scanners(void)
{
return que_.size();
}
SCANNER get_at(int pos)
{
SCANNER s;
s.name = s.model = "";
s.cfg = nullptr;
if(pos >= 0 && pos < que_.size())
{
s = que_[pos];
s.cfg->add_ref();
}
return s;
}
bool is_online(const char* scanner = nullptr)
{
if(!scanner)
scanner = opened_scanner_.c_str();
for(auto& v : que_)
{
if(v.name == scanner)
return v.online;
}
return false;
}
void set_online(bool online, const char* scanner = nullptr)
{
if(!scanner)
scanner = opened_scanner_.c_str();
for(auto& v : que_)
{
if(v.name == scanner)
{
v.online = online;
break;
}
}
}
void get_scanners(std::vector<std::string>& que)
{
for(auto& v: que_)
que.push_back(v.name);
}
int apply_scheme(const SANEAPI* saneApi, const char* scheme_name)
{
if(!handle_)
return SCANNER_ERR_NOT_OPEN;
for(auto& v: que_)
{
if(v.name == opened_scanner_)
{
gb::sane_config_schm* schm = v.cfg->get_scheme(scheme_name);
dev_que::apply_scheme(saneApi, handle_, schm);
if(schm)
{
v.cfg->select_scheme(schm->get_scheme_name().c_str());
schm->release();
}
else {
v.cfg->select_scheme(scheme_name);
}
applied_scheme_ = v.cfg->get_current_scheme_name();
v.cfg->save();
break;
}
}
return SCANNER_ERR_OK;
}
};
class device_menu : public QMenu
{
Q_OBJECT
typedef struct _pop_menu
{
QMenu* menu;
std::vector<QAction*> actions;
bool operator==(const QString& menu_title)
{
return menu->title() == menu_title;
}
}POPMENU;
std::vector<POPMENU> menus_;
QAction* cur_action_;
QAction* none_action_;
QActionGroup* group_action_;
std::mutex mutex_;
QMenu* find_device_menu(const QString& dev_name);
QAction* find_device_config(const QString& dev_name, const QString& cfg_name);
public:
device_menu(QWidget* parent = nullptr);
device_menu(const QString& title, QWidget* parent = nullptr);
void deviceMenuUpdate(dev_que* que);
void connectedDevice(const QString& device);
void disconnectedDevice(const QString& device);
void setOptionChecked(const QString& device, const QString& opt, bool checked);
void get_online_devices(QList<QString>& dev_names);
signals:
void scanOptionsChanged(const QString& device, const QString& opt, bool checked_now);
private slots:
void on_act_triggered(QAction* act);
};
#endif // DEVICE_MENU_H