ARB
AW_button.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : AW_button.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include "aw_at.hxx"
12 #include "aw_select.hxx"
13 #include "aw_awar.hxx"
14 #include "aw_window_Xm.hxx"
15 #include "aw_msg.hxx"
16 #include "aw_root.hxx"
17 #include "aw_xargs.hxx"
18 #include "aw_varupdate.hxx"
19 #include "aw_localdef.hxx"
20 
21 #include <arb_algo.h>
22 #include <ad_cb.h>
23 
24 #include <Xm/Frame.h>
25 #include <Xm/ToggleB.h>
26 #include <Xm/Label.h>
27 #include <Xm/List.h>
28 #include <Xm/PushB.h>
29 #include <Xm/Text.h>
30 #include <Xm/TextF.h>
31 #include <Xm/ScrolledW.h>
32 #include <Xm/Scale.h>
33 
34 void AW_variable_update_callback(Widget /*wgt*/, XtPointer variable_update_struct, XtPointer call_data) {
35  VarUpdateInfo *vui = (VarUpdateInfo *) variable_update_struct;
36  aw_assert(vui);
37 
38  vui->change_from_widget(call_data);
39 }
40 
43  bool changed;
44 
45  TrackedAwarChange(AW_awar *awar_) : awar(awar_), changed(false) {}
46 };
47 
49  aw_assert(cb_type == GB_CB_CHANGED);
50  aw_assert(tac->awar->gb_var == gbd);
51  tac->changed = true;
52 }
53 
54 #define SCALER_MIN_VALUE 0
55 #define SCALER_MAX_VALUE 1000
56 
57 static int calculate_scaler_value(AW_awar *awar, AW_ScalerType scalerType) {
58  float modAwarRel = AW_ScalerTransformer(scalerType).awar2scaler(awar);
59  int scalerValue = SCALER_MIN_VALUE + modAwarRel * (SCALER_MAX_VALUE-SCALER_MIN_VALUE);
60 
61  return scalerValue;
62 }
63 
64 static void write_scalervalue_to_awar(int scalerVal, AW_awar *awar, AW_ScalerType scalerType) {
65  float scaleRel = scalerVal/double(SCALER_MAX_VALUE-SCALER_MIN_VALUE);
66  aw_assert(scaleRel>=0.0 && scaleRel<=1.0);
67 
68  float aval = AW_ScalerTransformer(scalerType).scaler2awar(scaleRel, awar);
69 
70  switch (awar->variable_type) {
71  case AW_FLOAT:
72  awar->write_float(aval);
73  break;
74 
75  case AW_INT:
76  awar->write_int(aval);
77  break;
78 
79  default:
80  GBK_terminatef("Unsupported awar type %i in write_scalervalue_to_awar", int(awar->variable_type));
81  break;
82  }
83 }
84 
85 void VarUpdateInfo::change_from_widget(XtPointer call_data) {
87 
89  AW_root *root = awar->root;
90 
91  if (root->value_changed) {
92  root->changer_of_variable = widget;
93  }
94 
95  TrackedAwarChange tac(awar);
96  if (root->is_tracking()) {
97  // add a callback which writes macro-code (BEFORE any other callback happens; last added, first calledback)
98  GB_transaction ta(awar->gb_var);
99  GB_add_callback(awar->gb_var, GB_CB_CHANGED, makeDatabaseCallback(track_awar_change_cb, &tac));
100  }
101 
102  bool run_cb = true;
103  switch (widget_type) {
106  if (!root->value_changed) {
107  run_cb = false;
108  }
109  else {
110  char *new_text = XmTextGetString((widget));
111  error = awar->write_as_string(new_text);
112  XtFree(new_text);
113  }
114  break;
115 
116  case AW_WIDGET_TOGGLE:
117  root->changer_of_variable = NULp;
118  error = awar->toggle_toggle();
119  break;
120 
122  if (XmToggleButtonGetState(widget) == False) break; // no toggle is selected (?)
123  // fall-through
125  error = value.write_to(awar);
126  break;
127 
129  AW_selection_list_entry *entry = ts.sellist->list_table;
130  {
131  int incr = reinterpret_cast<XmListCallbackStruct*>(call_data)->item_position; // [1..N]
132  while (entry && --incr>0) entry = entry->next;
133  }
134  if (!entry) {
135  entry = ts.sellist->default_select; // use default selection
136  if (!entry) GBK_terminate("no default specified for selection list"); // or die
137  }
138  entry->get_value().write_to(awar);
139  break;
140  }
141 
143  break;
144 
145  case AW_WIDGET_SCALER: {
146  XmScaleCallbackStruct *xms = (XmScaleCallbackStruct*)call_data;
147  write_scalervalue_to_awar(xms->value, awar, ts.scalerType);
148  break;
149  }
150  default:
151  GBK_terminatef("Unknown widget type %i in AW_variable_update_callback", widget_type);
152  break;
153  }
154 
155  if (root->is_tracking()) {
156  {
157  GB_transaction ta(awar->gb_var);
158  GB_remove_callback(awar->gb_var, GB_CB_CHANGED, makeDatabaseCallback(track_awar_change_cb, &tac));
159  }
160  if (tac.changed) {
161  root->track_awar_change(awar);
162  }
163  }
164 
165  if (error) {
166  root->changer_of_variable = NULp;
167  awar->update();
168  aw_message(error);
169  }
170  else {
171  if (cbs && run_cb) cbs->run_callbacks(); // @@@ generally unwanted callback (see #559)
172  root->value_changed = false;
173 
174  aw_message_if(GB_incur_error()); // show error exported by awar-change-callback
175  }
176 
177  AW_cb::useraction_done(aw_parent);
178 }
179 
180 
181 static void AW_value_changed_callback(Widget /*wgt*/, XtPointer rooti, XtPointer /*call_data*/) {
182  AW_root *root = (AW_root *)rooti;
183  root->value_changed = true;
184 }
185 
186 void aw_attach_widget(Widget w, AW_at *_at, int default_width) {
187  short height = 0;
188  short width = 0;
189  if (!_at->to_position_exists) {
190  XtVaGetValues(w, XmNheight, &height, XmNwidth, &width, NULp);
191  if (default_width >0) width = default_width;
192 
193  switch (_at->correct_for_at_center) {
194  case 0: // left justified
195  _at->to_position_x = _at->x_for_next_button + width;
196  break;
197  case 1: // centered
198  _at->to_position_x = _at->x_for_next_button + width/2;
199  _at->x_for_next_button -= width/2;
200  break;
201  case 2: // right justified
202  _at->to_position_x = _at->x_for_next_button;
203  _at->x_for_next_button -= width;
204  break;
205  }
206  _at->to_position_y = _at->y_for_next_button + height;
207  _at->attach_x = _at->attach_lx;
208  _at->attach_y = _at->attach_ly;
209  }
210 
211 #define MIN_RIGHT_OFFSET 10
212 #define MIN_BOTTOM_OFFSET 10
213 
214  aw_xargs args(4*2);
215 
216  if (_at->attach_x) {
217  int right_offset = _at->max_x_size - _at->to_position_x;
218  if (right_offset<MIN_RIGHT_OFFSET) {
219  right_offset = MIN_RIGHT_OFFSET;
220  _at->max_x_size = _at->to_position_x+right_offset;
221  }
222 
223  args.add(XmNrightAttachment, XmATTACH_FORM);
224  args.add(XmNrightOffset, right_offset);
225  }
226  else {
227  args.add(XmNrightAttachment, XmATTACH_OPPOSITE_FORM);
228  args.add(XmNrightOffset, -_at->to_position_x);
229  }
230 
231  if (_at->attach_lx) {
232  args.add(XmNleftAttachment, XmATTACH_NONE);
233  args.add(XmNwidth, _at->to_position_x - _at->x_for_next_button);
234  }
235  else {
236  args.add(XmNleftAttachment, XmATTACH_FORM);
237  args.add(XmNleftOffset, _at->x_for_next_button);
238  }
239 
240  if (_at->attach_y) {
241  int bottom_offset = _at->max_y_size - _at->to_position_y;
242  if (bottom_offset<MIN_BOTTOM_OFFSET) {
243  bottom_offset = MIN_BOTTOM_OFFSET;
244  _at->max_y_size = _at->to_position_y+bottom_offset;
245  }
246 
247  args.add(XmNbottomAttachment, XmATTACH_FORM);
248  args.add(XmNbottomOffset, bottom_offset);
249  }
250  else {
251  args.add(XmNbottomAttachment, XmATTACH_OPPOSITE_FORM);
252  args.add(XmNbottomOffset, - _at->to_position_y);
253  }
254  if (_at->attach_ly) {
255  args.add(XmNtopAttachment, XmATTACH_NONE);
256  args.add(XmNheight, _at->to_position_y - _at->y_for_next_button);
257  }
258  else {
259  args.add(XmNtopAttachment, XmATTACH_FORM);
260  args.add(XmNtopOffset, _at->y_for_next_button);
261  }
262 
263  args.assign_to_widget(w);
264 }
265 
266 const char *AW_get_pixmapPath(const char *pixmapName) {
267  const char *pixmapsDir = "motifHack/pixmaps"; // see ../lib/motifHack/README
268 
269  return GB_concat_path_in_ARBLIB(pixmapsDir, pixmapName);
270 }
271 
272 static char *pixmapPath(const char *pixmapName) {
273  return nulldup(AW_get_pixmapPath(pixmapName));
274 }
275 
276 
277 #define MAX_LINE_LENGTH 200
278 __ATTR__USERESULT static GB_ERROR detect_bitmap_size(const char *pixmapname, int *width, int *height) {
279  GB_ERROR err = NULp;
280 
281  *width = 0;
282  *height = 0;
283 
284  char *path = pixmapPath(pixmapname);
285  FILE *in = fopen(path, "rt");
286  if (in) {
287  const char *subdir = strrchr(pixmapname, '/');
288  char *name = strdup(subdir ? subdir+1 : pixmapname);
289  {
290  char *dot = strrchr(name, '.');
291  if (dot) dot[0] = 0;
292  else err = "'.' expected";
293  }
294  int namelen = strlen(name);
295  char buffer[MAX_LINE_LENGTH];
296  bool done = false;
297 
298  while (!done && !err) {
299  if (!fgets(buffer, MAX_LINE_LENGTH, in)) {
300  err = GB_IO_error("reading", pixmapname);
301  }
302  else if (strchr(buffer, 0)[-1] != '\n') {
303  err = GBS_global_string("Line too long ('%s')", buffer); // increase MAX_LINE_LENGTH above
304  }
305  else if (strncmp(buffer, "#define", 7) != 0) {
306  done = true;
307  }
308  else {
309  char *name_pos = strstr(buffer+7, name);
310  if (name_pos) {
311  char *behind = name_pos+namelen;
312  if (strncmp(behind, "_width ", 7) == 0) *width = atoi(behind+7);
313  else if (strncmp(behind, "_height ", 8) == 0) *height = atoi(behind+8);
314  }
315  }
316  }
317 
318  if (done && ((*width == 0) || (*height == 0))) {
319  if (strstr(buffer, "XPM")) {
320  if (!fgets(buffer, MAX_LINE_LENGTH, in) || !fgets(buffer, MAX_LINE_LENGTH, in)) {
321  err = GB_IO_error("reading", pixmapname);
322  }
323  else {
324  char *temp = strtok(buffer+1, " ");
325  *width = atoi(temp);
326  temp = strtok(NULp, " ");
327  *height = atoi(temp);
328  }
329  }
330  else {
331  err = "can't detect size";
332  }
333  }
334 
335  free(name);
336  fclose(in);
337  }
338  else {
339  err = "no such file";
340  }
341 
342  if (err) {
343  err = GBS_global_string("%s: %s", pixmapname, err);
344  }
345 
346 #if defined(DUMP_BUTTON_CREATION)
347  printf("Bitmap '%s' has size %i/%i\n", pixmapname, *width, *height);
348 #endif // DUMP_BUTTON_CREATION
349 
350  free(path);
351  return err;
352 }
353 #undef MAX_LINE_LENGTH
354 
355 inline void calculate_textsize(const char *str, int *width, int *height) {
356  int textwidth = 0;
357  int textheight = 1;
358  int linewidth = 0;
359 
360  for (int p = 0; str[p]; ++p) {
361  if (str[p] == '\n') {
362  if (linewidth>textwidth) textwidth = linewidth;
363 
364  linewidth = 0;
365  textheight++;
366  }
367  else {
368  linewidth++;
369  }
370  }
371 
372  if (linewidth>textwidth) textwidth = linewidth;
373 
374  *width = textwidth;
375  *height = textheight;
376 }
377 
378 void AW_window::calculate_label_size(int *width, int *height, bool in_pixel) {
379  // in_pixel == true -> calculate size in pixels
380  // in_pixel == false -> calculate size in characters
381 
382  const char *label_ = _at->label_for_inputfield;
383  if (label_) {
384  aw_assert(label_[0]); // empty string is not allowed as label!
385 
386  calculate_textsize(label_, width, height);
388  *width = _at->length_of_label_for_inputfield;
389  }
390  if (in_pixel) {
391  *width = calculate_string_width(*width);
392  *height = calculate_string_height(*height, 0);
393  }
394  }
395  else {
396  *width = 0;
397  *height = 0;
398  }
399 }
400 
402  return p_global->get_last_widget();
403 }
404 
405 void aw_detect_text_size(const char *text, size_t& width, size_t& height) {
406  size_t text_width = strcspn(text, "\n");
407 
408  if (text[text_width]) {
409  aw_assert(text[text_width] == '\n');
410 
411  aw_detect_text_size(text+text_width+1, width, height);
412  if (text_width>width) width = text_width;
413  height++;
414  }
415  else { // EOS
416  width = text_width;
417  height = 1;
418  }
419 }
420 
421 void AW_window::create_autosize_button(const char *macro_name, AW_label buttonlabel, const char *mnemonic, unsigned xtraSpace) {
422  aw_assert(!AW_IS_IMAGEREF(buttonlabel)); // use create_button for graphical buttons!
423  aw_assert(!_at->to_position_exists); // wont work if to-position exists
424 
425  AW_awar *is_awar = get_root()->label_is_awar(buttonlabel);
426  size_t width, height;
427  if (is_awar) {
428  char *content = is_awar->read_as_string();
429  aw_assert(content[0]); /* you need to fill the awar before calling create_autosize_button,
430  * otherwise size cannot be detected */
431  aw_detect_text_size(content, width, height);
432  }
433  else {
434  aw_detect_text_size(buttonlabel, width, height);
435  }
436 
437  int len = width+(xtraSpace*2);
438  short length_of_buttons = _at->length_of_buttons;
439  short height_of_buttons = _at->height_of_buttons;
440 
441  _at->length_of_buttons = len+1;
442  _at->height_of_buttons = height;
443  create_button(macro_name, buttonlabel, mnemonic);
444  _at->length_of_buttons = length_of_buttons;
445  _at->height_of_buttons = height_of_buttons;
446 }
447 
448 void AW_window::create_button(const char *macro_name, AW_label buttonlabel, const char */*mnemonic*/, const char *color) {
449  // Create a button or text display.
450  //
451  // If a callback is bound via at->callback(), a button is created.
452  // Otherwise a text display is created.
453  //
454  // if buttonlabel starts with '#' the rest of buttonlabel is used as name of pixmap file used for button
455  // if buttonlabel contains a '/' it's interpreted as AWAR name and the button displays the content of the awar
456  // otherwise buttonlabel is interpreted as button label (may contain '\n').
457  //
458  // Note 1: Button width 0 does not work together with labels!
459 
460  // Note 2: "color" may be specified for the button background (see TuneOrSetBackground for details)
461 
462  TuneOrSetBackground(_at->attach_any ? INFO_FORM : INFO_WIDGET, // set background for buttons / text displays
463  color,
464  _callback ? TUNE_BUTTON : 0);
465 
466 #if defined(DUMP_BUTTON_CREATION)
467  printf("------------------------------ Button '%s'\n", buttonlabel);
468  printf("x_for_next_button=%i y_for_next_button=%i\n", _at->x_for_next_button, _at->y_for_next_button);
469 #endif // DUMP_BUTTON_CREATION
470 
471  if (_callback && ((long)_callback != 1)) {
472  if (macro_name) {
473  _callback->id = GBS_global_string_copy("%s/%s", this->window_defaults_name, macro_name);
475  }
476  else {
477  _callback->id = NULp;
478  }
479  }
480 #if defined(DEVEL_RALF) && 1
481  else {
482  aw_assert(!macro_name); // please pass NULp for buttons w/o callback
483  }
484 #endif
485 
486 #define SPACE_BEHIND_LABEL 10
487 
488 #define BUTTON_TEXT_X_PADDING 4
489 #define BUTTON_TEXT_Y_PADDING 10
490 
491 #define BUTTON_GRAPHIC_PADDING 12
492 #define FLAT_GRAPHIC_PADDING 4 // for buttons w/o callback
493 
494  bool is_graphical_button = AW_IS_IMAGEREF(buttonlabel);
495 
496 #if defined(ASSERTION_USED)
497  AW_awar *is_awar = is_graphical_button ? NULp : get_root()->label_is_awar(buttonlabel);
498 #endif // ASSERTION_USED
499 
500  int width_of_button = -1, height_of_button = -1;
501 
502  int width_of_label, height_of_label;
503  calculate_label_size(&width_of_label, &height_of_label, true);
504  int width_of_label_and_spacer = _at->label_for_inputfield ? width_of_label+SPACE_BEHIND_LABEL : 0;
505 
506  bool let_motif_choose_size = false;
507 
508  if (_at->to_position_exists) { // size has explicitly been specified in xfig -> calculate
509  width_of_button = _at->to_position_x - _at->x_for_next_button - width_of_label_and_spacer;
510  height_of_button = _at->to_position_y - _at->y_for_next_button;
511  }
512  else if (_at->length_of_buttons) { // button width specified from client code
513  width_of_button = BUTTON_TEXT_X_PADDING + calculate_string_width(_at->length_of_buttons+1);
514 
515  if (!is_graphical_button) {
516  if (_at->height_of_buttons) { // button height specified from client code
517  height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(_at->height_of_buttons, 0);
518  }
519  else {
520  int textwidth, textheight;
521  calculate_textsize(buttonlabel, &textwidth, &textheight);
522  height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
523  }
524  }
525  else {
526  height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(1, 0);
527  }
528  }
529  else { // no button_length() specified
530  aw_assert(!is_awar); // please specify button_length() for AWAR button!
531 
532  if (is_graphical_button) {
533  int width, height;
534  GB_ERROR err = detect_bitmap_size(buttonlabel+1, &width, &height);
535 
536  if (!err) {
538 
539  width_of_button = width+gpadding;
540  height_of_button = height+gpadding;
541  }
542  else {
543  err = GBS_global_string("button gfx error: %s", err);
544  aw_message(err);
545  let_motif_choose_size = true;
546  }
547  }
548  else {
549  int textwidth, textheight;
550  calculate_textsize(buttonlabel, &textwidth, &textheight);
551 
552  width_of_button = BUTTON_TEXT_X_PADDING + calculate_string_width(textwidth+1);
553  height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
554  }
555  }
556 
557  if (!let_motif_choose_size) {
558  if (height_of_button<height_of_label) height_of_button = height_of_label;
559  aw_assert(width_of_button && height_of_button);
560  }
561 
562  int x_label = _at->x_for_next_button;
563  int y_label = _at->y_for_next_button;
564  int x_button = x_label + width_of_label_and_spacer;
565  int y_button = y_label;
566 
567  int org_correct_for_at_center = _at->correct_for_at_center; // store original justification
568  int org_y_for_next_button = _at->y_for_next_button; // store original y pos (modified while creating label)
569 
570  if (!let_motif_choose_size) { // don't correct position of button w/o known size
571  // calculate justification manually
572 
573  int width_of_button_and_highlight = width_of_button + (_at->highlight ? 2*(_at->shadow_thickness+1)+1 : 0);
574  int width_of_label_and_button = width_of_label_and_spacer+width_of_button_and_highlight;
575 
576  if (_at->correct_for_at_center) { // not if left justified
577  int shiftback = width_of_label_and_button; // shiftback for right justification
578  if (_at->correct_for_at_center == 1) { // center justification
579  shiftback /= 2;
580  }
581  x_label -= shiftback;
582  x_button -= shiftback;
583  }
584 
585  // we already did the justification by calculating all positions manually, so..
586  _at->correct_for_at_center = 0; // ..from now on act like "left justified"!
587  }
588 
589  // correct label Y position
590  if (_callback) { // only if button is a real 3D-button
591  y_label += (height_of_button-height_of_label)/2;
592  }
593 
594  Widget parent_widget = (_at->attach_any) ? INFO_FORM : INFO_WIDGET;
596 
597  if (_at->label_for_inputfield) {
598  _at->x_for_next_button = x_label;
599  _at->y_for_next_button = y_label;
600 
601  Label clientlabel(_at->label_for_inputfield, this);
602  label_widget = XtVaCreateManagedWidget("label",
603  xmLabelWidgetClass,
604  parent_widget,
605  XmNwidth, (int)(width_of_label + 2),
606  RES_LABEL_CONVERT(clientlabel),
607  XmNrecomputeSize, false,
608  XmNalignment, XmALIGNMENT_BEGINNING,
609  XmNfontList, p_global->fontlist,
610  XmNx, (int)(x_label),
611  XmNy, (int)(y_label),
612  NULp);
613 
614  if (_at->attach_any) aw_attach_widget(label_widget, _at);
615  AW_label_in_awar_list(this, label_widget, _at->label_for_inputfield);
616  }
617 
618  _at->x_for_next_button = x_button;
619  _at->y_for_next_button = y_button;
620 
621  Widget fatherwidget = parent_widget; // used as father for button below
622  if (_at->highlight) {
623  if (_at->attach_any) {
624 #if defined(DEBUG)
625  printf("Attaching highlighted buttons does not work - "
626  "highlight ignored for button '%s'!\n", buttonlabel);
627 #endif // DEBUG
628  _at->highlight = false;
629  }
630  else {
631  int shadow_offset = _at->shadow_thickness;
632  int x_shadow = x_button - shadow_offset;
633  int y_shadow = y_button - shadow_offset;
634 
635  fatherwidget = XtVaCreateManagedWidget("draw_area",
636  xmFrameWidgetClass,
637  INFO_WIDGET,
638  XmNx, (int)(x_shadow),
639  XmNy, (int)(y_shadow),
640  XmNshadowType, XmSHADOW_IN,
641  XmNshadowThickness, _at->shadow_thickness,
642  NULp);
643  }
644  }
645 
646  Widget button = NULp;
647 
648  {
649  aw_xargs args(9);
650  args.add(XmNx, x_button);
651  args.add(XmNy, y_button);
652 
653  args.add(XmNfontList, (XtArgVal)p_global->fontlist);
654  args.add(XmNbackground, _at->background_color);
655 
656  if (!let_motif_choose_size) {
657  args.add(XmNwidth, width_of_button);
658  args.add(XmNheight, height_of_button);
659  }
660 
661  Label buttonLabel(buttonlabel, this);
662  if (_callback) {
663  args.add(XmNshadowThickness, _at->shadow_thickness);
664  args.add(XmNalignment, XmALIGNMENT_CENTER);
665 
666  button = XtVaCreateManagedWidget("button", xmPushButtonWidgetClass, fatherwidget, RES_LABEL_CONVERT(buttonLabel), NULp);
667  }
668  else { // button w/o callback; (flat, not clickable)
669  button = XtVaCreateManagedWidget("label", xmLabelWidgetClass, parent_widget, RES_LABEL_CONVERT(buttonLabel), NULp);
670  args.add(XmNalignment, (org_correct_for_at_center == 1) ? XmALIGNMENT_CENTER : XmALIGNMENT_BEGINNING);
671  }
672 
673  if (!_at->attach_any || !_callback) args.add(XmNrecomputeSize, false);
674  args.assign_to_widget(button);
675  if (_at->attach_any) aw_attach_widget(button, _at);
676 
677  if (_callback) {
678  root->make_sensitive(button, _at->widget_mask);
679  }
680  else {
681  aw_assert(_at->correct_for_at_center == 0);
682  AW_JUSTIFY_LABEL(button, _at->correct_for_at_center); // @@@ strange, again sets XmNalignment (already done above). maybe some relict. does nothing if (_at->correct_for_at_center == 0)
683  }
684 
685  AW_label_in_awar_list(this, button, buttonlabel);
686  }
687 
688  short height = 0;
689  short width = 0;
690 
691  if (_at->to_position_exists) {
692  // size has explicitly been specified in xfig -> calculate
693  height = _at->to_position_y - _at->y_for_next_button;
694  width = _at->to_position_x - _at->x_for_next_button;
695  }
696 
697  {
698  Widget toRecenter = NULp;
699  int recenterSize = 0;
700 
701  if (!height || !width) {
702  // ask motif for real button size
703  Widget ButOrHigh = _at->highlight ? fatherwidget : button;
704  XtVaGetValues(ButOrHigh, XmNheight, &height, XmNwidth, &width, NULp);
705 
706  if (let_motif_choose_size) {
707  if (_at->correct_for_at_center) {
708  toRecenter = ButOrHigh;
709  recenterSize = width;
710  }
711  width = 0; // ignore the used size (because it may use more than the window size)
712  }
713  }
714 
715  if (toRecenter) {
716  int shiftback = 0;
717  switch (_at->correct_for_at_center) {
718  case 1: shiftback = recenterSize/2; break;
719  case 2: shiftback = recenterSize; break;
720  }
721  if (shiftback) {
722  XtVaSetValues(toRecenter, XmNx, x_button-shiftback, NULp);
723  }
724  }
725  }
726 
727  _at->correct_for_at_center = org_correct_for_at_center; // restore original justification
728  _at->y_for_next_button = org_y_for_next_button;
729 
730  p_w->toggle_field = button;
731  this->_set_activate_callback((void *)button);
732  this->unset_at_commands();
733  this->increment_at_commands(width+SPACE_BEHIND_BUTTON, height);
734 }
735 
736 void AW_window::dump_at_position(const char *tmp_label) const {
737  printf("%s at x = %i / y = %i\n", tmp_label, _at->x_for_next_button, _at->y_for_next_button);
738 }
739 
740 void AW_window::update_label(Widget widget, const char *var_value) {
741  if (get_root()->changer_of_variable != widget) {
742  XtVaSetValues(widget, RES_CONVERT(XmNlabelString, var_value), NULp);
743  }
744  else {
746  }
747 }
748 
749 // ----------------------
750 // on/off toggle
751 
754  char *bitmapOrText[2];
755  int buttonWidth; // wanted width in characters
756 };
757 
758 void AW_window::update_toggle(Widget widget, const char *var, AW_CL cd_toggle_data) {
759  aw_toggle_data *tdata = (aw_toggle_data*)cd_toggle_data;
760  const char *text = tdata->bitmapOrText[(var[0] == '0' || var[0] == 'n') ? 0 : 1];
761 
762  if (tdata->isTextToggle) {
763  XtVaSetValues(widget, RES_CONVERT(XmNlabelString, text), NULp);
764  }
765  else {
766  char *path = pixmapPath(text+1);
767  XtVaSetValues(widget, RES_CONVERT(XmNlabelPixmap, path), NULp);
768  free(path);
769  }
770 }
771 
772 void AW_window::create_toggle(const char *var_name, aw_toggle_data *tdata) {
773  AW_cb *cbs = _callback;
774  _callback = (AW_cb *)1;
775 
776  {
777  int old_length_of_buttons = _at->length_of_buttons;
778 
779  if (tdata->buttonWidth == 0) {
780  if (tdata->isTextToggle) {
781  int l1 = strlen(tdata->bitmapOrText[0]);
782  int l2 = strlen(tdata->bitmapOrText[1]);
783 
784  _at->length_of_buttons = l1>l2 ? l1 : l2; // use longer text for button size
785  }
786  else {
787  _at->length_of_buttons = 0;
788  }
789  }
790  else {
791  _at->length_of_buttons = tdata->buttonWidth;
792  }
793 
794  create_button(NULp, tdata->bitmapOrText[0]);
795 
796  _at->length_of_buttons = old_length_of_buttons;
797  }
798 
799  AW_awar *vs = this->get_root()->awar(var_name);
800  {
801  char *var_value = vs->read_as_string();
802 
803  this->update_toggle(p_w->toggle_field, var_value, (AW_CL)tdata);
804  free(var_value);
805  }
806 
807  VarUpdateInfo *vui;
808  vui = new VarUpdateInfo(this, p_w->toggle_field, AW_WIDGET_TOGGLE, vs, cbs);
809 
810  XtAddCallback(p_w->toggle_field, XmNactivateCallback,
811  (XtCallbackProc) AW_variable_update_callback,
812  (XtPointer) vui);
813 
814  vs->tie_widget((AW_CL)tdata, p_w->toggle_field, AW_WIDGET_TOGGLE, this);
815 }
816 
817 
818 void AW_window::create_toggle(const char *var_name, const char *no, const char *yes, int buttonWidth) {
819  aw_toggle_data *tdata = new aw_toggle_data;
820  tdata->isTextToggle = false;
821 
824 
825  tdata->bitmapOrText[0] = strdup(no);
826  tdata->bitmapOrText[1] = strdup(yes);
827 
828  tdata->buttonWidth = buttonWidth;
829 
830  create_toggle(var_name, tdata);
831 }
832 
833 void AW_window::create_text_toggle(const char *var_name, const char *noText, const char *yesText, int buttonWidth) {
834  aw_toggle_data *tdata = new aw_toggle_data;
835  tdata->isTextToggle = true;
836  tdata->bitmapOrText[0] = strdup(noText);
837  tdata->bitmapOrText[1] = strdup(yesText);
838  tdata->buttonWidth = buttonWidth;
839 
840  create_toggle(var_name, tdata);
841 }
842 
843 
844 void AW_window::create_toggle(const char *var_name) {
845  create_toggle(var_name, "#no.xpm", "#yes.xpm");
846 }
847 
848 void AW_window::create_inverse_toggle(const char *var_name) {
849  // like create_toggle, but displays inverse value
850  // (i.e. it's checked if value is zero, and unchecked otherwise)
851  create_toggle(var_name, "#yes.xpm", "#no.xpm");
852 }
853 
854 // ---------------------
855 // input fields
856 
857 void AW_window::create_input_field(const char *var_name, int columns) {
858  Widget textField = NULp;
860  AW_cb *cbs;
861  VarUpdateInfo *vui;
862  char *str;
863  int xoff_for_label = 0;
864 
865  if (!columns) columns = _at->length_of_buttons;
866 
867  AW_awar *vs = root->awar(var_name);
868  str = root->awar(var_name)->read_as_string();
869 
870  int width_of_input_label, height_of_input_label;
871  calculate_label_size(&width_of_input_label, &height_of_input_label, true);
872 #if defined(DUMP_BUTTON_CREATION)
873  printf("width_of_input_label=%i height_of_input_label=%i label='%s'\n", width_of_input_label, height_of_input_label, _at->label_for_inputfield);
874 #endif // DUMP_BUTTON_CREATION
875 
876  int width_of_input = this->calculate_string_width(columns+1) + 9;
877  // calculate width for 1 additional character (input field is not completely used)
878  // + 4 pixel for shadow + 4 unknown missing pixels + 1 add. pixel needed for visible text area
879 
880  Widget parentWidget = _at->attach_any ? INFO_FORM : INFO_WIDGET;
881 
882  if (_at->label_for_inputfield) {
883  Label clientlabel(_at->label_for_inputfield, this);
884  label_widget = XtVaCreateManagedWidget("label",
885  xmLabelWidgetClass,
886  parentWidget,
887  XmNwidth, (int)(width_of_input_label + 2),
888  XmNhighlightThickness, 0,
889  RES_LABEL_CONVERT(clientlabel),
890  XmNrecomputeSize, false,
891  XmNalignment, XmALIGNMENT_BEGINNING,
892  XmNfontList, p_global->fontlist,
893  (_at->attach_any) ? NULp : XmNx, (int)_at->x_for_next_button,
894  XmNy, (int)(_at->y_for_next_button) + 2*root->y_correction_for_input_labels - height_of_input_label/2,
895  NULp);
896  if (_at->attach_any) aw_attach_widget(label_widget, _at);
897  xoff_for_label = width_of_input_label + 10;
898  }
899 
900 
901  int width_of_last_widget = xoff_for_label + width_of_input + 2;
902 
903  if (_at->to_position_exists) {
904  width_of_input = _at->to_position_x - _at->x_for_next_button - xoff_for_label + 2;
905  width_of_last_widget = _at->to_position_x - _at->x_for_next_button;
906  }
907 
908  {
909  TuneBackground(parentWidget, TUNE_INPUT);
910  textField = XtVaCreateManagedWidget("textField",
911  xmTextFieldWidgetClass,
912  parentWidget,
913  XmNwidth, (int)width_of_input,
914  XmNrows, 1,
915  XmNvalue, str,
916  XmNfontList, p_global->fontlist,
917  XmNbackground, _at->background_color,
918  (_at->attach_any) ? NULp : XmNx, (int)(_at->x_for_next_button + xoff_for_label),
919  XmNy, (int)(_at->y_for_next_button + 5) - 8,
920  NULp);
921  if (_at->attach_any) {
922  _at->x_for_next_button += xoff_for_label;
923  aw_attach_widget(textField, _at);
924  _at->x_for_next_button -= xoff_for_label;
925  }
926  }
927 
928  free(str);
929 
930  // user-own callback
931  cbs = _callback;
932 
933  // callback for enter
934  vui = new VarUpdateInfo(this, textField, AW_WIDGET_INPUT_FIELD, vs, cbs);
935 
936  XtAddCallback(textField, XmNactivateCallback,
937  (XtCallbackProc) AW_variable_update_callback,
938  (XtPointer) vui);
939  if (_d_callback) {
940  XtAddCallback(textField, XmNactivateCallback,
941  (XtCallbackProc) AW_server_callback,
942  (XtPointer) _d_callback);
943  _d_callback->id = GBS_global_string_copy("INPUT:%s", var_name);
944  get_root()->define_remote_command(_d_callback);
945  }
946 
947  // callback for losing focus
948  XtAddCallback(textField, XmNlosingFocusCallback,
949  (XtCallbackProc) AW_variable_update_callback,
950  (XtPointer) vui);
951  // callback for value changed
952  XtAddCallback(textField, XmNvalueChangedCallback,
953  (XtCallbackProc) AW_value_changed_callback,
954  (XtPointer) root);
955 
956  vs->tie_widget(0, textField, AW_WIDGET_INPUT_FIELD, this);
957  root->make_sensitive(textField, _at->widget_mask);
958 
959  short height;
960  XtVaGetValues(textField, XmNheight, &height, NULp);
961  int height_of_last_widget = height;
962 
963  if (_at->correct_for_at_center == 1) { // middle centered
964  XtVaSetValues(textField, XmNx, ((int)(_at->x_for_next_button + xoff_for_label) - (int)(width_of_last_widget/2) + 1), NULp);
965  if (label_widget) {
966  XtVaSetValues(label_widget, XmNx, ((int)(_at->x_for_next_button) - (int)(width_of_last_widget/2) + 1), NULp);
967  }
968  width_of_last_widget = width_of_last_widget / 2;
969  }
970  if (_at->correct_for_at_center == 2) { // right centered
971  XtVaSetValues(textField, XmNx, (int)(_at->x_for_next_button + xoff_for_label - width_of_last_widget + 3), NULp);
972  if (label_widget) {
973  XtVaSetValues(label_widget, XmNx, (int)(_at->x_for_next_button - width_of_last_widget + 3), NULp);
974  }
975  width_of_last_widget = 0;
976  }
977  width_of_last_widget -= 2;
978 
979  this->unset_at_commands();
980  this->increment_at_commands(width_of_last_widget, height_of_last_widget);
981 
982 }
983 
984 void AW_window::update_input_field(Widget widget, const char *var_value) {
985  XtVaSetValues(widget, XmNvalue, var_value, NULp);
986 }
987 
988 void AW_window::create_text_field(const char *var_name, int columns, int rows) {
989  Widget scrolledWindowText;
990  Widget scrolledText;
992  AW_cb *cbs;
993  VarUpdateInfo *vui;
994  char *str = NULp;
995  short width_of_last_widget = 0;
996  short height_of_last_widget = 0;
997  int width_of_text = 0;
998  int height_of_text = 0;
999  int xoff_for_label = 0;
1000 
1001  AW_awar *vs = root->awar(var_name);
1002  str = root->awar(var_name)->read_string();
1003 
1004  int width_of_text_label, height_of_text_label;
1005  calculate_label_size(&width_of_text_label, &height_of_text_label, true);
1006  // @@@ FIXME: use height_of_text_label for propper Y-adjusting of label
1007 
1008  // width_of_text_label = this->calculate_string_width( calculate_label_length() );
1009  width_of_text = this->calculate_string_width(columns) + 18;
1010  height_of_text = this->calculate_string_height(rows, rows*4) + 9;
1011 
1012 
1013  if (_at->label_for_inputfield) {
1014  Label clientlabel(_at->label_for_inputfield, this);
1015  label_widget = XtVaCreateManagedWidget("label",
1016  xmLabelWidgetClass,
1017  INFO_WIDGET,
1018  XmNx, (int)_at->x_for_next_button,
1019  XmNy, (int)(_at->y_for_next_button) + this->get_root()->y_correction_for_input_labels + 5 - 6,
1020  XmNwidth, (int)(width_of_text_label + 2),
1021  RES_LABEL_CONVERT(clientlabel),
1022  XmNrecomputeSize, false,
1023  XmNalignment, XmALIGNMENT_BEGINNING,
1024  XmNfontList, p_global->fontlist,
1025  NULp);
1026 
1027  xoff_for_label = width_of_text_label + 10;
1028 
1029  }
1030 
1031  {
1032  aw_xargs args(6);
1033  args.add(XmNscrollingPolicy, XmAPPLICATION_DEFINED);
1034  args.add(XmNvisualPolicy, XmVARIABLE);
1035  args.add(XmNscrollBarDisplayPolicy, XmSTATIC);
1036  args.add(XmNfontList, (XtArgVal)p_global->fontlist);
1037 
1038  if (_at->to_position_exists) {
1039  scrolledWindowText = XtVaCreateManagedWidget("scrolledWindowList1", xmScrolledWindowWidgetClass, INFO_FORM, NULp);
1040  args.assign_to_widget(scrolledWindowText);
1041 
1042  aw_attach_widget(scrolledWindowText, _at);
1043  width_of_text = _at->to_position_x - _at->x_for_next_button - xoff_for_label - 18;
1044  if (_at->y_for_next_button < _at->to_position_y - 18) {
1045  height_of_text = _at->to_position_y - _at->y_for_next_button - 18;
1046  }
1047  }
1048  else {
1049  scrolledWindowText = XtVaCreateManagedWidget("scrolledWindowText", xmScrolledWindowWidgetClass, INFO_WIDGET, NULp);
1050  args.add(XmNx, 10);
1051  args.add(XmNy, _at->y_for_next_button);
1052  args.assign_to_widget(scrolledWindowText);
1053  }
1054  }
1055 
1056  TuneBackground(scrolledWindowText, TUNE_INPUT);
1057  scrolledText = XtVaCreateManagedWidget("scrolledText1",
1058  xmTextWidgetClass,
1059  scrolledWindowText,
1060  XmNeditMode, XmMULTI_LINE_EDIT,
1061  XmNvalue, str,
1062  XmNscrollLeftSide, false,
1063  XmNwidth, (int)width_of_text,
1064  XmNheight, (int)height_of_text,
1065  XmNfontList, p_global->fontlist,
1066  XmNbackground, _at->background_color,
1067  NULp);
1068  free(str);
1069 
1070  if (!_at->to_position_exists) {
1071  XtVaGetValues(scrolledWindowText, XmNheight, &height_of_last_widget,
1072  XmNwidth, &width_of_last_widget, NULp);
1073 
1074  width_of_last_widget += (short)xoff_for_label;
1075 
1076  switch (_at->correct_for_at_center) {
1077  case 0: // left centered
1078  XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label), NULp);
1079  break;
1080 
1081  case 1: // middle centered
1082  XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label - (width_of_last_widget/2)), NULp);
1083  if (_at->label_for_inputfield) {
1084  XtVaSetValues(label_widget, XmNx, (int)(_at->x_for_next_button - (width_of_last_widget/2)), NULp);
1085  }
1086  width_of_last_widget = width_of_last_widget / 2;
1087  break;
1088 
1089  case 2: // right centered
1090  XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label - width_of_last_widget), NULp);
1091  if (_at->label_for_inputfield) {
1092  XtVaSetValues(label_widget, XmNx, (int)(_at->x_for_next_button - width_of_last_widget), NULp);
1093  }
1094  width_of_last_widget = 0;
1095  break;
1096  }
1097  }
1098 
1099  // user-own callback
1100  cbs = _callback;
1101 
1102  // callback for enter
1103  vui = new VarUpdateInfo(this, scrolledText, AW_WIDGET_TEXT_FIELD, vs, cbs);
1104  XtAddCallback(scrolledText, XmNactivateCallback, (XtCallbackProc) AW_variable_update_callback, (XtPointer) vui);
1105  // callback for losing focus
1106  XtAddCallback(scrolledText, XmNlosingFocusCallback, (XtCallbackProc) AW_variable_update_callback, (XtPointer) vui);
1107  // callback for value changed
1108  XtAddCallback(scrolledText, XmNvalueChangedCallback, (XtCallbackProc) AW_value_changed_callback, (XtPointer) root);
1109 
1110  vs->tie_widget(0, scrolledText, AW_WIDGET_TEXT_FIELD, this);
1111  root->make_sensitive(scrolledText, _at->widget_mask);
1112 
1113  this->unset_at_commands();
1114  this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1115 }
1116 
1117 
1118 void AW_window::update_text_field(Widget widget, const char *var_value) {
1119  XtVaSetValues(widget, XmNvalue, var_value, NULp);
1120 }
1121 
1122 static void scalerChanged_cb(Widget scale, XtPointer variable_update_struct, XtPointer call_data) {
1123  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct*)call_data;
1124  VarUpdateInfo *vui = (VarUpdateInfo*)variable_update_struct;
1125 
1126  bool do_update = true;
1127  if (cbs->reason == XmCR_DRAG) { // still dragging?
1128  double mean_callback_time = vui->get_awar()->mean_callback_time();
1129 
1130  const double MAX_DRAGGED_CALLBACK_TIME = 1.0;
1131  if (mean_callback_time>MAX_DRAGGED_CALLBACK_TIME) {
1132  do_update = false; // do not update while dragging, if update callback needs more than 1 second
1133  // Note that a longer update will happen once!
1134  }
1135  }
1136 
1137  if (do_update) {
1139  AW_variable_update_callback(scale, variable_update_struct, call_data);
1140  }
1141 }
1142 
1143 void AW_window::create_input_field_with_scaler(const char *awar_name, int textcolumns, int scaler_length, AW_ScalerType scalerType) {
1144  create_input_field(awar_name, textcolumns);
1145 
1146  Widget parentWidget = _at->attach_any ? INFO_FORM : INFO_WIDGET;
1147 
1148  AW_awar *vs = root->awar(awar_name);
1149  // Note: scaler also "works" if no min/max is defined for awar, but scaling is a bit weird
1150  int scalerValue = calculate_scaler_value(vs, scalerType);
1151 
1152  Widget scale = XtVaCreateManagedWidget("scale",
1153  xmScaleWidgetClass,
1154  parentWidget,
1155  XmNx, _at->x_for_next_button,
1156  XmNy, _at->y_for_next_button + 4,
1157  XmNorientation, XmHORIZONTAL,
1158  XmNscaleWidth, scaler_length,
1159  XmNshowValue, False,
1160  XmNminimum, SCALER_MIN_VALUE,
1161  XmNmaximum, SCALER_MAX_VALUE,
1162  XmNvalue, scalerValue,
1163  NULp);
1164 
1165  short width_of_last_widget = 0;
1166  short height_of_last_widget = 0;
1167 
1168  XtVaGetValues(scale,
1169  XmNheight, &height_of_last_widget,
1170  XmNwidth, &width_of_last_widget,
1171  NULp);
1172 
1173  AW_cb *cbs = _callback;
1174  VarUpdateInfo *vui = new VarUpdateInfo(this, scale, AW_WIDGET_SCALER, vs, cbs);
1175  vui->set_scalerType(scalerType);
1176 
1177  XtAddCallback(scale, XmNvalueChangedCallback, scalerChanged_cb, (XtPointer)vui);
1178  XtAddCallback(scale, XmNdragCallback, scalerChanged_cb, (XtPointer)vui);
1179 
1180  vs->tie_widget((AW_CL)scalerType, scale, AW_WIDGET_SCALER, this);
1181  root->make_sensitive(scale, _at->widget_mask);
1182 
1183  this->unset_at_commands();
1184  this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1185 }
1186 
1187 void AW_window::update_scaler(Widget widget, AW_awar *awar, AW_ScalerType scalerType) {
1188  int scalerVal = calculate_scaler_value(awar, scalerType);
1189  XtVaSetValues(widget, XmNvalue, scalerVal, NULp);
1190 }
1191 
1192 // -----------------------
1193 // selection list
1194 
1195 
1196 static void scroll_sellist(Widget scrolledList, bool upwards) {
1197  int oldPos, visible, items;
1198  XtVaGetValues(scrolledList,
1199  XmNtopItemPosition, &oldPos,
1200  XmNvisibleItemCount, &visible,
1201  XmNitemCount, &items,
1202  NULp);
1203 
1204  int amount = visible/5;
1205  if (amount<1) amount = 1;
1206  if (upwards) amount = -amount;
1207 
1208  int newPos = force_in_range(1, oldPos + amount, items-visible+2);
1209  if (newPos != oldPos) XmListSetPos(scrolledList, newPos);
1210 }
1211 
1212 static void scroll_sellist_up(Widget scrolledList, XEvent*, String*, Cardinal*) { scroll_sellist(scrolledList, true); }
1213 static void scroll_sellist_dn(Widget scrolledList, XEvent*, String*, Cardinal*) { scroll_sellist(scrolledList, false); }
1214 
1215 AW_selection_list* AW_window::create_selection_list(const char *var_name, int columns, int rows) {
1216  Widget scrolledWindowList; // @@@ fix locals
1217  Widget scrolledList;
1218  VarUpdateInfo *vui;
1219  AW_cb *cbs;
1220 
1221  int width_of_list;
1222  int height_of_list;
1223  int width_of_last_widget = 0;
1224  int height_of_last_widget = 0;
1225 
1226  aw_assert(!_at->label_for_inputfield); // labels have no effect for selection lists
1227 
1228  AW_awar *vs = NULp;
1229 
1230  aw_assert(var_name); // @@@ case where var_name is NULp is relict from multi-selection-list (not used; removed)
1231 
1232  if (var_name) vs = root->awar(var_name);
1233 
1234  width_of_list = this->calculate_string_width(columns) + 9;
1235  height_of_list = this->calculate_string_height(rows, 4*rows) + 9;
1236 
1237  {
1238  aw_xargs args(7);
1239  args.add(XmNvisualPolicy, XmVARIABLE);
1240  args.add(XmNscrollBarDisplayPolicy, XmSTATIC);
1241  args.add(XmNshadowThickness, 0);
1242  args.add(XmNfontList, (XtArgVal)p_global->fontlist);
1243 
1244  if (_at->to_position_exists) {
1245  width_of_list = _at->to_position_x - _at->x_for_next_button - 18;
1246  if (_at->y_for_next_button < _at->to_position_y - 18) {
1247  height_of_list = _at->to_position_y - _at->y_for_next_button - 18;
1248  }
1249  scrolledWindowList = XtVaCreateManagedWidget("scrolledWindowList1", xmScrolledWindowWidgetClass, INFO_FORM, NULp);
1250 
1251  args.assign_to_widget(scrolledWindowList);
1252  aw_attach_widget(scrolledWindowList, _at);
1253 
1254  width_of_last_widget = _at->to_position_x - _at->x_for_next_button;
1255  height_of_last_widget = _at->to_position_y - _at->y_for_next_button;
1256  }
1257  else {
1258  scrolledWindowList = XtVaCreateManagedWidget("scrolledWindowList1", xmScrolledWindowWidgetClass, INFO_WIDGET, NULp);
1259 
1260  args.add(XmNscrollingPolicy, XmAPPLICATION_DEFINED);
1261  args.add(XmNx, 10);
1262  args.add(XmNy, _at->y_for_next_button);
1263  args.assign_to_widget(scrolledWindowList);
1264  }
1265  }
1266 
1267  {
1268  int select_type = XmMULTIPLE_SELECT;
1269  if (vs) select_type = XmBROWSE_SELECT;
1270 
1271  TuneBackground(scrolledWindowList, TUNE_INPUT);
1272  scrolledList = XtVaCreateManagedWidget("scrolledList1",
1273  xmListWidgetClass,
1274  scrolledWindowList,
1275  XmNwidth, (int)width_of_list,
1276  XmNheight, (int) height_of_list,
1277  XmNscrollBarDisplayPolicy, XmSTATIC,
1278  XmNselectionPolicy, select_type,
1279  XmNlistSizePolicy, XmCONSTANT,
1280  XmNfontList, p_global->fontlist,
1281  XmNbackground, _at->background_color,
1282  NULp);
1283 
1284  static bool actionsAdded = false;
1285  if (!actionsAdded) {
1286  struct _XtActionsRec actions[2] = {
1287  {(char*)"scroll_sellist_up", scroll_sellist_up},
1288  {(char*)"scroll_sellist_dn", scroll_sellist_dn}
1289  };
1290 
1291  XtAppAddActions(p_global->context, actions, 2);
1292  }
1293 
1294  XtTranslations translations = XtParseTranslationTable(
1295  "<Btn4Down>:scroll_sellist_up()\n"
1296  "<Btn5Down>:scroll_sellist_dn()\n"
1297  );
1298  XtAugmentTranslations(scrolledList, translations);
1299  }
1300 
1301  if (!_at->to_position_exists) {
1302  short height;
1303  XtVaGetValues(scrolledList, XmNheight, &height, NULp);
1304  height_of_last_widget = height + 20;
1305  width_of_last_widget = width_of_list + 20;
1306 
1307  switch (_at->correct_for_at_center) {
1308  case 3: break;
1309  case 0: // left aligned
1310  XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button), NULp);
1311  break;
1312 
1313  case 1: // center aligned
1314  XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button - (width_of_last_widget/2)), NULp);
1315  width_of_last_widget = width_of_last_widget / 2;
1316  break;
1317 
1318  case 2: // right aligned
1319  XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button - width_of_list - 18), NULp);
1320  width_of_last_widget = 0;
1321  break;
1322  }
1323 
1324  }
1325 
1326  {
1327  int type = GB_STRING;
1328  if (vs) type = vs->variable_type;
1329 
1330  if (p_global->selection_list) {
1331  p_global->last_selection_list->next = new AW_selection_list(var_name, type, scrolledList);
1332  p_global->last_selection_list = p_global->last_selection_list->next;
1333  }
1334  else {
1335  p_global->last_selection_list = p_global->selection_list = new AW_selection_list(var_name, type, scrolledList);
1336  }
1337  }
1338 
1339 
1340  // user-own callback
1341  cbs = _callback; // @@@ generally unwanted (see #559)
1342 
1343  // callback for enter
1344  if (vs) {
1345  vui = new VarUpdateInfo(this, scrolledList, AW_WIDGET_SELECTION_LIST, vs, cbs);
1346  vui->set_sellist(p_global->last_selection_list);
1347 
1348  XtAddCallback(scrolledList, XmNbrowseSelectionCallback,
1349  (XtCallbackProc) AW_variable_update_callback,
1350  (XtPointer) vui);
1351 
1352  if (_d_callback) {
1353  XtAddCallback(scrolledList, XmNdefaultActionCallback,
1354  (XtCallbackProc) AW_server_callback,
1355  (XtPointer) _d_callback);
1356  }
1357  vs->tie_widget((AW_CL)p_global->last_selection_list, scrolledList, AW_WIDGET_SELECTION_LIST, this);
1358  root->make_sensitive(scrolledList, _at->widget_mask);
1359  }
1360 
1361  this->unset_at_commands();
1362  this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1363  return p_global->last_selection_list;
1364 }
1365 
void TuneBackground(Widget w, int modStrength)
Definition: AW_window.cxx:3172
class AW_root * root
Definition: aw_awar.hxx:95
#define AW_JUSTIFY_LABEL(widget, corr)
bool to_position_exists
Definition: aw_at.hxx:40
bool attach_x
Definition: aw_at.hxx:58
int x_for_next_button
Definition: aw_at.hxx:33
AW_cb * _callback
Definition: aw_window.hxx:289
const char * GB_ERROR
Definition: arb_core.h:25
short length_of_buttons
Definition: aw_at.hxx:21
static int calculate_scaler_value(AW_awar *awar, AW_ScalerType scalerType)
Definition: AW_button.cxx:57
bool attach_ly
Definition: aw_at.hxx:61
#define TUNE_BUTTON
Definition: aw_window.hxx:39
GB_TYPES type
void define_remote_command(class AW_cb *cbs)
Definition: AW_root.cxx:228
void aw_detect_text_size(const char *text, size_t &width, size_t &height)
Definition: AW_button.cxx:405
bool is_tracking() const
Definition: aw_root.hxx:179
#define SPACE_BEHIND_LABEL
GB_ERROR GB_incur_error()
Definition: arb_msg.h:49
static void dot(double **i, double **j, double **k)
Definition: trnsprob.cxx:59
AW_awar * label_is_awar(const char *label)
Definition: AW_root.cxx:218
GB_ERROR GB_add_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
Definition: ad_cb.cxx:356
void update_label(Widget widget, const char *var_value)
Definition: AW_button.cxx:740
void change_from_widget(XtPointer call_data)
Definition: AW_button.cxx:85
static void track_awar_change_cb(GBDATA *gbd, TrackedAwarChange *tac, GB_CB_TYPE cb_type)
Definition: AW_button.cxx:48
short length_of_label_for_inputfield
Definition: aw_at.hxx:23
void calculate_textsize(const char *str, int *width, int *height)
Definition: AW_button.cxx:355
void _set_activate_callback(void *widget)
Definition: AW_window.cxx:3105
int max_y_size
Definition: aw_at.hxx:36
AW_ScalerType
Definition: aw_window.hxx:228
#define TUNE_INPUT
Definition: aw_window.hxx:40
AW_VARIABLE_TYPE variable_type
Definition: aw_awar.hxx:102
void unset_at_commands()
Definition: AW_at.cxx:220
GB_ERROR GB_IO_error(const char *action, const char *filename)
Definition: arb_msg.cxx:285
short shadow_thickness
Definition: aw_at.hxx:20
GB_ERROR write_to(class AW_awar *awar) const
Definition: aw_scalar.cxx:29
int y_correction_for_input_labels
Definition: aw_root.hxx:107
static char * pixmapPath(const char *pixmapName)
Definition: AW_button.cxx:272
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
int to_position_y
Definition: aw_at.hxx:39
AW_awar * awar
Definition: AW_button.cxx:42
void GBK_terminatef(const char *templat,...)
Definition: arb_msg.cxx:523
char * id
Definition: aw_window.hxx:135
Definition: aw_at.hxx:18
char * window_defaults_name
window title
Definition: aw_window.hxx:347
void update_text_field(Widget widget, const char *var_value)
Definition: AW_button.cxx:1118
#define SCALER_MIN_VALUE
Definition: AW_button.cxx:54
short height_of_buttons
Definition: aw_at.hxx:22
char(& yes)[1]
Definition: downcast.h:30
const char * AW_get_pixmapPath(const char *pixmapName)
Definition: AW_button.cxx:266
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
GB_ERROR toggle_toggle()
Definition: AW_awar.cxx:573
#define FLAT_GRAPHIC_PADDING
const char * String
Definition: gb_aci_impl.h:59
void update_toggle(Widget widget, const char *var_value, AW_CL cd)
Definition: AW_button.cxx:758
void create_input_field_with_scaler(const char *awar_name, int textcolumns=4, int scaler_length=250, AW_ScalerType scalerType=AW_SCALER_LINEAR)
Definition: AW_button.cxx:1143
void update_input_field(Widget widget, const char *var_value)
Definition: AW_button.cxx:984
bool AW_IS_IMAGEREF(const char *label)
Definition: aw_localdef.hxx:13
static void scroll_sellist_up(Widget scrolledList, XEvent *, String *, Cardinal *)
Definition: AW_button.cxx:1212
Definition: aw_select.hxx:26
static AW_root * SINGLETON
Definition: aw_root.hxx:102
#define BUTTON_TEXT_Y_PADDING
static void write_scalervalue_to_awar(int scalerVal, AW_awar *awar, AW_ScalerType scalerType)
Definition: AW_button.cxx:64
#define short
Definition: ureadseq.h:8
Widget get_last_widget() const
Definition: AW_button.cxx:401
bool highlight
Definition: aw_at.hxx:24
#define MIN_RIGHT_OFFSET
#define RES_LABEL_CONVERT(label)
#define MAX_LINE_LENGTH
Definition: AW_button.cxx:277
float scaler2awar(float scaler, AW_awar *awar)
Definition: AW_window.cxx:188
void create_inverse_toggle(const char *awar_name)
Definition: AW_button.cxx:848
static void scalerChanged_cb(Widget scale, XtPointer variable_update_struct, XtPointer call_data)
Definition: AW_button.cxx:1122
void increment_at_commands(int width, int height)
Definition: AW_at.cxx:234
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:509
AW_cb * _d_callback
Definition: aw_window.hxx:290
static void scroll_sellist(Widget scrolledList, bool upwards)
Definition: AW_button.cxx:1196
static void scroll_sellist_dn(Widget scrolledList, XEvent *, String *, Cardinal *)
Definition: AW_button.cxx:1213
CONSTEXPR_INLINE const T & force_in_range(const T &lower_bound, const T &value, const T &upper_bound)
Definition: arb_algo.h:20
#define aw_assert(bed)
Definition: aw_position.hxx:29
void update()
Definition: AW_awar.cxx:390
bool attach_y
Definition: aw_at.hxx:59
#define false
Definition: ureadseq.h:13
AW_root * root
Definition: aw_window.hxx:272
double mean_callback_time() const
Definition: aw_awar.hxx:115
void track_awar_change(AW_awar *changed_awar)
Definition: aw_root.hxx:177
static char const * macro_name
Definition: mkptypes.cxx:81
void assign_to_widget(Widget w)
Definition: aw_xargs.hxx:45
static void error(const char *msg)
Definition: mkptypes.cxx:96
const char * mnemonic
#define SCALER_MAX_VALUE
Definition: AW_button.cxx:55
void aw_attach_widget(Widget w, AW_at *_at, int default_width)
Definition: AW_button.cxx:186
char * str
Definition: defines.h:20
char * read_as_string() const
#define BUTTON_GRAPHIC_PADDING
const AW_scalar & get_value() const
Definition: aw_select.hxx:48
AW_selection_list_entry * next
Definition: aw_select.hxx:34
void TuneOrSetBackground(Widget w, const char *color, int modStrength)
Definition: AW_window.cxx:3141
int label_widget(void *wgt, AW_label str, char *mnemonic=NULp, int width=0, int alignment=0)
#define INFO_WIDGET
int max_x_size
Definition: aw_at.hxx:35
void AW_variable_update_callback(Widget, XtPointer variable_update_struct, XtPointer call_data)
Definition: AW_button.cxx:34
float awar2scaler(AW_awar *awar)
Definition: AW_window.cxx:197
char * read_string() const
Definition: AW_awar.cxx:198
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
static void AW_value_changed_callback(Widget, XtPointer rooti, XtPointer)
Definition: AW_button.cxx:181
void create_autosize_button(const char *macro_name, AW_label label, const char *mnemonic=NULp, unsigned xtraSpace=1)
Definition: AW_button.cxx:421
#define BUTTON_TEXT_X_PADDING
AW_active widget_mask
Definition: aw_at.hxx:27
#define RES_CONVERT(res_name, res_value)
GB_ERROR write_as_string(const char *aw_string)
void create_input_field(const char *awar_name, int columns=0)
Definition: AW_button.cxx:857
#define p_global
AW_awar * get_awar()
unsigned long int background_color
Definition: aw_at.hxx:29
AW_window_Motif * p_w
Definition: aw_window.hxx:288
void update_scaler(Widget widget, AW_awar *awar, AW_ScalerType scalerType)
Definition: AW_button.cxx:1187
#define IF_ASSERTION_USED(x)
Definition: arb_assert.h:308
long AW_CL
Definition: cb.h:21
GBDATA * gb_var
Definition: aw_awar.hxx:97
#define __ATTR__USERESULT
Definition: attributes.h:58
void make_sensitive(Widget w, AW_active mask)
Definition: AW_window.cxx:3279
int y_for_next_button
Definition: aw_at.hxx:34
void GB_remove_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
Definition: ad_cb.cxx:360
AW_selection_list * create_selection_list(const char *awar_name, int columns, int rows)
Definition: AW_button.cxx:1215
int to_position_x
Definition: aw_at.hxx:38
char(& no)[2]
Definition: downcast.h:31
GB_CSTR GB_concat_path_in_ARBLIB(const char *relative_path_left, const char *anypath_right)
Definition: adsocket.cxx:1159
void aw_message(const char *msg)
Definition: AW_status.cxx:1142
char * bitmapOrText[2]
Definition: AW_button.cxx:754
void set_scalerType(AW_ScalerType scalerType_)
AW_root * get_root()
Definition: aw_window.hxx:359
TrackedAwarChange(AW_awar *awar_)
Definition: AW_button.cxx:45
void dump_at_position(const char *debug_label) const
Definition: AW_button.cxx:736
#define NULp
Definition: cxxforward.h:116
void create_text_toggle(const char *var_name, const char *noText, const char *yesText, int buttonWidth=0)
Definition: AW_button.cxx:833
char * label_for_inputfield
Definition: aw_at.hxx:31
#define INFO_FORM
bool value_changed
Definition: aw_root.hxx:105
void AW_label_in_awar_list(AW_window *aww, Widget widget, const char *str)
Definition: AW_window.cxx:2172
void AW_server_callback(Widget, XtPointer aw_cb_struct, XtPointer)
Definition: AW_window.cxx:1399
#define SPACE_BEHIND_BUTTON
Widget changer_of_variable
Definition: aw_root.hxx:106
#define MIN_BOTTOM_OFFSET
static void useraction_init()
Definition: aw_window.hxx:167
GB_transaction ta(gb_var)
void run_callbacks()
static __ATTR__USERESULT GB_ERROR detect_bitmap_size(const char *pixmapname, int *width, int *height)
Definition: AW_button.cxx:278
static void useraction_done(AW_window *aw)
Definition: aw_window.hxx:170
GB_ERROR write_float(float aw_float)
GB_CB_TYPE
Definition: arbdb_base.h:46
bool attach_any
Definition: aw_at.hxx:62
void add(String name, XtArgVal value)
Definition: aw_xargs.hxx:39
bool attach_lx
Definition: aw_at.hxx:60
int correct_for_at_center
Definition: aw_at.hxx:55
GB_ERROR write_int(long aw_int)
struct _WidgetRec * Widget
Definition: aw_base.hxx:48
void create_text_field(const char *awar_name, int columns=20, int rows=4)
Definition: AW_button.cxx:988
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
void tie_widget(AW_CL cd1, Widget widget, AW_widget_type type, AW_window *aww)
Definition: AW_awar.cxx:257
void create_button(const char *macro_name, AW_label label, const char *mnemonic=NULp, const char *color=NULp)
Definition: AW_button.cxx:448
void set_sellist(AW_selection_list *asl)