// // device_opt: option manager of device // // Created: 2023-09-07 // #pragma once #include #include #include #include #include #include "simple_logic.h" #include class device_option { gb_json* origin_; gb_json* now_; std::vector master_opts_; // options that value changed will affect others std::map slaver_; std::function user_; 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(void); gb_json* group_opt(const char* title); bool arrange_raw_json(const char* txt); // 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; } public: device_option(std::function user_priv = 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: bool init(const char* opt_json); 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 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(const char* name, int type/*OPT_VAL_xxx*/, int* size = nullptr); // return whole json-text if name was null std::string get_option_field_string(const char* name, const char* key); std::string get_option_value_type(int sane_ind); std::string get_option_value(int sane_ind, int type/*OPT_VAL_xxx*/, int* size = nullptr); // return whole json-text if name was null }; //{ // "noise-size": { // "cat": "base", // "group" : "base", // "title" : " 噪点优化尺寸", // "desc" : "设置需要去除的黑", // "ver" : 0, // "pos" : 0, // "fix-id" : 0, // "type" : "int", // "unit" : "none", // "affect" : 0, // "readonly" : false, // "visible" : true, // "enabled" : false, // "size" : 4, // "cur" : 10, // "default" : 10, // "range" : { // "min": 1, // "max" : { // "paper==A3": 50, // condition value // "default": 45} , // "step" : 1 // }, // "depend_or": ["is-noise-optimize==true"] // }, // // "paper": { // "cat": "base", // "group" : "base", // "title" : "纸张尺寸", // "desc" : "设置出图大小", // "ver" : 0, // "pos" : 0, // "fix-id" : 0, // "type" : "string", // "unit" : "none", // "affect" : 0, // "readonly" : false, // "visible" : true, // "enabled" : false, // "size" : 96, // "cur" : "匹配原始尺寸", // "default" : "匹配原始尺寸", // "range" : ["A3", "8开", { // "mode==24位彩色": "A4" // condition value // }, "A4横向", "16开", "16开横向", "A5", "A5横向", "A6", "A6横向", "B4", "B5", "B5横向", "B6", "B6横向", "Letter", "Letter横向", "Double Letter", "LEGAL", "匹配原始尺寸", "最大扫描尺寸自动裁切", "最大扫描尺寸", "三联试卷"] // } //}