diff options
Diffstat (limited to 'info-gtk.c')
-rw-r--r-- | info-gtk.c | 1043 |
1 files changed, 0 insertions, 1043 deletions
diff --git a/info-gtk.c b/info-gtk.c deleted file mode 100644 index 4ba9058cf..000000000 --- a/info-gtk.c +++ /dev/null @@ -1,1043 +0,0 @@ -/* info-gtk.c - * creates the UI for the info frame - - * controlled through the following interfaces: - * - * void show_dive_info(struct dive *dive) - * - * called from gtk-ui: - * GtkWidget *extended_dive_info_widget(void) - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <time.h> -#include <ctype.h> -#include <sys/time.h> -#include <glib/gi18n.h> - -#include "dive.h" -#include "display.h" -#include "display-gtk.h" -#include "divelist.h" -#include "info.h" - -typedef enum { EDIT_NEW_DIVE, EDIT_ALL, EDIT_WHEN } edit_control_t; -static GtkEntry *location, *buddy, *divemaster, *rating, *suit; -static GtkTextView *notes; -static GtkListStore *location_list, *people_list, *star_list, *suit_list; - -static char *get_text(GtkTextView *view) -{ - GtkTextBuffer *buffer; - GtkTextIter start; - GtkTextIter end; - - buffer = gtk_text_view_get_buffer(view); - gtk_text_buffer_get_start_iter(buffer, &start); - gtk_text_buffer_get_end_iter(buffer, &end); - return gtk_text_buffer_get_text(buffer, &start, &end, FALSE); -} - -/* - * Get the string from a combo box. - * - * The "master" string is the string of the current dive - we only consider it - * changed if the old string is either empty, or matches that master string. - */ -static char *get_combo_box_entry_text(GtkComboBox *combo_box, char **textp, const char *master) -{ - const char *newstring = get_active_text(combo_box); - return evaluate_string_change(newstring, textp, master); -} - -#define SET_TEXT_VALUE(x) \ - gtk_entry_set_text(x, dive && dive->x ? dive->x : "") - -void show_dive_info(struct dive *dive) -{ - const char *title = get_window_title(dive); - gtk_window_set_title(GTK_WINDOW(main_window), title); - free((void *)title); - SET_TEXT_VALUE(divemaster); - SET_TEXT_VALUE(buddy); - SET_TEXT_VALUE(location); - SET_TEXT_VALUE(suit); - gtk_entry_set_text(rating, star_strings[dive ? dive->rating : 0]); - gtk_text_buffer_set_text(gtk_text_view_get_buffer(notes), - dive && dive->notes ? dive->notes : "", -1); - /* I'm not quite sure /why/ this is only called when we have no dive - * -- need to investigate */ - if (!dive) - show_dive_equipment(NULL, W_IDX_PRIMARY); -} - -static void info_menu_edit_cb(GtkMenuItem *menuitem, gpointer user_data) -{ - if (amount_selected) - edit_multi_dive_info(NULL); -} - -static void add_menu_item(GtkMenuShell *menu, const char *label, const char *icon, void (*cb)(GtkMenuItem *, gpointer)) -{ - GtkWidget *item; - if (icon) { - GtkWidget *image; - item = gtk_image_menu_item_new_with_label(label); - image = gtk_image_new_from_stock(icon, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); - } else { - item = gtk_menu_item_new_with_label(label); - } - g_signal_connect(item, "activate", G_CALLBACK(cb), NULL); - gtk_widget_show(item); /* Yes, really */ - gtk_menu_shell_prepend(menu, item); -} - -static void populate_popup_cb(GtkTextView *entry, GtkMenuShell *menu, gpointer user_data) -{ - if (amount_selected) - add_menu_item(menu, _("Edit"), GTK_STOCK_EDIT, info_menu_edit_cb); -} - -static GtkEntry *text_value(GtkWidget *box, const char *label) -{ - GtkWidget *widget; - GtkWidget *frame = gtk_frame_new(label); - - gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0); - widget = gtk_entry_new(); - gtk_widget_set_can_focus(widget, FALSE); - gtk_editable_set_editable(GTK_EDITABLE(widget), FALSE); - gtk_container_add(GTK_CONTAINER(frame), widget); - g_signal_connect(widget, "populate-popup", G_CALLBACK(populate_popup_cb), NULL); - return GTK_ENTRY(widget); -} - -static GtkEntry *single_text_entry(GtkWidget *box, const char *label, const char *text) -{ - GtkEntry *entry; - GtkWidget *frame = gtk_frame_new(label); - - gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0); - entry = GTK_ENTRY(gtk_entry_new()); - gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(entry)); - if (text && *text) - gtk_entry_set_text(entry, text); - return entry; -} - -static GtkComboBox *text_entry(GtkWidget *box, const char *label, GtkListStore *completions, const char *text) -{ - GtkWidget *combo_box; - GtkWidget *frame = gtk_frame_new(label); - - gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0); - - combo_box = combo_box_with_model_and_entry(completions); - gtk_container_add(GTK_CONTAINER(frame), combo_box); - - if (text && *text) - set_active_text(GTK_COMBO_BOX(combo_box), text); - - return GTK_COMBO_BOX(combo_box); -} - -enum writable { - READ_ONLY, - READ_WRITE -}; - -static GtkTextView *text_view(GtkWidget *box, const char *label, enum writable writable) -{ - GtkWidget *view, *vbox; - GtkWidget *frame = gtk_frame_new(label); - - gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0); - box = gtk_hbox_new(FALSE, 3); - gtk_container_add(GTK_CONTAINER(frame), box); - vbox = gtk_vbox_new(FALSE, 3); - gtk_container_add(GTK_CONTAINER(box), vbox); - - GtkWidget* scrolled_window = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN); - - view = gtk_text_view_new(); - if (writable == READ_ONLY) { - gtk_widget_set_can_focus(view, FALSE); - gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE); - gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(view), FALSE); - g_signal_connect(view, "populate-popup", G_CALLBACK(populate_popup_cb), NULL); - } - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD); - gtk_container_add(GTK_CONTAINER(scrolled_window), view); - gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0); - return GTK_TEXT_VIEW(view); -} - -static GtkTreeIter string_entry_location; - -static gboolean match_string_entry(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) -{ - const char *string = data; - char *entry; - int cmp; - - gtk_tree_model_get(model, iter, 0, &entry, -1); - cmp = strcmp(entry, string); - if (entry) - free(entry); - - /* Stop. The entry is bigger than the new one */ - if (cmp > 0) - return TRUE; - - /* Exact match */ - if (!cmp) { - found_string_entry = MATCH_EXACT; - return TRUE; - } - - string_entry_location = *iter; - found_string_entry = MATCH_AFTER; - return FALSE; -} - -int match_list(GtkListStore *list, const char *string) -{ - found_string_entry = MATCH_PREPEND; - gtk_tree_model_foreach(GTK_TREE_MODEL(list), match_string_entry, (void *)string); - return found_string_entry; -} - -void add_string_list_entry(const char *string, GtkListStore *list) -{ - GtkTreeIter *iter, loc; - - if (!string || !*string) - return; - - switch (match_list(list, string)) { - case MATCH_EXACT: - return; - case MATCH_PREPEND: - iter = NULL; - break; - case MATCH_AFTER: - iter = &string_entry_location; - break; - } - gtk_list_store_insert_after(list, &loc, iter); - gtk_list_store_set(list, &loc, 0, string, -1); -} - -void add_people(const char *string) -{ - add_string_list_entry(string, people_list); -} - -void add_location(const char *string) -{ - add_string_list_entry(string, location_list); -} - -void add_suit(const char *string) -{ - add_string_list_entry(string, suit_list); -} - -/* this helper function is completely Gtk independent... but I really - * hope that a new UI would just have a decent star rating widget and - * we won't need this kludge... so I'll leave this in the -gtk file */ -static int get_rating(const char *string) -{ - int rating_val = 0; - int i; - - for (i = 0; i <= 5; i++) - if (!strcmp(star_strings[i],string)) - rating_val = i; - return rating_val; -} - -struct dive_info { - GtkComboBox *location, *divemaster, *buddy, *rating, *suit, *viz; - GtkEntry *airtemp, *gps; - GtkWidget *gps_icon; - GtkTextView *notes; -}; - -static void save_dive_info_changes(struct dive *dive, struct dive *master, struct dive_info *info, int tags_shown) -{ - char *old_text, *new_text; - const char *gps_text; - char *rating_string; - double newtemp; - int changed = 0; - - new_text = get_combo_box_entry_text(info->location, &dive->location, master->location); - if (new_text) { - add_location(new_text); - changed = 1; - } - - gps_text = gtk_entry_get_text(info->gps); - if (gps_changed(dive, master, gps_text)) - changed = 1; - - new_text = get_combo_box_entry_text(info->divemaster, &dive->divemaster, master->divemaster); - if (new_text) { - add_people(new_text); - changed = 1; - } - - new_text = get_combo_box_entry_text(info->buddy, &dive->buddy, master->buddy); - if (new_text) { - add_people(new_text); - changed = 1; - } - - new_text = get_combo_box_entry_text(info->suit, &dive->suit, master->suit); - if (new_text) { - add_suit(new_text); - changed = 1; - } - - rating_string = strdup(star_strings[dive->rating]); - new_text = get_combo_box_entry_text(info->rating, &rating_string, star_strings[master->rating]); - if (new_text) { - dive->rating = get_rating(rating_string); - changed = 1; - } - free(rating_string); - - rating_string = strdup(star_strings[dive->visibility]); - new_text = get_combo_box_entry_text(info->viz, &rating_string, star_strings[master->visibility]); - if (new_text) { - dive->visibility = get_rating(rating_string); - changed = 1; - } - free(rating_string); - - new_text = (char *)gtk_entry_get_text(info->airtemp); - if (sscanf(new_text, "%lf", &newtemp) == 1) { - unsigned long mkelvin; - switch (prefs.units.temperature) { - case CELSIUS: - mkelvin = C_to_mkelvin(newtemp); - break; - case FAHRENHEIT: - mkelvin = F_to_mkelvin(newtemp); - break; - default: - mkelvin = 0; - } - if (mkelvin != dive->airtemp.mkelvin && dive->airtemp.mkelvin == master->airtemp.mkelvin) { - dive->airtemp.mkelvin = mkelvin; - changed = 1; - } - } - - if (info->notes) { - old_text = dive->notes; - dive->notes = get_text(info->notes); - if (text_changed(old_text,dive->notes)) - changed = 1; - if (old_text) - g_free(old_text); - } - if (tags_shown && dive->dive_tags != master->dive_tags) { - changed = 1; - dive->dive_tags = master->dive_tags; - /* if a dive is selected and we aren't showing invalid dives and it is - * now marked as invalid we need to deselect it to keep the selection - * state consistent */ - if (!prefs.display_invalid_dives && dive->selected && dive->dive_tags & DTAG_INVALID) { - dive->selected = 0; - amount_selected--; - } - } - if (changed) { - mark_divelist_changed(TRUE); - update_dive(dive); - } -} - -static void dive_trip_widget(GtkWidget *box, dive_trip_t *trip, struct dive_info *info) -{ - GtkWidget *hbox, *label; - char buffer[128] = N_("Edit trip summary"); - - label = gtk_label_new(_(buffer)); - gtk_box_pack_start(GTK_BOX(box), label, FALSE, TRUE, 0); - - info->location = text_entry(box, _("Location"), location_list, trip->location); - - hbox = gtk_hbox_new(FALSE, 3); - gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0); - - info->notes = text_view(box, _("Notes"), READ_WRITE); - if (trip->notes && *trip->notes) - gtk_text_buffer_set_text(gtk_text_view_get_buffer(info->notes), trip->notes, -1); -} - -struct location_update { - char text[45]; - char set_by_hand; - GtkEntry *entry; - struct dive *dive; - void (*callback)(float, float); -} location_update; - -static void update_gps_entry(int lat, int lon) -{ - if (location_update.entry) { - print_gps_coordinates(location_update.text, 45, lat, lon); - gtk_entry_set_text(location_update.entry, location_update.text); - } -} - -static void update_gps_entry_callback(float lat, float lon) -{ - update_gps_entry(lat * 1000000, lon * 1000000); - location_update.set_by_hand = 1; -} - -static gboolean gps_map_callback(GtkWidget *w, gpointer data) -{ - double latitude, longitude; - const char *gps_text = NULL; - struct dive fake_dive; - - memset(&fake_dive, 0, sizeof(fake_dive)); - if (location_update.entry) { - gps_text = gtk_entry_get_text(location_update.entry); - parse_gps_text(gps_text, &latitude, &longitude); - fake_dive.latitude.udeg = rint(latitude * 1000000); - fake_dive.longitude.udeg = rint(longitude * 1000000); - } - show_gps_location(&fake_dive, update_gps_entry_callback); - return TRUE; -} - -/* - * If somebody sets the string by editing the text entry, - * we consider a clear string an opportunity to set things - * automatically. - * - * A non-empty string, on the other hand, means that we - * should *not* touch it when we change the location field. - */ -static gboolean gps_entry_change_cb(GtkEntry *gps, GdkEvent *event, gpointer userdata) -{ - const char *string = gtk_entry_get_text(gps); - - /* A clear string is never considered to be "set" */ - if (!string) { - location_update.set_by_hand = 0; - return FALSE; - } - - /* - * If it wasn't set by hand, and it hasn't changed, - * it's still not set by hand - */ - if (!location_update.set_by_hand) { - if (!strcmp(location_update.text, string)) - return FALSE; - } - - /* Otherwise, check if it's all empty.. */ - while (g_ascii_isspace(*string)) - string++; - location_update.set_by_hand = !!*string; - - return FALSE; -} - -static void location_entry_change_cb(GtkComboBox *location, gpointer *userdata) -{ - int i; - struct dive *dive; - const char *name; - - /* - * Don't do any automatic gps changes of entries that have been - * explicitly set to some value! - */ - if (location_update.set_by_hand) - return; - - name = get_active_text(location); - for_each_dive(i, dive) { - if (!dive_has_gps_location(dive)) - continue; - if (!dive->location || strcasecmp(dive->location, name)) - continue; - update_gps_entry(dive->latitude.udeg, dive->longitude.udeg); - return; - } - update_gps_entry(0, 0); -} - -static void set_dive_button_label(GtkWidget *button, struct dive *dive) -{ - char buffer[256]; - - /* if there is only one dc and it has no samples we can edit the depth, too */ - if (dive->dc.next || dive->dc.samples) - divename(buffer, sizeof(buffer), dive, _("(click to edit date/time)")); - else - divename(buffer, sizeof(buffer), dive, _("(click to edit date/time/depth)")); - gtk_button_set_label(GTK_BUTTON(button), buffer); -} - -static int dive_time_widget(struct dive *dive, edit_control_t editing); - -static gboolean base_data_cb(GtkWidget *w, GdkEvent *event, gpointer _data) -{ - struct dive *dive = _data; - - /* if there are more than one divecomputers or if there are any sample - * then only the start time (well, date and time) can be changed, - * otherwise (this is most likely a dive that was added manually in Subsurface - * and we can edit duration, max and mean depth, too */ - if (dive->dc.next || dive->dc.samples) - dive_time_widget(dive, EDIT_WHEN); - else - dive_time_widget(dive, EDIT_ALL); - set_dive_button_label(w, dive); - return FALSE; -} - -void divetag_toggle_cb(GtkWidget *widget, gpointer data) -{ - int togglebit = GPOINTER_TO_INT (data); - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) - edit_dive.dive_tags |= togglebit; - else - edit_dive.dive_tags &= ~togglebit; -} - -static void dive_info_widget(GtkWidget *obox, struct dive *dive, struct dive_info *info, int multi, int *show_tags) -{ - GtkWidget *hbox, *frame, *equipment, *ibox, *box, *button, *sbox, *framebox; - GtkWidget *image; - char buffer[256]; - char airtemp[10]; - const char *unit; - double value; - int i, tags; - struct dive *otherdive; - - if (multi) { - GtkWidget *label; - snprintf(buffer, sizeof(buffer), "%s", _("Edit multiple dives")); - label = gtk_label_new(buffer); - gtk_box_pack_start(GTK_BOX(obox), label, FALSE, TRUE, 0); - } else { - GtkWidget *basedata; - snprintf(buffer, sizeof(buffer), "%s", _("Edit dive")); - basedata = gtk_button_new_with_label(buffer); - set_dive_button_label(basedata, dive); - g_signal_connect(G_OBJECT(basedata), "button-press-event", G_CALLBACK(base_data_cb), dive); - gtk_box_pack_start(GTK_BOX(obox), basedata, FALSE, TRUE, 0); - } - /* two column layout (inner hbox ibox) within the outer vbox (obox) we are given */ - ibox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(obox), ibox, TRUE, TRUE, 0); - box = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(ibox), box, TRUE, TRUE, 0); - - info->location = text_entry(box, _("Location"), location_list, dive->location); - g_signal_connect(G_OBJECT(info->location), "changed", G_CALLBACK(location_entry_change_cb), NULL); - - hbox = gtk_hbox_new(FALSE, 2); - gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0); - info->gps = single_text_entry(hbox, _("GPS (WGS84 or GPS format)"), NULL); - - location_update.entry = info->gps; - location_update.dive = dive; - update_gps_entry(dive->latitude.udeg, dive->longitude.udeg); - location_update.set_by_hand = !!location_update.text[0]; - - gtk_widget_add_events(GTK_WIDGET(info->gps), GDK_FOCUS_CHANGE_MASK); - g_signal_connect(G_OBJECT(info->gps), "focus-out-event", G_CALLBACK(gps_entry_change_cb), NULL); - gtk_entry_set_width_chars(info->gps, 30); - info->gps_icon = gtk_button_new_with_label(_("Pick on map")); - gtk_box_pack_start(GTK_BOX(hbox), info->gps_icon, FALSE, FALSE, 6); - image = gtk_image_new_from_pixbuf(get_gps_icon()); - gtk_image_set_pixel_size(GTK_IMAGE(image), 128); - gtk_button_set_image(GTK_BUTTON(info->gps_icon), image); - - g_signal_connect(G_OBJECT(info->gps_icon), "clicked", G_CALLBACK(gps_map_callback), NULL); - hbox = gtk_hbox_new(FALSE, 3); - gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0); - - info->divemaster = text_entry(hbox, _("Dive master"), people_list, dive->divemaster); - info->buddy = text_entry(hbox, _("Buddy"), people_list, dive->buddy); - - hbox = gtk_hbox_new(FALSE, 3); - gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0); - - info->rating = text_entry(hbox, _("Rating"), star_list, star_strings[dive->rating]); - info->suit = text_entry(hbox, _("Suit"), suit_list, dive->suit); - - hbox = gtk_hbox_new(FALSE, 3); - gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0); - - info->viz = text_entry(hbox, _("Visibility"), star_list, star_strings[dive->visibility]); - - value = get_temp_units(dive->airtemp.mkelvin, &unit); - snprintf(buffer, sizeof(buffer), _("Air Temp in %s"), unit); - if (dive->airtemp.mkelvin) - snprintf(airtemp, sizeof(airtemp), "%.1f", value); - else - airtemp[0] = '\0'; - info->airtemp = single_text_entry(hbox, buffer, airtemp); - - frame = gtk_frame_new(_("Dive Tags")); - gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0); - - framebox = gtk_vbox_new(FALSE, 3); - gtk_container_add(GTK_CONTAINER(frame), framebox); - - /* we only want to show the tags if we have a single dive or if all selected - * dives have the exact same set of tags (like none at all right after import) */ - i = 0; - *show_tags = 1; - tags = dive->dive_tags; - for_each_dive(i, otherdive) - if (otherdive && otherdive->selected && otherdive->dive_tags != tags) - *show_tags = 0; - if (*show_tags) { - /* check boxes for the (currently fixed) list of tags; - * let's do 5 per row */ - const int cols = 5; - int rows = DTAG_NR / cols + (DTAG_NR % cols) ? 1 : 0; - GtkWidget *table = gtk_table_new(rows, cols, TRUE); - for (i = 0; i < DTAG_NR; i++) { - int x = i % cols; - int y = i / cols; - button = gtk_check_button_new_with_label(_(dtag_names[i])); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & (1 << i)); - gtk_table_attach_defaults(GTK_TABLE(table), button, x, x+1, y, y+1); - g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), - GINT_TO_POINTER(1 << i)); - } - gtk_box_pack_start(GTK_BOX(framebox), table, TRUE, FALSE, 3); - } else { - sbox = gtk_label_new(_("Tags are only shown if they are identical for all edited dives")); - gtk_box_pack_start(GTK_BOX(framebox), sbox, TRUE, FALSE, 3); - } - /* only show notes if editing a single dive */ - if (multi) { - info->notes = NULL; - } else { - info->notes = text_view(box, _("Notes"), READ_WRITE); - gtk_widget_set_size_request(GTK_WIDGET(info->notes), -1, 128); - if (dive->notes && *dive->notes) - gtk_text_buffer_set_text(gtk_text_view_get_buffer(info->notes), dive->notes, -1); - } - hbox = gtk_hbox_new(FALSE, 3); - gtk_box_pack_start(GTK_BOX(ibox), hbox, TRUE, TRUE, 0); - - /* create a secondary Equipment widget */ - frame = gtk_frame_new(_("Equipment")); - equipment = equipment_widget(W_IDX_SECONDARY); - gtk_container_add(GTK_CONTAINER(frame), equipment); - gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); -} - -gboolean edit_trip(dive_trip_t *trip) -{ - GtkWidget *dialog, *vbox; - int success; - gboolean changed = FALSE; - char *old_text, *new_text; - struct dive_info info; - - memset(&info, 0, sizeof(struct dive_info)); - dialog = gtk_dialog_new_with_buttons(_("Edit Trip Info"), - GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - NULL); - gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 300); - vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); - dive_trip_widget(vbox, trip, &info); - gtk_widget_show_all(dialog); - success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT; - if (success) { - /* we need to store the edited location and notes */ - new_text = get_combo_box_entry_text(info.location, &trip->location, trip->location); - if (new_text) { - add_location(new_text); - changed = TRUE; - } - if (info.notes) { - old_text = trip->notes; - trip->notes = get_text(info.notes); - if (text_changed(old_text, trip->notes)) - changed = TRUE; - if (old_text) - g_free(old_text); - } - if (changed) - mark_divelist_changed(TRUE); - } - gtk_widget_destroy(dialog); - return changed; -} - -int edit_multi_dive_info(struct dive *single_dive) -{ - int success; - GtkWidget *dialog, *vbox, *scrolled_window, *viewport; - GtkRequisition size; - struct dive_info info; - struct dive *master; - int multi; - int tags_shown; - - scrolled_window = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - dialog = gtk_dialog_new_with_buttons(_("Dive Info"), - GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - NULL); - - vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); - gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0); - vbox = g_object_new(GTK_TYPE_VBOX, NULL); - gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), vbox); - master = single_dive; - if (!master) - master = current_dive; - if (!master) - return 0; - /* See if we should use multi dive mode */ - multi = FALSE; - if (!single_dive) { - int i; - struct dive *dive; - - for_each_dive(i, dive) { - if (dive != master && dive->selected) { - multi = TRUE; - break; - } - } - } - /* edit a temporary copy of the master dive; - * edit_dive is a global dive structure that is modified by the - * cylinder / weightsystem dialogs if we open W_IDX_SECONDARY - * edit widgets as we do here */ - memcpy(&edit_dive, master, sizeof(struct dive)); - - dive_info_widget(vbox, &edit_dive, &info, multi, &tags_shown); - save_equipment_data(&edit_dive); - gtk_widget_show_all(dialog); - viewport = gtk_widget_get_ancestor(vbox, GTK_TYPE_VIEWPORT); -#if GTK_CHECK_VERSION(3,0,0) - gtk_widget_get_preferred_size(viewport, NULL, &size); -#else - gtk_widget_size_request(viewport, &size); -#endif - gtk_widget_set_size_request(scrolled_window, size.width, size.height); - /* add the equipment post the "blank" layout estimate */ - show_dive_equipment(&edit_dive, W_IDX_SECONDARY); - success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT; - if (success) { - mark_divelist_changed(TRUE); - /* Update the non-current selected dives first */ - if (!single_dive) { - int i; - struct dive *dive; - - for_each_dive(i, dive) { - if (dive == master || !dive->selected) - continue; - /* copy all "info" fields */ - save_dive_info_changes(dive, &edit_dive, &info, tags_shown); - /* copy the cylinders / weightsystems */ - update_equipment_data(dive, &edit_dive); - /* this is extremely inefficient... it loops through all - dives to find the right one - but we KNOW the index already */ - update_cylinder_related_info(dive); - flush_divelist(dive); - } - } - - /* Update the master dive last! */ - save_dive_info_changes(master, &edit_dive, &info, tags_shown); - update_equipment_data(master, &edit_dive); - update_cylinder_related_info(master); - /* if there was only one dive we might also have changed dive->when - * or even the duration and depth information (in a dive without samples) */ - if (! multi) { - update_time_depth(master, &edit_dive); - /* these values could have changed because of the edit - so let's - * recreate them */ - master->duration.seconds = 0; - master->maxdepth.mm = 0; - master->meandepth.mm = 0; - (void)fixup_dive(master); - } - dive_list_update_dives(); - } - gtk_widget_destroy(dialog); - location_update.entry = NULL; - - return success; -} - -int edit_dive_info(struct dive *dive, gboolean newdive) -{ - if (!dive || (!newdive && !amount_selected)) - return 0; - - return edit_multi_dive_info(dive); -} - -static GtkWidget *frame_box(GtkWidget *vbox, const char *fmt, ...) -{ - va_list ap; - char buffer[128]; - GtkWidget *frame, *hbox; - - va_start(ap, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, ap); - va_end(ap); - - frame = gtk_frame_new(buffer); - gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 0); - hbox = gtk_hbox_new(0, 3); - gtk_container_add(GTK_CONTAINER(frame), hbox); - return hbox; -} - -/* returns the dialog plus pointers to the calendar, hour and minute widget - * plus the hbox that holds the time entry (in case the caller wants to put - * a duration entry widget next to the time entry widget */ -GtkWidget *create_date_time_widget(struct tm *time, GtkWidget **cal, GtkWidget **h, - GtkWidget **m, GtkWidget **timehbox) -{ - GtkWidget *dialog; - GtkWidget *hbox, *vbox; - GtkWidget *label; - - dialog = gtk_dialog_new_with_buttons(_("Date and Time"), - GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - NULL); - - vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); - - /* Calendar hbox */ - hbox = frame_box(vbox, _("Date:")); - *cal = gtk_calendar_new(); - gtk_box_pack_start(GTK_BOX(hbox), *cal, FALSE, TRUE, 0); - - /* Time hbox */ - *timehbox = gtk_hbox_new(TRUE, 3); - gtk_box_pack_start(GTK_BOX(vbox), *timehbox, FALSE, FALSE, 0); - hbox = frame_box(*timehbox, _("Time")); - - *h = gtk_spin_button_new_with_range (0.0, 23.0, 1.0); - *m = gtk_spin_button_new_with_range (0.0, 59.0, 1.0); - - gtk_calendar_select_month(GTK_CALENDAR(*cal), time->tm_mon, time->tm_year + 1900); - gtk_calendar_select_day(GTK_CALENDAR(*cal), time->tm_mday); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(*h), time->tm_hour); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(*m), time->tm_min); - - gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(*h), TRUE); - gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(*m), TRUE); - - gtk_box_pack_end(GTK_BOX(hbox), *m, FALSE, FALSE, 0); - label = gtk_label_new(":"); - gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_box_pack_end(GTK_BOX(hbox), *h, FALSE, FALSE, 0); - - return dialog; -} - -static int mm_from_spinbutton(GtkWidget *depth) -{ - int result; - double val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(depth)); - if (prefs.units.length == FEET) { - result = feet_to_mm(val); - } else { - result = val * 1000 + 0.5; - } - return result; -} - -static int dive_time_widget(struct dive *dive, edit_control_t editing) -{ - GtkWidget *dialog; - GtkWidget *cal, *vbox, *hbox, *box; - GtkWidget *h, *m; - GtkWidget *duration, *depth, *avgdepth; - guint yval, mval, dval; - struct tm tm, *time; - int success; - double depthinterval; - - /* - * If we have a dive selected, 'add dive' will default - * to one hour after the end of that dive. Otherwise, - * we'll just take the current time. - */ - if (editing != EDIT_NEW_DIVE) { - utc_mkdate(dive->when, &tm); - time = &tm; - } else if (amount_selected == 1) { - timestamp_t when = current_dive->when; - when += current_dive->duration.seconds; - when += 60*60; - utc_mkdate(when, &tm); - time = &tm; - } else { - time_t now; - struct timeval tv; - gettimeofday(&tv, NULL); - now = tv.tv_sec; - time = localtime(&now); - } - dialog = create_date_time_widget(time, &cal, &h, &m, &hbox); - vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); - - if (editing != EDIT_WHEN) { - /* Duration box */ - box = frame_box(hbox, _("Duration (min)")); - duration = gtk_spin_button_new_with_range (0.0, 1000.0, 1.0); - if (editing != EDIT_NEW_DIVE) - gtk_spin_button_set_value(GTK_SPIN_BUTTON(duration), dive->dc.duration.seconds / 60.0); - gtk_box_pack_end(GTK_BOX(box), duration, FALSE, FALSE, 0); - - hbox = gtk_hbox_new(TRUE, 3); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - /* Depth box */ - box = frame_box(hbox, _("Max Depth (%s):"), prefs.units.length == FEET ? _("ft") : _("m")); - if (prefs.units.length == FEET) { - depthinterval = 1.0; - } else { - depthinterval = 0.1; - } - depth = gtk_spin_button_new_with_range (0.0, 1000.0, depthinterval); - if (editing != EDIT_NEW_DIVE) { - if (prefs.units.length == FEET) { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(depth), mm_to_feet(dive->dc.maxdepth.mm)); - } else { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(depth), dive->dc.maxdepth.mm / 1000.0); - } - } - gtk_box_pack_end(GTK_BOX(box), depth, FALSE, FALSE, 0); - - box = frame_box(hbox, _("Avg Depth (%s):"), prefs.units.length == FEET ? _("ft") : _("m")); - if (prefs.units.length == FEET) { - depthinterval = 1.0; - } else { - depthinterval = 0.1; - } - avgdepth = gtk_spin_button_new_with_range (0.0, 1000.0, depthinterval); - if (editing != EDIT_NEW_DIVE) { - if (prefs.units.length == FEET) { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(avgdepth), mm_to_feet(dive->dc.meandepth.mm)); - } else { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(avgdepth), dive->dc.meandepth.mm / 1000.0); - } - } - gtk_box_pack_end(GTK_BOX(box), avgdepth, FALSE, FALSE, 0); - } - /* All done, show it and wait for editing */ - gtk_widget_show_all(dialog); - success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT; - if (!success) { - gtk_widget_destroy(dialog); - return 0; - } - - memset(&tm, 0, sizeof(tm)); - gtk_calendar_get_date(GTK_CALENDAR(cal), &yval, &mval, &dval); - tm.tm_year = yval; - tm.tm_mon = mval; - tm.tm_mday = dval; - - tm.tm_hour = gtk_spin_button_get_value(GTK_SPIN_BUTTON(h)); - tm.tm_min = gtk_spin_button_get_value(GTK_SPIN_BUTTON(m)); - - if (editing != EDIT_WHEN) { - dive->dc.maxdepth.mm = mm_from_spinbutton(depth); - dive->dc.meandepth.mm = mm_from_spinbutton(avgdepth); - dive->dc.duration.seconds = gtk_spin_button_get_value(GTK_SPIN_BUTTON(duration))*60; - } - gtk_widget_destroy(dialog); - dive->when = utc_mktime(&tm); - - return 1; -} - -int add_new_dive(struct dive *dive) -{ - if (!dive) - return 0; - - if (!dive_time_widget(dive, EDIT_NEW_DIVE)) - return 0; - - return edit_dive_info(dive, TRUE); -} - -GtkWidget *extended_dive_info_widget(void) -{ - GtkWidget *vbox, *hbox; - vbox = gtk_vbox_new(FALSE, 6); - - people_list = gtk_list_store_new(1, G_TYPE_STRING); - location_list = gtk_list_store_new(1, G_TYPE_STRING); - star_list = gtk_list_store_new(1, G_TYPE_STRING); - add_string_list_entry(star_strings[0], star_list); - add_string_list_entry(star_strings[1], star_list); - add_string_list_entry(star_strings[2], star_list); - add_string_list_entry(star_strings[3], star_list); - add_string_list_entry(star_strings[4], star_list); - add_string_list_entry(star_strings[5], star_list); - suit_list = gtk_list_store_new(1, G_TYPE_STRING); - - gtk_container_set_border_width(GTK_CONTAINER(vbox), 6); - location = text_value(vbox, _("Location")); - - hbox = gtk_hbox_new(FALSE, 3); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); - - divemaster = text_value(hbox, _("Divemaster")); - buddy = text_value(hbox, _("Buddy")); - - hbox = gtk_hbox_new(FALSE, 3); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); - - rating = text_value(hbox, _("Rating")); - suit = text_value(hbox, _("Suit")); - - notes = text_view(vbox, _("Notes"), READ_ONLY); - return vbox; -} - -void info_widget_destroy(void) -{ - g_object_unref(people_list); - g_object_unref(location_list); - g_object_unref(star_list); - g_object_unref(suit_list); -} |