-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnumber.hpp
349 lines (310 loc) · 11.6 KB
/
number.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/**
* Copyright (C) 2013-2019, Ariel Vina Rodriguez ( [email protected] )
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file nana.ext\include\number.hpp
*
* @author Ariel Vina-Rodriguez (qPCR4vir)
*
* @brief Provide GUI controls (nana widgets) to represent numbers
*
* Extension to nana. From: https://github.com/qPCR4vir/nana.ext
*
* To be used together with:
*
* - the Nana C++ GUI library, from: https://github.com/cnjinhao/nana
*
*/
#ifndef NANA_GUI_Number_HPP
#define NANA_GUI_Number_HPP
#pragma warning(disable : 4996)
// From: https://github.com/qPCR4vir/nana.ext
#include <EditableForm.hpp>
#include <Units.hpp>
namespace nana {
class NumberLabel : public label
{
public:
NumberLabel ( widget &parent,
double val=0,
unsigned decimals=2,
unsigned width=6)
: label(parent),
_val(val), _decimals(decimals), _width(width)
{
display();
}
double _val;
unsigned _decimals,
_width;
double Value( )const{ return _val;}
double Value(double val) {_val=val; display(); return _val;}
void display()
{
std::string val(50,0);
snprintf(&val[0],val.size(), (" %*.*f"), _width, _decimals, _val );
caption (val.c_str());
}
};
class NumberBox : public textbox
{
public:
NumberBox ( window parent,
double val=0,
unsigned decimals=2,
unsigned width=6)
: textbox(parent),
_val(val), _decimals(decimals), _width(width)
{
multi_lines(false);
display();
events().focus([&](const arg_focus & ei)
{ if (!ei.getting)
validate_edit( );
});
}
double _val;
unsigned _decimals,
_width;
double Value( )const{ return _val;}
double Value(double val) {_val=val; display(); return _val;}
void read()
{
try { _val=std::stod (caption() ); }
catch (...) {; }
}
void validate_edit()
{
read();
display();
}
void display()
{
std::string val(50,0);
snprintf(&val[0],val.size(), (" %*.*f"), _width, _decimals, _val );
caption (val.c_str());
}
};
class NumberUpDown : public CompoWidget
{
button _up{*this, ("^")}, _down{*this, ("v")};
label _label;
double _val, _min, _max, _step;
unsigned _decimals, _width;
public:
textbox _num{*this};
NumberUpDown ( widget &parent_, const std::string &label,
double val, double min, double max,
const std::string &DefFileName=("NumUpDown.VertCenter.lay.txt"),
double step=1, unsigned width=6, unsigned decimals=2 );
double Value ( )const{ return _val; }
double Min ( )const{ return _min; }
double Max ( )const{ return _max; }
double Step ( )const{ return _step; }
unsigned Width ( )const{ return _width;}
unsigned Decimals ( )const{ return _decimals;}
double Value (double val)
{
auto old_v = _val;
changed=false;
// add_validate //
if (val < _min) val = _min;
else if(val > _max) val = _max;
if ( _val != val )
{
_val=val;
try{changed=Validate();} catch(...){}
if (!changed )
_val=old_v;
}
display () ;
return _val;
}
double Min (double val) { _min=val; /*validate();*/ return _min; }
double Max (double val) { _max=val; /*validate(); */ return _max; }
double Step (double val) { _step=val; /* ();*/ return _step; }
unsigned Width (unsigned val) { _width=val;/* display ();*/ return _width;}
unsigned Decimals (unsigned val) { _decimals=val;/* display();*/return _decimals;}
double read ()
{
try{ return std::stod (_num.caption() ); }
catch (...) { return _val; }
}
void validate()
{
if (_val < _min) _val = _min;
else if(_val > _max) _val = _max;
display();
}
void validate_edit() { Value (read()); }
void add (double step) { Value (step+Value()); }
void display ()
{
std::string val(50,0);
snprintf(&val[0],val.size(), (" %*.*f"), _width, _decimals, _val );
_num.caption (val.c_str());
}
void SetDefLayout () override
{
_DefLayout= " <horizontal "
" <width=60 vertical <><height=15 label gap=1><> > \n"
" <width=50 vertical <><height=19 Num ><> > \n"
" <width=30 vertical <><height=19 UpDown ><> > \n"
" > " ;
}
void AsignWidgetToFields() override
{
_place.field("Num" ) << _num ;
_place.field("UpDown" ) << _up << _down ;
_place.field("label" ) << _label;
}
};
class UnitPicker : public combox
{
RTunits::unit_name _defUnitName;
RTunits::CUnit _defUnit{_defUnitName};
const RTunits::magnitude_name magnitude= RTunits::magnitude_name{_defUnit.magnitude};
public:
UnitPicker(widget &wd, const RTunits::unit_name& def)
:combox(wd), _defUnitName(def)
{
editable(false);
for(const RTunits::unit_name& un : RTunits::MagnitudesDic().at(magnitude) )
push_back ( un ); /*CUnit::UnitsDic().at(un).to_string ()*/
caption( def );
//ext_event().selected=[&](combox& cb)
//{
// _cb.caption(_cb.caption().substr(6, _cb.caption().find_first_of((" ="),6)-6 ));
//};
}
double to_def (double val) ///< Convert a value in user selected Unit into Default Unit
{
return RTunits::CUnit( caption() , _defUnitName ).conv (val);
}
double to_def (double val, const RTunits::unit_name& un ) ///< Convert a value in Unit un into Default Unit
{
return RTunits::CUnit(un , _defUnitName ).conv (val);
}
double from_def (double val) ///< Convert a value in Default Unit into user selected Unit
{
return RTunits::CUnit( _defUnitName, caption() ).conv (val);
}
double from_def (double val, const RTunits::unit_name& un ) ///< Convert a value in Default Unit into Unit un
{
return RTunits::CUnit( _defUnitName, caption() ).conv (val);
}
double convert_to(double val, const RTunits::unit_name& un) ///< Convert a value in user selected Unit into Unit un
{
return RTunits::CUnit( caption() , un ).conv (val);
}
double convert_from(double val, const RTunits::unit_name& un) ///< Convert a value in Unit un into the user selected Unit
{
return RTunits::CUnit(un , caption() ).conv (val);
}
};
class NumUnitUpDown : public CompoWidget
{
//double _val;
RTunits::unit_name _curr_un;
public:
NumberUpDown _num; /// \todo: make private and provide a function to change the def lay, especially the length of the label
UnitPicker _unit; /// \todo: make private and provide a function to change the def lay, especially the length of the label
NumUnitUpDown ( window wd,
const std::string& label,
double defVal, double min, double max,
const RTunits::unit_name& def_unit ,
const std::string& DefLayFile =("NumUnitUpDonw.Lay.txt"),
double step=1, unsigned width=6, unsigned decimals=2)
: CompoWidget (wd,label,("NumUnitUpDonw.Lay.txt")),
_num(*this,label, defVal, min,max,("Vert-Invert.NumUpDonw.Lay.txt"),step,width,decimals),
_unit(*this, def_unit), _curr_un(def_unit) //_val(defVal)
{
_unit.events().selected([&](const nana::arg_combox& arg_cb)
{
RTunits::CUnit u(_curr_un , /*charset*/( _unit.caption() )); /*CUnit::unit_name ( nana::charset(cb.option ()) ) */
if(u.error )
{ _unit.caption (_unit.caption ()+("?"));
return;
}
_num.Max ( u.conv(_num.Max () ) );
_num.Min ( u.conv(_num.Min () ) );
_num.Value ( u.conv(_num.Value() ) );
if (u.conv.linear )
_num.Step( u.conv.c*_num.Step() );
_curr_un=/*charset*/(_unit.caption ());
});
InitMyLayout();
SelectClickableWidget( _num);
SelectClickableWidget( _unit);
//_num.add_validated ( [&](){Validated ();} );
}
virtual void add_validated(const std::function<bool(void)>& v) override
{
_num.add_validated (v);
//_validated.push_back (v);
}
virtual void add_validate(const std::function<bool(void)>& v) override
{
_num.add_validate (v);
//_validated.push_back (v);
}
void SetDefLayout () override
{
SetDefLayout (60);
}
void SetDefLayout (unsigned lab, unsigned n=50, unsigned unit=50)
{
std::stringstream lay;
// redefine layout of this complete widget: NumUnitUpDown
lay << " < \n"
" <vertical min=" << lab+15+n << " Num > \n"
" <vertical min=" << unit << " <>< height=21 vertical Unit ><> > \n"
" > ";
_DefLayout = lay.str(); // move a copy
// redefine layout of the NumUpDown part (inside the previous Num)
lay.str("");
lay << " <horizontal \n"
" <width=" << lab << " vertical <><height=15 gap=1 label ><> > \n"
" <width=" << 15 << " vertical <><height=21 vertical UpDown ><> > \n"
" <min=" << n << " vertical <><height=21 Num ><> > \n"
" > ";
_num._DefLayout = lay.str(); // move a copy
}
void ResetLayout (unsigned lab, unsigned n=50, unsigned unit=50)
{
SetDefLayout (lab, n, unit);
ResetDefLayout(); _num. ResetDefLayout();
ReCollocate( ); _num.ReCollocate( );
}
void AsignWidgetToFields() override
{
_place.field("Num" ) << _num ;
_place.field("Unit" ) << _unit ;
}
/// expressed in default Units
double Value()
{
return _unit.to_def(_num.Value());
}
/// expressed in the specified "un" Units
double Value(const RTunits::unit_name& un)
{
return _unit.convert_to(_num.Value(),un);
}
/// expressed in default Units
void Value(double val_in_default_Units)
{
_num.Value(_unit.from_def(val_in_default_Units));
}
/// expressed in the specified "un" Units
void Value(double val, const RTunits::unit_name& un)
{
_num.Value(_unit.convert_from(val,un));
}
};
} // namespace nana
//cb.caption(_cb.caption().substr(6, _cb.caption().find_first_of((" ="),6)-6 ));
#endif