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_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, const char *non_at_label) {
379  // in_pixel == true -> calculate size in pixels
380  // in_pixel == false -> calculate size in characters
381 
382  const char *label_ = non_at_label ? non_at_label : _at->label_for_inputfield;
383  if (label_) {
384  calculate_textsize(label_, width, height);
386  *width = _at->length_of_label_for_inputfield;
387  }
388  if (in_pixel) {
389  *width = calculate_string_width(*width);
390  *height = calculate_string_height(*height, 0);
391  }
392  }
393  else {
394  *width = 0;
395  *height = 0;
396  }
397 }
398 
400  return p_global->get_last_widget();
401 }
402 
403 void aw_detect_text_size(const char *text, size_t& width, size_t& height) {
404  size_t text_width = strcspn(text, "\n");
405 
406  if (text[text_width]) {
407  aw_assert(text[text_width] == '\n');
408 
409  aw_detect_text_size(text+text_width+1, width, height);
410  if (text_width>width) width = text_width;
411  height++;
412  }
413  else { // EOS
414  width = text_width;
415  height = 1;
416  }
417 }
418 
419 void AW_window::create_autosize_button(const char *macro_name, AW_label buttonlabel, const char *mnemonic, unsigned xtraSpace) {
420  aw_assert(!AW_IS_IMAGEREF(buttonlabel)); // use create_button for graphical buttons!
421  aw_assert(!_at->to_position_exists); // wont work if to-position exists
422 
423  AW_awar *is_awar = get_root()->label_is_awar(buttonlabel);
424  size_t width, height;
425  if (is_awar) {
426  char *content = is_awar->read_as_string();
427  aw_assert(content[0]); /* you need to fill the awar before calling create_autosize_button,
428  * otherwise size cannot be detected */
429  aw_detect_text_size(content, width, height);
430  }
431  else {
432  aw_detect_text_size(buttonlabel, width, height);
433  }
434 
435  int len = width+(xtraSpace*2);
436  short length_of_buttons = _at->length_of_buttons;
437  short height_of_buttons = _at->height_of_buttons;
438 
439  _at->length_of_buttons = len+1;
440  _at->height_of_buttons = height;
441  create_button(macro_name, buttonlabel, mnemonic);
442  _at->length_of_buttons = length_of_buttons;
443  _at->height_of_buttons = height_of_buttons;
444 }
445 
446 void AW_window::create_button(const char *macro_name, AW_label buttonlabel, const char */*mnemonic*/, const char *color) {
447  // Create a button or text display.
448  //
449  // If a callback is bound via at->callback(), a button is created.
450  // Otherwise a text display is created.
451  //
452  // if buttonlabel starts with '#' the rest of buttonlabel is used as name of pixmap file used for button
453  // if buttonlabel contains a '/' it's interpreted as AWAR name and the button displays the content of the awar
454  // otherwise buttonlabel is interpreted as button label (may contain '\n').
455  //
456  // Note 1: Button width 0 does not work together with labels!
457 
458  // Note 2: "color" may be specified for the button background (see TuneOrSetBackground for details)
459 
460  TuneOrSetBackground(_at->attach_any ? INFO_FORM : INFO_WIDGET, // set background for buttons / text displays
461  color,
462  _callback ? TUNE_BUTTON : 0);
463 
464 #if defined(DUMP_BUTTON_CREATION)
465  printf("------------------------------ Button '%s'\n", buttonlabel);
466  printf("x_for_next_button=%i y_for_next_button=%i\n", _at->x_for_next_button, _at->y_for_next_button);
467 #endif // DUMP_BUTTON_CREATION
468 
469  if (_callback && ((long)_callback != 1)) {
470  if (macro_name) {
471  _callback->id = GBS_global_string_copy("%s/%s", this->window_defaults_name, macro_name);
473  }
474  else {
475  _callback->id = NULp;
476  }
477  }
478 #if defined(DEVEL_RALF) && 1
479  else {
480  aw_assert(!macro_name); // please pass NULp for buttons w/o callback
481  }
482 #endif
483 
484 #define SPACE_BEHIND_LABEL 10
485 
486 #define BUTTON_TEXT_X_PADDING 4
487 #define BUTTON_TEXT_Y_PADDING 10
488 
489 #define BUTTON_GRAPHIC_PADDING 12
490 #define FLAT_GRAPHIC_PADDING 4 // for buttons w/o callback
491 
492  bool is_graphical_button = AW_IS_IMAGEREF(buttonlabel);
493 
494 #if defined(ASSERTION_USED)
495  AW_awar *is_awar = is_graphical_button ? NULp : get_root()->label_is_awar(buttonlabel);
496 #endif // ASSERTION_USED
497 
498  int width_of_button = -1, height_of_button = -1;
499 
500  int width_of_label, height_of_label;
501  calculate_label_size(&width_of_label, &height_of_label, true, NULp);
502  int width_of_label_and_spacer = _at->label_for_inputfield ? width_of_label+SPACE_BEHIND_LABEL : 0;
503 
504  bool let_motif_choose_size = false;
505 
506  if (_at->to_position_exists) { // size has explicitly been specified in xfig -> calculate
507  width_of_button = _at->to_position_x - _at->x_for_next_button - width_of_label_and_spacer;
508  height_of_button = _at->to_position_y - _at->y_for_next_button;
509  }
510  else if (_at->length_of_buttons) { // button width specified from client code
511  width_of_button = BUTTON_TEXT_X_PADDING + calculate_string_width(_at->length_of_buttons+1);
512 
513  if (!is_graphical_button) {
514  if (_at->height_of_buttons) { // button height specified from client code
515  height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(_at->height_of_buttons, 0);
516  }
517  else {
518  int textwidth, textheight;
519  calculate_textsize(buttonlabel, &textwidth, &textheight);
520  height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
521  }
522  }
523  else {
524  height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(1, 0);
525  }
526  }
527  else { // no button_length() specified
528  aw_assert(!is_awar); // please specify button_length() for AWAR button!
529 
530  if (is_graphical_button) {
531  int width, height;
532  GB_ERROR err = detect_bitmap_size(buttonlabel+1, &width, &height);
533 
534  if (!err) {
536 
537  width_of_button = width+gpadding;
538  height_of_button = height+gpadding;
539  }
540  else {
541  err = GBS_global_string("button gfx error: %s", err);
542  aw_message(err);
543  let_motif_choose_size = true;
544  }
545  }
546  else {
547  int textwidth, textheight;
548  calculate_textsize(buttonlabel, &textwidth, &textheight);
549 
550  width_of_button = BUTTON_TEXT_X_PADDING + calculate_string_width(textwidth+1);
551  height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
552  }
553  }
554 
555  if (!let_motif_choose_size) {
556  if (height_of_button<height_of_label) height_of_button = height_of_label;
557  aw_assert(width_of_button && height_of_button);
558  }
559 
560  int x_label = _at->x_for_next_button;
561  int y_label = _at->y_for_next_button;
562  int x_button = x_label + width_of_label_and_spacer;
563  int y_button = y_label;
564 
565  int org_correct_for_at_center = _at->correct_for_at_center; // store original justification
566  int org_y_for_next_button = _at->y_for_next_button; // store original y pos (modified while creating label)
567 
568  if (!let_motif_choose_size) { // don't correct position of button w/o known size
569  // calculate justification manually
570 
571  int width_of_button_and_highlight = width_of_button + (_at->highlight ? 2*(_at->shadow_thickness+1)+1 : 0);
572  int width_of_label_and_button = width_of_label_and_spacer+width_of_button_and_highlight;
573 
574  if (_at->correct_for_at_center) { // not if left justified
575  int shiftback = width_of_label_and_button; // shiftback for right justification
576  if (_at->correct_for_at_center == 1) { // center justification
577  shiftback /= 2;
578  }
579  x_label -= shiftback;
580  x_button -= shiftback;
581  }
582 
583  // we already did the justification by calculating all positions manually, so..
584  _at->correct_for_at_center = 0; // ..from now on act like "left justified"!
585  }
586 
587  // correct label Y position
588  if (_callback) { // only if button is a real 3D-button
589  y_label += (height_of_button-height_of_label)/2;
590  }
591 
592  Widget parent_widget = (_at->attach_any) ? INFO_FORM : INFO_WIDGET;
593  Widget tmp_label = NULp;
594 
595  if (_at->label_for_inputfield) {
596  _at->x_for_next_button = x_label;
597  _at->y_for_next_button = y_label;
598 
599  Label clientlabel(_at->label_for_inputfield, this);
600  tmp_label = XtVaCreateManagedWidget("label",
601  xmLabelWidgetClass,
602  parent_widget,
603  XmNwidth, (int)(width_of_label + 2),
604  RES_LABEL_CONVERT(clientlabel),
605  XmNrecomputeSize, false,
606  XmNalignment, XmALIGNMENT_BEGINNING,
607  XmNfontList, p_global->fontlist,
608  XmNx, (int)(x_label),
609  XmNy, (int)(y_label),
610  NULp);
611 
612  if (_at->attach_any) aw_attach_widget(tmp_label, _at);
613  AW_label_in_awar_list(this, tmp_label, _at->label_for_inputfield);
614  }
615 
616  _at->x_for_next_button = x_button;
617  _at->y_for_next_button = y_button;
618 
619  Widget fatherwidget = parent_widget; // used as father for button below
620  if (_at->highlight) {
621  if (_at->attach_any) {
622 #if defined(DEBUG)
623  printf("Attaching highlighted buttons does not work - "
624  "highlight ignored for button '%s'!\n", buttonlabel);
625 #endif // DEBUG
626  _at->highlight = false;
627  }
628  else {
629  int shadow_offset = _at->shadow_thickness;
630  int x_shadow = x_button - shadow_offset;
631  int y_shadow = y_button - shadow_offset;
632 
633  fatherwidget = XtVaCreateManagedWidget("draw_area",
634  xmFrameWidgetClass,
635  INFO_WIDGET,
636  XmNx, (int)(x_shadow),
637  XmNy, (int)(y_shadow),
638  XmNshadowType, XmSHADOW_IN,
639  XmNshadowThickness, _at->shadow_thickness,
640  NULp);
641  }
642  }
643 
644  Widget button = NULp;
645 
646  {
647  aw_xargs args(9);
648  args.add(XmNx, x_button);
649  args.add(XmNy, y_button);
650 
651  args.add(XmNfontList, (XtArgVal)p_global->fontlist);
652  args.add(XmNbackground, _at->background_color);
653 
654  if (!let_motif_choose_size) {
655  args.add(XmNwidth, width_of_button);
656  args.add(XmNheight, height_of_button);
657  }
658 
659  Label buttonLabel(buttonlabel, this);
660  if (_callback) {
661  args.add(XmNshadowThickness, _at->shadow_thickness);
662  args.add(XmNalignment, XmALIGNMENT_CENTER);
663 
664  button = XtVaCreateManagedWidget("button", xmPushButtonWidgetClass, fatherwidget, RES_LABEL_CONVERT(buttonLabel), NULp);
665  }
666  else { // button w/o callback; (flat, not clickable)
667  button = XtVaCreateManagedWidget("label", xmLabelWidgetClass, parent_widget, RES_LABEL_CONVERT(buttonLabel), NULp);
668  args.add(XmNalignment, (org_correct_for_at_center == 1) ? XmALIGNMENT_CENTER : XmALIGNMENT_BEGINNING);
669  }
670 
671  if (!_at->attach_any || !_callback) args.add(XmNrecomputeSize, false);
672  args.assign_to_widget(button);
673  if (_at->attach_any) aw_attach_widget(button, _at);
674 
675  if (_callback) {
676  root->make_sensitive(button, _at->widget_mask);
677  }
678  else {
679  aw_assert(_at->correct_for_at_center == 0);
680  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)
681  }
682 
683  AW_label_in_awar_list(this, button, buttonlabel);
684  }
685 
686  short height = 0;
687  short width = 0;
688 
689  if (_at->to_position_exists) {
690  // size has explicitly been specified in xfig -> calculate
691  height = _at->to_position_y - _at->y_for_next_button;
692  width = _at->to_position_x - _at->x_for_next_button;
693  }
694 
695  {
696  Widget toRecenter = NULp;
697  int recenterSize = 0;
698 
699  if (!height || !width) {
700  // ask motif for real button size
701  Widget ButOrHigh = _at->highlight ? fatherwidget : button;
702  XtVaGetValues(ButOrHigh, XmNheight, &height, XmNwidth, &width, NULp);
703 
704  if (let_motif_choose_size) {
705  if (_at->correct_for_at_center) {
706  toRecenter = ButOrHigh;
707  recenterSize = width;
708  }
709  width = 0; // ignore the used size (because it may use more than the window size)
710  }
711  }
712 
713  if (toRecenter) {
714  int shiftback = 0;
715  switch (_at->correct_for_at_center) {
716  case 1: shiftback = recenterSize/2; break;
717  case 2: shiftback = recenterSize; break;
718  }
719  if (shiftback) {
720  XtVaSetValues(toRecenter, XmNx, x_button-shiftback, NULp);
721  }
722  }
723  }
724 
725  _at->correct_for_at_center = org_correct_for_at_center; // restore original justification
726  _at->y_for_next_button = org_y_for_next_button;
727 
728  p_w->toggle_field = button;
729  this->_set_activate_callback((void *)button);
730  this->unset_at_commands();
731  this->increment_at_commands(width+SPACE_BEHIND_BUTTON, height);
732 }
733 
734 void AW_window::dump_at_position(const char *tmp_label) const {
735  printf("%s at x = %i / y = %i\n", tmp_label, _at->x_for_next_button, _at->y_for_next_button);
736 }
737 
738 void AW_window::update_label(Widget widget, const char *var_value) {
739  if (get_root()->changer_of_variable != widget) {
740  XtVaSetValues(widget, RES_CONVERT(XmNlabelString, var_value), NULp);
741  }
742  else {
744  }
745 }
746 
747 // ----------------------
748 // on/off toggle
749 
752  char *bitmapOrText[2];
753  int buttonWidth; // wanted width in characters
754 };
755 
756 void AW_window::update_toggle(Widget widget, const char *var, AW_CL cd_toggle_data) {
757  aw_toggle_data *tdata = (aw_toggle_data*)cd_toggle_data;
758  const char *text = tdata->bitmapOrText[(var[0] == '0' || var[0] == 'n') ? 0 : 1];
759 
760  if (tdata->isTextToggle) {
761  XtVaSetValues(widget, RES_CONVERT(XmNlabelString, text), NULp);
762  }
763  else {
764  char *path = pixmapPath(text+1);
765  XtVaSetValues(widget, RES_CONVERT(XmNlabelPixmap, path), NULp);
766  free(path);
767  }
768 }
769 
770 void AW_window::create_toggle(const char *var_name, aw_toggle_data *tdata) {
771  AW_cb *cbs = _callback;
772  _callback = (AW_cb *)1;
773 
774  {
775  int old_length_of_buttons = _at->length_of_buttons;
776 
777  if (tdata->buttonWidth == 0) {
778  if (tdata->isTextToggle) {
779  int l1 = strlen(tdata->bitmapOrText[0]);
780  int l2 = strlen(tdata->bitmapOrText[1]);
781 
782  _at->length_of_buttons = l1>l2 ? l1 : l2; // use longer text for button size
783  }
784  else {
785  _at->length_of_buttons = 0;
786  }
787  }
788  else {
789  _at->length_of_buttons = tdata->buttonWidth;
790  }
791 
792  create_button(NULp, tdata->bitmapOrText[0]);
793 
794  _at->length_of_buttons = old_length_of_buttons;
795  }
796 
797  AW_awar *vs = this->get_root()->awar(var_name);
798  {
799  char *var_value = vs->read_as_string();
800 
801  this->update_toggle(p_w->toggle_field, var_value, (AW_CL)tdata);
802  free(var_value);
803  }
804 
805  VarUpdateInfo *vui;
806  vui = new VarUpdateInfo(this, p_w->toggle_field, AW_WIDGET_TOGGLE, vs, cbs);
807 
808  XtAddCallback(p_w->toggle_field, XmNactivateCallback,
809  (XtCallbackProc) AW_variable_update_callback,
810  (XtPointer) vui);
811 
812  vs->tie_widget((AW_CL)tdata, p_w->toggle_field, AW_WIDGET_TOGGLE, this);
813 }
814 
815 
816 void AW_window::create_toggle(const char *var_name, const char *no, const char *yes, int buttonWidth) {
817  aw_toggle_data *tdata = new aw_toggle_data;
818  tdata->isTextToggle = false;
819 
822 
823  tdata->bitmapOrText[0] = strdup(no);
824  tdata->bitmapOrText[1] = strdup(yes);
825 
826  tdata->buttonWidth = buttonWidth;
827 
828  create_toggle(var_name, tdata);
829 }
830 
831 void AW_window::create_text_toggle(const char *var_name, const char *noText, const char *yesText, int buttonWidth) {
832  aw_toggle_data *tdata = new aw_toggle_data;
833  tdata->isTextToggle = true;
834  tdata->bitmapOrText[0] = strdup(noText);
835  tdata->bitmapOrText[1] = strdup(yesText);
836  tdata->buttonWidth = buttonWidth;
837 
838  create_toggle(var_name, tdata);
839 }
840 
841 
842 void AW_window::create_toggle(const char *var_name) {
843  create_toggle(var_name, "#no.xpm", "#yes.xpm");
844 }
845 
846 void AW_window::create_inverse_toggle(const char *var_name) {
847  // like create_toggle, but displays inverse value
848  // (i.e. it's checked if value is zero, and unchecked otherwise)
849  create_toggle(var_name, "#yes.xpm", "#no.xpm");
850 }
851 
852 // ---------------------
853 // input fields
854 
855 void AW_window::create_input_field(const char *var_name, int columns) {
856  Widget textField = NULp;
857  Widget tmp_label = NULp;
858  AW_cb *cbs;
859  VarUpdateInfo *vui;
860  char *str;
861  int xoff_for_label = 0;
862 
863  if (!columns) columns = _at->length_of_buttons;
864 
865  AW_awar *vs = root->awar(var_name);
866  str = root->awar(var_name)->read_as_string();
867 
868  int width_of_input_label, height_of_input_label;
869  calculate_label_size(&width_of_input_label, &height_of_input_label, true, NULp);
870  // @@@ FIXME: use height_of_input_label for propper Y-adjusting of label
871  // width_of_input_label = this->calculate_string_width( calculate_label_length() );
872 
873  int width_of_input = this->calculate_string_width(columns+1) + 9;
874  // calculate width for 1 additional character (input field is not completely used)
875  // + 4 pixel for shadow + 4 unknown missing pixels + 1 add. pixel needed for visible text area
876 
877  Widget parentWidget = _at->attach_any ? INFO_FORM : INFO_WIDGET;
878 
879  if (_at->label_for_inputfield) {
880  Label clientlabel(_at->label_for_inputfield, this);
881  tmp_label = XtVaCreateManagedWidget("label",
882  xmLabelWidgetClass,
883  parentWidget,
884  XmNwidth, (int)(width_of_input_label + 2),
885  XmNhighlightThickness, 0,
886  RES_LABEL_CONVERT(clientlabel),
887  XmNrecomputeSize, false,
888  XmNalignment, XmALIGNMENT_BEGINNING,
889  XmNfontList, p_global->fontlist,
890  (_at->attach_any) ? NULp : XmNx, (int)_at->x_for_next_button,
891  XmNy, (int)(_at->y_for_next_button) + root->y_correction_for_input_labels -1,
892  NULp);
893  if (_at->attach_any) aw_attach_widget(tmp_label, _at);
894  xoff_for_label = width_of_input_label + 10;
895  }
896 
897 
898  int width_of_last_widget = xoff_for_label + width_of_input + 2;
899 
900  if (_at->to_position_exists) {
901  width_of_input = _at->to_position_x - _at->x_for_next_button - xoff_for_label + 2;
902  width_of_last_widget = _at->to_position_x - _at->x_for_next_button;
903  }
904 
905  {
906  TuneBackground(parentWidget, TUNE_INPUT);
907  textField = XtVaCreateManagedWidget("textField",
908  xmTextFieldWidgetClass,
909  parentWidget,
910  XmNwidth, (int)width_of_input,
911  XmNrows, 1,
912  XmNvalue, str,
913  XmNfontList, p_global->fontlist,
914  XmNbackground, _at->background_color,
915  (_at->attach_any) ? NULp : XmNx, (int)(_at->x_for_next_button + xoff_for_label),
916  XmNy, (int)(_at->y_for_next_button + 5) - 8,
917  NULp);
918  if (_at->attach_any) {
919  _at->x_for_next_button += xoff_for_label;
920  aw_attach_widget(textField, _at);
921  _at->x_for_next_button -= xoff_for_label;
922  }
923  }
924 
925  free(str);
926 
927  // user-own callback
928  cbs = _callback;
929 
930  // callback for enter
931  vui = new VarUpdateInfo(this, textField, AW_WIDGET_INPUT_FIELD, vs, cbs);
932 
933  XtAddCallback(textField, XmNactivateCallback,
934  (XtCallbackProc) AW_variable_update_callback,
935  (XtPointer) vui);
936  if (_d_callback) {
937  XtAddCallback(textField, XmNactivateCallback,
938  (XtCallbackProc) AW_server_callback,
939  (XtPointer) _d_callback);
940  _d_callback->id = GBS_global_string_copy("INPUT:%s", var_name);
941  get_root()->define_remote_command(_d_callback);
942  }
943 
944  // callback for losing focus
945  XtAddCallback(textField, XmNlosingFocusCallback,
946  (XtCallbackProc) AW_variable_update_callback,
947  (XtPointer) vui);
948  // callback for value changed
949  XtAddCallback(textField, XmNvalueChangedCallback,
950  (XtCallbackProc) AW_value_changed_callback,
951  (XtPointer) root);
952 
953  vs->tie_widget(0, textField, AW_WIDGET_INPUT_FIELD, this);
954  root->make_sensitive(textField, _at->widget_mask);
955 
956  short height;
957  XtVaGetValues(textField, XmNheight, &height, NULp);
958  int height_of_last_widget = height;
959 
960  if (_at->correct_for_at_center == 1) { // middle centered
961  XtVaSetValues(textField, XmNx, ((int)(_at->x_for_next_button + xoff_for_label) - (int)(width_of_last_widget/2) + 1), NULp);
962  if (tmp_label) {
963  XtVaSetValues(tmp_label, XmNx, ((int)(_at->x_for_next_button) - (int)(width_of_last_widget/2) + 1), NULp);
964  }
965  width_of_last_widget = width_of_last_widget / 2;
966  }
967  if (_at->correct_for_at_center == 2) { // right centered
968  XtVaSetValues(textField, XmNx, (int)(_at->x_for_next_button + xoff_for_label - width_of_last_widget + 3), NULp);
969  if (tmp_label) {
970  XtVaSetValues(tmp_label, XmNx, (int)(_at->x_for_next_button - width_of_last_widget + 3), NULp);
971  }
972  width_of_last_widget = 0;
973  }
974  width_of_last_widget -= 2;
975 
976  this->unset_at_commands();
977  this->increment_at_commands(width_of_last_widget, height_of_last_widget);
978 
979 }
980 
981 void AW_window::update_input_field(Widget widget, const char *var_value) {
982  XtVaSetValues(widget, XmNvalue, var_value, NULp);
983 }
984 
985 void AW_window::create_text_field(const char *var_name, int columns, int rows) {
986  Widget scrolledWindowText;
987  Widget scrolledText;
988  Widget tmp_label = NULp;
989  AW_cb *cbs;
990  VarUpdateInfo *vui;
991  char *str = NULp;
992  short width_of_last_widget = 0;
993  short height_of_last_widget = 0;
994  int width_of_text = 0;
995  int height_of_text = 0;
996  int xoff_for_label = 0;
997 
998  AW_awar *vs = root->awar(var_name);
999  str = root->awar(var_name)->read_string();
1000 
1001  int width_of_text_label, height_of_text_label;
1002  calculate_label_size(&width_of_text_label, &height_of_text_label, true, NULp);
1003  // @@@ FIXME: use height_of_text_label for propper Y-adjusting of label
1004 
1005  // width_of_text_label = this->calculate_string_width( calculate_label_length() );
1006  width_of_text = this->calculate_string_width(columns) + 18;
1007  height_of_text = this->calculate_string_height(rows, rows*4) + 9;
1008 
1009 
1010  if (_at->label_for_inputfield) {
1011  Label clientlabel(_at->label_for_inputfield, this);
1012  tmp_label = XtVaCreateManagedWidget("label",
1013  xmLabelWidgetClass,
1014  INFO_WIDGET,
1015  XmNx, (int)_at->x_for_next_button,
1016  XmNy, (int)(_at->y_for_next_button) + this->get_root()->y_correction_for_input_labels + 5 - 6,
1017  XmNwidth, (int)(width_of_text_label + 2),
1018  RES_LABEL_CONVERT(clientlabel),
1019  XmNrecomputeSize, false,
1020  XmNalignment, XmALIGNMENT_BEGINNING,
1021  XmNfontList, p_global->fontlist,
1022  NULp);
1023 
1024  xoff_for_label = width_of_text_label + 10;
1025 
1026  }
1027 
1028  {
1029  aw_xargs args(6);
1030  args.add(XmNscrollingPolicy, XmAPPLICATION_DEFINED);
1031  args.add(XmNvisualPolicy, XmVARIABLE);
1032  args.add(XmNscrollBarDisplayPolicy, XmSTATIC);
1033  args.add(XmNfontList, (XtArgVal)p_global->fontlist);
1034 
1035  if (_at->to_position_exists) {
1036  scrolledWindowText = XtVaCreateManagedWidget("scrolledWindowList1", xmScrolledWindowWidgetClass, INFO_FORM, NULp);
1037  args.assign_to_widget(scrolledWindowText);
1038 
1039  aw_attach_widget(scrolledWindowText, _at);
1040  width_of_text = _at->to_position_x - _at->x_for_next_button - xoff_for_label - 18;
1041  if (_at->y_for_next_button < _at->to_position_y - 18) {
1042  height_of_text = _at->to_position_y - _at->y_for_next_button - 18;
1043  }
1044  }
1045  else {
1046  scrolledWindowText = XtVaCreateManagedWidget("scrolledWindowText", xmScrolledWindowWidgetClass, INFO_WIDGET, NULp);
1047  args.add(XmNx, 10);
1048  args.add(XmNy, _at->y_for_next_button);
1049  args.assign_to_widget(scrolledWindowText);
1050  }
1051  }
1052 
1053  TuneBackground(scrolledWindowText, TUNE_INPUT);
1054  scrolledText = XtVaCreateManagedWidget("scrolledText1",
1055  xmTextWidgetClass,
1056  scrolledWindowText,
1057  XmNeditMode, XmMULTI_LINE_EDIT,
1058  XmNvalue, str,
1059  XmNscrollLeftSide, false,
1060  XmNwidth, (int)width_of_text,
1061  XmNheight, (int)height_of_text,
1062  XmNfontList, p_global->fontlist,
1063  XmNbackground, _at->background_color,
1064  NULp);
1065  free(str);
1066 
1067  if (!_at->to_position_exists) {
1068  XtVaGetValues(scrolledWindowText, XmNheight, &height_of_last_widget,
1069  XmNwidth, &width_of_last_widget, NULp);
1070 
1071  width_of_last_widget += (short)xoff_for_label;
1072 
1073  switch (_at->correct_for_at_center) {
1074  case 0: // left centered
1075  XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label), NULp);
1076  break;
1077 
1078  case 1: // middle centered
1079  XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label - (width_of_last_widget/2)), NULp);
1080  if (_at->label_for_inputfield) {
1081  XtVaSetValues(tmp_label, XmNx, (int)(_at->x_for_next_button - (width_of_last_widget/2)), NULp);
1082  }
1083  width_of_last_widget = width_of_last_widget / 2;
1084  break;
1085 
1086  case 2: // right centered
1087  XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label - width_of_last_widget), NULp);
1088  if (_at->label_for_inputfield) {
1089  XtVaSetValues(tmp_label, XmNx, (int)(_at->x_for_next_button - width_of_last_widget), NULp);
1090  }
1091  width_of_last_widget = 0;
1092  break;
1093  }
1094  }
1095 
1096  // user-own callback
1097  cbs = _callback;
1098 
1099  // callback for enter
1100  vui = new VarUpdateInfo(this, scrolledText, AW_WIDGET_TEXT_FIELD, vs, cbs);
1101  XtAddCallback(scrolledText, XmNactivateCallback, (XtCallbackProc) AW_variable_update_callback, (XtPointer) vui);
1102  // callback for losing focus
1103  XtAddCallback(scrolledText, XmNlosingFocusCallback, (XtCallbackProc) AW_variable_update_callback, (XtPointer) vui);
1104  // callback for value changed
1105  XtAddCallback(scrolledText, XmNvalueChangedCallback, (XtCallbackProc) AW_value_changed_callback, (XtPointer) root);
1106 
1107  vs->tie_widget(0, scrolledText, AW_WIDGET_TEXT_FIELD, this);
1108  root->make_sensitive(scrolledText, _at->widget_mask);
1109 
1110  this->unset_at_commands();
1111  this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1112 }
1113 
1114 
1115 void AW_window::update_text_field(Widget widget, const char *var_value) {
1116  XtVaSetValues(widget, XmNvalue, var_value, NULp);
1117 }
1118 
1119 static void scalerChanged_cb(Widget scale, XtPointer variable_update_struct, XtPointer call_data) {
1120  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct*)call_data;
1121  VarUpdateInfo *vui = (VarUpdateInfo*)variable_update_struct;
1122 
1123  bool do_update = true;
1124  if (cbs->reason == XmCR_DRAG) { // still dragging?
1125  double mean_callback_time = vui->get_awar()->mean_callback_time();
1126 
1127  const double MAX_DRAGGED_CALLBACK_TIME = 1.0;
1128  if (mean_callback_time>MAX_DRAGGED_CALLBACK_TIME) {
1129  do_update = false; // do not update while dragging, if update callback needs more than 1 second
1130  // Note that a longer update will happen once!
1131  }
1132  }
1133 
1134  if (do_update) {
1136  AW_variable_update_callback(scale, variable_update_struct, call_data);
1137  }
1138 }
1139 
1140 void AW_window::create_input_field_with_scaler(const char *awar_name, int textcolumns, int scaler_length, AW_ScalerType scalerType) {
1141  create_input_field(awar_name, textcolumns);
1142 
1143  Widget parentWidget = _at->attach_any ? INFO_FORM : INFO_WIDGET;
1144 
1145  AW_awar *vs = root->awar(awar_name);
1146  // Note: scaler also "works" if no min/max is defined for awar, but scaling is a bit weird
1147  int scalerValue = calculate_scaler_value(vs, scalerType);
1148 
1149  Widget scale = XtVaCreateManagedWidget("scale",
1150  xmScaleWidgetClass,
1151  parentWidget,
1152  XmNx, _at->x_for_next_button,
1153  XmNy, _at->y_for_next_button + 4,
1154  XmNorientation, XmHORIZONTAL,
1155  XmNscaleWidth, scaler_length,
1156  XmNshowValue, False,
1157  XmNminimum, SCALER_MIN_VALUE,
1158  XmNmaximum, SCALER_MAX_VALUE,
1159  XmNvalue, scalerValue,
1160  NULp);
1161 
1162  short width_of_last_widget = 0;
1163  short height_of_last_widget = 0;
1164 
1165  XtVaGetValues(scale,
1166  XmNheight, &height_of_last_widget,
1167  XmNwidth, &width_of_last_widget,
1168  NULp);
1169 
1170  AW_cb *cbs = _callback;
1171  VarUpdateInfo *vui = new VarUpdateInfo(this, scale, AW_WIDGET_SCALER, vs, cbs);
1172  vui->set_scalerType(scalerType);
1173 
1174  XtAddCallback(scale, XmNvalueChangedCallback, scalerChanged_cb, (XtPointer)vui);
1175  XtAddCallback(scale, XmNdragCallback, scalerChanged_cb, (XtPointer)vui);
1176 
1177  vs->tie_widget((AW_CL)scalerType, scale, AW_WIDGET_SCALER, this);
1178  root->make_sensitive(scale, _at->widget_mask);
1179 
1180  this->unset_at_commands();
1181  this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1182 }
1183 
1184 void AW_window::update_scaler(Widget widget, AW_awar *awar, AW_ScalerType scalerType) {
1185  int scalerVal = calculate_scaler_value(awar, scalerType);
1186  XtVaSetValues(widget, XmNvalue, scalerVal, NULp);
1187 }
1188 
1189 // -----------------------
1190 // selection list
1191 
1192 
1193 static void scroll_sellist(Widget scrolledList, bool upwards) {
1194  int oldPos, visible, items;
1195  XtVaGetValues(scrolledList,
1196  XmNtopItemPosition, &oldPos,
1197  XmNvisibleItemCount, &visible,
1198  XmNitemCount, &items,
1199  NULp);
1200 
1201  int amount = visible/5;
1202  if (amount<1) amount = 1;
1203  if (upwards) amount = -amount;
1204 
1205  int newPos = force_in_range(1, oldPos + amount, items-visible+2);
1206  if (newPos != oldPos) XmListSetPos(scrolledList, newPos);
1207 }
1208 
1209 static void scroll_sellist_up(Widget scrolledList, XEvent*, String*, Cardinal*) { scroll_sellist(scrolledList, true); }
1210 static void scroll_sellist_dn(Widget scrolledList, XEvent*, String*, Cardinal*) { scroll_sellist(scrolledList, false); }
1211 
1212 AW_selection_list* AW_window::create_selection_list(const char *var_name, int columns, int rows, bool /*fallback2default*/) {
1213  // Note: fallback2default has no meaning in motif-version (always acts like 'false', i.e. never does fallback)
1214  // see also AW_option_toggle.cxx@create_option_menu
1215 
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:3144
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:281
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:403
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:738
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:3077
int max_y_size
Definition: aw_at.hxx:36
AW_ScalerType
Definition: aw_window.hxx:223
#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:293
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:204
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:477
char * id
Definition: aw_window.hxx:130
Definition: aw_at.hxx:18
char * window_defaults_name
window title
Definition: aw_window.hxx:336
void update_text_field(Widget widget, const char *var_value)
Definition: AW_button.cxx:1115
#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:575
#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:756
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:1140
void update_input_field(Widget widget, const char *var_value)
Definition: AW_button.cxx:981
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:1209
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:399
bool highlight
Definition: aw_at.hxx:24
#define MIN_RIGHT_OFFSET
AW_selection_list * create_selection_list(const char *awar_name, int columns, int rows, bool fallback2default)
Definition: AW_button.cxx:1212
#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:185
void create_inverse_toggle(const char *awar_name)
Definition: AW_button.cxx:846
static void scalerChanged_cb(Widget scale, XtPointer variable_update_struct, XtPointer call_data)
Definition: AW_button.cxx:1119
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:463
AW_cb * _d_callback
Definition: aw_window.hxx:282
static void scroll_sellist(Widget scrolledList, bool upwards)
Definition: AW_button.cxx:1193
static void scroll_sellist_dn(Widget scrolledList, XEvent *, String *, Cardinal *)
Definition: AW_button.cxx:1210
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:393
bool attach_y
Definition: aw_at.hxx:59
#define false
Definition: ureadseq.h:13
AW_root * root
Definition: aw_window.hxx:264
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:3113
#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:194
char * read_string() const
Definition: AW_awar.cxx:201
GB_CSTR GB_path_in_ARBLIB(const char *relative_path)
Definition: adsocket.cxx:1124
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:419
#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:855
#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:280
void update_scaler(Widget widget, AW_awar *awar, AW_ScalerType scalerType)
Definition: AW_button.cxx:1184
#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:3244
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
int to_position_x
Definition: aw_at.hxx:38
char(& no)[2]
Definition: downcast.h:31
void aw_message(const char *msg)
Definition: AW_status.cxx:932
char * bitmapOrText[2]
Definition: AW_button.cxx:752
void set_scalerType(AW_ScalerType scalerType_)
AW_root * get_root()
Definition: aw_window.hxx:348
TrackedAwarChange(AW_awar *awar_)
Definition: AW_button.cxx:45
void dump_at_position(const char *debug_label) const
Definition: AW_button.cxx:734
#define NULp
Definition: cxxforward.h:97
void create_text_toggle(const char *var_name, const char *noText, const char *yesText, int buttonWidth=0)
Definition: AW_button.cxx:831
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:2144
void AW_server_callback(Widget, XtPointer aw_cb_struct, XtPointer)
Definition: AW_window.cxx:1383
#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:162
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:165
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:985
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:195
void tie_widget(AW_CL cd1, Widget widget, AW_widget_type type, AW_window *aww)
Definition: AW_awar.cxx:260
void create_button(const char *macro_name, AW_label label, const char *mnemonic=NULp, const char *color=NULp)
Definition: AW_button.cxx:446
void set_sellist(AW_selection_list *asl)