2023-09-08 09:42:40 +00:00
//
// device_opt: option manager of device
//
// Created: 2023-09-07
//
# pragma once
# include <sane/sane_ex.h>
# include <string>
# include <vector>
# include <map>
# include <functional>
2023-10-31 07:08:24 +00:00
# include <algorithm>
# include <memory>
2023-09-08 09:42:40 +00:00
# include "simple_logic.h"
# include <json/gb_json.h>
2023-11-10 06:38:12 +00:00
# include <hginclude/utils.h>
2023-09-08 09:42:40 +00:00
2023-10-31 06:51:14 +00:00
class sane_opt_provider ;
2023-09-08 09:42:40 +00:00
2023-11-10 06:38:12 +00:00
class device_option : public refer
2023-09-08 09:42:40 +00:00
{
gb_json * origin_ ;
gb_json * now_ ;
2023-10-31 06:51:14 +00:00
std : : map < std : : string , sane_opt_provider * > src_ ;
2023-09-08 09:42:40 +00:00
std : : vector < std : : string > master_opts_ ; // options that value changed will affect others
std : : map < std : : string , simple_logic * > slaver_ ;
2023-09-21 03:23:38 +00:00
std : : function < bool ( int ) > user_ ;
2023-10-31 06:51:14 +00:00
std : : function < void ( const char * ) > log_ ;
2023-09-08 09:42:40 +00:00
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 < std : : string , EXPRCALC > compare_ ; // simple condition compare
class condition_value
{
typedef struct _cond_val
{
simple_logic * logic ;
std : : string value ;
} CONDVAL ;
std : : vector < CONDVAL > vals_ ;
2023-10-16 07:52:16 +00:00
device_option * parent_ ; // if this value was valid, the condition value is a consistant value with vals_[0].value
2023-09-08 09:42:40 +00:00
void clear ( void )
{
for ( auto & v : vals_ )
{
if ( v . logic )
delete v . logic ;
}
vals_ . clear ( ) ;
2023-10-16 07:52:16 +00:00
parent_ = nullptr ;
2023-09-08 09:42:40 +00:00
}
public :
2023-10-16 07:52:16 +00:00
condition_value ( ) : parent_ ( nullptr )
2023-09-08 09:42:40 +00:00
{ }
~ condition_value ( )
{
clear ( ) ;
}
public :
2023-10-16 07:52:16 +00:00
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 ) ;
2023-09-08 09:42:40 +00:00
} ;
class range_value
{
bool is_range_ ; // true - range; false - list
int val_ind_ ;
std : : vector < condition_value * > 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 < std : : string , range_value * > range_value_ ;
2023-09-14 03:28:21 +00:00
std : : map < std : : string , condition_value * > init_value_ ;
2023-09-25 08:47:05 +00:00
std : : map < std : : string , condition_value * > support_value_ ;
2023-10-16 07:52:16 +00:00
std : : map < std : : string , std : : vector < std : : string > > depend_opts_ ; // values that depend on other option's current value <master option name, [slaver-option-nam.field ...]>
2023-09-08 09:42:40 +00:00
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 * ) ) ;
2023-11-02 09:07:28 +00:00
// Function: parse string function - .left(cnt), .right(cnt), .mid(start, cnt)
//
// Parameter: expr - expression of string function, e.g. mode.left(2)
//
// name - to receive the final option name, e.g. mode
//
// start - to receive the starting position of the sub-string, negative is for right()
//
// cnt - to receive the length of the sub string, -1 is to end
//
// Return: true if was string function
static bool is_string_function ( const char * expr , std : : string & name , int & start , int & cnt ) ;
2023-09-08 09:42:40 +00:00
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 ) ;
2023-10-31 06:51:14 +00:00
void clear_for_reconstruct ( void ) ;
2023-09-13 03:20:51 +00:00
gb_json * group_opt ( const char * title ) ;
2023-10-31 06:51:14 +00:00
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
2023-09-08 09:42:40 +00:00
void init_depends ( gb_json * opt ) ;
gb_json * copy_opt ( gb_json * from ) ;
2023-09-25 08:47:05 +00:00
int visibility ( gb_json * jsn ) ;
2023-09-14 09:53:17 +00:00
bool to_now ( bool init , bool * changed ) ;
2023-09-08 09:42:40 +00:00
2023-09-15 09:53:13 +00:00
protected :
2023-09-08 09:42:40 +00:00
static std : : string option_value ( gb_json * jsn , bool def_val ) ;
template < class T >
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 ;
2023-10-16 07:52:16 +00:00
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 ) ;
}
}
2023-09-08 09:42:40 +00:00
}
2023-10-16 07:52:16 +00:00
if ( child )
2023-09-08 09:42:40 +00:00
{
2023-10-16 07:52:16 +00:00
ret = new condition_value ( ) ;
if ( ! ret - > set_value ( child , type , parent ) )
{
delete ret ;
ret = nullptr ;
}
child - > release ( ) ;
2023-09-08 09:42:40 +00:00
}
return ret ;
}
2023-10-16 07:52:16 +00:00
template < class T >
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 < class T >
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 < T > ( range , " min " , vl ) )
{
if ( * ( T * ) value < vl )
{
* ( T * ) value = vl ;
refined = true ;
}
else if ( get_range < T > ( range , " max " , vu ) )
{
if ( * ( T * ) value > vu )
{
* ( T * ) value = vu ;
refined = true ;
}
else if ( get_range < T > ( range , " step " , s ) )
{
2023-11-01 07:12:11 +00:00
// step check, FIXED me ...
2023-10-16 07:52:16 +00:00
T cur ( * ( T * ) value ) ;
2023-11-01 07:12:11 +00:00
cur - = vl ;
cur / = s ;
if ( ! IS_DOUBLE_EQUAL ( cur , ( int ) cur ) )
2023-10-16 07:52:16 +00:00
{
2023-11-01 07:12:11 +00:00
cur * = s ;
cur + = vl ;
if ( cur > vu )
cur = vu ;
refined = ! IS_DOUBLE_EQUAL ( cur , * ( T * ) value ) ;
* ( T * ) value = cur ;
2023-10-16 07:52:16 +00:00
}
}
}
}
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 ;
}
2023-10-31 06:51:14 +00:00
template < typename . . . Args >
void write_log ( const char * fmt , Args . . . args )
{
if ( log_ )
{
size_t size = snprintf ( nullptr , 0 , fmt , args . . . ) + 2 ;
std : : unique_ptr < char [ ] > buf ( new char [ size ] ) ;
snprintf ( buf . get ( ) , size , fmt , args . . . ) ;
log_ ( buf . get ( ) ) ;
}
}
2023-11-03 10:03:22 +00:00
2023-09-15 09:53:13 +00:00
public :
2023-10-31 06:51:14 +00:00
device_option ( std : : function < bool ( int ) > user_priv = std : : function < bool ( int ) > ( )
, std : : function < void ( const char * ) > log = std : : function < void ( const char * ) > ( ) ) ;
2023-09-15 09:53:13 +00:00
~ device_option ( ) ;
2023-09-13 03:20:51 +00:00
static std : : string trans_group ( const char * utf8 , bool to_title ) ;
static std : : string get_group ( int ind , bool title ) ;
2023-09-08 09:42:40 +00:00
public :
2023-10-31 06:51:14 +00:00
void clear ( void ) ;
bool add ( sane_opt_provider * sop ) ;
2023-09-08 09:42:40 +00:00
bool refine_data ( const char * name , void * value ) ; // return true if the 'value' is out of range and refined it in the range
2023-10-31 10:04:26 +00:00
int update_data ( const char * name , void * value , bool reorder_if_need = true ) ; // return scanner_err. name and value would be null if invoked for language changed
2023-10-31 06:51:14 +00:00
int restore ( sane_opt_provider * holder ) ; //
2023-09-08 09:42:40 +00:00
2023-09-15 09:53:13 +00:00
int count ( void ) ; // return option count
2023-09-22 07:43:53 +00:00
bool is_auto_restore_default ( const char * name ) ;
2023-09-15 09:53:13 +00:00
std : : string get_name_by_sane_id ( int sane_ind ) ;
2023-09-08 09:42:40 +00:00
std : : string get_option_value_type ( const char * name ) ;
2023-09-15 09:53:13 +00:00
std : : string get_option_value_type ( int sane_ind ) ;
2023-10-31 06:51:14 +00:00
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
2023-09-08 09:42:40 +00:00
} ;
//{
2023-10-31 06:51:14 +00:00
// "resolution": {
2023-09-08 09:42:40 +00:00
// "cat": "base",
// "group" : "base",
2023-10-31 06:51:14 +00:00
// "title" : "<22> ֱ<EFBFBD> <D6B1> <EFBFBD> ",
// "desc" : "<22> <> <EFBFBD> <EFBFBD> ɨ<EFBFBD> <C9A8> ͼ<EFBFBD> <CDBC> <EFBFBD> ķֱ<C4B7> <D6B1> <EFBFBD> ",
2023-09-08 09:42:40 +00:00
// "type" : "int",
2023-10-31 06:51:14 +00:00
// "fix-id" : 34840,
2023-09-08 09:42:40 +00:00
// "size" : 4,
2023-10-31 06:51:14 +00:00
// "cur" : 200,
// "default" : 200,
2023-09-08 09:42:40 +00:00
// "range" : {
2023-10-31 06:51:14 +00:00
// "min": 100,
// "max" : {
// "default": 600,
// "paper==<3D> <> <EFBFBD> <EFBFBD> ɨ<EFBFBD> <C9A8> <EFBFBD> ߴ <EFBFBD> <DFB4> Զ<EFBFBD> <D4B6> <EFBFBD> <EFBFBD> <EFBFBD> || paper==<3D> <> <EFBFBD> <EFBFBD> ɨ<EFBFBD> <C9A8> <EFBFBD> ߴ <EFBFBD> || paper==<3D> <> <EFBFBD> <EFBFBD> <EFBFBD> Ծ<EFBFBD> " : 500
// },
2023-09-08 09:42:40 +00:00
// "step" : 1
2023-10-31 06:51:14 +00:00
// }
2023-09-08 09:42:40 +00:00
// },
//
// "paper": {
// "cat": "base",
// "group" : "base",
// "title" : "ֽ<> ųߴ <C5B3> ",
// "desc" : "<22> <> <EFBFBD> ó<EFBFBD> ͼ<EFBFBD> <CDBC> С ",
// "type" : "string",
2023-10-31 06:51:14 +00:00
// "fix-id" : 34831,
// "size" : 44,
2023-09-08 09:42:40 +00:00
// "cur" : "ƥ<> <C6A5> ԭʼ <D4AD> ߴ <EFBFBD> ",
// "default" : "ƥ<> <C6A5> ԭʼ <D4AD> ߴ <EFBFBD> ",
2023-10-31 06:51:14 +00:00
// "range" : ["A3", "8<> <38> ", "A4", "16<31> <36> ", "A5", "A6", "B4", "B5", "B6", "Letter", "Double Letter", "LEGAL", "ƥ<> <C6A5> ԭʼ <D4AD> ߴ <EFBFBD> ", {
// "resolution<500": "<22> <> <EFBFBD> <EFBFBD> ɨ<EFBFBD> <C9A8> <EFBFBD> ߴ <EFBFBD> <DFB4> Զ<EFBFBD> <D4B6> <EFBFBD> <EFBFBD> <EFBFBD> "
// }, {
// "resolution<500": "<22> <> <EFBFBD> <EFBFBD> ɨ<EFBFBD> <C9A8> <EFBFBD> ߴ <EFBFBD> "
// }, {
// "resolution<500": "<22> <> <EFBFBD> <EFBFBD> <EFBFBD> Ծ<EFBFBD> "
// }]
2023-09-08 09:42:40 +00:00
// }
2023-10-31 06:51:14 +00:00
//}