webperimental: killstack decides stack protects.
[freeciv.git] / client / gui-gtk-4.0 / cma_fe.c
blob5672c695d8261221325815657d30ce709587cf7f
1 /***********************************************************************
2 Freeciv - Copyright (C) 2001 - R. Falke, M. Kaufman
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <gdk/gdkkeysyms.h>
20 /* utility */
21 #include "fcintl.h"
22 #include "log.h"
23 #include "mem.h"
24 #include "support.h"
26 /* common */
27 #include "events.h"
28 #include "game.h"
30 /* client */
31 #include "chatline_g.h"
32 #include "citydlg_g.h"
33 #include "client_main.h"
34 #include "cma_fec.h"
35 #include "messagewin_g.h"
36 #include "options.h"
38 /* client/gui-gtk-4.0 */
39 #include "cityrep.h"
40 #include "dialogs.h"
41 #include "gui_main.h"
42 #include "gui_stuff.h"
43 #include "helpdlg.h"
44 #include "inputdlg.h"
46 #include "cma_fe.h"
48 #define BUFFER_SIZE 64
50 #define SPECLIST_TAG dialog
51 #define SPECLIST_TYPE struct cma_dialog
52 #include "speclist.h"
54 #define dialog_list_iterate(dialoglist, pdialog) \
55 TYPED_LIST_ITERATE(struct cma_dialog, dialoglist, pdialog)
56 #define dialog_list_iterate_end LIST_ITERATE_END
58 static struct dialog_list *dialog_list;
60 static int allow_refreshes = 1;
62 static struct cma_dialog *get_cma_dialog(struct city *pcity);
64 static void update_cma_preset_list(struct cma_dialog *pdialog);
66 static gboolean cma_preset_key_pressed_callback(GtkWidget *w, GdkEventKey *ev,
67 gpointer data);
68 static void cma_del_preset_callback(GtkWidget *w, gpointer data);
69 static void cma_preset_remove(struct cma_dialog *pdialog, int preset_index);
70 static void cma_preset_remove_response(GtkWidget *w, gint response,
71 gpointer data);
73 static void cma_add_preset_callback(GtkWidget *w, gpointer data);
74 static void cma_preset_add_popup_callback(gpointer data, gint response,
75 const char *input);
77 static void cma_active_callback(GtkWidget *w, gpointer data);
78 static void cma_activate_preset_callback(GtkTreeView *view, GtkTreePath *path,
79 GtkTreeViewColumn *col, gpointer data);
81 static void hscale_changed(GtkWidget *get, gpointer data);
82 static void set_hscales(const struct cm_parameter *const parameter,
83 struct cma_dialog *pdialog);
85 /**************************************************************************
86 Initialize cma front end system
87 **************************************************************************/
88 void cma_fe_init()
90 dialog_list = dialog_list_new();
93 /**************************************************************************
94 Free resources allocated for cma front end system
95 **************************************************************************/
96 void cma_fe_done()
98 dialog_list_destroy(dialog_list);
101 /**************************************************************************
102 only called when the city dialog is closed.
103 **************************************************************************/
104 void close_cma_dialog(struct city *pcity)
106 struct cma_dialog *pdialog = get_cma_dialog(pcity);
108 if (pdialog == NULL) {
109 /* A city which is being investigated doesn't contain cma dialog */
110 return;
112 gtk_widget_destroy(pdialog->shell);
115 /**************************************************************************
116 Destroy cma dialog
117 **************************************************************************/
118 static void cma_dialog_destroy_callback(GtkWidget *w, gpointer data)
120 struct cma_dialog *pdialog = (struct cma_dialog *) data;
122 dialog_list_remove(dialog_list, pdialog);
123 free(pdialog);
126 /****************************************************************
127 return the cma_dialog for a given city.
128 *****************************************************************/
129 struct cma_dialog *get_cma_dialog(struct city *pcity)
131 dialog_list_iterate(dialog_list, pdialog) {
132 if (pdialog->pcity == pcity) {
133 return pdialog;
135 } dialog_list_iterate_end;
137 return NULL;
140 /**************************************************************************
141 User has pressed button in cma dialog
142 **************************************************************************/
143 static gboolean button_press_callback(GtkTreeView *view, GdkEventButton *ev,
144 gpointer data)
146 GtkTreePath *path;
147 GtkTreeViewColumn *column;
149 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view),
150 ev->x, ev->y, &path, &column, NULL, NULL)) {
151 if (ev->type == GDK_BUTTON_PRESS) {
152 cma_activate_preset_callback(view, path, column, data);
153 } else if (ev->type == GDK_2BUTTON_PRESS) {
154 struct cma_dialog *pdialog = (struct cma_dialog *) data;
155 struct cm_parameter param;
157 cmafec_get_fe_parameter(pdialog->pcity, &param);
158 cma_put_city_under_agent(pdialog->pcity, &param);
159 refresh_city_dialog(pdialog->pcity);
162 gtk_tree_path_free(path);
164 return FALSE;
167 /**************************************************************************
168 User has requested help
169 **************************************************************************/
170 static void help_callback(GtkWidget *w, gpointer data)
172 popup_help_dialog_string(HELP_CMA_ITEM);
175 /**************************************************************************
176 Cell data function for cma dialog
177 **************************************************************************/
178 static void cell_data_func(GtkTreeViewColumn *col, GtkCellRenderer *cell,
179 GtkTreeModel *model, GtkTreeIter *it, gpointer data)
181 struct cma_dialog *pdialog = (struct cma_dialog *) data;
182 char *s1;
183 const char *s2;
184 int i1, i2;
185 struct cm_parameter param;
186 GtkTreePath *path;
188 gtk_tree_model_get(model, it, 0, &s1, -1);
189 if (s1 == NULL) {
190 return;
192 path = gtk_tree_model_get_path(model, it);
193 i1 = gtk_tree_path_get_indices(path)[0];
194 gtk_tree_path_free(path);
196 cmafec_get_fe_parameter(pdialog->pcity, &param);
197 s2 = cmafec_get_short_descr(&param);
198 i2 = cmafec_preset_get_index_of_parameter(&param);
200 if (!strcmp(s1, s2) && i1 == i2) {
201 g_object_set(G_OBJECT(cell), "style", PANGO_STYLE_ITALIC,
202 "weight", PANGO_WEIGHT_BOLD, NULL);
203 } else {
204 g_object_set(G_OBJECT(cell), "style", PANGO_STYLE_NORMAL,
205 "weight", PANGO_WEIGHT_NORMAL, NULL);
208 g_free(s1);
211 /**************************************************************************
212 Instantiates a new struct for each city_dialog window that is open.
213 **************************************************************************/
214 struct cma_dialog *create_cma_dialog(struct city *pcity, bool tiny)
216 struct cma_dialog *pdialog;
217 struct cm_parameter param;
218 GtkWidget *frame, *page, *hbox, *label, *table;
219 GtkWidget *vbox, *sw, *hscale, *button;
220 GtkListStore *store;
221 GtkCellRenderer *rend;
222 GtkWidget *view;
223 GtkTreeViewColumn *column;
224 gint layout_width;
226 cmafec_get_fe_parameter(pcity, &param);
227 pdialog = fc_malloc(sizeof(struct cma_dialog));
228 pdialog->pcity = pcity;
229 pdialog->shell = gtk_grid_new();
230 gtk_orientable_set_orientation(GTK_ORIENTABLE(pdialog->shell),
231 GTK_ORIENTATION_VERTICAL);
232 gtk_grid_set_row_spacing(GTK_GRID(pdialog->shell), 8);
233 gtk_widget_set_margin_start(pdialog->shell, 8);
234 gtk_widget_set_margin_end(pdialog->shell, 8);
235 gtk_widget_set_margin_top(pdialog->shell, 8);
236 gtk_widget_set_margin_bottom(pdialog->shell, 8);
237 g_signal_connect(pdialog->shell, "destroy",
238 G_CALLBACK(cma_dialog_destroy_callback), pdialog);
240 page = gtk_grid_new();
241 gtk_grid_set_column_spacing(GTK_GRID(page), 12);
242 gtk_container_add(GTK_CONTAINER(pdialog->shell), page);
244 vbox = gtk_grid_new();
245 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
246 GTK_ORIENTATION_VERTICAL);
247 gtk_grid_set_row_spacing(GTK_GRID(pdialog->shell), 2);
248 gtk_container_add(GTK_CONTAINER(page), vbox);
250 sw = gtk_scrolled_window_new(NULL, NULL);
251 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
252 GTK_SHADOW_ETCHED_IN);
253 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
254 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
256 store = gtk_list_store_new(1, G_TYPE_STRING);
257 pdialog->store = store;
259 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
260 gtk_widget_set_hexpand(view, TRUE);
261 gtk_widget_set_vexpand(view, TRUE);
262 g_object_unref(store);
263 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
264 pdialog->preset_list = view;
265 pdialog->selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
267 g_signal_connect(pdialog->preset_list, "button_press_event",
268 G_CALLBACK(button_press_callback), pdialog);
270 gtk_widget_set_tooltip_text(view,
271 _("For information on\n"
272 "the citizen governor and governor presets,\n"
273 "including sample presets,\n"
274 "see README.governor."));
276 rend = gtk_cell_renderer_text_new();
277 column = gtk_tree_view_column_new_with_attributes(NULL, rend,
278 "text", 0, NULL);
279 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
280 gtk_tree_view_column_set_cell_data_func(column, rend, cell_data_func,
281 pdialog, NULL);
283 label = g_object_new(GTK_TYPE_LABEL,
284 "use-underline", TRUE,
285 "mnemonic-widget", view,
286 "label", _("Prese_ts:"),
287 "xalign", 0.0, "yalign", 0.5, NULL);
288 gtk_container_add(GTK_CONTAINER(vbox), label);
290 gtk_container_add(GTK_CONTAINER(sw), view);
291 gtk_container_add(GTK_CONTAINER(vbox), sw);
293 g_signal_connect(view, "row_activated",
294 G_CALLBACK(cma_activate_preset_callback), pdialog);
295 g_signal_connect(view, "key-press-event",
296 G_CALLBACK(cma_preset_key_pressed_callback), pdialog);
298 hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
299 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_EDGE);
300 gtk_container_add(GTK_CONTAINER(vbox), hbox);
302 button = icon_label_button_new("document-new", _("Ne_w"));
303 gtk_container_add(GTK_CONTAINER(hbox), button);
304 g_signal_connect(button, "clicked",
305 G_CALLBACK(cma_add_preset_callback), pdialog);
306 pdialog->add_preset_command = button;
308 pdialog->del_preset_command = icon_label_button_new("edit-delete", _("Delete"));
309 gtk_container_add(GTK_CONTAINER(hbox), pdialog->del_preset_command);
310 g_signal_connect(pdialog->del_preset_command, "clicked",
311 G_CALLBACK(cma_del_preset_callback), pdialog);
313 /* the right-hand side */
315 vbox = gtk_grid_new();
316 g_object_set(vbox, "margin", 2, NULL);
317 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
318 GTK_ORIENTATION_VERTICAL);
319 gtk_container_add(GTK_CONTAINER(page), vbox);
321 /* Result */
322 if (!tiny) {
323 frame = gtk_frame_new(_("Results"));
324 gtk_widget_set_vexpand(frame, TRUE);
325 gtk_widget_set_valign(frame, GTK_ALIGN_CENTER);
326 gtk_container_add(GTK_CONTAINER(vbox), frame);
328 pdialog->result_label =
329 gtk_label_new("food\n prod\n trade\n\n people\n grow\n prod\n name");
330 gtk_widget_set_name(pdialog->result_label, "city_label");
331 gtk_container_add(GTK_CONTAINER(frame), pdialog->result_label);
332 gtk_label_set_justify(GTK_LABEL(pdialog->result_label), GTK_JUSTIFY_LEFT);
333 } else {
334 pdialog->result_label = NULL;
337 /* Minimal Surplus and Factor */
339 table = gtk_grid_new();
340 g_object_set(table, "margin", 2, NULL);
341 gtk_container_add(GTK_CONTAINER(vbox), table);
343 label = gtk_label_new(_("Minimal Surplus"));
344 gtk_widget_set_halign(label, GTK_ALIGN_START);
345 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
346 gtk_grid_attach(GTK_GRID(table), label, 1, 0, 1, 1);
347 label = gtk_label_new(_("Factor"));
348 gtk_widget_set_halign(label, GTK_ALIGN_START);
349 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
350 gtk_grid_attach(GTK_GRID(table), label, 2, 0, 1, 1);
352 output_type_iterate(i) {
353 label = gtk_label_new(get_output_name(i));
354 gtk_grid_attach(GTK_GRID(table), label, 0, i + 1, 1, 1);
355 gtk_widget_set_halign(label, GTK_ALIGN_START);
356 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
358 pdialog->minimal_surplus[i] = hscale =
359 gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, NULL);
360 gtk_range_set_range(GTK_RANGE(hscale),
361 GUI_GTK_OPTION(governor_range_min),
362 GUI_GTK_OPTION(governor_range_max));
363 gtk_range_set_increments(GTK_RANGE(hscale), 1, 1);
364 pango_layout_get_pixel_size(gtk_scale_get_layout(GTK_SCALE(hscale)),
365 &layout_width, NULL);
366 gtk_widget_set_size_request(hscale, layout_width + 51 * 2, -1);
368 gtk_grid_attach(GTK_GRID(table), hscale, 1, i + 1, 1, 1);
369 gtk_scale_set_digits(GTK_SCALE(hscale), 0);
370 gtk_scale_set_value_pos(GTK_SCALE(hscale), GTK_POS_LEFT);
372 g_signal_connect(pdialog->minimal_surplus[i],
373 "value-changed",
374 G_CALLBACK(hscale_changed), pdialog);
376 pdialog->factor[i] = hscale =
377 gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, NULL);
378 gtk_range_set_range(GTK_RANGE(hscale), 0, 25);
379 gtk_range_set_increments(GTK_RANGE(hscale), 1, 1);
380 pango_layout_get_pixel_size(gtk_scale_get_layout(GTK_SCALE(hscale)),
381 &layout_width, NULL);
382 gtk_widget_set_size_request(hscale, layout_width + 26 * 2, -1);
384 gtk_grid_attach(GTK_GRID(table), hscale, 2, i + 1, 1, 1);
385 gtk_scale_set_digits(GTK_SCALE(hscale), 0);
386 gtk_scale_set_value_pos(GTK_SCALE(hscale), GTK_POS_LEFT);
388 g_signal_connect(pdialog->factor[i], "value-changed",
389 G_CALLBACK(hscale_changed), pdialog);
390 } output_type_iterate_end;
392 /* Happy Surplus and Factor */
394 label = gtk_label_new(_("Celebrate"));
395 gtk_grid_attach(GTK_GRID(table), label, 0, O_LAST + 1, 1, 1);
396 gtk_widget_set_halign(label, GTK_ALIGN_START);
397 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
399 pdialog->happy_button = gtk_check_button_new();
400 gtk_widget_set_halign(pdialog->happy_button, GTK_ALIGN_END);
401 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pdialog->happy_button),
402 FALSE);
403 gtk_grid_attach(GTK_GRID(table), pdialog->happy_button, 1, O_LAST + 1, 1, 1);
405 g_signal_connect(pdialog->happy_button, "toggled",
406 G_CALLBACK(hscale_changed), pdialog);
408 pdialog->factor[O_LAST] = hscale =
409 gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, NULL);
410 gtk_range_set_range(GTK_RANGE(hscale), 0, 50);
411 gtk_range_set_increments(GTK_RANGE(hscale), 1, 1);
412 pango_layout_get_pixel_size(gtk_scale_get_layout(GTK_SCALE(hscale)),
413 &layout_width, NULL);
414 gtk_widget_set_size_request(hscale, layout_width + 51 * 2, -1);
416 gtk_grid_attach(GTK_GRID(table), hscale, 2, O_LAST + 1, 1, 1);
417 gtk_scale_set_digits(GTK_SCALE(hscale), 0);
418 gtk_scale_set_value_pos(GTK_SCALE(hscale), GTK_POS_LEFT);
420 g_signal_connect(pdialog->factor[O_LAST],
421 "value-changed",
422 G_CALLBACK(hscale_changed), pdialog);
424 /* buttons */
426 hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
427 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_EDGE);
428 gtk_container_add(GTK_CONTAINER(vbox), hbox);
430 button = icon_label_button_new("help-browser", _("Help"));
431 g_signal_connect(button, "clicked",
432 G_CALLBACK(help_callback), NULL);
433 gtk_container_add(GTK_CONTAINER(hbox), button);
434 gtk_button_box_set_child_non_homogeneous(GTK_BUTTON_BOX(hbox),
435 button, TRUE);
437 pdialog->active_command = gtk_toggle_button_new();
438 gtk_button_set_use_underline(GTK_BUTTON(pdialog->active_command), TRUE);
439 gtk_widget_set_name(pdialog->active_command, "comment_label");
440 gtk_container_add(GTK_CONTAINER(hbox), pdialog->active_command);
442 gtk_widget_show(pdialog->shell);
444 dialog_list_prepend(dialog_list, pdialog);
446 update_cma_preset_list(pdialog);
448 gtk_tree_view_focus(GTK_TREE_VIEW(view));
450 /* refresh is done in refresh_city_dialog */
452 return pdialog;
455 /**************************************************************************
456 refreshes the cma dialog
457 **************************************************************************/
458 void refresh_cma_dialog(struct city *pcity, enum cma_refresh refresh)
460 struct cm_result *result = cm_result_new(pcity);
461 struct cm_parameter param;
462 struct cma_dialog *pdialog = get_cma_dialog(pcity);
463 int controlled = cma_is_city_under_agent(pcity, NULL);
465 cmafec_get_fe_parameter(pcity, &param);
467 if (pdialog->result_label != NULL) {
468 /* fill in result label */
469 cm_result_from_main_map(result, pcity);
470 gtk_label_set_text(GTK_LABEL(pdialog->result_label),
471 cmafec_get_result_descr(pcity, result, &param));
474 /* if called from a hscale, we _don't_ want to do this */
475 if (refresh != DONT_REFRESH_HSCALES) {
476 set_hscales(&param, pdialog);
479 gtk_widget_queue_draw(pdialog->preset_list);
481 gtk_widget_set_sensitive(pdialog->active_command, can_client_issue_orders());
483 g_signal_handlers_disconnect_matched(pdialog->active_command,
484 G_SIGNAL_MATCH_FUNC,
485 0, 0, NULL, cma_active_callback, NULL);
486 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pdialog->active_command),
487 controlled);
488 g_signal_connect(pdialog->active_command, "clicked",
489 G_CALLBACK(cma_active_callback), pdialog);
491 if (controlled) {
492 gtk_button_set_label(GTK_BUTTON(pdialog->active_command),
493 _("Governor Enabl_ed"));
494 } else {
495 gtk_button_set_label(GTK_BUTTON(pdialog->active_command),
496 _("Governor Disabl_ed"));
499 if (pdialog->result_label != NULL) {
500 gtk_widget_set_sensitive(pdialog->result_label, controlled);
503 cm_result_destroy(result);
506 /**************************************************************************
507 fills in the preset list
508 **************************************************************************/
509 static void update_cma_preset_list(struct cma_dialog *pdialog)
511 char buf[BUFFER_SIZE];
512 GtkTreeIter it;
513 int i;
515 /* Fill preset list */
516 gtk_list_store_clear(pdialog->store);
518 /* Append the presets */
519 if (cmafec_preset_num()) {
520 for (i = 0; i < cmafec_preset_num(); i++) {
521 fc_strlcpy(buf, cmafec_preset_get_descr(i), sizeof(buf));
522 gtk_list_store_append(pdialog->store, &it);
523 gtk_list_store_set(pdialog->store, &it, 0, buf, -1);
528 /****************************************************************
529 callback for selecting a preset from the preset view
530 *****************************************************************/
531 static void cma_activate_preset_callback(GtkTreeView *view, GtkTreePath *path,
532 GtkTreeViewColumn *col, gpointer data)
534 struct cma_dialog *pdialog = (struct cma_dialog *) data;
535 int preset_index;
536 const struct cm_parameter *pparam;
538 preset_index = gtk_tree_path_get_indices(path) [0];
540 pparam = cmafec_preset_get_parameter(preset_index);
542 /* save the change */
543 cmafec_set_fe_parameter(pdialog->pcity, pparam);
545 if (cma_is_city_under_agent(pdialog->pcity, NULL)) {
546 cma_release_city(pdialog->pcity);
547 cma_put_city_under_agent(pdialog->pcity, pparam);
549 refresh_city_dialog(pdialog->pcity);
552 /**************************************************************************
553 pops up a dialog to allow to name your new preset
554 **************************************************************************/
555 static void cma_add_preset_callback(GtkWidget *w, gpointer data)
557 struct cma_dialog *pdialog = (struct cma_dialog *) data;
558 const char *default_name;
559 GtkWidget *parent = gtk_widget_get_toplevel(pdialog->shell);
560 int index;
562 if ((index = gtk_tree_selection_get_row(pdialog->selection)) != -1) {
563 default_name = cmafec_preset_get_descr(index);
564 } else {
565 default_name = _("new preset");
568 pdialog->name_shell = input_dialog_create(GTK_WINDOW(parent),
569 _("Name new preset"),
570 _("What should we name the preset?"),
571 default_name,
572 cma_preset_add_popup_callback, pdialog);
575 /****************************************************************
576 callback for the add_preset popup
577 *****************************************************************/
578 static void cma_preset_add_popup_callback(gpointer data, gint response,
579 const char *input)
581 struct cma_dialog *pdialog = (struct cma_dialog *) data;
583 if (pdialog) {
584 if (response == GTK_RESPONSE_OK) {
585 struct cm_parameter param;
587 cmafec_get_fe_parameter(pdialog->pcity, &param);
588 cmafec_preset_add(input, &param);
589 update_cma_preset_list(pdialog);
590 refresh_cma_dialog(pdialog->pcity, DONT_REFRESH_HSCALES);
591 /* if this or other cities have this set as "custom" */
592 city_report_dialog_update();
593 } /* else CANCEL or DELETE_EVENT */
595 pdialog->name_shell = NULL;
599 /****************************************************************
600 Key pressed in preset list
601 *****************************************************************/
602 static gboolean cma_preset_key_pressed_callback(GtkWidget *w, GdkEventKey *ev,
603 gpointer data)
605 struct cma_dialog *pdialog = (struct cma_dialog *) data;
606 int index;
608 if ((index = gtk_tree_selection_get_row(pdialog->selection)) == -1) {
609 return FALSE;
612 if (ev->type == GDK_KEY_PRESS) {
613 switch (ev->keyval) {
614 case GDK_KEY_Delete:
615 cma_preset_remove(pdialog, index);
616 break;
617 case GDK_KEY_Insert:
618 cma_add_preset_callback(NULL, pdialog);
619 break;
620 default:
621 return FALSE;
623 return TRUE;
625 return FALSE;
629 /**************************************************************************
630 callback for del_preset
631 **************************************************************************/
632 static void cma_del_preset_callback(GtkWidget *w, gpointer data)
634 struct cma_dialog *pdialog = (struct cma_dialog *) data;
635 int index;
637 if ((index = gtk_tree_selection_get_row(pdialog->selection)) == -1) {
638 return;
641 cma_preset_remove(pdialog, index);
644 /**************************************************************************
645 pops up a dialog to remove a preset
646 **************************************************************************/
647 static void cma_preset_remove(struct cma_dialog *pdialog, int preset_index)
649 GtkWidget *parent = gtk_widget_get_toplevel(pdialog->shell), *shl;
651 pdialog->id = preset_index;
652 shl = gtk_message_dialog_new(NULL,
653 GTK_DIALOG_DESTROY_WITH_PARENT,
654 GTK_MESSAGE_QUESTION,
655 GTK_BUTTONS_YES_NO,
656 _("Remove this preset?"));
657 setup_dialog(shl, parent);
658 pdialog->preset_remove_shell = shl;
660 gtk_window_set_title(GTK_WINDOW(shl), cmafec_preset_get_descr(preset_index));
661 gtk_window_set_position(GTK_WINDOW(shl), GTK_WIN_POS_CENTER_ON_PARENT);
663 g_signal_connect(shl, "response",
664 G_CALLBACK(cma_preset_remove_response), pdialog);
666 gtk_window_present(GTK_WINDOW(shl));
669 /****************************************************************
670 callback for the remove_preset popup
671 *****************************************************************/
672 static void cma_preset_remove_response(GtkWidget *w, gint response,
673 gpointer data)
675 struct cma_dialog *pdialog = (struct cma_dialog *) data;
677 if (response == GTK_RESPONSE_YES) {
678 cmafec_preset_remove(pdialog->id);
679 pdialog->id = -1;
680 update_cma_preset_list(pdialog);
681 refresh_cma_dialog(pdialog->pcity, DONT_REFRESH_HSCALES);
682 /* if this or other cities have this set, reset to "custom" */
683 city_report_dialog_update();
685 gtk_widget_destroy(w);
687 pdialog->preset_remove_shell = NULL;
690 /**************************************************************************
691 activates/deactivates agent control.
692 **************************************************************************/
693 static void cma_active_callback(GtkWidget *w, gpointer data)
695 struct cma_dialog *pdialog = (struct cma_dialog *) data;
697 if (cma_is_city_under_agent(pdialog->pcity, NULL)) {
698 cma_release_city(pdialog->pcity);
699 } else {
700 struct cm_parameter param;
702 cmafec_get_fe_parameter(pdialog->pcity, &param);
703 cma_put_city_under_agent(pdialog->pcity, &param);
705 refresh_city_dialog(pdialog->pcity);
708 /****************************************************************
709 called to adjust the sliders when a preset is selected
710 notice that we don't want to call update_result here.
711 *****************************************************************/
712 static void set_hscales(const struct cm_parameter *const parameter,
713 struct cma_dialog *pdialog)
715 allow_refreshes = 0;
716 output_type_iterate(i) {
717 gtk_range_set_value(GTK_RANGE(pdialog->minimal_surplus[i]),
718 parameter->minimal_surplus[i]);
719 gtk_range_set_value(GTK_RANGE(pdialog->factor[i]), parameter->factor[i]);
720 } output_type_iterate_end;
721 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pdialog->happy_button),
722 parameter->require_happy);
723 gtk_range_set_value(GTK_RANGE(pdialog->factor[O_LAST]),
724 parameter->happy_factor);
725 allow_refreshes = 1;
728 /************************************************************************
729 callback if we moved the sliders.
730 *************************************************************************/
731 static void hscale_changed(GtkWidget *get, gpointer data)
733 struct cma_dialog *pdialog = (struct cma_dialog *) data;
734 struct cm_parameter param;
736 if (!allow_refreshes) {
737 return;
740 cmafec_get_fe_parameter(pdialog->pcity, &param);
741 output_type_iterate(i) {
742 param.minimal_surplus[i] =
743 (int) (gtk_range_get_value(GTK_RANGE(pdialog->minimal_surplus[i])));
744 param.factor[i] =
745 (int) (gtk_range_get_value(GTK_RANGE(pdialog->factor[i])));
746 } output_type_iterate_end;
747 param.require_happy =
748 (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pdialog->happy_button)) ? 1 : 0);
749 param.happy_factor =
750 (int) (gtk_range_get_value(GTK_RANGE(pdialog->factor[O_LAST])));
752 /* save the change */
753 cmafec_set_fe_parameter(pdialog->pcity, &param);
755 /* refreshes the cma */
756 if (cma_is_city_under_agent(pdialog->pcity, NULL)) {
757 cma_release_city(pdialog->pcity);
758 cma_put_city_under_agent(pdialog->pcity, &param);
759 refresh_city_dialog(pdialog->pcity);
760 } else {
761 refresh_cma_dialog(pdialog->pcity, DONT_REFRESH_HSCALES);