1 | // ================================================================ // |
---|
2 | // // |
---|
3 | // File : AW_modal.cxx // |
---|
4 | // Purpose : Modal dialogs // |
---|
5 | // // |
---|
6 | // Institute of Microbiology (Technical University Munich) // |
---|
7 | // http://www.arb-home.de/ // |
---|
8 | // // |
---|
9 | // ================================================================ // |
---|
10 | |
---|
11 | #include <aw_window.hxx> |
---|
12 | #include <aw_global.hxx> |
---|
13 | #include <aw_file.hxx> |
---|
14 | #include <aw_awar.hxx> |
---|
15 | #include "aw_root.hxx" |
---|
16 | #include "aw_question.hxx" |
---|
17 | #include "aw_advice.hxx" |
---|
18 | #include "aw_msg.hxx" |
---|
19 | #include "aw_select.hxx" |
---|
20 | |
---|
21 | #include <arbdbt.h> |
---|
22 | #include <arb_strarray.h> |
---|
23 | |
---|
24 | #include <deque> |
---|
25 | #include <string> |
---|
26 | #include <algorithm> |
---|
27 | |
---|
28 | using namespace std; |
---|
29 | |
---|
30 | #define AWAR_QUESTION "tmp/question" |
---|
31 | |
---|
32 | #define AW_MESSAGE_LISTEN_DELAY 500 // look in ms whether a father died |
---|
33 | |
---|
34 | static int aw_message_cb_result; |
---|
35 | |
---|
36 | void message_cb(AW_window *, AW_CL cd1) { |
---|
37 | long result = (long)cd1; |
---|
38 | if (result == -1) { // exit |
---|
39 | exit(EXIT_FAILURE); |
---|
40 | } |
---|
41 | aw_message_cb_result = ((int)result); |
---|
42 | return; |
---|
43 | } |
---|
44 | |
---|
45 | static void aw_message_timer_listen_event(AW_root *awr, AW_CL cl1, AW_CL cl2) |
---|
46 | { |
---|
47 | #if defined(TRACE_STATUS_MORE) |
---|
48 | fprintf(stderr, "in aw_message_timer_listen_event\n"); fflush(stdout); |
---|
49 | #endif // TRACE_STATUS_MORE |
---|
50 | |
---|
51 | AW_window *aww = ((AW_window *)cl1); |
---|
52 | if (aww->is_shown()) { |
---|
53 | awr->add_timed_callback_never_disabled(AW_MESSAGE_LISTEN_DELAY, aw_message_timer_listen_event, cl1, cl2); |
---|
54 | } |
---|
55 | } |
---|
56 | |
---|
57 | // -------------------- |
---|
58 | // aw_question |
---|
59 | |
---|
60 | void AW_reactivate_all_questions() { |
---|
61 | GB_transaction ta(AW_ROOT_DEFAULT); |
---|
62 | GBDATA *gb_neverAskedAgain = GB_search(AW_ROOT_DEFAULT, "answers", GB_FIND); |
---|
63 | const char *msg = "No questions were disabled yet."; |
---|
64 | |
---|
65 | if (gb_neverAskedAgain) { |
---|
66 | int reactivated = 0; |
---|
67 | for (GBDATA *gb_q = GB_child(gb_neverAskedAgain); gb_q; gb_q = GB_nextChild(gb_q)) { |
---|
68 | if (GB_read_int(gb_q)) { |
---|
69 | GB_write_int(gb_q, 0); |
---|
70 | reactivated++; |
---|
71 | } |
---|
72 | } |
---|
73 | if (reactivated) { |
---|
74 | msg = GBS_global_string("Reactivated %i questions (for this session)\n" |
---|
75 | "To reactivate them for future sessions, save properties.", |
---|
76 | reactivated); |
---|
77 | } |
---|
78 | } |
---|
79 | aw_message(msg); |
---|
80 | } |
---|
81 | |
---|
82 | int aw_question(const char *uniqueID, const char *question, const char *buttons, bool fixedSizeButtons, const char *helpfile) { |
---|
83 | // return 0 for first button, 1 for second button, 2 for third button, ... |
---|
84 | // |
---|
85 | // the single buttons are separated by commas (e.g. "YES,NO") |
---|
86 | // If the button-name starts with ^ it starts a new row of buttons |
---|
87 | // (if a button named 'EXIT' is pressed the program terminates using exit(EXIT_FAILURE)) |
---|
88 | // |
---|
89 | // The remaining arguments only apply if 'buttons' is non-zero: |
---|
90 | // |
---|
91 | // If fixedSizeButtons is true all buttons have the same size |
---|
92 | // otherwise the size for every button is set depending on the text length |
---|
93 | // |
---|
94 | // If 'helpfile' is non-zero a HELP button is added. |
---|
95 | |
---|
96 | aw_assert(buttons); |
---|
97 | |
---|
98 | AW_root *root = AW_root::SINGLETON; |
---|
99 | |
---|
100 | char *awar_name_neverAskAgain = NULL; |
---|
101 | int have_auto_answer = 0; |
---|
102 | |
---|
103 | if (uniqueID) { |
---|
104 | GB_ERROR error = GB_check_key(uniqueID); |
---|
105 | if (error) { |
---|
106 | aw_message(error); |
---|
107 | uniqueID = NULL; |
---|
108 | } |
---|
109 | else { |
---|
110 | awar_name_neverAskAgain = GBS_global_string_copy("answers/%s", uniqueID); |
---|
111 | AW_awar *awar_neverAskAgain = root->awar_int(awar_name_neverAskAgain, 0, AW_ROOT_DEFAULT); |
---|
112 | have_auto_answer = awar_neverAskAgain->read_int(); |
---|
113 | } |
---|
114 | } |
---|
115 | |
---|
116 | if (have_auto_answer>0) { |
---|
117 | aw_message_cb_result = have_auto_answer-1; |
---|
118 | } |
---|
119 | else { |
---|
120 | char *button_list = strdup(buttons ? buttons : "OK"); |
---|
121 | if (button_list[0] == 0) { |
---|
122 | freedup(button_list, "Maybe ok,EXIT"); |
---|
123 | GBK_dump_backtrace(stderr, "Empty buttonlist"); |
---|
124 | question = GBS_global_string_copy("%s\n" |
---|
125 | "(Program error - Unsure what happens when you click ok\n" |
---|
126 | " Check console for backtrace and report error)", |
---|
127 | question); |
---|
128 | } |
---|
129 | |
---|
130 | AW_awar *awar_quest = root->awar_string(AWAR_QUESTION); |
---|
131 | if (!question) question = "<oops - no question?!>"; |
---|
132 | awar_quest->write_string(question); |
---|
133 | |
---|
134 | size_t question_length, question_lines; |
---|
135 | aw_detect_text_size(question, question_length, question_lines); |
---|
136 | |
---|
137 | // hash key to find matching window |
---|
138 | char *hindex = GBS_global_string_copy("%s$%s$%zu$%zu$%i$%s", |
---|
139 | button_list, uniqueID ? uniqueID : "<NOID>", |
---|
140 | question_length, question_lines, int(fixedSizeButtons), |
---|
141 | helpfile ? helpfile : ""); |
---|
142 | |
---|
143 | static GB_HASH *hash_windows = 0; |
---|
144 | if (!hash_windows) hash_windows = GBS_create_hash(256, GB_MIND_CASE); |
---|
145 | AW_window_message *aw_msg = (AW_window_message *)GBS_read_hash(hash_windows, hindex); |
---|
146 | |
---|
147 | #if defined(DEBUG) |
---|
148 | printf("hindex='%s'\n", hindex); |
---|
149 | #endif // DEBUG |
---|
150 | |
---|
151 | if (!aw_msg) { |
---|
152 | aw_msg = new AW_window_message; |
---|
153 | GBS_write_hash(hash_windows, hindex, (long)aw_msg); |
---|
154 | |
---|
155 | aw_msg->init(root, "QUESTION BOX", false); |
---|
156 | aw_msg->recalc_size_atShow(AW_RESIZE_DEFAULT); // force size recalc (ignores user size) |
---|
157 | |
---|
158 | aw_msg->label_length(10); |
---|
159 | |
---|
160 | aw_msg->at(10, 10); |
---|
161 | aw_msg->auto_space(10, 10); |
---|
162 | |
---|
163 | aw_msg->button_length(question_length+3); |
---|
164 | aw_msg->button_height(question_lines+1); |
---|
165 | |
---|
166 | aw_msg->create_button(0, AWAR_QUESTION); |
---|
167 | |
---|
168 | aw_msg->button_height(0); |
---|
169 | |
---|
170 | aw_msg->at_newline(); |
---|
171 | |
---|
172 | if (fixedSizeButtons) { |
---|
173 | size_t max_button_length = helpfile ? 4 : 0; |
---|
174 | char *pos = button_list; |
---|
175 | |
---|
176 | while (1) { |
---|
177 | char *comma = strchr(pos, ','); |
---|
178 | if (!comma) comma = strchr(pos, 0); |
---|
179 | |
---|
180 | size_t len = comma-pos; |
---|
181 | if (len>max_button_length) max_button_length = len; |
---|
182 | |
---|
183 | if (!comma[0]) break; |
---|
184 | pos = comma+1; |
---|
185 | } |
---|
186 | |
---|
187 | aw_msg->button_length(max_button_length+2); |
---|
188 | } |
---|
189 | else { |
---|
190 | aw_msg->button_length(0); |
---|
191 | } |
---|
192 | |
---|
193 | // insert the buttons: |
---|
194 | char *ret = strtok(button_list, ","); |
---|
195 | bool help_button_done = false; |
---|
196 | int counter = 0; |
---|
197 | |
---|
198 | while (ret) { |
---|
199 | if (ret[0] == '^') { |
---|
200 | if (helpfile && !help_button_done) { |
---|
201 | aw_msg->callback(AW_POPUP_HELP, (AW_CL)helpfile); |
---|
202 | aw_msg->create_button("HELP", "HELP", "H"); |
---|
203 | help_button_done = true; |
---|
204 | } |
---|
205 | aw_msg->at_newline(); |
---|
206 | ++ret; |
---|
207 | } |
---|
208 | if (strcmp(ret, "EXIT") == 0) { |
---|
209 | aw_msg->callback(message_cb, -1); |
---|
210 | } |
---|
211 | else { |
---|
212 | aw_msg->callback(message_cb, (AW_CL)counter++); |
---|
213 | } |
---|
214 | |
---|
215 | if (fixedSizeButtons) { |
---|
216 | aw_msg->create_button(0, ret); |
---|
217 | } |
---|
218 | else { |
---|
219 | aw_msg->create_autosize_button(0, ret); |
---|
220 | } |
---|
221 | ret = strtok(NULL, ","); |
---|
222 | } |
---|
223 | |
---|
224 | if (helpfile && !help_button_done) { // if not done above |
---|
225 | aw_msg->callback(AW_POPUP_HELP, (AW_CL)helpfile); |
---|
226 | aw_msg->create_button("HELP", "HELP", "H"); |
---|
227 | help_button_done = true; |
---|
228 | } |
---|
229 | |
---|
230 | if (uniqueID) { |
---|
231 | aw_msg->at_newline(); |
---|
232 | const char *label = counter>1 ? "Never ask again" : "Never notify me again"; |
---|
233 | aw_msg->label_length(strlen(label)); |
---|
234 | aw_msg->label(label); |
---|
235 | aw_msg->create_toggle(awar_name_neverAskAgain); |
---|
236 | } |
---|
237 | |
---|
238 | aw_msg->window_fit(); |
---|
239 | } |
---|
240 | else { |
---|
241 | #if defined(DEBUG) |
---|
242 | printf("[Reusing existing aw_question-window]\n"); |
---|
243 | #endif |
---|
244 | } |
---|
245 | free(hindex); |
---|
246 | aw_msg->show_modal(); |
---|
247 | |
---|
248 | free(button_list); |
---|
249 | aw_message_cb_result = -13; |
---|
250 | |
---|
251 | #if defined(TRACE_STATUS_MORE) |
---|
252 | fprintf(stderr, "add aw_message_timer_listen_event with delay = %i\n", AW_MESSAGE_LISTEN_DELAY); fflush(stdout); |
---|
253 | #endif // TRACE_STATUS_MORE |
---|
254 | root->add_timed_callback_never_disabled(AW_MESSAGE_LISTEN_DELAY, aw_message_timer_listen_event, (AW_CL)aw_msg, 0); |
---|
255 | |
---|
256 | { |
---|
257 | LocallyModify<bool> flag(root->disable_callbacks, true); |
---|
258 | while (aw_message_cb_result == -13) { |
---|
259 | root->process_events(); |
---|
260 | } |
---|
261 | } |
---|
262 | aw_msg->hide(); |
---|
263 | |
---|
264 | if (awar_name_neverAskAgain) { |
---|
265 | AW_awar *awar_neverAskAgain = root->awar(awar_name_neverAskAgain); |
---|
266 | |
---|
267 | if (awar_neverAskAgain->read_int()) { // user checked "Never ask again" |
---|
268 | int givenAnswer = aw_message_cb_result >= 0 ? aw_message_cb_result+1 : 0; |
---|
269 | awar_neverAskAgain->write_int(givenAnswer); // store given answer for "never asking again" |
---|
270 | |
---|
271 | if (givenAnswer && strchr(buttons, ',') != 0) { |
---|
272 | const char *appname = root->program_name; |
---|
273 | char *advice = GBS_global_string_copy("You will not be asked that question again in this session.\n" |
---|
274 | "%s will always assume the answer you just gave.\n" |
---|
275 | "\n" |
---|
276 | "When you restart %s that question will be asked again.\n" |
---|
277 | "To disable that question permanently for future sessions,\n" |
---|
278 | "you need to save properties.\n" |
---|
279 | "\n" |
---|
280 | "Depending on the type of question doing that might be\n" |
---|
281 | "helpful or obstructive.\n" |
---|
282 | "Disabled questions can be reactivated from the properties menu.\n", |
---|
283 | appname, appname); |
---|
284 | AW_advice(advice, AW_ADVICE_TOGGLE, "Disabling questions", NULL); |
---|
285 | free(advice); |
---|
286 | } |
---|
287 | } |
---|
288 | } |
---|
289 | } |
---|
290 | |
---|
291 | free(awar_name_neverAskAgain); |
---|
292 | |
---|
293 | switch (aw_message_cb_result) { |
---|
294 | case -1: // exit with core |
---|
295 | fprintf(stderr, "Core dump requested\n"); |
---|
296 | ARB_SIGSEGV(1); |
---|
297 | break; |
---|
298 | case -2: // exit without core |
---|
299 | exit(-1); |
---|
300 | break; |
---|
301 | } |
---|
302 | return aw_message_cb_result; |
---|
303 | } |
---|
304 | |
---|
305 | bool aw_ask_sure(const char *uniqueID, const char *msg) { |
---|
306 | return aw_question(uniqueID, msg, "Yes,No", true, NULL) == 0; |
---|
307 | } |
---|
308 | void aw_popup_ok(const char *msg) { |
---|
309 | aw_question(NULL, msg, "Ok", true, NULL); |
---|
310 | } |
---|
311 | void aw_popup_exit(const char *msg) { |
---|
312 | aw_question(NULL, msg, "EXIT", true, NULL); |
---|
313 | aw_assert(0); // should not be reached |
---|
314 | exit(EXIT_FAILURE); |
---|
315 | } |
---|
316 | |
---|
317 | |
---|
318 | // ----------------- |
---|
319 | // aw_input |
---|
320 | |
---|
321 | static char *aw_input_cb_result = 0; |
---|
322 | static int aw_string_selected_button = -2; |
---|
323 | |
---|
324 | int aw_string_selection_button() { |
---|
325 | aw_assert(aw_string_selected_button != -2); |
---|
326 | return aw_string_selected_button; |
---|
327 | } |
---|
328 | |
---|
329 | #define AW_INPUT_AWAR "tmp/input/string" |
---|
330 | #define AW_INPUT_TITLE_AWAR "tmp/input/title" |
---|
331 | |
---|
332 | #define AW_FILE_SELECT_BASE "tmp/file_select" |
---|
333 | #define AW_FILE_SELECT_DIR_AWAR AW_FILE_SELECT_BASE "/directory" |
---|
334 | #define AW_FILE_SELECT_FILE_AWAR AW_FILE_SELECT_BASE "/file_name" |
---|
335 | #define AW_FILE_SELECT_FILTER_AWAR AW_FILE_SELECT_BASE "/filter" |
---|
336 | #define AW_FILE_SELECT_TITLE_AWAR AW_FILE_SELECT_BASE "/title" |
---|
337 | |
---|
338 | static void create_input_awars(AW_root *aw_root) { |
---|
339 | aw_root->awar_string(AW_INPUT_TITLE_AWAR, "", AW_ROOT_DEFAULT); |
---|
340 | aw_root->awar_string(AW_INPUT_AWAR, "", AW_ROOT_DEFAULT); |
---|
341 | } |
---|
342 | |
---|
343 | static void create_fileSelection_awars(AW_root *aw_root) { |
---|
344 | aw_root->awar_string(AW_FILE_SELECT_TITLE_AWAR, "", AW_ROOT_DEFAULT); |
---|
345 | aw_root->awar_string(AW_FILE_SELECT_DIR_AWAR, "", AW_ROOT_DEFAULT); |
---|
346 | aw_root->awar_string(AW_FILE_SELECT_FILE_AWAR, "", AW_ROOT_DEFAULT); |
---|
347 | aw_root->awar_string(AW_FILE_SELECT_FILTER_AWAR, "", AW_ROOT_DEFAULT); |
---|
348 | } |
---|
349 | |
---|
350 | |
---|
351 | // ------------------------- |
---|
352 | // aw_input history |
---|
353 | |
---|
354 | static deque<string> input_history; // front contains newest entries |
---|
355 | |
---|
356 | #if defined(DEBUG) |
---|
357 | // # define TRACE_HISTORY |
---|
358 | #endif // DEBUG |
---|
359 | |
---|
360 | |
---|
361 | #if defined(TRACE_HISTORY) |
---|
362 | static void dumpHistory(const char *where) { |
---|
363 | printf("History [%s]:\n", where); |
---|
364 | for (deque<string>::iterator h = input_history.begin(); h != input_history.end(); ++h) { |
---|
365 | printf("'%s'\n", h->c_str()); |
---|
366 | } |
---|
367 | } |
---|
368 | #endif // TRACE_HISTORY |
---|
369 | |
---|
370 | static void input_history_insert(const char *str, bool front) { |
---|
371 | string s(str); |
---|
372 | |
---|
373 | if (input_history.empty()) { |
---|
374 | input_history.push_front(""); // insert an empty string into history |
---|
375 | } |
---|
376 | else { |
---|
377 | deque<string>::iterator found = find(input_history.begin(), input_history.end(), s); |
---|
378 | if (found != input_history.end()) { |
---|
379 | input_history.erase(found); |
---|
380 | } |
---|
381 | } |
---|
382 | if (front) { |
---|
383 | input_history.push_front(s); |
---|
384 | } |
---|
385 | else { |
---|
386 | input_history.push_back(s); |
---|
387 | } |
---|
388 | |
---|
389 | #if defined(TRACE_HISTORY) |
---|
390 | dumpHistory(GBS_global_string("input_history_insert('%s', front=%i)", str, front)); |
---|
391 | #endif // TRACE_HISTORY |
---|
392 | } |
---|
393 | |
---|
394 | void input_history_cb(AW_window *aw, AW_CL cl_mode) { |
---|
395 | int mode = (int)cl_mode; // -1 = '<' +1 = '>' |
---|
396 | AW_root *aw_root = aw->get_root(); |
---|
397 | AW_awar *awar = aw_root->awar(AW_INPUT_AWAR); |
---|
398 | char *content = awar->read_string(); |
---|
399 | |
---|
400 | if (content) input_history_insert(content, mode == 1); |
---|
401 | |
---|
402 | if (!input_history.empty()) { |
---|
403 | if (mode == -1) { |
---|
404 | string s = input_history.front(); |
---|
405 | awar->write_string(s.c_str()); |
---|
406 | input_history.pop_front(); |
---|
407 | input_history.push_back(s); |
---|
408 | } |
---|
409 | else { |
---|
410 | string s = input_history.back(); |
---|
411 | awar->write_string(s.c_str()); |
---|
412 | input_history.pop_back(); |
---|
413 | input_history.push_front(s); |
---|
414 | } |
---|
415 | } |
---|
416 | |
---|
417 | #if defined(TRACE_HISTORY) |
---|
418 | dumpHistory(GBS_global_string("input_history_cb(mode=%i)", mode)); |
---|
419 | #endif // TRACE_HISTORY |
---|
420 | |
---|
421 | free(content); |
---|
422 | } |
---|
423 | |
---|
424 | void input_cb(AW_window *aw, AW_CL cd1) { |
---|
425 | // any previous contents were passed to client (who is responsible to free the resources) |
---|
426 | // so DON'T free aw_input_cb_result here: |
---|
427 | aw_input_cb_result = 0; |
---|
428 | aw_string_selected_button = int(cd1); |
---|
429 | |
---|
430 | if (cd1 >= 0) { // <0 = cancel button -> no result |
---|
431 | // create heap-copy of result -> client will get the owner |
---|
432 | aw_input_cb_result = aw->get_root()->awar(AW_INPUT_AWAR)->read_as_string(); |
---|
433 | } |
---|
434 | } |
---|
435 | |
---|
436 | void file_selection_cb(AW_window *aw, AW_CL cd1) { |
---|
437 | // any previous contents were passed to client (who is responsible to free the resources) |
---|
438 | // so DON'T free aw_input_cb_result here: |
---|
439 | aw_input_cb_result = 0; |
---|
440 | aw_string_selected_button = int(cd1); |
---|
441 | |
---|
442 | if (cd1 >= 0) { // <0 = cancel button -> no result |
---|
443 | // create heap-copy of result -> client will get the owner |
---|
444 | aw_input_cb_result = aw->get_root()->awar(AW_FILE_SELECT_FILE_AWAR)->read_as_string(); |
---|
445 | } |
---|
446 | } |
---|
447 | |
---|
448 | #define INPUT_SIZE 50 // size of input prompts in aw_input and aw_string_selection |
---|
449 | |
---|
450 | static AW_window_message *new_input_window(AW_root *root, const char *title, const char *buttons) { |
---|
451 | // helper for aw_input and aw_string_selection |
---|
452 | // |
---|
453 | // 'buttons' comma separated list of button names (buttons starting with \n force a newline) |
---|
454 | |
---|
455 | AW_window_message *aw_msg = new AW_window_message; |
---|
456 | |
---|
457 | aw_msg->init(root, title, false); |
---|
458 | |
---|
459 | aw_msg->label_length(0); |
---|
460 | aw_msg->auto_space(10, 10); |
---|
461 | |
---|
462 | aw_msg->at(10, 10); |
---|
463 | aw_msg->button_length(INPUT_SIZE+1); |
---|
464 | aw_msg->create_button(0, AW_INPUT_TITLE_AWAR); |
---|
465 | |
---|
466 | aw_msg->at_newline(); |
---|
467 | aw_msg->create_input_field(AW_INPUT_AWAR, INPUT_SIZE); |
---|
468 | |
---|
469 | size_t butCount = 2; // ok and cancel |
---|
470 | ConstStrArray button_names; |
---|
471 | int maxlen = 6; // use as min.length for buttons (for 'CANCEL') |
---|
472 | |
---|
473 | if (buttons) { |
---|
474 | GBT_split_string(button_names, buttons, ','); |
---|
475 | butCount = button_names.size(); |
---|
476 | |
---|
477 | for (size_t b = 0; b<butCount; b++) { |
---|
478 | int len = strlen(button_names[b]); |
---|
479 | if (len>maxlen) maxlen = len; |
---|
480 | } |
---|
481 | |
---|
482 | } |
---|
483 | |
---|
484 | aw_msg->button_length(maxlen+1); |
---|
485 | |
---|
486 | #define MAXBUTTONSPERLINE 5 |
---|
487 | |
---|
488 | aw_msg->at_newline(); |
---|
489 | aw_msg->callback(input_history_cb, -1); aw_msg->create_button("bwd", "<<", 0); |
---|
490 | aw_msg->callback(input_history_cb, 1); aw_msg->create_button("fwd", ">>", 0); |
---|
491 | size_t thisLine = 2; |
---|
492 | |
---|
493 | // @@@ add a history button (opening a window with elements from history) |
---|
494 | |
---|
495 | if (butCount>(MAXBUTTONSPERLINE-thisLine) && butCount <= MAXBUTTONSPERLINE) { // approx. 5 buttons (2+3) fit into one line |
---|
496 | aw_msg->at_newline(); |
---|
497 | thisLine = 0; |
---|
498 | } |
---|
499 | |
---|
500 | if (buttons) { |
---|
501 | for (size_t b = 0; b<butCount; b++) { |
---|
502 | const char *name = button_names[b]; |
---|
503 | bool forceLF = name[0] == '\n'; |
---|
504 | |
---|
505 | if (thisLine >= MAXBUTTONSPERLINE || forceLF) { |
---|
506 | aw_msg->at_newline(); |
---|
507 | thisLine = 0; |
---|
508 | if (forceLF) name++; |
---|
509 | } |
---|
510 | aw_msg->callback(input_cb, b); // use b == 0 as result for 1st button, 1 for 2nd button, etc. |
---|
511 | aw_msg->create_button(name, name, ""); |
---|
512 | thisLine++; |
---|
513 | } |
---|
514 | } |
---|
515 | else { |
---|
516 | aw_msg->callback(input_cb, 0); aw_msg->create_button("OK", "OK", "O"); |
---|
517 | aw_msg->callback(input_cb, -1); aw_msg->create_button("CANCEL", "CANCEL", "C"); |
---|
518 | } |
---|
519 | |
---|
520 | return aw_msg; |
---|
521 | } |
---|
522 | |
---|
523 | char *aw_input(const char *title, const char *prompt, const char *default_input) { |
---|
524 | // prompt user to enter a string |
---|
525 | // |
---|
526 | // title = title of window |
---|
527 | // prompt = question |
---|
528 | // default_input = default for answer (NULL -> "") |
---|
529 | // |
---|
530 | // result is NULL, if cancel was pressed |
---|
531 | // otherwise result contains the user input (maybe an empty string) |
---|
532 | |
---|
533 | static AW_window_message *aw_msg = 0; |
---|
534 | |
---|
535 | AW_root *root = AW_root::SINGLETON; |
---|
536 | if (!aw_msg) create_input_awars(root); // first call -> create awars |
---|
537 | |
---|
538 | root->awar(AW_INPUT_TITLE_AWAR)->write_string(prompt); |
---|
539 | aw_assert(strlen(prompt) <= INPUT_SIZE); |
---|
540 | |
---|
541 | AW_awar *inAwar = root->awar(AW_INPUT_AWAR); |
---|
542 | if (default_input) { |
---|
543 | input_history_insert(default_input, true); // insert default into history |
---|
544 | inAwar->write_string(default_input); |
---|
545 | } |
---|
546 | else { |
---|
547 | inAwar->write_string(""); |
---|
548 | } |
---|
549 | |
---|
550 | aw_assert(GB_get_transaction_level(inAwar->gb_var) <= 0); // otherwise history would not work |
---|
551 | |
---|
552 | if (!aw_msg) aw_msg = new_input_window(root, title, NULL); |
---|
553 | else aw_msg->set_window_title(title); |
---|
554 | |
---|
555 | aw_msg->window_fit(); |
---|
556 | aw_msg->show_modal(); |
---|
557 | char dummy[] = ""; |
---|
558 | aw_input_cb_result = dummy; |
---|
559 | |
---|
560 | root->add_timed_callback_never_disabled(AW_MESSAGE_LISTEN_DELAY, aw_message_timer_listen_event, (AW_CL)aw_msg, 0); |
---|
561 | { |
---|
562 | LocallyModify<bool> flag(root->disable_callbacks, true); |
---|
563 | while (aw_input_cb_result == dummy) { |
---|
564 | root->process_events(); |
---|
565 | } |
---|
566 | } |
---|
567 | aw_msg->hide(); |
---|
568 | |
---|
569 | if (aw_input_cb_result) input_history_insert(aw_input_cb_result, true); |
---|
570 | return aw_input_cb_result; |
---|
571 | } |
---|
572 | |
---|
573 | char *aw_input(const char *prompt, const char *default_input) { |
---|
574 | return aw_input("Enter string", prompt, default_input); |
---|
575 | } |
---|
576 | |
---|
577 | static char *aw_input2awar(const char *title, const char *prompt, const char *awar_name) { |
---|
578 | AW_root *aw_root = AW_root::SINGLETON; |
---|
579 | AW_awar *awar = aw_root->awar(awar_name); |
---|
580 | char *default_value = awar->read_string(); |
---|
581 | char *result = aw_input(title, prompt, default_value); |
---|
582 | |
---|
583 | awar->write_string(result); |
---|
584 | free(default_value); |
---|
585 | |
---|
586 | return result; |
---|
587 | } |
---|
588 | |
---|
589 | char *aw_input2awar(const char *prompt, const char *awar_name) { |
---|
590 | return aw_input2awar("Enter string", prompt, awar_name); |
---|
591 | } |
---|
592 | |
---|
593 | |
---|
594 | char *aw_string_selection(const char *title, const char *prompt, const char *default_input, const char *value_list, const char *buttons, char *(*check_fun)(const char*)) { |
---|
595 | // A modal input window. A String may be entered by hand or selected from value_list |
---|
596 | // |
---|
597 | // title window title |
---|
598 | // prompt prompt at input field |
---|
599 | // default_input default value (if NULL => ""). |
---|
600 | // value_list Existing selections (separated by ';') or NULL if no selection exists |
---|
601 | // buttons String containing answer button names separated by ',' (default is "OK,Cancel") |
---|
602 | // Use aw_string_selected_button() to detect which has been pressed. |
---|
603 | // check_fun function to correct input (or NULL for no check). The function may return NULL to indicate no correction |
---|
604 | // |
---|
605 | // returns the value of the inputfield |
---|
606 | |
---|
607 | static GB_HASH *str_sels = 0; // for each 'buttons' store window + selection list |
---|
608 | |
---|
609 | if (!str_sels) str_sels = GBS_create_hash(100, GB_MIND_CASE); |
---|
610 | |
---|
611 | struct str_sel_data { |
---|
612 | AW_window_message *aw_msg; |
---|
613 | AW_selection_list *sel; |
---|
614 | }; |
---|
615 | |
---|
616 | const char *bkey = buttons ? buttons : ",default,"; |
---|
617 | str_sel_data *sd = (str_sel_data*)GBS_read_hash(str_sels, bkey); |
---|
618 | if (!sd) { |
---|
619 | sd = new str_sel_data; |
---|
620 | sd->aw_msg = 0; |
---|
621 | sd->sel = 0; |
---|
622 | |
---|
623 | GBS_write_hash(str_sels, bkey, (long)sd); |
---|
624 | } |
---|
625 | |
---|
626 | AW_window_message *& aw_msg = sd->aw_msg; |
---|
627 | AW_selection_list *& sel = sd->sel; |
---|
628 | |
---|
629 | AW_root *root = AW_root::SINGLETON; |
---|
630 | if (!aw_msg) create_input_awars(root); // first call -> create awars |
---|
631 | |
---|
632 | root->awar(AW_INPUT_TITLE_AWAR)->write_string(prompt); |
---|
633 | aw_assert(strlen(prompt) <= INPUT_SIZE); |
---|
634 | |
---|
635 | AW_awar *inAwar = root->awar(AW_INPUT_AWAR); |
---|
636 | if (default_input) { |
---|
637 | input_history_insert(default_input, true); // insert default into history |
---|
638 | inAwar->write_string(default_input); |
---|
639 | } |
---|
640 | else { |
---|
641 | inAwar->write_string(""); |
---|
642 | } |
---|
643 | |
---|
644 | aw_assert(GB_get_transaction_level(inAwar->gb_var) <= 0); // otherwise history would not work |
---|
645 | |
---|
646 | if (!aw_msg) { |
---|
647 | aw_msg = new_input_window(root, title, buttons); |
---|
648 | |
---|
649 | aw_msg->at_newline(); |
---|
650 | sel = aw_msg->create_selection_list(AW_INPUT_AWAR, INPUT_SIZE, 10); |
---|
651 | sel->insert_default("", ""); |
---|
652 | sel->update(); |
---|
653 | } |
---|
654 | else { |
---|
655 | aw_msg->set_window_title(title); |
---|
656 | } |
---|
657 | aw_msg->window_fit(); |
---|
658 | |
---|
659 | // update the selection box : |
---|
660 | aw_assert(sel); |
---|
661 | sel->clear(); |
---|
662 | if (value_list) { |
---|
663 | char *values = strdup(value_list); |
---|
664 | char *word; |
---|
665 | |
---|
666 | for (word = strtok(values, ";"); word; word = strtok(0, ";")) { |
---|
667 | sel->insert(word, word); |
---|
668 | } |
---|
669 | free(values); |
---|
670 | } |
---|
671 | sel->insert_default("<new>", ""); |
---|
672 | sel->update(); |
---|
673 | |
---|
674 | // do modal loop : |
---|
675 | aw_msg->show_modal(); |
---|
676 | char dummy[] = ""; |
---|
677 | aw_input_cb_result = dummy; |
---|
678 | |
---|
679 | root->add_timed_callback_never_disabled(AW_MESSAGE_LISTEN_DELAY, aw_message_timer_listen_event, (AW_CL)aw_msg, 0); |
---|
680 | { |
---|
681 | LocallyModify<bool> flag(root->disable_callbacks, true); |
---|
682 | |
---|
683 | char *last_input = root->awar(AW_INPUT_AWAR)->read_string(); |
---|
684 | while (aw_input_cb_result == dummy) { |
---|
685 | root->process_events(); |
---|
686 | |
---|
687 | char *this_input = root->awar(AW_INPUT_AWAR)->read_string(); |
---|
688 | if (strcmp(this_input, last_input) != 0) { |
---|
689 | if (check_fun) { |
---|
690 | char *corrected_input = check_fun(this_input); |
---|
691 | if (corrected_input) { |
---|
692 | if (strcmp(corrected_input, this_input) != 0) { |
---|
693 | root->awar(AW_INPUT_AWAR)->write_string(corrected_input); |
---|
694 | } |
---|
695 | free(corrected_input); |
---|
696 | } |
---|
697 | } |
---|
698 | reassign(last_input, this_input); |
---|
699 | } |
---|
700 | free(this_input); |
---|
701 | |
---|
702 | if (!aw_msg->is_shown()) { // somebody hided/closed the window |
---|
703 | input_cb(aw_msg, (AW_CL)-1); // CANCEL |
---|
704 | break; |
---|
705 | } |
---|
706 | } |
---|
707 | |
---|
708 | free(last_input); |
---|
709 | } |
---|
710 | aw_msg->hide(); |
---|
711 | |
---|
712 | return aw_input_cb_result; |
---|
713 | } |
---|
714 | |
---|
715 | char *aw_string_selection2awar(const char *title, const char *prompt, const char *awar_name, const char *value_list, const char *buttons, char *(*check_fun)(const char*)) { |
---|
716 | // params see aw_string_selection |
---|
717 | // default_value is taken from and result is written back to awar 'awar_name' |
---|
718 | |
---|
719 | AW_root *aw_root = AW_root::SINGLETON; |
---|
720 | AW_awar *awar = aw_root->awar(awar_name); |
---|
721 | char *default_value = awar->read_string(); |
---|
722 | char *result = aw_string_selection(title, prompt, default_value, value_list, buttons, check_fun); |
---|
723 | |
---|
724 | awar->write_string(result); |
---|
725 | free(default_value); |
---|
726 | |
---|
727 | return result; |
---|
728 | } |
---|
729 | |
---|
730 | // -------------------------- |
---|
731 | // aw_file_selection |
---|
732 | |
---|
733 | char *aw_file_selection(const char *title, const char *dir, const char *def_name, const char *suffix) { |
---|
734 | AW_root *root = AW_root::SINGLETON; |
---|
735 | |
---|
736 | static AW_window_simple *aw_msg = 0; |
---|
737 | if (!aw_msg) create_fileSelection_awars(root); |
---|
738 | |
---|
739 | { |
---|
740 | char *edir = GBS_eval_env(dir); |
---|
741 | char *edef_name = GBS_eval_env(def_name); |
---|
742 | |
---|
743 | root->awar(AW_FILE_SELECT_TITLE_AWAR) ->write_string(title); |
---|
744 | root->awar(AW_FILE_SELECT_DIR_AWAR) ->write_string(edir); |
---|
745 | root->awar(AW_FILE_SELECT_FILE_AWAR) ->write_string(edef_name); |
---|
746 | root->awar(AW_FILE_SELECT_FILTER_AWAR)->write_string(suffix); |
---|
747 | |
---|
748 | free(edef_name); |
---|
749 | free(edir); |
---|
750 | } |
---|
751 | |
---|
752 | if (!aw_msg) { |
---|
753 | aw_msg = new AW_window_simple; |
---|
754 | |
---|
755 | aw_msg->init(root, "AW_FILE_SELECTION", "File selection"); |
---|
756 | aw_msg->allow_delete_window(false); // disable closing the window |
---|
757 | |
---|
758 | aw_msg->load_xfig("fileselect.fig"); |
---|
759 | |
---|
760 | aw_msg->at("title"); |
---|
761 | aw_msg->create_button(0, AW_FILE_SELECT_TITLE_AWAR); |
---|
762 | |
---|
763 | AW_create_fileselection(aw_msg, AW_FILE_SELECT_BASE); |
---|
764 | |
---|
765 | aw_msg->button_length(7); |
---|
766 | |
---|
767 | aw_msg->at("ok"); |
---|
768 | aw_msg->callback(file_selection_cb, 0); |
---|
769 | aw_msg->create_button("OK", "OK", "O"); |
---|
770 | |
---|
771 | aw_msg->at("cancel"); |
---|
772 | aw_msg->callback(file_selection_cb, -1); |
---|
773 | aw_msg->create_button("CANCEL", "CANCEL", "C"); |
---|
774 | |
---|
775 | aw_msg->window_fit(); |
---|
776 | } |
---|
777 | |
---|
778 | aw_msg->show_modal(); |
---|
779 | char dummy[] = ""; |
---|
780 | aw_input_cb_result = dummy; |
---|
781 | |
---|
782 | root->add_timed_callback_never_disabled(AW_MESSAGE_LISTEN_DELAY, aw_message_timer_listen_event, (AW_CL)aw_msg, 0); |
---|
783 | { |
---|
784 | LocallyModify<bool> flag(root->disable_callbacks, true); |
---|
785 | while (aw_input_cb_result == dummy) { |
---|
786 | root->process_events(); |
---|
787 | } |
---|
788 | } |
---|
789 | aw_msg->hide(); |
---|
790 | |
---|
791 | return aw_input_cb_result; |
---|
792 | } |
---|
793 | |
---|
794 | |
---|