ARB
AW_preset.cxx
Go to the documentation of this file.
1 // ================================================================ //
2 // //
3 // File : AW_preset.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // ================================================================ //
10 
11 #ifndef IN_ARB_WINDOW
12 #error MODULE_... is not known
13 #endif
14 
15 #include <aw_color_groups.hxx>
16 #include "aw_preset.hxx"
17 #include "aw_root.hxx"
18 #include "aw_awar.hxx"
19 #include "aw_device.hxx"
20 #include "aw_advice.hxx"
21 #include "aw_question.hxx"
22 #include "aw_msg.hxx"
23 
24 #include "aw_def.hxx"
25 #include "aw_nawar.hxx"
26 #include "aw_xfont.hxx"
27 #include "aw_rgb.hxx"
28 
29 #include <arbdbt.h>
30 #include <arb_strbuf.h>
31 
32 #include <vector>
33 #include <map>
34 #include <string>
35 
36 #if defined(DEBUG)
37 #include <ctime>
38 #endif
39 
40 
41 using std::string;
42 
43 #define AWAR_RANGE_OVERLAY "tmp/GCS/range/overlay" // global toggle (used for all gc-managers!)
44 #define AWAR_COLOR_GROUPS_PREFIX "colorGroups" // [Note: before arb-7.0 the prefix was "color_groups"]
45 #define AWAR_COLOR_GROUPS_USE AWAR_COLOR_GROUPS_PREFIX "/use" // int : whether to use the colors in display or not
46 
47 #define ATPL_GCMAN_LOCAL "GCS/%s" // awar prefix for awars local to gc-manager
48 #define ATPL_GC_LOCAL ATPL_GCMAN_LOCAL "/MANAGE_GCS/%s" // awar prefix for awars local to a single gc
49 
50 #define ALL_FONTS_ID "all_fonts"
51 
52 #define NO_FONT -1
53 #define NO_SIZE -2
54 
55 // prototypes for motif-only section at bottom of this file:
56 static void popup_color_chooser_window(AW_window *aww, const char *awar_name, const char *color_description);
57 static void popup_font_chooser_window(AW_window *aww, const char *gc_base_name, const struct gc_desc *gcd);
58 
59 CONSTEXPR_INLINE bool valid_color_group(int color_group) {
60  return color_group>0 && color_group<=AW_COLOR_GROUPS;
61 }
62 
63 inline const char* gcman_specific_awarname(const char *tpl, const char *gcman_id, const char *localpart) {
64  aw_assert(!GB_check_key(gcman_id)); // has to be a key
65  aw_assert(!GB_check_hkey(localpart)); // has to be a key or hierarchical key
66 
67  static SmartCharPtr awar_name;
68  awar_name = GBS_global_string_copy(tpl, gcman_id, localpart);
69  return &*awar_name;
70 }
71 inline const char* gc_awarname(const char *tpl, const char *gcman_id, const string& colname) {
72  return gcman_specific_awarname(tpl, gcman_id, colname.c_str());
73 }
74 inline const char* gcman_awarname(const char* gcman_id, const char *localpart) {
75  return gcman_specific_awarname(ATPL_GCMAN_LOCAL "/%s", gcman_id, localpart);
76 }
77 
78 inline const char* color_awarname (const char* gcman_id, const string& colname) { return gc_awarname(ATPL_GC_LOCAL "/colorname", gcman_id, colname); }
79 inline const char* fontname_awarname(const char* gcman_id, const string& colname) { return gc_awarname(ATPL_GC_LOCAL "/font", gcman_id, colname); }
80 inline const char* fontsize_awarname(const char* gcman_id, const string& colname) { return gc_awarname(ATPL_GC_LOCAL "/size", gcman_id, colname); }
81 inline const char* fontinfo_awarname(const char* gcman_id, const string& colname) { return gc_awarname(ATPL_GC_LOCAL "/info", gcman_id, colname); }
82 
83 // ----------------------
84 // color groups
85 
86 struct ColorGroupDef {
87  const char *description;
88  const char *rgb_nt;
89  const char *rgb_e4;
90 
91  const char *defaultColorgroupName(int color_group) {
92  const char *result = NULp;
93  if (valid_color_group(color_group)) {
94  if (color_group<10) {
95  result = GBS_global_string(AW_COLOR_GROUP_PREFIX "_%i_%s", color_group, description);
96  }
97  else {
98  result = GBS_global_string(AW_COLOR_GROUP_PREFIX "%2i_%s", color_group, description);
99  }
100  }
101  return result;
102  }
103 
104  const char *rgbValue(bool for_edit4) {
105  return for_edit4 ? rgb_e4 : rgb_nt;
106  }
107 };
108 
110  // name NTREE EDIT4
111  // rrggbb rrggbb
112  { "red", "D50000", "FFDCDC" }, // 01
113  { "cyan", "00ffff", "CFFFFF" }, // 02
114  { "green", "00FF77", "B1FFD6" }, // 03
115  { "purple", "c700c7", "F1BFF1" }, // 04
116  { "blue", "0000ff", "D7D7FF" }, // 05
117  { "orange", "FFCE5B", "FFEAB9" }, // 06
118  { "dark_red", "AB2323", "DCB8B8" }, // 07
119  { "petrol", "008888", "8BBBBB" }, // 08
120  { "dark_green", "008800", "97CB97" }, // 09
121  { "dark_purple", "880088", "B177B1" }, // 10
122  { "dark_blue", "000088", "9898E2" }, // 11
123  { "olive", "888800", "C8D98F" }, // 12
124 };
125 
126 inline const char *colorgroupname_awarname(int color_group) {
127  if (!valid_color_group(color_group)) return NULp;
128  return GBS_global_string(AWAR_COLOR_GROUPS_PREFIX "/name%i", color_group);
129 }
130 inline const char* default_colorgroup_name(int color_group) {
131  return color_group_def[color_group-1].defaultColorgroupName(color_group);
132 }
133 
134 
135 const int GC_BACKGROUND = -1;
136 const int GC_INVALID = -2;
137 
138 const int NO_INDEX = -1;
139 
140 enum gc_type {
144 };
145 
146 #define RANGE_INDEX_BITS 4
147 #define RANGE_INDEX_MASK ((1<<RANGE_INDEX_BITS)-1)
148 
149 inline int build_range_gc_number(int range_idx, int color_idx) {
150  aw_assert(range_idx == (range_idx & RANGE_INDEX_MASK));
151  return (color_idx << RANGE_INDEX_BITS) | range_idx;
152 }
153 
154 inline string name2ID(const char *name) { // does not test uniqueness!
155  char *keyCopy = GBS_string_2_key(name);
156  string id = keyCopy;
157  free(keyCopy);
158  return id;
159 }
160 inline string name2ID(const string& name) { return name2ID(name.c_str()); }
161 
162 struct gc_desc {
163  // data for one GC
164  // - used to populate color config windows and
165  // - in change-callbacks
166 
167  int gc; // -1 = background;
168  // if type!=GC_TYPE_RANGE: [0..n-1] (where n=AW_gc_manager::drag_gc_offset if no gc_ranges defined)
169  // if type==GC_TYPE_RANGE: contains range- and color-index
170  string colorlabel; // label to appear next to chooser
171  string key; // key (normally build from colorlabel)
172  bool has_font; // show font selector
173  bool fixed_width_font; // only allow fixed width fonts
174  bool same_line; // no line break after this
176 
177  gc_desc(int gc_, gc_type type_) :
178  gc(gc_),
179  has_font(true),
180  fixed_width_font(false),
181  same_line(false),
182  type(type_)
183  {}
184 
185  bool is_color_group() const { return type == GC_TYPE_GROUP; }
186  bool belongs_to_range() const { return type == GC_TYPE_RANGE; }
187 
189  int get_color_index() const { aw_assert(belongs_to_range()); return gc >> RANGE_INDEX_BITS; }
190 
191 private:
192  bool parse_char(char c) {
193  switch (c) {
194  case '#': fixed_width_font = true; break;
195  case '+': same_line = true; break;
196  case '-': has_font = false; break;
197  default : return false;
198  }
199  return true;
200  }
201 
202  void correct() {
203  if (same_line && has_font) same_line = false; // GC needs full line if defining both color and font
204  }
205 public:
206 
207  const char *parse_decl(const char *decl, const char *id_prefix) {
208  // returns default color
209  int offset = 0;
210  while (decl[offset]) {
211  if (!parse_char(decl[offset])) break;
212  offset++;
213  }
214  correct();
215 
216  decl += offset;
217 
218  const char *split = strchr(decl, '$');
219  const char *default_color = NULp;
220  if (split) { // defines a default color
221  colorlabel = string(decl, split-decl);
222  default_color = split+1;
223  }
224  else {
225  colorlabel = decl;
226  default_color = "black";
227  }
228 
229  key = string(null2empty(id_prefix)) + name2ID(colorlabel);
230 
231  return default_color;
232  }
233 };
234 
235 // --------------------------------
236 // types for color-ranges
237 
244 };
245 
246 class gc_range {
247  string name; // name of range shown in config window
248  string id;
249  gc_range_type type;
250 
251  int index; // in range-array of AW_gc_manager
252  int color_count; // number of support colors (ie. customizable colors)
253  int gc_index; // of first support color in GCs-array of AW_gc_manager
254 
255 public:
256  gc_range(const string& name_, gc_range_type type_, int index_, int gc_index_) :
257  name(name_),
258  id(name2ID(name)),
259  type(type_),
260  index(index_),
261  color_count(0),
262  gc_index(gc_index_)
263  {}
264 
265  void add_color(const string& colordef, AW_gc_manager *gcman);
266  void update_colors(const AW_gc_manager *gcman) const;
267 
268  AW_rgb_normalized get_color(int idx, const AW_gc_manager *gcman) const;
269 
270  const string& get_name() const { return name; }
271  const string& get_id() const { return id; }
272  gc_range_type get_type() const { return type; }
273  int get_dimension() const {
274  switch (type) {
275  case GC_RANGE_LINEAR:
276  case GC_RANGE_CYCLIC: return 1;
277 
278  case GC_RANGE_PLANAR: return 2;
279  case GC_RANGE_SPATIAL: return 3;
280  case GC_RANGE_INVALID: aw_assert(0); break;
281  }
282  return 0;
283  }
284 };
285 
286 // --------------------
287 // GC manager
288 
289 class AW_gc_manager : virtual Noncopyable {
290  const char *gc_base_name;
291  AW_device *device;
292  int drag_gc_offset; // = drag_gc (as used by clients)
293 
294  int first_colorgroup_idx; // index into 'GCs' or NO_INDEX (if no color groups defined)
295 
296  AW_window *aww; // motif only (colors get allocated in window)
297  int colorindex_base; // motif-only (colorindex of background-color)
298 
299  typedef std::vector<gc_desc> gc_container;
300  typedef std::vector<gc_range> gc_range_container;
301 
302  gc_container GCs;
303  gc_range_container color_ranges;
304  unsigned active_range_number; // offset into 'color_ranges'
305 
306  GcChangedCallback changed_cb;
307 
308  mutable bool suppress_changed_cb; // if true -> collect cb-trigger in 'did_suppress_change'
309  mutable GcChange did_suppress_change; // "max" change suppressed so far (will be triggered by delay_changed_callbacks())
310  static const GcChange GC_NOTHING_CHANGED = GcChange(0);
311 
312 #if defined(ASSERTION_USED)
313  bool valid_idx(int idx) const { return idx>=0 && idx<int(GCs.size()); }
314  bool valid_gc(int gc) const {
315  // does not test gc is really valid, just tests whether it is completely out-of-bounds
316  return gc>=GC_BACKGROUND && gc < drag_gc_offset;
317  }
318 #endif
319 
320  AW_color_idx colorindex(int gc) const {
321  aw_assert(valid_gc(gc));
322  return AW_color_idx(colorindex_base+gc+1);
323  }
324  static void ignore_change_cb(GcChange) {}
325 
326  void allocate_gc(int gc) const;
327 
328  void update_gc_color_internal(int gc, const char *color) const;
329  void update_range_colors(const gc_desc& gcd) const;
330  void update_range_font(int fname, int fsize) const;
331 
332 public:
333  static const char **color_group_defaults;
334 
335  static bool use_color_groups;
336  static bool show_range_overlay;
337 
339 
340  AW_gc_manager(const char* name, AW_device* device_, int drag_gc_offset_,
341  AW_window *aww_, int colorindex_base_)
342  : gc_base_name(name),
343  device(device_),
344  drag_gc_offset(drag_gc_offset_),
345  first_colorgroup_idx(NO_INDEX),
346  aww(aww_),
347  colorindex_base(colorindex_base_),
348  active_range_number(-1), // => will be initialized from init_color_ranges
349  changed_cb(makeGcChangedCallback(ignore_change_cb)),
350  suppress_changed_cb(false),
351  did_suppress_change(GC_NOTHING_CHANGED)
352  {}
353 
354  void init_all_fonts() const;
355  void update_all_fonts(bool sizeChanged) const;
356 
357  void init_color_ranges(int& gc);
358  bool has_color_range() const { return !color_ranges.empty(); }
359  int first_range_gc() const { return drag_gc_offset - AW_RANGE_COLORS; }
360 
361  bool has_color_groups() const { return first_colorgroup_idx != NO_INDEX; }
362  bool has_variable_width_font() const;
363 
364  int size() const { return GCs.size(); }
365  const gc_desc& get_gc_desc(int idx) const {
366  aw_assert(valid_idx(idx));
367  return GCs[idx];
368  }
369  const char *get_base_name() const { return gc_base_name; }
370  int get_drag_gc() const { return drag_gc_offset; }
371 
372  void add_gc (const char *gc_description, int& gc, gc_type type, const char *id_prefix = NULp);
373  void add_gc_range(const char *gc_description);
374  void reserve_gcs (const char *gc_description, int& gc);
375  void add_color_groups(int& gc);
376 
377  void update_gc_color(int idx) const;
378  void update_gc_font(int idx) const;
379 
380  void update_range_gc_color(int idx, const char *color) const {
381  update_gc_color_internal(first_range_gc()+idx, color);
382  }
383 
384  void create_gc_buttons(AW_window *aww, gc_type for_gc_type);
385 
386  void set_changed_cb(const GcChangedCallback& ccb) { changed_cb = ccb; }
387  void trigger_changed_cb(GcChange whatChanged) const {
388  if (suppress_changed_cb) {
389  did_suppress_change = GcChange(std::max(whatChanged, did_suppress_change));
390  }
391  else {
392 #if defined(DEBUG) && 0
393  fprintf(stderr, "[changed_cb] @ %zu\n", clock());
394 #endif
395  changed_cb(whatChanged);
396  }
397  }
398 
399  void delay_changed_callbacks(bool suppress) const {
400  aw_assert(suppress != suppress_changed_cb);
401 
402  suppress_changed_cb = suppress;
403  if (suppress) {
404  did_suppress_change = GC_NOTHING_CHANGED;
405  }
406  else if (did_suppress_change>GC_NOTHING_CHANGED) {
407  trigger_changed_cb(did_suppress_change);
408  }
409  }
410 
411  const char *get_current_color(int idx) const {
413  }
414 
415  void getColorRangeNames(int dimension, ConstStrArray& ids, ConstStrArray& names) const;
416  void activateColorRange(const char *id);
417  const char *getActiveColorRangeID(int *dimension) const;
418 
419  const char *awarname_active_range() const { return gcman_awarname(get_base_name(), "range/active"); }
420  void active_range_changed_cb(AW_root *awr);
421 };
422 
424 
427 
428 // ---------------------------
429 // GC awar callbacks
430 
431 void AW_gc_manager::update_gc_font(int idx) const {
432  aw_assert(valid_idx(idx));
433 
434  static bool avoid_recursion = false;
435  if (avoid_recursion) return;
436  LocallyModify<bool> flag(avoid_recursion, true);
437 
438  const gc_desc& gcd0 = GCs[idx];
439  aw_assert(gcd0.gc != GC_BACKGROUND); // background has no font
440 
441  AW_awar *awar_fontname = AW_root::SINGLETON->awar(fontname_awarname(gc_base_name, gcd0.key));
442  AW_awar *awar_fontsize = AW_root::SINGLETON->awar(fontsize_awarname(gc_base_name, gcd0.key));
443  AW_awar *awar_fontinfo = AW_root::SINGLETON->awar(fontinfo_awarname(gc_base_name, gcd0.key));
444 
445  int fname = awar_fontname->read_int();
446  int fsize = awar_fontsize->read_int();
447 
448  if (fname == NO_FONT) return;
449 
450  int found_font_size;
451  device->set_font(gcd0.gc, fname, fsize, &found_font_size);
452  device->set_font(gcd0.gc+drag_gc_offset, fname, fsize, NULp);
453 
454  bool autocorrect_fontsize = (found_font_size != fsize) && (found_font_size != -1);
455  if (autocorrect_fontsize) {
456  awar_fontsize->write_int(found_font_size);
457  fsize = found_font_size;
458  }
459 
460  // set font of all following GCs which do NOT define a font themselves
461  for (int i = idx+1; i<int(GCs.size()); ++i) {
462  const gc_desc& gcd = GCs[i];
463  if (gcd.has_font) break; // abort if GC defines its own font
464  if (gcd.belongs_to_range()) {
465  update_range_font(fname, fsize);
466  break; // all leftover GCs belong to ranges = > stop here
467  }
468 
469  device->set_font(gcd.gc, fname, fsize, NULp);
470  device->set_font(gcd.gc+drag_gc_offset, fname, fsize, NULp);
471  }
472 
473  awar_fontinfo->write_string(GBS_global_string("%s | %i", AW_get_font_shortname(fname), fsize));
474 
476 }
477 static void gc_fontOrSize_changed_cb(AW_root*, AW_gc_manager *mgr, int idx) {
478  mgr->update_gc_font(idx);
479 }
480 inline bool font_has_fixed_width(AW_font aw_font_nr) {
481  return AW_font_2_xfig(aw_font_nr) < 0;
482 }
483 void AW_gc_manager::update_all_fonts(bool sizeChanged) const {
485 
486  int fname = awr->awar(fontname_awarname(gc_base_name, ALL_FONTS_ID))->read_int();
487  int fsize = awr->awar(fontsize_awarname(gc_base_name, ALL_FONTS_ID))->read_int();
488 
489  if (fname == NO_FONT) return;
490 
491  delay_changed_callbacks(true); // temp. disable callbacks
492  for (gc_container::const_iterator g = GCs.begin(); g != GCs.end(); ++g) {
493  if (g->has_font) {
494  if (sizeChanged) {
495  awr->awar(fontsize_awarname(gc_base_name, g->key))->write_int(fsize);
496  }
497  else {
498  bool update = !g->fixed_width_font || font_has_fixed_width(fname);
499  if (update) awr->awar(fontname_awarname(gc_base_name, g->key))->write_int(fname);
500  }
501  }
502  }
504 }
505 static void all_fontsOrSizes_changed_cb(AW_root*, const AW_gc_manager *mgr, bool sizeChanged) {
506  mgr->update_all_fonts(sizeChanged);
507 }
508 
509 void AW_gc_manager::update_gc_color_internal(int gc, const char *color) const {
510  AW_color_idx colorIdx = colorindex(gc);
511  aww->alloc_named_data_color(colorIdx, color);
512 
513  if (gc == GC_BACKGROUND && colorIdx == AW_DATA_BG) {
514  // if background color changes, all drag-gc colors need to be updated
515  // (did not understand why, just refactored existing code --ralf)
516 
517  for (int i = 1; i<size(); ++i) {
518  const gc_desc& gcd = GCs[i];
519  if (gcd.belongs_to_range()) break; // do not update range-GCs here
520 
521  int g = gcd.gc;
522  colorIdx = colorindex(g);
523  device->set_foreground_color(g + drag_gc_offset, colorIdx);
524  }
525  if (has_color_range()) { // update drag GCs of all range GCs
526  for (int i = 0; i<AW_RANGE_COLORS; ++i) {
527  int g = first_range_gc()+i;
528  colorIdx = colorindex(g);
529  device->set_foreground_color(g + drag_gc_offset, colorIdx);
530  }
531  }
532  }
533  else {
534  if (gc == GC_BACKGROUND) gc = 0; // special case: background color of bottom-area (only used by arb_phylo)
535 
536  device->set_foreground_color(gc, colorIdx);
537  device->set_foreground_color(gc + drag_gc_offset, colorIdx);
538  }
539 }
540 
542  aw_assert(idx>=0 && idx<color_count);
543  return AW_rgb_normalized(gcman->get_current_color(gc_index+idx));
544 }
545 
546 STATIC_ASSERT(AW_PLANAR_COLORS*AW_PLANAR_COLORS == AW_RANGE_COLORS); // Note: very strong assertion (could also use less than AW_RANGE_COLORS)
548 
549 void gc_range::update_colors(const AW_gc_manager *gcman) const {
554  // @@@ try HSV color blending as alternative
555 
556  if (type == GC_RANGE_LINEAR) {
557  aw_assert(color_count == 2); // currently exactly 2 support-colors are required for linear ranges
558 
559  AW_rgb_normalized low = get_color(0, gcman);
560  AW_rgb_normalized high = get_color(1, gcman);
561 
562  AW_rgb_diff low2high = high-low;
563  for (int i = 0; i<AW_RANGE_COLORS; ++i) { // blend colors
564  float factor = i/float(AW_RANGE_COLORS-1);
565  gcman->update_range_gc_color(i, AW_rgb16(low + factor*low2high).ascii());
566  }
567  }
568  else if (type == GC_RANGE_CYCLIC) {
569  aw_assert(color_count >= 3); // less than 3 colors does not make sense for cyclic ranges!
570 
571  AW_rgb_normalized low = get_color(0, gcman);
572  int i1 = 0;
573  for (int part = 0; part<color_count; ++part) {
574  AW_rgb_normalized high = get_color((part+1)%color_count, gcman);
575  AW_rgb_diff low2high = high-low;
576 
577  int i2 = AW_RANGE_COLORS * (float(part+1)/color_count);
578  aw_assert(implicated((part+1) == color_count, i2 == AW_RANGE_COLORS));
579 
580  for (int i = i1; i<i2; ++i) { // blend colors
581  int o = i-i1;
582  float factor = o/float(i2-i1-1);
583  gcman->update_range_gc_color(i, AW_rgb16(low + factor*low2high).ascii());
584  }
585 
586  low = high;
587  i1 = i2;
588  }
589  }
590  else if (type == GC_RANGE_PLANAR) {
591  aw_assert(color_count == 3); // currently exactly 3 support-colors are required for planar ranges
592 
593  AW_rgb_normalized low = get_color(0, gcman);
594  AW_rgb_normalized dim1 = get_color(1, gcman);
595  AW_rgb_normalized dim2 = get_color(2, gcman);
596 
597  AW_rgb_diff low2dim1 = dim1-low;
598  AW_rgb_diff low2dim2 = dim2-low;
599 
600  for (int i1 = 0; i1<AW_PLANAR_COLORS; ++i1) {
601  float fact1 = i1/float(AW_PLANAR_COLORS-1);
602  AW_rgb_diff diff1 = fact1*low2dim1;
603 
604  for (int i2 = 0; i2<AW_PLANAR_COLORS; ++i2) {
605  float fact2 = i2/float(AW_PLANAR_COLORS-1);
606  AW_rgb_diff diff2 = fact2*low2dim2;
607 
608  AW_rgb_normalized mixcol = low + (diff1+diff2);
609 
610  gcman->update_range_gc_color(i1*AW_PLANAR_COLORS+i2, AW_rgb16(mixcol).ascii());
611  }
612  }
613  }
614  else if (type == GC_RANGE_SPATIAL) {
615  aw_assert(color_count == 4); // currently exactly 4 support-colors are required for planar ranges
616 
617  AW_rgb_normalized low = get_color(0, gcman);
618  AW_rgb_normalized dim1 = get_color(1, gcman);
619  AW_rgb_normalized dim2 = get_color(2, gcman);
620  AW_rgb_normalized dim3 = get_color(3, gcman);
621 
622  AW_rgb_diff low2dim1 = dim1-low;
623  AW_rgb_diff low2dim2 = dim2-low;
624  AW_rgb_diff low2dim3 = dim3-low;
625 
626  for (int i1 = 0; i1<AW_SPATIAL_COLORS; ++i1) {
627  float fact1 = i1/float(AW_SPATIAL_COLORS-1);
628  AW_rgb_diff diff1 = fact1*low2dim1;
629 
630  for (int i2 = 0; i2<AW_SPATIAL_COLORS; ++i2) {
631  float fact2 = i2/float(AW_SPATIAL_COLORS-1);
632  AW_rgb_diff diff2 = fact2*low2dim2;
633 
634  for (int i3 = 0; i3<AW_SPATIAL_COLORS; ++i3) {
635  float fact3 = i3/float(AW_SPATIAL_COLORS-1);
636  AW_rgb_diff diff3 = fact3*low2dim3;
637 
638  AW_rgb_normalized mixcol = low + (diff1+diff2+diff3);
639  gcman->update_range_gc_color((i1*AW_SPATIAL_COLORS+i2)*AW_SPATIAL_COLORS+i3, AW_rgb16(mixcol).ascii());
640  }
641  }
642  }
643  }
644  else {
645  aw_assert(0); // unsupported range-type
646  }
647 }
648 void AW_gc_manager::update_range_colors(const gc_desc& gcd) const {
649  int defined_ranges = color_ranges.size();
650  int range_idx = gcd.get_range_index();
651 
652  if (range_idx<defined_ranges) {
653  const gc_range& gcr = color_ranges[range_idx];
654  gcr.update_colors(this);
655  }
656 }
657 void AW_gc_manager::update_range_font(int fname, int fsize) const {
658  // set font for all GCs belonging to color-range
659  int first_gc = first_range_gc();
660  for (int i = 0; i<AW_RANGE_COLORS; ++i) {
661  int gc = first_gc+i;
662  device->set_font(gc, fname, fsize, NULp);
663  device->set_font(gc+drag_gc_offset, fname, fsize, NULp);
664  }
665 }
666 
667 void AW_gc_manager::update_gc_color(int idx) const {
668  aw_assert(valid_idx(idx));
669 
670  const gc_desc& gcd = GCs[idx];
671  const char *color = AW_root::SINGLETON->awar(color_awarname(gc_base_name, gcd.key))->read_char_pntr();
672 
673  if (gcd.belongs_to_range()) {
674  update_range_colors(gcd); // @@@ should not happen during startup and only if affected range is the active range
675  }
676  else {
677  update_gc_color_internal(gcd.gc, color);
678  }
679 
681 }
682 static void gc_color_changed_cb(AW_root*, AW_gc_manager *mgr, int idx) {
683  mgr->update_gc_color(idx);
684 }
685 
687  static bool warned = false;
688  if (!warned) {
689  AW_advice("Color group names are used at various places of the interface.\n"
690  "To activate the changed names everywhere, you have to\n"
691  "save properties and restart the program.",
692  AW_ADVICE_TOGGLE, "Color group name has been changed", NULp);
693  warned = true;
694  }
695 
696  for (int i = 1; i <= AW_COLOR_GROUPS; ++i) {
697  const char *awarname = colorgroupname_awarname(i);
698  AW_awar *awar_colorgroupname = awr->awar(awarname);
699  char *content = awar_colorgroupname->read_string();
700  size_t len = strlen(content);
701  if (len>AW_COLOR_GROUP_NAME_LEN) {
702  content[AW_COLOR_GROUP_NAME_LEN] = 0;
703  awar_colorgroupname->write_string(content);
704  aw_message("the colorgroup name was too long and has been truncated.");
705  }
706  free(content);
707  }
708 }
709 
711  AW_gc_manager::use_color_groups = awr->awar(AWAR_COLOR_GROUPS_USE)->read_int();
713 }
714 static void range_overlay_changed_cb(AW_root *awr, AW_gc_manager *gcmgr) {
715  AW_gc_manager::show_range_overlay = awr->awar(AWAR_RANGE_OVERLAY)->read_int();
717 }
718 
719 // ----------------------------
720 // define color-ranges
721 
722 void gc_range::add_color(const string& colordef, AW_gc_manager *gcman) {
723  int gc = build_range_gc_number(index, color_count);
724  gcman->add_gc(colordef.c_str(), gc, GC_TYPE_RANGE, get_id().c_str());
725  color_count++;
726 }
727 
728 void AW_gc_manager::add_gc_range(const char *gc_description) {
729  GB_ERROR error = NULp;
730  const char *comma = strchr(gc_description+1, ',');
731  if (!comma) error = "',' expected";
732  else {
733  string range_name(gc_description+1, comma-gc_description-1);
734  const char *colon = strchr(comma+1, ':');
735  if (!colon) error = "':' expected";
736  else {
738  string range_type(comma+1, colon-comma-1);
739 
740  if (range_type == "linear") rtype = GC_RANGE_LINEAR;
741  else if (range_type == "planar") rtype = GC_RANGE_PLANAR;
742  else if (range_type == "spatial") rtype = GC_RANGE_SPATIAL;
743  else if (range_type == "cyclic") rtype = GC_RANGE_CYCLIC;
744 
745  if (rtype == GC_RANGE_INVALID) {
746  error = GBS_global_string("invalid range-type '%s'", range_type.c_str());
747  }
748 
749  if (!error) {
750  gc_range range(range_name, rtype, color_ranges.size(), GCs.size());
751 
752  const char *color_start = colon+1;
753  comma = strchr(color_start, ',');
754  while (comma) {
755  range.add_color(string(color_start, comma-color_start), this);
756  color_start = comma+1;
757  comma = strchr(color_start, ',');
758  }
759  range.add_color(string(color_start), this);
760 
761  color_ranges.push_back(range); // add to manager
762  }
763  }
764  }
765 
766  if (error) {
767  GBK_terminatef("Failed to parse color range specification '%s'\n(Reason: %s)", gc_description, error);
768  }
769 }
770 
772  // read AWAR (awarname_active_range), compare with 'active_range_number', if differs = > update colors
773  // (triggered by AWAR)
774 
775  unsigned wanted_range_number = awr->awar(awarname_active_range())->read_int();
776  if (wanted_range_number != active_range_number) {
777  aw_assert(wanted_range_number<color_ranges.size());
778 
779  active_range_number = wanted_range_number;
780  const gc_range& active_range = color_ranges[active_range_number];
781  active_range.update_colors(this);
782  }
783 }
784 static void active_range_changed_cb(AW_root *awr, AW_gc_manager *gcman) { gcman->active_range_changed_cb(awr); }
785 
787  if (has_color_range()) {
788  aw_assert(gc == first_range_gc()); // 'drag_gc_offset' is wrong (is passed as 'base_drag' to AW_manage_GC)
789  int last_gc = gc + AW_RANGE_COLORS-1;
790  while (gc<=last_gc) allocate_gc(gc++);
791 
792  active_range_changed_cb(AW_root::SINGLETON); // either initializes default-range (=0) or the range-in-use when saving props
793  }
794 }
795 void AW_gc_manager::activateColorRange(const char *id) {
796  unsigned wanted_range_number = 0;
797  for (gc_range_container::const_iterator r = color_ranges.begin(); r != color_ranges.end(); ++r) {
798  const gc_range& range = *r;
799  if (range.get_id() == id) {
800  aw_assert(wanted_range_number<color_ranges.size());
801  AW_root::SINGLETON->awar(awarname_active_range())->write_int(wanted_range_number); // => will update color range of all identical gc-managers
802  break;
803  }
804  ++wanted_range_number;
805  }
806 }
807 const char *AW_gc_manager::getActiveColorRangeID(int *dimension) const {
808  const gc_range& range = color_ranges[active_range_number];
809  if (dimension) *dimension = range.get_dimension();
810  return range.get_id().c_str();
811 }
812 
813 
815  for (gc_range_container::const_iterator r = color_ranges.begin(); r != color_ranges.end(); ++r) {
816  const gc_range& range = *r;
817  if (range.get_dimension() == dimension) {
818  ids.put(range.get_id().c_str());
819  names.put(range.get_name().c_str());
820  }
821  }
822 }
823 
824 // -------------------------
825 // reserve/add GCs
826 
827 void AW_gc_manager::reserve_gcs(const char *gc_description, int& gc) {
828  aw_assert(gc_description[0] == '!');
829 
830  // just reserve one or several GCs (eg. done in arb_pars)
831  int amount = atoi(gc_description+1);
832  aw_assert(amount>=1);
833 
834  gc += amount;
835 }
836 
837 void AW_gc_manager::allocate_gc(int gc) const {
838  device->new_gc(gc);
839  device->set_line_attributes(gc, 1, AW_SOLID);
840  device->set_function(gc, AW_COPY);
841 
842  int gc_drag = gc + drag_gc_offset;
843  device->new_gc(gc_drag);
844  device->set_line_attributes(gc_drag, 1, AW_SOLID);
845  device->set_function(gc_drag, AW_XOR);
846  device->establish_default(gc_drag);
847 }
848 
849 void AW_gc_manager::add_gc(const char *gc_description, int& gc, gc_type type, const char *id_prefix) {
850  aw_assert(!strchr("*!&", gc_description[0]));
851  aw_assert(implicated(type != GC_TYPE_RANGE, !has_color_range())); // color ranges have to be specified AFTER all other color definition strings (in call to AW_manage_GC)
852 
853  GCs.push_back(gc_desc(gc, type));
854  gc_desc &gcd = GCs.back();
855  int idx = int(GCs.size()-1); // index position where new GC has been added
856 
857  if (gcd.is_color_group() && first_colorgroup_idx == NO_INDEX) {
858  first_colorgroup_idx = idx; // remember index of first color-group
859  }
860 
861  bool is_background = gc == GC_BACKGROUND;
862  bool alloc_gc = (!is_background || colorindex_base != AW_DATA_BG) && !gcd.belongs_to_range();
863  if (alloc_gc) {
864  allocate_gc(gc + is_background); // increment only happens for AW_BOTTOM_AREA defining GCs
865  }
866 
867  const char *default_color = gcd.parse_decl(gc_description, id_prefix);
868 
869  aw_assert(strcmp(gcd.key.c_str(), ALL_FONTS_ID) != 0); // id is reserved
870 #if defined(ASSERTION_USED)
871  {
872  const string& lastId = gcd.key;
873  for (int i = 0; i<idx; ++i) {
874  const gc_desc& check = GCs[i];
875  aw_assert(check.key != lastId); // duplicate GC-ID!
876  }
877  }
878 #endif
879 
880 #if !defined(ARB_OPENGL)
881  // normally the first GC should define a font (wrong for RNA3D)
882  aw_assert(implicated(gc == 0 && type != GC_TYPE_RANGE, gcd.has_font));
883 #endif
884 
885  if (default_color[0] == '{') {
886  // use current value of an already defined color as default for current color:
887  // (e.g. used in SECEDIT)
888  const char *close_brace = strchr(default_color+1, '}');
889  aw_assert(close_brace); // missing '}' in reference!
890  char *referenced_colorlabel = ARB_strpartdup(default_color+1, close_brace-1);
891 
892  IF_ASSERTION_USED(bool found = false);
893 
894  for (gc_container::iterator g = GCs.begin(); g != GCs.end(); ++g) {
895  if (strcmp(g->colorlabel.c_str(), referenced_colorlabel) == 0) {
896  default_color = AW_root::SINGLETON->awar(color_awarname(gc_base_name, g->key))->read_char_pntr(); // @@@ should use default value (not current value)
897  IF_ASSERTION_USED(found = true);
898  break;
899  }
900  }
901 
902  aw_assert(found); // unknown default color!
903  free(referenced_colorlabel);
904  }
905 
906  // @@@ add assertion vs duplicate ids here?
907  AW_root::SINGLETON->awar_string(color_awarname(gc_base_name, gcd.key), default_color)
908  ->add_callback(makeRootCallback(gc_color_changed_cb, this, idx));
909  gc_color_changed_cb(NULp, this, idx);
910 
911  if (!is_background) { // no font for background
912  if (gcd.has_font) {
913  aw_assert(!gcd.belongs_to_range()); // no fonts supported for ranges
914 
916 
917  RootCallback fontChange_cb = makeRootCallback(gc_fontOrSize_changed_cb, this, idx);
918  AW_root::SINGLETON->awar_int(fontname_awarname(gc_base_name, gcd.key), default_font)->add_callback(fontChange_cb);
919  AW_root::SINGLETON->awar_int(fontsize_awarname(gc_base_name, gcd.key), DEF_FONTSIZE)->add_callback(fontChange_cb);
920  AW_root::SINGLETON->awar_string(fontinfo_awarname(gc_base_name, gcd.key), "<select font>");
921  }
922  // Note: fonts are not initialized here. This is done in init_all_fonts() after all GCs have been defined.
923  }
924 
925  gc++;
926 }
928  int ad_font = -1;
929  int ad_size = -1;
931 
932  // initialize fonts of all defined GCs:
933  for (int idx = 0; idx<int(GCs.size()); ++idx) {
934  const gc_desc& gcd = GCs[idx];
935  if (gcd.has_font) {
936  update_gc_font(idx);
937 
938  if (ad_font == -1) {
939  ad_font = awr->awar(fontname_awarname(gc_base_name, gcd.key))->read_int();
940  ad_size = awr->awar(fontsize_awarname(gc_base_name, gcd.key))->read_int();
941  }
942  }
943  }
944 
945  // init global font awars (used to set ALL fonts)
946  AW_root::SINGLETON->awar_int(fontname_awarname(gc_base_name, ALL_FONTS_ID), ad_font)->add_callback(makeRootCallback(all_fontsOrSizes_changed_cb, this, false));
947  AW_root::SINGLETON->awar_int(fontsize_awarname(gc_base_name, ALL_FONTS_ID), ad_size)->add_callback(makeRootCallback(all_fontsOrSizes_changed_cb, this, true));
948 }
949 
951  for (gc_container::const_iterator g = GCs.begin(); g != GCs.end(); ++g) {
952  if (g->has_font && !g->fixed_width_font) return true;
953  }
954  return false;
955 }
956 
958  for (int i = 1; i <= AW_COLOR_GROUPS; ++i) {
960  }
961 }
962 
965  const char **color_group_gc_default = AW_gc_manager::color_group_defaults;
966  while (*color_group_gc_default) {
967  add_gc(*color_group_gc_default++, gc, GC_TYPE_GROUP);
968  }
969 }
970 
972  const char *gc_base_name,
973  AW_device *device,
974  int base_drag,
975  AW_GCM_AREA area,
976  const GcChangedCallback& changecb,
977  const char *default_background_color,
978  ...)
979 {
1017  aw_assert(default_background_color[0]);
1018 
1019 #if defined(ASSERTION_USED)
1020  int base_drag_given = base_drag;
1021 #endif
1022 
1023  AW_root *aw_root = AW_root::SINGLETON;
1024 
1025  int colidx_base = area == AW_GCM_DATA_AREA ? AW_DATA_BG : AW_WINDOW_BG;
1026  AW_gc_manager *gcmgr = new AW_gc_manager(gc_base_name, device, base_drag, aww, colidx_base);
1027 
1028  int gc = GC_BACKGROUND; // gets incremented by add_gc
1029  char background[50];
1030  sprintf(background, "-background$%s", default_background_color);
1031  gcmgr->add_gc(background, gc, GC_TYPE_NORMAL);
1032 
1033  va_list parg;
1034  va_start(parg, default_background_color);
1035 
1036  bool defined_color_groups = false;
1037 
1038  const char *id;
1039  while ( (id = va_arg(parg, char*)) ) {
1040  switch (id[0]) {
1041  case '!': gcmgr->reserve_gcs(id, gc); break;
1042  case '*': gcmgr->add_gc_range(id); break;
1043  case '&':
1044  if (strcmp(id, "&color_groups") == 0) { // trigger use of color groups
1045  aw_assert(!defined_color_groups); // color-groups trigger specified twice!
1046  if (!defined_color_groups) {
1047  gcmgr->add_color_groups(gc);
1048  defined_color_groups = true;
1049  }
1050  }
1051  else { aw_assert(0); } // unknown trigger
1052  break;
1053  default: gcmgr->add_gc(id, gc, GC_TYPE_NORMAL); break;
1054  }
1055  }
1056  va_end(parg);
1057 
1058  {
1059  AW_awar *awar_useGroups = aw_root->awar_int(AWAR_COLOR_GROUPS_USE, 1);
1060 
1061  awar_useGroups->add_callback(makeRootCallback(color_group_use_changed_cb, gcmgr));
1062  AW_gc_manager::use_color_groups = awar_useGroups->read_int();
1063  }
1064 
1065  aw_root->awar_int(AWAR_RANGE_OVERLAY, 0)->add_callback(makeRootCallback(range_overlay_changed_cb, gcmgr));
1066  aw_root->awar_int(gcmgr->awarname_active_range(), 0)->add_callback(makeRootCallback(active_range_changed_cb, gcmgr));
1067 
1068  gcmgr->init_color_ranges(gc);
1069  gcmgr->init_all_fonts();
1070 
1071  // installing changed callback here avoids that it gets triggered by initializing GCs
1072  gcmgr->set_changed_cb(changecb);
1073 
1074 #if defined(ASSERTION_USED)
1075  if (strcmp(gc_base_name, "ARB_PARSIMONY") == 0) {
1076  // ARB_PARSIMONY does not define color-ranges, but uses same GCs as ARB_NTREE
1077  // => accept weird 'base_drag_given'
1078  aw_assert(gc == (base_drag_given-AW_RANGE_COLORS));
1079  }
1080  else {
1081  aw_assert(gc == base_drag_given); // parameter 'base_drag' has wrong value
1082  // (has to be next value after last GC or after last color-group-GC)
1083  }
1084 #endif
1085 
1086  // @@@ add check: 1. all range IDs have to be unique
1087  // @@@ add check: 2. all GC IDs have to be unique
1088 
1089  return gcmgr;
1090 }
1091 
1092 void AW_copy_GC_colors(AW_root *aw_root, const char *source_gcman, const char *dest_gcman, const char *id0, ...) {
1093  // read the color values of the specified GCs from 'source_gcman'
1094  // and write the values into same-named GCs of 'dest_gcman'.
1095  //
1096  // 'id0' is the first of a list of color ids.
1097  // Notes:
1098  // - a NULp sentinel has to be passed after the last color
1099  // - the ids (may) differ from the descriptions passed to AW_manage_GC (ids are keys!)
1100 
1101  va_list parg;
1102  va_start(parg, id0);
1103 
1104  const char *id = id0;
1105  while (id) {
1106  const char *value = aw_root->awar(color_awarname(source_gcman, id))->read_char_pntr();
1107  aw_root->awar(color_awarname(dest_gcman, id))->write_string(value);
1108 
1109  id = va_arg(parg, const char*); // another argument?
1110  }
1111 
1112  va_end(parg);
1113 }
1114 
1115 void AW_init_color_group_defaults(const char *for_program) {
1116  // if for_program == NULp defaults of arb_ntree are silently used + awars are not generated
1117  // if for_program is unknown a warning is shown
1118 
1119  aw_assert(!AW_gc_manager::color_group_defaults);
1120 
1121  bool for_edit4 = false;
1122  if (for_program) {
1123  if (strcmp(for_program, "arb_edit4") == 0) {
1124  for_edit4 = true;
1125  }
1126 #if defined(ASSERTION_USED)
1127  else {
1128  aw_assert(strcmp(for_program, "arb_ntree") == 0); // you might want to add specific defaults for_program
1129  // alternatively pass NULp to use ARB_NTREE_color_group
1130  }
1131 #endif
1132  }
1133 
1134  const int BUFSIZE = AW_COLOR_GROUPS*40;
1135  const char SEP = '\1';
1136  GBS_strstruct printBuffer(BUFSIZE);
1137 
1138  for (int i = 0; i<AW_COLOR_GROUPS; ++i) {
1139  if (!(i&1)) printBuffer.put('+'); // newline after every 2nd color
1140  printBuffer.put('-');
1141  printBuffer.cat(default_colorgroup_name(i+1));
1142  printBuffer.put('$');
1143  printBuffer.put('#');
1144  printBuffer.cat(color_group_def[i].rgbValue(for_edit4));
1145  printBuffer.put(SEP);
1146  }
1147 
1148  aw_assert(printBuffer.get_position()<BUFSIZE); // avoid need to resize buffer
1149 
1150  static ConstStrArray singleDefs;
1151  {
1152  char *alldefs = printBuffer.release();
1153  arb_assert(alldefs[0]); // check whether using SPLIT_DROPEMPTY would be better here. Currently will generate an array containing one empty string.
1154  GBT_splitNdestroy_string(singleDefs, alldefs, SEP);
1155  }
1156 
1157  static const char *cg_def[AW_COLOR_GROUPS+1];
1158  for (int i = 0; i<AW_COLOR_GROUPS; ++i) {
1159  cg_def[i] = singleDefs[i];
1160  }
1161  cg_def[AW_COLOR_GROUPS] = NULp;
1162 
1163  AW_gc_manager::color_group_defaults = cg_def;
1164 
1166 }
1167 
1172 }
1175  return AWAR_COLOR_GROUPS_USE;
1176 }
1177 
1178 char *AW_get_color_group_name(AW_root *awr, int color_group) {
1180  aw_assert(valid_color_group(color_group));
1181  return awr->awar(colorgroupname_awarname(color_group))->read_string();
1182 }
1183 
1184 static void create_color_button(AW_window *aws, const char *awar_name, const char *color_description) {
1185  const char *color = aws->get_root()->awar(awar_name)->read_char_pntr();
1186  char *button_id = GBS_global_string_copy("sel_color[%s]", awar_name);
1187 
1188  aws->callback(makeWindowCallback(popup_color_chooser_window, strdup(awar_name), strdup(color_description)));
1189  aws->create_button(button_id, " ", NULp, color);
1190 
1191  free(button_id);
1192 }
1193 
1194 static void create_font_button(AW_window *aws, const char *gc_base_name, const gc_desc& gcd) {
1195  char *button_id = GBS_global_string_copy("sel_font_%s", gcd.key.c_str());
1196 
1197  aws->callback(makeWindowCallback(popup_font_chooser_window, gc_base_name, &gcd));
1198  aws->create_button(button_id, fontinfo_awarname(gc_base_name, gcd.key));
1199 
1200  free(button_id);
1201 }
1202 
1203 static const int STD_LABEL_LEN = 15;
1204 static const int COLOR_BUTTON_LEN = 10;
1205 static const int FONT_BUTTON_LEN = COLOR_BUTTON_LEN+STD_LABEL_LEN+1;
1206 // => color+font has ~same length as 2 colors (does not work for color groups)
1207 
1209  for (int idx = 0; idx<int(GCs.size()); ++idx) {
1210  const gc_desc& gcd = GCs[idx];
1211 
1212  if (gcd.is_color_group()) { if (for_gc_type != GC_TYPE_GROUP) continue; }
1213  else if (gcd.belongs_to_range()) { if (for_gc_type != GC_TYPE_RANGE) continue; }
1214  else { if (for_gc_type != GC_TYPE_NORMAL) continue; }
1215 
1216  if (for_gc_type == GC_TYPE_RANGE) {
1217  if (gcd.get_color_index() == 0) { // first color of range
1218  const gc_range& range = color_ranges[gcd.get_range_index()];
1219 
1220  const char *type_info = NULp;
1221  switch (range.get_type()) {
1222  case GC_RANGE_LINEAR: type_info = "linear 1D range"; break;
1223  case GC_RANGE_CYCLIC: type_info = "cyclic 1D range"; break;
1224  case GC_RANGE_PLANAR: type_info = "planar 2D range"; break;
1225  case GC_RANGE_SPATIAL: type_info = "spatial 3D range"; break;
1226  case GC_RANGE_INVALID: type_info = "invalid range "; aw_assert(0); break;
1227  }
1228 
1229  const char *range_headline = GBS_global_string("%s (%s)", range.get_name().c_str(), type_info);
1230  aws->button_length(60);
1231  aws->create_button(NULp, range_headline, NULp, "+");
1232  aws->at_newline();
1233  }
1234  }
1235 
1236  if (for_gc_type == GC_TYPE_GROUP) {
1237  int color_group_no = idx-first_colorgroup_idx+1;
1238  char buf[13];
1239  sprintf(buf, "%2i:", color_group_no); // @@@ shall this short label be stored in gc_desc?
1240  aws->label_length(3);
1241  aws->label(buf);
1242  aws->create_input_field(colorgroupname_awarname(color_group_no), 21);
1243  }
1244  else {
1245  aws->label_length(STD_LABEL_LEN);
1246  aws->label(gcd.colorlabel.c_str());
1247  }
1248 
1249  aws->button_length(COLOR_BUTTON_LEN);
1250  create_color_button(aws, color_awarname(gc_base_name, gcd.key), gcd.colorlabel.c_str());
1251  if (gcd.has_font) {
1252  aws->button_length(FONT_BUTTON_LEN);
1253  create_font_button(aws, gc_base_name, gcd);
1254  }
1255  if (!gcd.same_line) aws->at_newline();
1256  }
1257 }
1258 
1259 typedef std::map<AW_gc_manager*, AW_window_simple*> GroupWindowRegistry;
1260 
1263 
1264  static GroupWindowRegistry existing_window;
1265  GroupWindowRegistry::iterator found = existing_window.find(gcmgr);
1266  AW_window_simple *aws = found == existing_window.end() ? NULp : found->second;
1267 
1268  if (!aws) {
1269  aws = new AW_window_simple;
1270 
1271  aws->init(aww->get_root(), "COLOR_GROUP_DEF2", "Define color groups");
1272 
1273  aws->at(10, 10);
1274  aws->auto_space(1, 1);
1275 
1276  aws->callback(AW_POPDOWN);
1277  aws->create_button("CLOSE", "CLOSE", "C");
1278  aws->callback(makeHelpCallback("color_props_groups.hlp"));
1279  aws->create_button("HELP", "HELP", "H");
1280  aws->at_newline();
1281 
1282  aws->label_length(20);
1283  aws->label("Enable color groups:");
1284  aws->create_toggle(AWAR_COLOR_GROUPS_USE);
1285  aws->at_newline();
1286 
1287  gcmgr->create_gc_buttons(aws, GC_TYPE_GROUP);
1288 
1289  aws->window_fit();
1290  existing_window[gcmgr] = aws;
1291  }
1292 
1293  aws->activate();
1294 }
1295 
1297  static GroupWindowRegistry existing_window;
1298  GroupWindowRegistry::iterator found = existing_window.find(gcmgr);
1299  AW_window_simple *aws = found == existing_window.end() ? NULp : found->second;
1300 
1301  if (!aws) {
1302  aws = new AW_window_simple;
1303 
1304  aws->init(aww->get_root(), "COLOR_RANGE_EDIT", "Edit color ranges");
1305 
1306  aws->at(10, 10);
1307  aws->auto_space(5, 5);
1308 
1309  aws->callback(AW_POPDOWN);
1310  aws->create_button("CLOSE", "CLOSE", "C");
1311  aws->callback(makeHelpCallback("color_ranges.hlp"));
1312  aws->create_button("HELP", "HELP", "H");
1313  aws->at_newline();
1314 
1315  aws->label("Overlay active range");
1316  aws->create_toggle(AWAR_RANGE_OVERLAY);
1317  aws->at_newline();
1318 
1319  gcmgr->create_gc_buttons(aws, GC_TYPE_RANGE);
1320 
1321  aws->window_fit();
1322  existing_window[gcmgr] = aws;
1323  }
1324 
1325  aws->activate();
1326 }
1327 
1328 AW_window *AW_create_gc_window_named(AW_root *aw_root, AW_gc_manager *gcman, const char *wid, const char *windowname) {
1329  // same as AW_create_gc_window, but uses different window id and name
1330  // (use if if there are two or more color def windows in one application,
1331  // otherwise they save the same window properties)
1332 
1333  AW_window_simple *aws = new AW_window_simple;
1334 
1335  aws->init(aw_root, wid, windowname);
1336 
1337  aws->at(10, 10);
1338  aws->auto_space(2, 2);
1339 
1340  aws->callback(AW_POPDOWN);
1341  aws->create_button("CLOSE", "CLOSE", "C");
1342  aws->callback(makeHelpCallback("color_props.hlp"));
1343  aws->create_button("HELP", "HELP", "H");
1344  aws->at_newline();
1345 
1346  // select all fonts:
1347  {
1348  static gc_desc allFont_fake_desc(-1, GC_TYPE_NORMAL);
1349  allFont_fake_desc.colorlabel = "<all fonts>";
1350  allFont_fake_desc.key = ALL_FONTS_ID;
1351  allFont_fake_desc.fixed_width_font = !gcman->has_variable_width_font();
1352  aws->callback(makeWindowCallback(popup_font_chooser_window, gcman->get_base_name(), &allFont_fake_desc));
1353  }
1354  aws->label_length(STD_LABEL_LEN);
1355  aws->label("All fonts:");
1356  aws->button_length(COLOR_BUTTON_LEN);
1357  aws->create_button("select_all_fonts", "Select", "s");
1358  aws->at_newline();
1359 
1360  gcman->create_gc_buttons(aws, GC_TYPE_NORMAL);
1361 
1362  bool groups_or_range = false;
1363  if (gcman->has_color_groups()) {
1364  aws->callback(makeWindowCallback(AW_popup_gc_color_groups_window, gcman));
1365  aws->create_autosize_button("EDIT_COLOR_GROUP", "Edit color groups", "E");
1366  groups_or_range = true;
1367  }
1368  if (gcman->has_color_range()) {
1369  aws->callback(makeWindowCallback(AW_popup_gc_color_range_window, gcman));
1370  aws->create_autosize_button("EDIT_COLOR_RANGE", "Edit color ranges", "r");
1371  groups_or_range = true;
1372  }
1373  if (groups_or_range) aws->at_newline();
1374 
1375  aws->window_fit();
1376  return aws;
1377 }
1379  return AW_create_gc_window_named(aw_root, gcman, "COLOR_DEF2", "Colors and Fonts");
1380 }
1381 
1383  return gcman->get_drag_gc();
1384 }
1385 
1386 void AW_displayColorRange(AW_device *device, int first_range_gc, AW::Position start, AW_pos xsize, AW_pos ysize) {
1396  using namespace AW;
1397 
1398  if (AW_gc_manager::show_range_overlay) {
1399  Vector size(xsize, ysize);
1400  for (int x = 0; x<AW_PLANAR_COLORS; ++x) {
1401  for (int y = 0; y<AW_PLANAR_COLORS; ++y) {
1402  int gc = first_range_gc + y*AW_PLANAR_COLORS+x;
1403  Vector toCorner(x*xsize, y*ysize);
1404  Position corner = start+toCorner;
1405  device->box(gc, FillStyle::SOLID, Rectangle(corner, size));
1406  }
1407  }
1408  }
1409 }
1410 
1411 void AW_getColorRangeNames(const AW_gc_manager *gcman, int dimension, ConstStrArray& ids, ConstStrArray& names) {
1418  ids.clear();
1419  names.clear();
1420  gcman->getColorRangeNames(dimension, ids, names);
1421 }
1422 
1423 int AW_getFirstRangeGC(AW_gc_manager *gcman) { return gcman->first_range_gc(); }
1424 void AW_activateColorRange(AW_gc_manager *gcman, const char *id) { gcman->activateColorRange(id); }
1425 
1426 const char *AW_getActiveColorRangeID(AW_gc_manager *gcman, int *dimension) {
1431  return gcman->getActiveColorRangeID(dimension);
1432 }
1433 
1434 #if defined(UNIT_TESTS)
1438  }
1439  AW_gc_manager::use_color_groups = true;
1440 }
1441 #endif
1442 
1443 // @@@ move code below somewhere more sensible
1444 
1446  aw->insert_menu_topic("enable_advices", "Reactivate advices", "R", "advice.hlp", AWM_ALL, AW_reactivate_all_advices);
1447  aw->insert_menu_topic("enable_questions", "Reactivate questions", "q", "questions.hlp", AWM_ALL, AW_reactivate_all_questions);
1448  aw->insert_menu_topic("reset_win_layout", "Reset window layout", "w", "reset_win_layout.hlp", AWM_ALL, AW_forget_all_window_geometry);
1449 }
1452 
1453 void AW_save_specific_properties(AW_window *aw, const char *filename) { // special version for EDIT4
1454  GB_ERROR error = aw->get_root()->save_properties(filename);
1455  if (error) aw_message(error);
1456 }
1459 }
1460 
1461 // --------------------------------
1462 // RGB <-> HSV conversion
1463 
1464 class AW_hsv {
1465  float H, S, V;
1466 public:
1467  AW_hsv(float hue, float saturation, float value) : H(hue), S(saturation), V(value) {
1468  aw_assert(H>=0.0 && H<360.0);
1469  aw_assert(S>=0.0 && S<=1.0);
1470  aw_assert(V>=0.0 && V<=1.0);
1471  }
1473  float R = col.r();
1474  float G = col.g();
1475  float B = col.b();
1476 
1477  float min = std::min(std::min(R, G), B);
1478  float max = std::max(std::max(R, G), B);
1479 
1480  if (min == max) {
1481  H = 0;
1482  }
1483  else {
1484  H = 60;
1485 
1486  if (max == R) { H *= 0 + (G-B)/(max-min); }
1487  else if (max == G) { H *= 2 + (B-R)/(max-min); }
1488  else { H *= 4 + (R-G)/(max-min); }
1489 
1490  if (H<0) H += 360;
1491  }
1492 
1493  S = max ? (max-min)/max : 0;
1494  V = max;
1495  }
1496 #if defined(Cxx11)
1497  AW_hsv(const AW_rgb16& col) : AW_hsv(AW_rgb_normalized(col)) {}
1498 #else // !defined(Cxx11)
1499  AW_hsv(const AW_rgb16& col) { *this = AW_rgb_normalized(col); }
1500 #endif
1501 
1503  int hi = int(H/60);
1504  float f = H/60-hi;
1505 
1506  float p = V*(1-S);
1507  float q = V*(1-S*f);
1508  float t = V*(1-S*(1-f));
1509 
1510  switch (hi) {
1511  case 0: return AW_rgb_normalized(V, t, p); // 0 <= H < 60 (deg)
1512  case 1: return AW_rgb_normalized(q, V, p); // 60 <= H < 120
1513  case 2: return AW_rgb_normalized(p, V, t); // 120 <= H < 180
1514  case 3: return AW_rgb_normalized(p, q, V); // 180 <= H < 240
1515  case 4: return AW_rgb_normalized(t, p, V); // 240 <= H < 300
1516  case 5: return AW_rgb_normalized(V, p, q); // 300 <= H < 360
1517  }
1518  aw_assert(0);
1519  return AW_rgb_normalized(0, 0, 0);
1520  }
1521 
1522  float h() const { return H; }
1523  float s() const { return S; }
1524  float v() const { return V; }
1525 };
1526 
1527 
1528 // --------------------------------------------------------------------------------
1529 
1530 #ifdef UNIT_TESTS
1531 #ifndef TEST_UNIT_H
1532 #include <test_unit.h>
1533 #endif
1534 
1535 void TEST_rgb_hsv_conversion() {
1536  // Note: more related tests in AW_rgb.cxx@RGB_TESTS
1537 
1538  const int tested[] = {
1539  // testing full rgb space takes too long
1540  // just test all combinations of these:
1541 
1542  0, 1, 2, 3, 4, 5,
1543  58, 59, 60, 61, 62,
1544  998, 999, 1000, 1001, 1002,
1545  32766, 32767, 32768, 32769, 32770,
1546  39998, 39999, 40000, 40001, 40002,
1547  65531, 65532, 65533, 65534, 65535
1548  };
1549 
1550  for (unsigned i = 0; i<ARRAY_ELEMS(tested); ++i) {
1551  int r = tested[i];
1552  for (unsigned j = 0; j<ARRAY_ELEMS(tested); ++j) {
1553  int g = tested[j];
1554  for (unsigned k = 0; k<ARRAY_ELEMS(tested); ++k) {
1555  int b = tested[k];
1556 
1557  TEST_ANNOTATE(GBS_global_string("rgb=%i/%i/%i", r, g, b));
1558 
1559  AW_hsv hsv(AW_rgb16(r, g, b));
1560 
1561  // check range overflow
1562  TEST_EXPECT(hsv.h()>=0.0 && hsv.h()<360.0);
1563  TEST_EXPECT(hsv.s()>=0.0 && hsv.s()<=1.0);
1564  TEST_EXPECT(hsv.v()>=0.0 && hsv.v()<=1.0);
1565 
1566  AW_rgb16 RGB(hsv.rgb());
1567 
1568  // fprintf(stderr, "rgb=%i/%i/%i hsv=%i/%i/%i RGB=%i/%i/%i\n", r, g, b, h, s, v, R, G, B);
1569 
1570  // check that rgb->hsv->RGB produces a similar color
1571  const int MAXDIFF = 1; // less than .0015% difference per channel
1572  const int MAXDIFFSUM = 2; // less than .003% difference overall
1573 
1574  TEST_EXPECT(abs(r-RGB.r()) <= MAXDIFF);
1575  TEST_EXPECT(abs(g-RGB.g()) <= MAXDIFF);
1576  TEST_EXPECT(abs(b-RGB.b()) <= MAXDIFF);
1577 
1578  TEST_EXPECT((abs(r-RGB.r())+abs(g-RGB.g())+abs(b-RGB.b())) <= MAXDIFFSUM);
1579  }
1580  }
1581  }
1582 
1583  for (unsigned i = 0; i<ARRAY_ELEMS(tested); ++i) {
1584  int h = tested[i]*320/65535;
1585  for (unsigned j = 0; j<ARRAY_ELEMS(tested); ++j) {
1586  float s = tested[j]/65535.0;
1587  for (unsigned k = 0; k<ARRAY_ELEMS(tested); ++k) {
1588  float v = tested[k]/65535.0;
1589 
1590  TEST_ANNOTATE(GBS_global_string("hsv=%i/%.3f/%.3f", h, s, v));
1591 
1592  AW_rgb16 rgb(AW_hsv(h, s, v).rgb());
1593  AW_rgb16 RGB(AW_hsv(rgb).rgb());
1594 
1595  // fprintf(stderr, "hsv=%i/%i/%i rgb=%i/%i/%i HSV=%i/%i/%i RGB=%i/%i/%i\n", h, s, v, r, g, b, H, S, V, R, G, B);
1596 
1597  // check that hsv->rgb->HSV->RGB produces a similar color (comparing hsv makes no sense)
1598  const int MAXDIFF = 1; // less than .0015% difference per channel
1599  const int MAXDIFFSUM = 2; // less than .003% difference overall
1600 
1601  TEST_EXPECT(abs(rgb.r()-RGB.r()) <= MAXDIFF);
1602  TEST_EXPECT(abs(rgb.g()-RGB.g()) <= MAXDIFF);
1603  TEST_EXPECT(abs(rgb.b()-RGB.b()) <= MAXDIFF);
1604 
1605  TEST_EXPECT((abs(rgb.r()-RGB.r())+abs(rgb.g()-RGB.g())+abs(rgb.b()-RGB.b())) <= MAXDIFFSUM);
1606  }
1607  }
1608  }
1609 
1610  // specific conversion (showed wrong 'hue' and 'saturation' until [14899])
1611  {
1612  AW_hsv hsv(AW_rgb16(0, 0, 14906));
1613 
1614  TEST_EXPECT_SIMILAR(hsv.h(), 240.0, 0.001); //= ~ 240 deg
1615  TEST_EXPECT_SIMILAR(hsv.s(), 1.0, 0.001); //= 100%
1616  TEST_EXPECT_SIMILAR(hsv.v(), 0.227, 0.001); //= ~ 22.7%
1617 
1618  AW_rgb16 rgb(hsv.rgb());
1619 
1620  TEST_EXPECT_EQUAL(rgb.r(), 0);
1621  TEST_EXPECT_EQUAL(rgb.g(), 0);
1622  TEST_EXPECT_EQUAL(rgb.b(), 14906);
1623  }
1624 }
1625 
1626 #endif // UNIT_TESTS
1627 
1628 // --------------------------------------------------------------------------------
1629 
1630 
1631 // ------------------------------
1632 // motif color selector
1633 
1634 #define AWAR_SELECTOR_COLOR_LABEL "tmp/aw/color_label"
1635 
1636 #define AWAR_CV_R "tmp/aw/color_r" // rgb..
1637 #define AWAR_CV_G "tmp/aw/color_g"
1638 #define AWAR_CV_B "tmp/aw/color_b"
1639 #define AWAR_CV_H "tmp/aw/color_h" // hsv..
1640 #define AWAR_CV_S "tmp/aw/color_s"
1641 #define AWAR_CV_V "tmp/aw/color_v"
1642 
1643 static char *current_color_awarname = NULp; // name of the currently modified color-awar
1644 static bool ignore_color_value_change = false;
1646 
1647 static void aw_set_rgb_sliders(AW_root *awr, const AW_rgb_normalized& col) {
1648  color_value_change_was_ignored = false;
1649  {
1650  LocallyModify<bool> delayUpdate(ignore_color_value_change, true);
1651  awr->awar(AWAR_CV_R)->write_float(col.r());
1652  awr->awar(AWAR_CV_G)->write_float(col.g());
1653  awr->awar(AWAR_CV_B)->write_float(col.b());
1654  }
1655  if (color_value_change_was_ignored) awr->awar(AWAR_CV_B)->touch();
1656 }
1657 
1659  const char *color = awr->awar(current_color_awarname)->read_char_pntr();
1661 }
1662 
1663 inline void aw_set_color(AW_root *awr, const char *color_name) {
1664  awr->awar(current_color_awarname)->write_string(color_name);
1666 }
1667 static void aw_set_color(AW_window *aww, const char *color_name) {
1668  aw_set_color(aww->get_root(), color_name);
1669 }
1670 
1671 static void colorslider_changed_cb(AW_root *awr, bool hsv_changed) {
1672  if (ignore_color_value_change) {
1673  color_value_change_was_ignored = true;
1674  }
1675  else {
1676  LocallyModify<bool> noRecursion(ignore_color_value_change, true);
1677 
1678  if (hsv_changed) {
1679  float h = awr->awar(AWAR_CV_H)->read_float();
1680  float s = awr->awar(AWAR_CV_S)->read_float();
1681  float v = awr->awar(AWAR_CV_V)->read_float();
1682 
1683  if (h>=360.0) h -= 360;
1684 
1685  AW_rgb_normalized col(AW_hsv(h, s, v).rgb());
1686  aw_set_color(awr, AW_rgb16(col).ascii());
1687 
1688  awr->awar(AWAR_CV_R)->write_float(col.r());
1689  awr->awar(AWAR_CV_G)->write_float(col.g());
1690  awr->awar(AWAR_CV_B)->write_float(col.b());
1691  }
1692  else {
1694  awr->awar(AWAR_CV_G)->read_float(),
1695  awr->awar(AWAR_CV_B)->read_float());
1696 
1697  aw_set_color(awr, AW_rgb16(col).ascii());
1698 
1699  AW_hsv hsv(col);
1700 
1701  awr->awar(AWAR_CV_H)->write_float(hsv.h());
1702  awr->awar(AWAR_CV_S)->write_float(hsv.s());
1703  awr->awar(AWAR_CV_V)->write_float(hsv.v());
1704  }
1705  }
1706 }
1709  static const char *colorValueAwars[] = {
1713  };
1714 
1715  for (int cv = 0; cv<6; ++cv) {
1716  awr->awar_float(colorValueAwars[cv])
1717  ->set_minmax(0.0, cv == 1 ? 360.0 : 1.0)
1718  ->add_callback(makeRootCallback(colorslider_changed_cb, bool(cv%2)));
1719  }
1720 }
1721 static void popup_color_chooser_window(AW_window *aww, const char *awar_name, const char *color_description) {
1722  AW_root *awr = aww->get_root();
1723  static AW_window_simple *aws = NULp;
1724  if (!aws) {
1726 
1727  aws = new AW_window_simple;
1728  aws->init(awr, "COLORS", "Select color");
1729 
1730  int x1 = 10;
1731  int y1 = 10;
1732 
1733  aws->at(x1, y1);
1734  aws->auto_space(3, 3);
1735  aws->callback(AW_POPDOWN);
1736  aws->create_button("CLOSE", "CLOSE", "C");
1737 
1738  aws->button_length(20);
1739  aws->create_button(NULp, AWAR_SELECTOR_COLOR_LABEL);
1740  aws->at_newline();
1741 
1742  int x2, y2;
1743  aws->get_at_position(&x2, &y2);
1744  y2 += 3;
1745 
1746  struct ColorValue {
1747  const char *label;
1748  const char *awar;
1749  } colorValue[] = {
1750  { "R", AWAR_CV_R }, { "H", AWAR_CV_H },
1751  { "G", AWAR_CV_G }, { "S", AWAR_CV_S },
1752  { "B", AWAR_CV_B }, { "V", AWAR_CV_V },
1753  };
1754 
1755  const int INPUTFIELD_WIDTH = 12;
1756  const int SCALERLENGTH = 320;
1757 
1758  for (int row = 0; row<3; ++row) {
1759  aws->at(x1, y1+(row+1)*(y2-y1));
1760  const ColorValue *vc = &colorValue[row*2];
1761  aws->label(vc->label);
1762  aws->create_input_field_with_scaler(vc->awar, INPUTFIELD_WIDTH, SCALERLENGTH, AW_SCALER_LINEAR);
1763  ++vc;
1764  aws->label(vc->label);
1765  aws->create_input_field_with_scaler(vc->awar, INPUTFIELD_WIDTH, SCALERLENGTH, AW_SCALER_LINEAR);
1766  }
1767 
1768  aws->button_length(1);
1769  aws->at_newline();
1770 
1771  const float SATVAL_INCREMENT = 0.2;
1772  const int HUE_INCREMENT = 10;
1773  const int COLORS_PER_ROW = 360/HUE_INCREMENT;
1774 
1775  for (int v = 5; v>=2; --v) {
1776  float val = v*SATVAL_INCREMENT;
1777  bool rev = !(v%2);
1778  for (int s = rev ? 2 : 5; rev ? s<=5 : s>=2; s = rev ? s+1 : s-1) {
1779  float sat = s*SATVAL_INCREMENT;
1780  for (int hue = 0; hue<360; hue += HUE_INCREMENT) {
1781  const char *color_name = AW_rgb16(AW_hsv(hue, sat, val).rgb()).ascii();
1782  aws->callback(makeWindowCallback(aw_set_color, strdup(color_name)));
1783  aws->create_button(color_name, "", NULp, color_name);
1784  }
1785  aws->at_newline();
1786  }
1787  }
1788 
1789  for (int p = 0; p<COLORS_PER_ROW; ++p) {
1790  float grey = (1.0 * p) / (COLORS_PER_ROW-1);
1791  const char *color_name = AW_rgb16(AW_rgb_normalized(grey, grey, grey)).ascii();
1792 
1793  aws->callback(makeWindowCallback(aw_set_color, strdup(color_name)));
1794  aws->create_button(color_name, "=", NULp, color_name);
1795  }
1796  aws->at_newline();
1797 
1798  aws->window_fit();
1799  }
1800  awr->awar(AWAR_SELECTOR_COLOR_LABEL)->write_string(color_description);
1801  freedup(current_color_awarname, awar_name);
1803  aws->activate();
1804 }
1805 
1806 // ----------------------------
1807 // motif font chooser
1808 
1809 #define AWAR_SELECTOR_FONT_LABEL "tmp/aw/font_label"
1810 #define AWAR_SELECTOR_FONT_NAME "tmp/aw/font_name"
1811 #define AWAR_SELECTOR_FONT_SIZE "tmp/aw/font_size"
1812 
1814  awr->awar_string(AWAR_SELECTOR_FONT_LABEL, "<invalid>");
1817 }
1818 
1819 static void popup_font_chooser_window(AW_window *aww, const char *gc_base_name, const gc_desc *gcd) {
1820  AW_root *awr = aww->get_root();
1821 
1822  static AW_window_simple *aw_fontChoose[2] = { NULp, NULp }; // one for fixed-width font; one general
1823 
1824  bool fixed_width_only = gcd->fixed_width_font;
1825 
1826  AW_window_simple*& aws = aw_fontChoose[fixed_width_only];
1827  AW_window_simple*& awo = aw_fontChoose[!fixed_width_only];
1828 
1829  if (!aws) {
1830  if (!awo) create_font_chooser_awars(awr); // only called once
1831 
1832  aws = new AW_window_simple;
1833  aws->init(awr, "FONT", fixed_width_only ? "Select fixed width font" : "Select font");
1834 
1835  aws->auto_space(10, 10);
1836 
1837  aws->callback(AW_POPDOWN);
1838  aws->create_button("CLOSE", "CLOSE", "C");
1839 
1840  aws->button_length(20);
1841  aws->create_button(NULp, AWAR_SELECTOR_FONT_LABEL);
1842  aws->at_newline();
1843 
1844  aws->label("Font:");
1845  aws->create_option_menu(AWAR_SELECTOR_FONT_NAME);
1846  {
1847  int fonts_inserted = 0;
1848  for (int order = 1; order>=0; order--) {
1849  for (int font_nr = 0; ; font_nr++) {
1850  AW_font aw_font_nr = font_nr;
1851  bool found;
1852  const char *font_string = AW_get_font_specification(aw_font_nr, found);
1853 
1854  if (!font_string) {
1855  fprintf(stderr, "[Font detection: tried=%i, found=%i]\n", font_nr, fonts_inserted);
1856  break;
1857  }
1858 
1859  if (found != bool(order)) continue; // display found fonts at top
1860  if (fixed_width_only && !font_has_fixed_width(aw_font_nr)) continue;
1861 
1862  aws->insert_option(font_string, NULp, font_nr);
1863  ++fonts_inserted;
1864  }
1865  }
1866  if (!fonts_inserted) aws->insert_option("No suitable fonts detected", NULp, 0);
1867  aws->insert_default_option("<no font selected>", NULp, NO_FONT);
1868  aws->update_option_menu();
1869  }
1870 
1871  aws->at_newline();
1872 
1873  aws->label("Size:");
1874  aws->create_input_field_with_scaler(AWAR_SELECTOR_FONT_SIZE, 3, 330);
1875  aws->at_newline();
1876 
1877  aws->window_fit();
1878  }
1879 
1881  awr->awar(AWAR_SELECTOR_FONT_NAME)->map(awr->awar(fontname_awarname(gc_base_name, gcd->key)));
1882  awr->awar(AWAR_SELECTOR_FONT_SIZE)->map(awr->awar(fontsize_awarname(gc_base_name, gcd->key)));
1883 
1884  if (awo) awo->hide(); // both windows use same awars -> hide the other window to avoid chaos
1885  aws->activate();
1886 }
1887 
1888 // -----------------------------------
1889 // frame colors (motif only)
1890 
1891 static void aw_message_reload(AW_root *) {
1892  aw_message("Sorry, to activate new colors:\n"
1893  " save properties\n"
1894  " and restart application");
1895 }
1896 
1897 static void AW_preset_create_font_chooser(AW_window *aws, const char *awar, const char *label, bool message_reload) {
1898  if (message_reload) aws->get_root()->awar(awar)->add_callback(aw_message_reload);
1899 
1900  aws->label(label);
1901  aws->create_option_menu(awar);
1902 
1903  aws->insert_option("5x8", "5", "5x8");
1904  aws->insert_option("6x10", "6", "6x10");
1905  aws->insert_option("7x13", "7", "7x13");
1906  aws->insert_option("7x13bold", "7", "7x13bold");
1907  aws->insert_option("8x13", "8", "8x13");
1908  aws->insert_option("8x13bold", "8", "8x13bold");
1909  aws->insert_option("9x15", "9", "9x15");
1910  aws->insert_option("9x15bold", "9", "9x15bold");
1911  aws->insert_option("helvetica-12", "9", "helvetica-12");
1912  aws->insert_option("helvetica-bold-12", "9", "helvetica-bold-12");
1913  aws->insert_option("helvetica-13", "9", "helvetica-13");
1914  aws->insert_option("helvetica-bold-13", "9", "helvetica-bold-13");
1915 
1916  aws->insert_default_option("other", "o", "");
1917  aws->update_option_menu();
1918 }
1919 static void AW_preset_create_color_button(AW_window *aws, const char *awar_name, const char *label) {
1920  aws->get_root()->awar(awar_name)->add_callback(aw_message_reload);
1921  aws->label(label);
1922  create_color_button(aws, awar_name, label);
1923 }
1924 
1926  AW_window_simple *aws = new AW_window_simple;
1927  const int tabstop = 400;
1928  aws->init(root, "PROPS_FRAME", "WINDOW_PROPERTIES");
1929 
1930  aws->label_length(25);
1931  aws->button_length(20);
1932 
1933  aws->at (10, 10);
1934  aws->auto_space(10, 10);
1935 
1936  aws->callback (AW_POPDOWN);
1937  aws->create_button("CLOSE", "CLOSE", "C");
1938 
1939  aws->callback(makeHelpCallback("props_frame.hlp"));
1940  aws->create_button("HELP", "HELP", "H");
1941 
1942  aws->at_newline();
1943 
1944  AW_preset_create_font_chooser(aws, "window/font", "Main Menu Font", 1);
1945  aws->at_x(tabstop);
1946  aws->create_input_field("window/font", 12);
1947 
1948  aws->at_newline();
1949 
1950  aws->button_length(10);
1951  AW_preset_create_color_button(aws, "window/background", "Application Background");
1952  aws->at_x(tabstop);
1953  aws->create_input_field("window/background", 12);
1954 
1955  aws->at_newline();
1956 
1957  AW_preset_create_color_button(aws, "window/foreground", "Application Foreground");
1958  aws->at_x(tabstop);
1959  aws->create_input_field("window/foreground", 12);
1960 
1961  aws->at_newline();
1962 
1963  AW_preset_create_color_button(aws, "window/color_1", "Color 1");
1964  aws->at_x(tabstop);
1965  aws->create_input_field("window/color_1", 12);
1966 
1967  aws->at_newline();
1968 
1969  AW_preset_create_color_button(aws, "window/color_2", "Color 2");
1970  aws->at_x(tabstop);
1971  aws->create_input_field("window/color_2", 12);
1972 
1973  aws->at_newline();
1974 
1975  AW_preset_create_color_button(aws, "window/color_3", "Color 3");
1976 
1977  aws->at_x(tabstop);
1978  aws->create_input_field("window/color_3", 12);
1979 
1980  aws->at_newline();
1981 
1982  aws->window_fit();
1983  return aws;
1984 }
1985 
static bool ignore_color_value_change
Definition: AW_preset.cxx:1644
#define AWAR_COLOR_GROUPS_PREFIX
Definition: AW_preset.cxx:44
GB_ERROR GB_check_key(const char *key) __ATTR__USERESULT
Definition: adstring.cxx:85
void insert_option(AW_label choice_label, const char *mnemonic, const char *var_value, const char *name_of_color=NULp)
#define arb_assert(cond)
Definition: arb_assert.h:245
AW_window * AW_create_gc_window_named(AW_root *aw_root, AW_gc_manager *gcman, const char *wid, const char *windowname)
Definition: AW_preset.cxx:1328
#define NO_SIZE
Definition: AW_preset.cxx:53
#define SEP
Definition: xferset.cxx:430
bool font_has_fixed_width(AW_font aw_font_nr)
Definition: AW_preset.cxx:480
void add_gc(const char *gc_description, int &gc, gc_type type, const char *id_prefix=NULp)
Definition: AW_preset.cxx:849
void AW_init_colorgroup_name_awars(AW_root *awr)
Definition: AW_preset.cxx:957
string result
void reserve_gcs(const char *gc_description, int &gc)
Definition: AW_preset.cxx:827
static void gc_color_changed_cb(AW_root *, AW_gc_manager *mgr, int idx)
Definition: AW_preset.cxx:682
const int NO_INDEX
Definition: AW_preset.cxx:138
bool has_variable_width_font() const
Definition: AW_preset.cxx:950
const char * id
Definition: AliAdmin.cxx:17
void put(const char *elem)
Definition: arb_strarray.h:188
void button_length(int length)
Definition: AW_at.cxx:288
#define TEST_EXPECT_SIMILAR(expr, want, epsilon)
Definition: test_unit.h:1298
#define AWAR_SELECTOR_FONT_LABEL
Definition: AW_preset.cxx:1809
const char * fontsize_awarname(const char *gcman_id, const string &colname)
Definition: AW_preset.cxx:80
const char * awarname_active_range() const
Definition: AW_preset.cxx:419
#define implicated(hypothesis, conclusion)
Definition: arb_assert.h:289
static char * y[maxsp+1]
return string(buffer, length)
void insert_menu_topic(const char *id, const char *name, const char *mnemonic, const char *help_text_, AW_active mask, const WindowCallback &wcb)
Definition: AW_window.cxx:604
static void aw_set_rgb_sliders(AW_root *awr, const AW_rgb_normalized &col)
Definition: AW_preset.cxx:1647
#define AWAR_CV_V
Definition: AW_preset.cxx:1641
bool AW_color_groups_active()
Definition: AW_preset.cxx:1168
void init_color_ranges(int &gc)
Definition: AW_preset.cxx:786
const char * defaultColorgroupName(int color_group)
Definition: AW_preset.cxx:91
void set_line_attributes(int gc, short width, AW_linestyle style)
Definition: AW_device.cxx:465
static void colorslider_changed_cb(AW_root *awr, bool hsv_changed)
Definition: AW_preset.cxx:1671
void set_function(int gc, AW_function function)
Definition: AW_device.cxx:468
void establish_default(int gc)
Definition: AW_device.cxx:474
bool belongs_to_range() const
Definition: AW_preset.cxx:186
void AW_popup_gc_color_range_window(AW_window *aww, AW_gc_manager *gcmgr)
Definition: AW_preset.cxx:1296
AW_rgb_normalized get_color(int idx, const AW_gc_manager *gcman) const
Definition: AW_preset.cxx:541
void AW_reactivate_all_advices(AW_window *)
reactivates all advices which were disabled by the user
Definition: AW_advice.cxx:137
static char * current_color_awarname
Definition: AW_preset.cxx:1643
#define ALL_FONTS_ID
Definition: AW_preset.cxx:50
const char * AW_get_font_specification(AW_font font_nr, bool &found)
Definition: AW_xfont.cxx:666
GB_ERROR save_properties(const char *filename=NULp) __ATTR__USERESULT
Definition: AW_root.cxx:690
float s() const
Definition: AW_preset.cxx:1523
void AW_forget_all_window_geometry(AW_window *aww)
Definition: AW_window.cxx:2221
void at(int x, int y)
Definition: AW_at.cxx:93
static void popup_font_chooser_window(AW_window *aww, const char *gc_base_name, const struct gc_desc *gcd)
const char * fontinfo_awarname(const char *gcman_id, const string &colname)
Definition: AW_preset.cxx:81
#define AW_COLOR_GROUPS
static void AW_preset_create_color_button(AW_window *aws, const char *awar_name, const char *label)
Definition: AW_preset.cxx:1919
long read_int() const
Definition: AW_awar.cxx:184
AW_awar * set_minmax(float min, float max)
Definition: AW_awar.cxx:530
static void gc_fontOrSize_changed_cb(AW_root *, AW_gc_manager *mgr, int idx)
Definition: AW_preset.cxx:477
const string & get_id() const
Definition: AW_preset.cxx:271
void add_color(const string &colordef, AW_gc_manager *gcman)
Definition: AW_preset.cxx:722
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
bool has_color_range() const
Definition: AW_preset.cxx:358
void AW_advice(const char *message, AW_Advice_Type type, const char *title, const char *corresponding_help)
Show a message box with an advice for the user.
Definition: AW_advice.cxx:160
int get_range_index() const
Definition: AW_preset.cxx:188
int AW_font_2_xfig(AW_font font_nr)
Definition: AW_xfont.cxx:724
void GBK_terminatef(const char *templat,...)
Definition: arb_msg.cxx:523
void AW_POPDOWN(AW_window *window)
Definition: AW_window.cxx:52
char * release()
Definition: arb_strbuf.h:129
void AW_insert_common_property_menu_entries(AW_window_menu_modes *awmm)
Definition: AW_preset.cxx:1450
static void range_overlay_changed_cb(AW_root *awr, AW_gc_manager *gcmgr)
Definition: AW_preset.cxx:714
AW_color_idx
Definition: aw_base.hxx:83
char * GBS_string_2_key(const char *str)
Definition: adstring.cxx:52
bool fixed_width_font
Definition: AW_preset.cxx:173
void cat(const char *from)
Definition: arb_strbuf.h:199
AW_hsv(float hue, float saturation, float value)
Definition: AW_preset.cxx:1467
const char * AW_getActiveColorRangeID(AW_gc_manager *gcman, int *dimension)
Definition: AW_preset.cxx:1426
char * ARB_strpartdup(const char *start, const char *end)
Definition: arb_string.h:51
void AW_activateColorRange(AW_gc_manager *gcman, const char *id)
Definition: AW_preset.cxx:1424
#define AWAR_COLOR_GROUPS_USE
Definition: AW_preset.cxx:45
void create_gc_buttons(AW_window *aww, gc_type for_gc_type)
Definition: AW_preset.cxx:1208
const gc_desc & get_gc_desc(int idx) const
Definition: AW_preset.cxx:365
void add_color_groups(int &gc)
Definition: AW_preset.cxx:963
const string & get_name() const
Definition: AW_preset.cxx:270
static void color_group_name_changed_cb(AW_root *awr)
Definition: AW_preset.cxx:686
gc_range(const string &name_, gc_range_type type_, int index_, int gc_index_)
Definition: AW_preset.cxx:256
const char * rgbValue(bool for_edit4)
Definition: AW_preset.cxx:104
AW_gc_manager * AW_manage_GC(AW_window *aww, const char *gc_base_name, AW_device *device, int base_drag, AW_GCM_AREA area, const GcChangedCallback &changecb, const char *default_background_color,...)
Definition: AW_preset.cxx:971
#define ARRAY_ELEMS(array)
Definition: arb_defs.h:19
#define AWAR_CV_S
Definition: AW_preset.cxx:1640
void update_option_menu()
#define AWAR_CV_B
Definition: AW_preset.cxx:1638
gc_range_type
Definition: AW_preset.cxx:238
void aw_set_color(AW_root *awr, const char *color_name)
Definition: AW_preset.cxx:1663
static void AW_popup_gc_color_groups_window(AW_window *aww, AW_gc_manager *gcmgr)
Definition: AW_preset.cxx:1261
AW_awar * add_callback(const RootCallback &cb)
Definition: AW_awar.cxx:231
#define AWAR_CV_H
Definition: AW_preset.cxx:1639
const int GC_INVALID
Definition: AW_preset.cxx:136
const char * ascii() const
Definition: AW_rgb.cxx:56
const char * AW_get_color_groups_active_awarname()
Definition: AW_preset.cxx:1173
static HelixNrInfo * start
const char * default_colorgroup_name(int color_group)
Definition: AW_preset.cxx:130
const char * rgb_e4
Definition: AW_preset.cxx:89
bool same_line
Definition: AW_preset.cxx:174
GB_ERROR GB_check_hkey(const char *key) __ATTR__USERESULT
Definition: adstring.cxx:92
static FullNameMap names
const char * read_char_pntr() const
Definition: AW_awar.cxx:168
GcChange
Definition: aw_base.hxx:94
#define AW_PLANAR_COLORS
#define DEF_FONTSIZE
Definition: aw_def.hxx:22
static void create_font_button(AW_window *aws, const char *gc_base_name, const gc_desc &gcd)
Definition: AW_preset.cxx:1194
static AW_root * SINGLETON
Definition: aw_root.hxx:102
double AW_pos
Definition: aw_base.hxx:29
int AW_get_drag_gc(AW_gc_manager *gcman)
Definition: AW_preset.cxx:1382
static const int COLOR_BUTTON_LEN
Definition: AW_preset.cxx:1204
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
#define TEST_EXPECT(cond)
Definition: test_unit.h:1328
void update_all_fonts(bool sizeChanged) const
Definition: AW_preset.cxx:483
float g() const
Definition: aw_rgb.hxx:95
void set_font(int gc, AW_font fontnr, int size, int *found_size)
Definition: AW_device.cxx:458
#define AWAR_SELECTOR_COLOR_LABEL
Definition: AW_preset.cxx:1634
std::map< AW_gc_manager *, AW_window_simple * > GroupWindowRegistry
Definition: AW_preset.cxx:1259
static void popup_color_chooser_window(AW_window *aww, const char *awar_name, const char *color_description)
Definition: AW_preset.cxx:1721
void set_foreground_color(int gc, AW_color_idx color)
Definition: AW_device.cxx:471
static void active_range_changed_cb(AW_root *awr, AW_gc_manager *gcman)
Definition: AW_preset.cxx:784
static const char * default_color(int cset, int elem)
int get_color_index() const
Definition: AW_preset.cxx:189
const char * awarname(const char *awarname_template, int idx)
Definition: ED4_flags.cxx:37
void set_changed_cb(const GcChangedCallback &ccb)
Definition: AW_preset.cxx:386
static bool color_groups_initialized()
Definition: AW_preset.cxx:338
int size() const
Definition: AW_preset.cxx:364
AW_awar * awar_float(const char *var_name, float default_value=0.0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:574
string colorlabel
Definition: AW_preset.cxx:170
void new_gc(int gc)
Definition: AW_device.cxx:449
#define true
Definition: ureadseq.h:14
void AW_save_properties(AW_window *aw)
Definition: AW_preset.cxx:1457
#define aw_assert(bed)
Definition: aw_position.hxx:29
static void all_fontsOrSizes_changed_cb(AW_root *, const AW_gc_manager *mgr, bool sizeChanged)
Definition: AW_preset.cxx:505
#define false
Definition: ureadseq.h:13
void fake_AW_init_color_groups()
#define AWAR_SELECTOR_FONT_NAME
Definition: AW_preset.cxx:1810
static void aw_set_sliders_from_color(AW_root *awr)
Definition: AW_preset.cxx:1658
AW_window * AW_create_gc_window(AW_root *aw_root, AW_gc_manager *gcman)
Definition: AW_preset.cxx:1378
AW_rgb_normalized rgb() const
Definition: AW_preset.cxx:1502
float h() const
Definition: AW_preset.cxx:1522
const char * parse_decl(const char *decl, const char *id_prefix)
Definition: AW_preset.cxx:207
void touch()
Definition: AW_awar.cxx:207
static void error(const char *msg)
Definition: mkptypes.cxx:96
static void aw_create_colorslider_awars(AW_root *awr)
Definition: AW_preset.cxx:1707
gc_type
Definition: AW_preset.cxx:140
static bool color_value_change_was_ignored
Definition: AW_preset.cxx:1645
const char * fontname_awarname(const char *gcman_id, const string &colname)
Definition: AW_preset.cxx:79
float b() const
Definition: aw_rgb.hxx:96
void add_gc_range(const char *gc_description)
Definition: AW_preset.cxx:728
AW_window * AW_preset_window(AW_root *root)
Definition: AW_preset.cxx:1925
#define CONSTEXPR_INLINE
Definition: cxxforward.h:111
void label(const char *label)
Definition: AW_window.cxx:111
int build_range_gc_number(int range_idx, int color_idx)
Definition: AW_preset.cxx:149
const char * rgb_nt
Definition: AW_preset.cxx:88
AW_hsv(const AW_rgb16 &col)
Definition: AW_preset.cxx:1499
static void add_common_property_menu_entries(AW_window *aw)
Definition: AW_preset.cxx:1445
static void create_font_chooser_awars(AW_root *awr)
Definition: AW_preset.cxx:1813
const int GC_BACKGROUND
Definition: AW_preset.cxx:135
const char * description
Definition: AW_preset.cxx:87
static const char ** color_group_defaults
Definition: AW_preset.cxx:333
float v() const
Definition: AW_preset.cxx:1524
gc_desc(int gc_, gc_type type_)
Definition: AW_preset.cxx:177
void AW_copy_GC_colors(AW_root *aw_root, const char *source_gcman, const char *dest_gcman, const char *id0,...)
Definition: AW_preset.cxx:1092
int get_drag_gc() const
Definition: AW_preset.cxx:370
char * read_string() const
Definition: AW_awar.cxx:198
static bool show_range_overlay
Definition: AW_preset.cxx:336
const char * get_current_color(int idx) const
Definition: AW_preset.cxx:411
#define AW_COLOR_GROUP_NAME_LEN
const char * gcman_specific_awarname(const char *tpl, const char *gcman_id, const char *localpart)
Definition: AW_preset.cxx:63
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:568
void AW_reactivate_all_questions(AW_window *)
bool has_font
Definition: AW_preset.cxx:172
void getColorRangeNames(int dimension, ConstStrArray &ids, ConstStrArray &names) const
Definition: AW_preset.cxx:814
string name2ID(const char *name)
Definition: AW_preset.cxx:154
va_end(argPtr)
#define RANGE_INDEX_BITS
Definition: AW_preset.cxx:146
float read_float() const
Definition: AW_awar.cxx:177
void trigger_changed_cb(GcChange whatChanged) const
Definition: AW_preset.cxx:387
void insert_default_option(AW_label choice_label, const char *mnemonic, const char *var_value, const char *name_of_color=NULp)
#define AWAR_SELECTOR_FONT_SIZE
Definition: AW_preset.cxx:1811
char * AW_get_color_group_name(AW_root *awr, int color_group)
Definition: AW_preset.cxx:1178
long int flag
Definition: f2c.h:39
void delay_changed_callbacks(bool suppress) const
Definition: AW_preset.cxx:399
#define ATPL_GCMAN_LOCAL
Definition: AW_preset.cxx:47
static const int STD_LABEL_LEN
Definition: AW_preset.cxx:1203
static ColorGroupDef color_group_def[AW_COLOR_GROUPS+1]
Definition: AW_preset.cxx:109
int get_dimension() const
Definition: AW_preset.cxx:273
void create_input_field(const char *awar_name, int columns=0)
Definition: AW_button.cxx:857
gc_range_type get_type() const
Definition: AW_preset.cxx:272
const char * colorgroupname_awarname(int color_group)
Definition: AW_preset.cxx:126
AW_awar * awar_int(const char *var_name, long default_value=0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:594
void AW_displayColorRange(AW_device *device, int first_range_gc, AW::Position start, AW_pos xsize, AW_pos ysize)
Definition: AW_preset.cxx:1386
void activateColorRange(const char *id)
Definition: AW_preset.cxx:795
#define IF_ASSERTION_USED(x)
Definition: arb_assert.h:308
void AW_getColorRangeNames(const AW_gc_manager *gcman, int dimension, ConstStrArray &ids, ConstStrArray &names)
Definition: AW_preset.cxx:1411
#define NO_FONT
Definition: AW_preset.cxx:52
void update_gc_color(int idx) const
Definition: AW_preset.cxx:667
#define AW_RANGE_COLORS
const char * getActiveColorRangeID(int *dimension) const
Definition: AW_preset.cxx:807
bool is_color_group() const
Definition: AW_preset.cxx:185
bool has_color_groups() const
Definition: AW_preset.cxx:361
static const int FONT_BUTTON_LEN
Definition: AW_preset.cxx:1205
AW_gc_manager(const char *name, AW_device *device_, int drag_gc_offset_, AW_window *aww_, int colorindex_base_)
Definition: AW_preset.cxx:340
#define MAX_FONTSIZE
Definition: aw_def.hxx:23
AW_awar * map(const char *awarn)
Definition: AW_awar.cxx:521
void init_all_fonts() const
Definition: AW_preset.cxx:927
static void aw_message_reload(AW_root *)
Definition: AW_preset.cxx:1891
va_start(argPtr, format)
static void color_group_use_changed_cb(AW_root *awr, AW_gc_manager *gcmgr)
Definition: AW_preset.cxx:710
const char * get_base_name() const
Definition: AW_preset.cxx:369
#define abs(x)
Definition: f2c.h:151
#define ATPL_GC_LOCAL
Definition: AW_preset.cxx:48
STATIC_ASSERT(AW_PLANAR_COLORS *AW_PLANAR_COLORS==AW_RANGE_COLORS)
void aw_message(const char *msg)
Definition: AW_status.cxx:1142
AW_option_menu_struct * create_option_menu(const char *awar_name)
void AW_save_specific_properties(AW_window *aw, const char *filename)
Definition: AW_preset.cxx:1453
void active_range_changed_cb(AW_root *awr)
Definition: AW_preset.cxx:771
AW_root * get_root()
Definition: aw_window.hxx:359
gc_type type
Definition: AW_preset.cxx:175
#define NULp
Definition: cxxforward.h:116
static bool use_color_groups
Definition: AW_preset.cxx:335
#define AWAR_CV_G
Definition: AW_preset.cxx:1637
AW_GCM_AREA
Definition: aw_preset.hxx:37
int first_range_gc() const
Definition: AW_preset.cxx:359
GB_ERROR write_string(const char *aw_string)
#define offset(field)
Definition: GLwDrawA.c:73
float r() const
Definition: aw_rgb.hxx:94
#define AWAR_RANGE_OVERLAY
Definition: AW_preset.cxx:43
void update_range_gc_color(int idx, const char *color) const
Definition: AW_preset.cxx:380
#define RANGE_INDEX_MASK
Definition: AW_preset.cxx:147
#define MIN_FONTSIZE
Definition: aw_def.hxx:21
static void create_color_button(AW_window *aws, const char *awar_name, const char *color_description)
Definition: AW_preset.cxx:1184
void AW_init_color_group_defaults(const char *for_program)
Definition: AW_preset.cxx:1115
void update_gc_font(int idx) const
Definition: AW_preset.cxx:431
void callback(const WindowCallback &cb)
Definition: AW_window.cxx:142
bool box(int gc, AW::FillStyle filled, const AW::Rectangle &rect, AW_bitset filteri=AW_ALL_DEVICES_SCALED)
Definition: aw_device.hxx:471
#define BUFSIZE
Definition: trnsprob.h:20
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:584
GB_ERROR write_float(float aw_float)
AW_hsv(const AW_rgb_normalized &col)
Definition: AW_preset.cxx:1472
#define AWAR_CV_R
Definition: AW_preset.cxx:1636
const char * gc_awarname(const char *tpl, const char *gcman_id, const string &colname)
Definition: AW_preset.cxx:71
#define min(a, b)
Definition: f2c.h:153
#define AW_SPATIAL_COLORS
void label_length(int length)
Definition: AW_at.cxx:284
void GBT_splitNdestroy_string(ConstStrArray &names, char *&namelist, const char *separator, SplitMode mode)
void at_newline()
Definition: AW_at.cxx:119
void update_colors(const AW_gc_manager *gcman) const
Definition: AW_preset.cxx:549
static void AW_preset_create_font_chooser(AW_window *aws, const char *awar, const char *label, bool message_reload)
Definition: AW_preset.cxx:1897
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1294
GB_ERROR write_int(long aw_int)
AW_color_idx alloc_named_data_color(int colnum, const char *colorname)
Definition: AW_window.cxx:2092
const char * AW_get_font_shortname(AW_font font_nr)
Definition: AW_xfont.cxx:719
const char * gcman_awarname(const char *gcman_id, const char *localpart)
Definition: AW_preset.cxx:74
size_t get_position() const
Definition: arb_strbuf.h:112
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
const char * label
void put(char c)
Definition: arb_strbuf.h:174
string key
Definition: AW_preset.cxx:171
void create_button(const char *macro_name, AW_label label, const char *mnemonic=NULp, const char *color=NULp)
Definition: AW_button.cxx:448
#define AW_COLOR_GROUP_PREFIX
int AW_getFirstRangeGC(AW_gc_manager *gcman)
Definition: AW_preset.cxx:1423
const char * color_awarname(const char *gcman_id, const string &colname)
Definition: AW_preset.cxx:78
CONSTEXPR_INLINE bool valid_color_group(int color_group)
Definition: AW_preset.cxx:59
GB_write_int const char s
Definition: AW_awar.cxx:154
#define max(a, b)
Definition: f2c.h:154