// // device_opt: option manager of device // // Created: 2023-09-07 // #pragma once #include #include #include #include #include #include #include #include "simple_logic.h" #include class sane_opt_provider; class device_option { gb_json* origin_; gb_json* now_; std::map src_; std::vector master_opts_; // options that value changed will affect others std::map slaver_; std::function user_; std::function log_; typedef struct _expr_calc { std::string name; std::string val1; std::string val2; bool not_op; bool(*compare)(gb_json*, void* val, void* v1, void* v2); }EXPRCALC; std::map compare_; // simple condition compare class condition_value { typedef struct _cond_val { simple_logic *logic; std::string value; }CONDVAL; std::vector vals_; device_option* parent_; // if this value was valid, the condition value is a consistant value with vals_[0].value void clear(void) { for (auto& v : vals_) { if (v.logic) delete v.logic; } vals_.clear(); parent_ = nullptr; } public: condition_value() : parent_(nullptr) {} ~condition_value() { clear(); } public: bool set_value(gb_json* jsn, const char* type, device_option* parent); // jsn contains only ONE value or its object, or nullptr for a consistant value std::string value(bool(*compare)(const char*, void*), void* param); }; class range_value { bool is_range_; // true - range; false - list int val_ind_; std::vector vals_; void clear(void) { for (auto& v : vals_) delete v; vals_.clear(); } public: range_value() : is_range_(false), val_ind_(0) {} ~range_value() { clear(); } public: bool set_value(gb_json* jsn, const char* type, device_option *parent); // jsn contains all range object int count(void) { return vals_.size(); } bool is_range(void) { return is_range_; } // return first element in list-value or min-value of range std::string first_value(bool(*compare)(const char*, void*), void* param) { val_ind_ = 0; if (val_ind_ < count()) return vals_[val_ind_]->value(compare, param); else return ""; } // return next element in list-value or max-value of range std::string next_value(bool(*compare)(const char*, void*), void* param) { if (++val_ind_ < count()) return vals_[val_ind_]->value(compare, param); else return ""; } }; std::map range_value_; std::map init_value_; std::map support_value_; std::map > depend_opts_; // values that depend on other option's current value static bool is_equal_b(gb_json* opt, void* val, void* v1, void* v2); static bool is_equal_i(gb_json* opt, void* val, void* v1, void* v2); static bool is_equal_f(gb_json* opt, void* val, void* v1, void* v2); static bool is_equal_s(gb_json* opt, void* val, void* v1, void* v2); static bool is_less_b(gb_json* opt, void* val, void* v1, void* v2); static bool is_less_i(gb_json* opt, void* val, void* v1, void* v2); static bool is_less_f(gb_json* opt, void* val, void* v1, void* v2); static bool is_less_s(gb_json* opt, void* val, void* v1, void* v2); static bool is_great_b(gb_json* opt, void* val, void* v1, void* v2); static bool is_great_i(gb_json* opt, void* val, void* v1, void* v2); static bool is_great_f(gb_json* opt, void* val, void* v1, void* v2); static bool is_great_s(gb_json* opt, void* val, void* v1, void* v2); static bool is_between_b(gb_json* opt, void* val, void* v1, void* v2); static bool is_between_i(gb_json* opt, void* val, void* v1, void* v2); static bool is_between_f(gb_json* opt, void* val, void* v1, void* v2); static bool is_between_s(gb_json* opt, void* val, void* v1, void* v2); static bool is_opt_enabled(gb_json* opt, void* val, void* v1, void* v2); static bool get_equal(const char* type, bool(**f)(gb_json*, void*, void*, void*)); static bool get_less(const char* type, bool(**f)(gb_json*, void*, void*, void*)); static bool get_great(const char* type, bool(**f)(gb_json*, void*, void*, void*)); static bool get_between(const char* type, bool(**f)(gb_json*, void*, void*, void*)); static std::string from_text_value(const char* type, const char* text_val); static bool parse_simple_logic_expression(gb_json* root, const char* expr, std::string* name, EXPRCALC& calc); static void init_condition(const char* expr, void* param); static bool calc_simple_logic_expression(const char* expr, void* param); void clear_for_reconstruct(void); gb_json* group_opt(const char* title); int next_group(int start); // return index of the next group int insert_group(const char* name, const char* title); // return index of the group void insert_option(gb_json* opt, sane_opt_provider* from, const char* group = nullptr); bool arrange_raw_json(sane_opt_provider* sop); // create origin_ and re-arrange groups void init_depends(gb_json* opt); gb_json* copy_opt(gb_json* from); int visibility(gb_json* jsn); bool to_now(bool init, bool* changed); protected: static std::string option_value(gb_json* jsn, bool def_val); template static condition_value* to_condition_value(gb_json* jsn, const char* key, const char* type, device_option* parent) { condition_value* ret = nullptr; gb_json* child = nullptr; if (!jsn->get_value(key, child)) { T v; if(jsn->get_value(key, v)) child = new gb_json("", v); else { std::string sv(""); if (jsn->get_value(key, sv)) { // consistant with another option ... ret = new condition_value(); ret->set_value(nullptr, sv.c_str(), parent); if (std::find(parent->master_opts_.begin(), parent->master_opts_.end(), sv) == parent->master_opts_.end()) parent->master_opts_.push_back(sv); } } } if (child) { ret = new condition_value(); if (!ret->set_value(child, type, parent)) { delete ret; ret = nullptr; } child->release(); } return ret; } template bool get_range(gb_json* jsn, const char* key, T& val) { if (jsn->get_value(key, val)) return true; std::string optn(""); if (!jsn->get_value(key, optn)) return false; gb_json* opt = nullptr; if (now_) now_->get_value(optn.c_str(), opt); if (!opt && origin_) origin_->get_value(optn.c_str(), opt); if (!opt) return false; bool ret = opt->get_value("cur", val); opt->release(); return ret; } template bool refine_data_to_range(gb_json* jsn, void* value) { bool refined = false; gb_json* range = nullptr; jsn->get_value("range", range); if (range) { T vl, vu, s; if (get_range(range, "min", vl)) { if (*(T*)value < vl) { *(T*)value = vl; refined = true; } else if (get_range(range, "max", vu)) { if (*(T*)value > vu) { *(T*)value = vu; refined = true; } else if (get_range(range, "step", s)) { T cur(*(T*)value); vl = cur - vl; vl /= s; if (!IS_DOUBLE_EQUAL(vl, (int)vl)) { vl += .5f; vl = (int)vl * s; if (vl > vu) vl = vu; *(T*)value = vl; refined = true; } } } } else { gb_json* val = range->first_child(); bool found = false; while (val) { if (val->value(vl)) { if (*(T*)value == vl) { found = true; val->release(); break; } } val->release(); val = range->next_child(); } if (!found) { if (jsn->get_value("default", vl)) { refined = true; *(T*)value = vl; } } } range->release(); } return refined; } template void write_log(const char* fmt, Args ... args) { if (log_) { size_t size = snprintf(nullptr, 0, fmt, args ...) + 2; std::unique_ptr buf(new char[size]); snprintf(buf.get(), size, fmt, args ...); log_(buf.get()); } } public: device_option(std::function user_priv = std::function() , std::function log = std::function()); ~device_option(); static std::string trans_group(const char* utf8, bool to_title); static std::string get_group(int ind, bool title); public: void clear(void); bool add(sane_opt_provider* sop); bool refine_data(const char* name, void* value); // return true if the 'value' is out of range and refined it in the range int update_data(const char* name, void* value); // return scanner_err. name and value would be null if invoked for language changed int restore(sane_opt_provider* holder); // int count(void); // return option count bool is_auto_restore_default(const char* name); std::string get_name_by_sane_id(int sane_ind); std::string get_option_value_type(const char* name); std::string get_option_value_type(int sane_ind); std::string get_option_field_string(const char* name, const char* key); std::string get_option_value(const char* name, int type/*OPT_VAL_xxx*/, int* size = nullptr, void* in_data = nullptr); // return whole json-text if name was null std::string get_option_value(int sane_ind, int type/*OPT_VAL_xxx*/, int* size = nullptr, void* in_data = nullptr); // return whole json-text if name was null }; //{ // "resolution": { // "cat": "base", // "group" : "base", // "title" : "分辨率", // "desc" : "设置扫描图像的分辨率", // "type" : "int", // "fix-id" : 34840, // "size" : 4, // "cur" : 200, // "default" : 200, // "range" : { // "min": 100, // "max" : { // "default": 600, // "paper==最大扫描尺寸自动裁切 || paper==最大扫描尺寸 || paper==三联试卷" : 500 // }, // "step" : 1 // } // }, // // "paper": { // "cat": "base", // "group" : "base", // "title" : "纸张尺寸", // "desc" : "设置出图大小", // "type" : "string", // "fix-id" : 34831, // "size" : 44, // "cur" : "匹配原始尺寸", // "default" : "匹配原始尺寸", // "range" : ["A3", "8开", "A4", "16开", "A5", "A6", "B4", "B5", "B6", "Letter", "Double Letter", "LEGAL", "匹配原始尺寸", { // "resolution<500": "最大扫描尺寸自动裁切" // }, { // "resolution<500": "最大扫描尺寸" // }, { // "resolution<500": "三联试卷" // }] // } //}