2011-09-20 19:40:34 +00:00
|
|
|
/* gtk-gui.c */
|
|
|
|
/* gtk UI implementation */
|
|
|
|
/* creates the window and overall layout
|
|
|
|
* divelist, dive info, equipment and printing are handled in their own source files
|
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
2012-01-03 05:53:33 +00:00
|
|
|
#include <unistd.h>
|
2012-09-09 16:06:44 +00:00
|
|
|
#include <sys/stat.h>
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
#include "dive.h"
|
|
|
|
#include "divelist.h"
|
|
|
|
#include "display.h"
|
|
|
|
#include "display-gtk.h"
|
|
|
|
|
|
|
|
#include "libdivecomputer.h"
|
|
|
|
|
2011-09-27 23:23:59 +00:00
|
|
|
GtkWidget *main_window;
|
2011-09-20 19:40:34 +00:00
|
|
|
GtkWidget *main_vbox;
|
|
|
|
GtkWidget *error_info_bar;
|
|
|
|
GtkWidget *error_label;
|
2011-12-06 21:00:01 +00:00
|
|
|
GtkWidget *vpane, *hpane;
|
2012-08-19 01:06:32 +00:00
|
|
|
GtkWidget *notebook;
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
int error_count;
|
2012-09-16 03:51:06 +00:00
|
|
|
const char *existing_filename;
|
2011-09-20 19:40:34 +00:00
|
|
|
const char *divelist_font;
|
2012-09-09 16:06:44 +00:00
|
|
|
const char *default_filename;
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2011-10-28 05:10:35 +00:00
|
|
|
struct units output_units;
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
static GtkWidget *dive_profile;
|
|
|
|
|
2011-09-27 17:16:40 +00:00
|
|
|
visible_cols_t visible_cols = {TRUE, FALSE};
|
|
|
|
|
2012-06-22 20:37:39 +00:00
|
|
|
static const char *default_dive_computer_vendor;
|
|
|
|
static const char *default_dive_computer_product;
|
2012-05-30 04:54:09 +00:00
|
|
|
static const char *default_dive_computer_device;
|
2012-05-02 17:26:34 +00:00
|
|
|
|
2012-06-22 20:37:39 +00:00
|
|
|
static int is_default_dive_computer(const char *vendor, const char *product)
|
2012-05-02 17:26:34 +00:00
|
|
|
{
|
2012-06-22 20:37:39 +00:00
|
|
|
return default_dive_computer_vendor && !strcmp(vendor, default_dive_computer_vendor) &&
|
|
|
|
default_dive_computer_product && !strcmp(product, default_dive_computer_product);
|
2012-05-02 17:26:34 +00:00
|
|
|
}
|
|
|
|
|
2012-05-30 04:54:09 +00:00
|
|
|
static int is_default_dive_computer_device(const char *name)
|
|
|
|
{
|
|
|
|
return default_dive_computer_device && !strcmp(name, default_dive_computer_device);
|
|
|
|
}
|
|
|
|
|
2012-06-22 20:37:39 +00:00
|
|
|
static void set_default_dive_computer(const char *vendor, const char *product)
|
2012-05-02 17:26:34 +00:00
|
|
|
{
|
2012-06-22 20:37:39 +00:00
|
|
|
if (!vendor || !*vendor)
|
|
|
|
return;
|
|
|
|
if (!product || !*product)
|
2012-05-02 17:26:34 +00:00
|
|
|
return;
|
2012-06-22 20:37:39 +00:00
|
|
|
if (is_default_dive_computer(vendor, product))
|
2012-05-02 17:26:34 +00:00
|
|
|
return;
|
2012-06-22 20:37:39 +00:00
|
|
|
default_dive_computer_vendor = vendor;
|
|
|
|
default_dive_computer_product = product;
|
|
|
|
subsurface_set_conf("dive_computer_vendor", PREF_STRING, vendor);
|
|
|
|
subsurface_set_conf("dive_computer_product", PREF_STRING, product);
|
2012-05-02 17:26:34 +00:00
|
|
|
}
|
|
|
|
|
2012-05-30 04:54:09 +00:00
|
|
|
static void set_default_dive_computer_device(const char *name)
|
|
|
|
{
|
|
|
|
if (!name || !*name)
|
|
|
|
return;
|
|
|
|
if (is_default_dive_computer_device(name))
|
|
|
|
return;
|
|
|
|
default_dive_computer_device = name;
|
|
|
|
subsurface_set_conf("dive_computer_device", PREF_STRING, name);
|
|
|
|
}
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
void repaint_dive(void)
|
|
|
|
{
|
|
|
|
update_dive(current_dive);
|
2011-09-27 17:38:07 +00:00
|
|
|
if (dive_profile)
|
|
|
|
gtk_widget_queue_draw(dive_profile);
|
2011-09-20 19:40:34 +00:00
|
|
|
}
|
|
|
|
|
2011-10-11 22:58:38 +00:00
|
|
|
static gboolean need_icon = TRUE;
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
static void on_info_bar_response(GtkWidget *widget, gint response,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
if (response == GTK_RESPONSE_OK)
|
|
|
|
{
|
|
|
|
gtk_widget_destroy(widget);
|
|
|
|
error_info_bar = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void report_error(GError* error)
|
|
|
|
{
|
|
|
|
if (error == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2012-08-26 21:41:05 +00:00
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
if (error_info_bar == NULL)
|
|
|
|
{
|
|
|
|
error_count = 1;
|
|
|
|
error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK,
|
|
|
|
GTK_RESPONSE_OK,
|
|
|
|
NULL);
|
|
|
|
g_signal_connect(error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
|
|
|
|
gtk_info_bar_set_message_type(GTK_INFO_BAR(error_info_bar),
|
|
|
|
GTK_MESSAGE_ERROR);
|
2012-08-26 21:41:05 +00:00
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
error_label = gtk_label_new(error->message);
|
|
|
|
GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(error_info_bar));
|
|
|
|
gtk_container_add(GTK_CONTAINER(container), error_label);
|
2012-08-26 21:41:05 +00:00
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(main_vbox), error_info_bar, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show_all(main_vbox);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error_count++;
|
|
|
|
char buffer[256];
|
|
|
|
snprintf(buffer, sizeof(buffer), "Failed to open %i files.", error_count);
|
|
|
|
gtk_label_set(GTK_LABEL(error_label), buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-15 22:22:36 +00:00
|
|
|
static GtkFileFilter *setup_filter(void)
|
2011-09-20 19:40:34 +00:00
|
|
|
{
|
2012-09-15 22:22:36 +00:00
|
|
|
GtkFileFilter *filter = gtk_file_filter_new();
|
2011-09-26 16:18:23 +00:00
|
|
|
gtk_file_filter_add_pattern(filter, "*.xml");
|
|
|
|
gtk_file_filter_add_pattern(filter, "*.XML");
|
2011-10-03 15:27:36 +00:00
|
|
|
gtk_file_filter_add_pattern(filter, "*.sda");
|
|
|
|
gtk_file_filter_add_pattern(filter, "*.SDA");
|
2011-09-26 16:18:23 +00:00
|
|
|
gtk_file_filter_add_mime_type(filter, "text/xml");
|
|
|
|
gtk_file_filter_set_name(filter, "XML file");
|
2012-08-26 19:51:18 +00:00
|
|
|
|
2012-09-15 22:22:36 +00:00
|
|
|
return filter;
|
2012-08-26 19:51:18 +00:00
|
|
|
}
|
|
|
|
|
2012-07-31 17:55:41 +00:00
|
|
|
static void file_save_as(GtkWidget *w, gpointer data)
|
2011-09-20 19:40:34 +00:00
|
|
|
{
|
|
|
|
GtkWidget *dialog;
|
2012-08-18 16:48:15 +00:00
|
|
|
char *filename = NULL;
|
2012-08-26 19:51:18 +00:00
|
|
|
char *current_file;
|
|
|
|
char *current_dir;
|
|
|
|
|
2012-08-17 17:57:24 +00:00
|
|
|
dialog = gtk_file_chooser_dialog_new("Save File As",
|
2011-09-20 19:40:34 +00:00
|
|
|
GTK_WINDOW(main_window),
|
|
|
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
|
|
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
|
|
|
|
NULL);
|
2012-07-17 14:49:27 +00:00
|
|
|
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
|
|
|
|
|
2012-09-16 03:51:06 +00:00
|
|
|
if (existing_filename) {
|
|
|
|
current_dir = g_path_get_dirname(existing_filename);
|
|
|
|
current_file = g_path_get_basename(existing_filename);
|
|
|
|
} else {
|
|
|
|
const char *current_default = subsurface_default_filename();
|
|
|
|
current_dir = g_path_get_dirname(current_default);
|
|
|
|
current_file = g_path_get_basename(current_default);
|
|
|
|
}
|
2012-08-26 19:51:18 +00:00
|
|
|
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), current_dir);
|
|
|
|
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), current_file);
|
2012-08-26 21:20:48 +00:00
|
|
|
|
|
|
|
free(current_dir);
|
2012-08-26 22:35:48 +00:00
|
|
|
free(current_file);
|
2012-08-26 21:20:48 +00:00
|
|
|
|
2012-07-17 14:49:27 +00:00
|
|
|
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
|
|
|
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
|
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
|
|
|
|
if (filename){
|
|
|
|
save_dives(filename);
|
2012-09-10 19:27:00 +00:00
|
|
|
set_filename(filename, TRUE);
|
2011-09-20 19:40:34 +00:00
|
|
|
g_free(filename);
|
2012-07-17 14:49:27 +00:00
|
|
|
mark_divelist_changed(FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-31 17:55:41 +00:00
|
|
|
static void file_save(GtkWidget *w, gpointer data)
|
|
|
|
{
|
2012-09-09 16:06:44 +00:00
|
|
|
const char *current_default;
|
|
|
|
|
2012-07-31 17:55:41 +00:00
|
|
|
if (!existing_filename)
|
|
|
|
return file_save_as(w, data);
|
|
|
|
|
2012-09-09 16:06:44 +00:00
|
|
|
current_default = subsurface_default_filename();
|
|
|
|
if (strcmp(existing_filename, current_default) == 0) {
|
|
|
|
/* if we are using the default filename the directory
|
|
|
|
* that we are creating the file in may not exist */
|
2012-09-13 18:17:38 +00:00
|
|
|
char *current_def_dir;
|
2012-09-09 16:06:44 +00:00
|
|
|
struct stat sb;
|
|
|
|
|
2012-09-13 18:17:38 +00:00
|
|
|
current_def_dir = g_path_get_dirname(existing_filename);
|
2012-09-09 16:06:44 +00:00
|
|
|
if (stat(current_def_dir, &sb) != 0) {
|
2012-09-11 18:42:47 +00:00
|
|
|
g_mkdir(current_def_dir, S_IRWXU);
|
2012-09-09 16:06:44 +00:00
|
|
|
}
|
2012-09-13 18:17:38 +00:00
|
|
|
free(current_def_dir);
|
2012-09-09 16:06:44 +00:00
|
|
|
}
|
2012-07-31 17:55:41 +00:00
|
|
|
save_dives(existing_filename);
|
2012-08-17 17:57:24 +00:00
|
|
|
mark_divelist_changed(FALSE);
|
2012-07-31 17:55:41 +00:00
|
|
|
}
|
|
|
|
|
2012-07-17 14:09:29 +00:00
|
|
|
static gboolean ask_save_changes()
|
2011-09-21 04:29:09 +00:00
|
|
|
{
|
2011-09-21 17:16:33 +00:00
|
|
|
GtkWidget *dialog, *label, *content;
|
2012-07-17 14:09:29 +00:00
|
|
|
gboolean quit = TRUE;
|
2011-09-21 04:29:09 +00:00
|
|
|
dialog = gtk_dialog_new_with_buttons("Save Changes?",
|
|
|
|
GTK_WINDOW(main_window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
|
2011-12-13 22:34:42 +00:00
|
|
|
GTK_STOCK_NO, GTK_RESPONSE_NO,
|
2012-07-17 14:09:29 +00:00
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
2011-09-21 04:29:09 +00:00
|
|
|
NULL);
|
2011-09-21 17:16:33 +00:00
|
|
|
content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
|
2012-07-17 14:05:40 +00:00
|
|
|
|
|
|
|
if (!existing_filename){
|
|
|
|
label = gtk_label_new (
|
2012-09-10 21:32:55 +00:00
|
|
|
"You have unsaved changes\nWould you like to save those before closing the datafile?");
|
2012-07-17 14:05:40 +00:00
|
|
|
} else {
|
2012-08-21 21:26:58 +00:00
|
|
|
char *label_text = (char*) malloc(sizeof(char) * (93 + strlen(existing_filename)));
|
2012-07-17 14:05:40 +00:00
|
|
|
sprintf(label_text,
|
2012-09-10 21:32:55 +00:00
|
|
|
"You have unsaved changes to file: %s \nWould you like to save those before closing the datafile?",
|
2012-07-17 14:05:40 +00:00
|
|
|
existing_filename);
|
|
|
|
label = gtk_label_new (label_text);
|
2012-09-18 23:51:48 +00:00
|
|
|
free(label_text);
|
2012-07-17 14:05:40 +00:00
|
|
|
}
|
2011-09-21 17:16:33 +00:00
|
|
|
gtk_container_add (GTK_CONTAINER (content), label);
|
|
|
|
gtk_widget_show_all (dialog);
|
|
|
|
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
|
2012-08-17 17:57:24 +00:00
|
|
|
gint outcode = gtk_dialog_run(GTK_DIALOG(dialog));
|
2012-07-17 14:09:29 +00:00
|
|
|
if (outcode == GTK_RESPONSE_ACCEPT) {
|
2011-09-21 04:29:09 +00:00
|
|
|
file_save(NULL,NULL);
|
2012-07-17 14:09:29 +00:00
|
|
|
} else if (outcode == GTK_RESPONSE_CANCEL) {
|
|
|
|
quit = FALSE;
|
2011-09-21 04:29:09 +00:00
|
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
2012-07-17 14:09:29 +00:00
|
|
|
return quit;
|
2011-09-21 04:29:09 +00:00
|
|
|
}
|
|
|
|
|
2012-09-10 21:32:55 +00:00
|
|
|
static void file_close(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (unsaved_changes())
|
|
|
|
if (ask_save_changes() == FALSE)
|
|
|
|
return;
|
2012-09-13 17:46:09 +00:00
|
|
|
|
|
|
|
if (existing_filename)
|
2012-09-16 03:51:06 +00:00
|
|
|
free((void *)existing_filename);
|
2012-09-10 21:32:55 +00:00
|
|
|
existing_filename = NULL;
|
|
|
|
|
|
|
|
/* free the dives and trips */
|
|
|
|
for (i = 0; i < dive_table.nr; i++)
|
|
|
|
free(get_dive(i));
|
|
|
|
dive_table.nr = 0;
|
|
|
|
dive_table.preexisting = 0;
|
2012-09-16 00:49:29 +00:00
|
|
|
mark_divelist_changed(FALSE);
|
2012-09-10 23:07:42 +00:00
|
|
|
|
|
|
|
/* inlined version of g_list_free_full(dive_trip_list, free); */
|
|
|
|
g_list_foreach(dive_trip_list, (GFunc)free, NULL);
|
|
|
|
g_list_free(dive_trip_list);
|
|
|
|
|
2012-09-10 21:32:55 +00:00
|
|
|
dive_trip_list = NULL;
|
|
|
|
|
|
|
|
/* clear the selection and the statistics */
|
|
|
|
amount_selected = 0;
|
|
|
|
selected_dive = 0;
|
|
|
|
process_selected_dives();
|
|
|
|
clear_stats_widgets();
|
|
|
|
|
|
|
|
/* clear the equipment page */
|
|
|
|
clear_equipment_widgets();
|
|
|
|
|
|
|
|
/* redraw the screen */
|
|
|
|
dive_list_update_dives();
|
|
|
|
show_dive_info(NULL);
|
|
|
|
}
|
|
|
|
|
2012-09-15 12:33:25 +00:00
|
|
|
static void file_open(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog;
|
|
|
|
GtkFileFilter *filter;
|
2012-09-16 03:51:06 +00:00
|
|
|
const char *current_default;
|
2012-09-15 12:33:25 +00:00
|
|
|
|
|
|
|
dialog = gtk_file_chooser_dialog_new("Open File",
|
|
|
|
GTK_WINDOW(main_window),
|
|
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
|
|
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
|
|
|
NULL);
|
2012-09-16 03:51:06 +00:00
|
|
|
current_default = subsurface_default_filename();
|
|
|
|
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), current_default);
|
2012-09-15 21:24:34 +00:00
|
|
|
/* when opening the data file we should allow only one file to be chosen */
|
|
|
|
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
|
2012-09-15 12:33:25 +00:00
|
|
|
|
2012-09-15 22:22:36 +00:00
|
|
|
filter = setup_filter();
|
2012-09-15 12:33:25 +00:00
|
|
|
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
|
|
|
|
|
|
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
2012-09-16 09:05:53 +00:00
|
|
|
GSList *fn_glist;
|
2012-09-15 12:33:25 +00:00
|
|
|
char *filename;
|
2012-09-16 09:01:25 +00:00
|
|
|
|
|
|
|
/* first, close the existing file, if any, and forget its name */
|
|
|
|
file_close(w, data);
|
|
|
|
free((void *)existing_filename);
|
|
|
|
existing_filename = NULL;
|
|
|
|
|
2012-09-16 09:05:53 +00:00
|
|
|
/* we know there is only one filename */
|
|
|
|
fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
|
2012-09-15 12:33:25 +00:00
|
|
|
|
|
|
|
GError *error = NULL;
|
2012-09-16 09:05:53 +00:00
|
|
|
filename = fn_glist->data;
|
|
|
|
parse_file(filename, &error);
|
|
|
|
if (error != NULL)
|
|
|
|
{
|
|
|
|
report_error(error);
|
|
|
|
g_error_free(error);
|
|
|
|
error = NULL;
|
2012-09-15 12:33:25 +00:00
|
|
|
}
|
2012-09-16 09:05:53 +00:00
|
|
|
g_free(filename);
|
2012-09-15 12:33:25 +00:00
|
|
|
g_slist_free(fn_glist);
|
|
|
|
report_dives(FALSE);
|
|
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
}
|
|
|
|
|
2011-09-21 17:31:03 +00:00
|
|
|
static gboolean on_delete(GtkWidget* w, gpointer data)
|
2011-09-21 04:29:09 +00:00
|
|
|
{
|
2011-09-21 14:34:00 +00:00
|
|
|
/* Make sure to flush any modified dive data */
|
|
|
|
update_dive(NULL);
|
|
|
|
|
2012-07-17 14:09:29 +00:00
|
|
|
gboolean quit = TRUE;
|
2011-09-21 04:29:09 +00:00
|
|
|
if (unsaved_changes())
|
2012-07-17 14:09:29 +00:00
|
|
|
quit = ask_save_changes();
|
2011-09-21 17:31:03 +00:00
|
|
|
|
2012-07-17 14:09:29 +00:00
|
|
|
if (quit){
|
|
|
|
return FALSE; /* go ahead, kill the program, we're good now */
|
|
|
|
} else {
|
|
|
|
return TRUE; /* We are not leaving */
|
|
|
|
}
|
2011-09-21 17:31:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void on_destroy(GtkWidget* w, gpointer data)
|
|
|
|
{
|
2011-09-21 04:29:09 +00:00
|
|
|
gtk_main_quit();
|
|
|
|
}
|
|
|
|
|
2012-09-12 16:18:56 +00:00
|
|
|
void quit(GtkWidget *w, gpointer data)
|
2011-09-20 19:40:34 +00:00
|
|
|
{
|
2011-09-21 17:16:33 +00:00
|
|
|
/* Make sure to flush any modified dive data */
|
|
|
|
update_dive(NULL);
|
|
|
|
|
2012-07-17 14:09:29 +00:00
|
|
|
gboolean quit = TRUE;
|
2011-09-21 17:16:33 +00:00
|
|
|
if (unsaved_changes())
|
2012-07-17 14:09:29 +00:00
|
|
|
quit = ask_save_changes();
|
|
|
|
|
|
|
|
if (quit){
|
|
|
|
gtk_main_quit();
|
|
|
|
}
|
2011-09-20 19:40:34 +00:00
|
|
|
}
|
|
|
|
|
2011-10-02 20:05:12 +00:00
|
|
|
GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title,
|
2011-12-11 19:40:17 +00:00
|
|
|
data_func_t data_func, unsigned int flags)
|
2011-10-02 20:05:12 +00:00
|
|
|
{
|
|
|
|
GtkCellRenderer *renderer;
|
|
|
|
GtkTreeViewColumn *col;
|
|
|
|
double xalign = 0.0; /* left as default */
|
2011-12-11 19:40:17 +00:00
|
|
|
PangoAlignment align;
|
|
|
|
gboolean visible;
|
|
|
|
|
|
|
|
align = (flags & ALIGN_LEFT) ? PANGO_ALIGN_LEFT :
|
|
|
|
(flags & ALIGN_RIGHT) ? PANGO_ALIGN_RIGHT :
|
|
|
|
PANGO_ALIGN_CENTER;
|
|
|
|
visible = !(flags & INVISIBLE);
|
2011-10-02 20:05:12 +00:00
|
|
|
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
|
|
col = gtk_tree_view_column_new();
|
|
|
|
|
|
|
|
gtk_tree_view_column_set_title(col, title);
|
2011-12-11 19:40:17 +00:00
|
|
|
if (!(flags & UNSORTABLE))
|
|
|
|
gtk_tree_view_column_set_sort_column_id(col, index);
|
2011-10-02 20:05:12 +00:00
|
|
|
gtk_tree_view_column_set_resizable(col, TRUE);
|
|
|
|
gtk_tree_view_column_pack_start(col, renderer, TRUE);
|
|
|
|
if (data_func)
|
|
|
|
gtk_tree_view_column_set_cell_data_func(col, renderer, data_func, (void *)(long)index, NULL);
|
|
|
|
else
|
|
|
|
gtk_tree_view_column_add_attribute(col, renderer, "text", index);
|
|
|
|
gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
|
|
|
|
switch (align) {
|
|
|
|
case PANGO_ALIGN_LEFT:
|
|
|
|
xalign = 0.0;
|
|
|
|
break;
|
|
|
|
case PANGO_ALIGN_CENTER:
|
|
|
|
xalign = 0.5;
|
|
|
|
break;
|
|
|
|
case PANGO_ALIGN_RIGHT:
|
|
|
|
xalign = 1.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
|
|
|
|
gtk_tree_view_column_set_visible(col, visible);
|
|
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
|
|
|
|
return col;
|
|
|
|
}
|
|
|
|
|
2012-01-05 16:16:08 +00:00
|
|
|
static void create_radio(GtkWidget *vbox, const char *w_name, ...)
|
2011-09-20 19:40:34 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
GtkRadioButton *group = NULL;
|
|
|
|
GtkWidget *box, *label;
|
|
|
|
|
|
|
|
box = gtk_hbox_new(TRUE, 10);
|
2011-09-20 21:05:46 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 0);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2012-01-05 16:16:08 +00:00
|
|
|
label = gtk_label_new(w_name);
|
2011-09-20 19:40:34 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
|
|
|
|
|
2012-01-05 16:16:08 +00:00
|
|
|
va_start(args, w_name);
|
2011-09-20 19:40:34 +00:00
|
|
|
for (;;) {
|
|
|
|
int enabled;
|
|
|
|
const char *name;
|
|
|
|
GtkWidget *button;
|
|
|
|
void *callback_fn;
|
|
|
|
|
|
|
|
name = va_arg(args, char *);
|
|
|
|
if (!name)
|
|
|
|
break;
|
|
|
|
callback_fn = va_arg(args, void *);
|
|
|
|
enabled = va_arg(args, int);
|
|
|
|
|
|
|
|
button = gtk_radio_button_new_with_label_from_widget(group, name);
|
|
|
|
group = GTK_RADIO_BUTTON(button);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), enabled);
|
|
|
|
g_signal_connect(button, "toggled", G_CALLBACK(callback_fn), NULL);
|
|
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define UNITCALLBACK(name, type, value) \
|
|
|
|
static void name(GtkWidget *w, gpointer data) \
|
|
|
|
{ \
|
|
|
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) \
|
|
|
|
menu_units.type = value; \
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct units menu_units;
|
|
|
|
|
|
|
|
UNITCALLBACK(set_meter, length, METERS)
|
|
|
|
UNITCALLBACK(set_feet, length, FEET)
|
|
|
|
UNITCALLBACK(set_bar, pressure, BAR)
|
|
|
|
UNITCALLBACK(set_psi, pressure, PSI)
|
|
|
|
UNITCALLBACK(set_liter, volume, LITER)
|
|
|
|
UNITCALLBACK(set_cuft, volume, CUFT)
|
|
|
|
UNITCALLBACK(set_celsius, temperature, CELSIUS)
|
|
|
|
UNITCALLBACK(set_fahrenheit, temperature, FAHRENHEIT)
|
2011-12-24 03:41:16 +00:00
|
|
|
UNITCALLBACK(set_kg, weight, KG)
|
|
|
|
UNITCALLBACK(set_lbs, weight, LBS)
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2011-09-27 17:16:40 +00:00
|
|
|
#define OPTIONCALLBACK(name, option) \
|
|
|
|
static void name(GtkWidget *w, gpointer data) \
|
|
|
|
{ \
|
|
|
|
option = GTK_TOGGLE_BUTTON(w)->active; \
|
|
|
|
}
|
|
|
|
|
|
|
|
OPTIONCALLBACK(otu_toggle, visible_cols.otu)
|
|
|
|
OPTIONCALLBACK(sac_toggle, visible_cols.sac)
|
2011-10-23 20:36:37 +00:00
|
|
|
OPTIONCALLBACK(nitrox_toggle, visible_cols.nitrox)
|
|
|
|
OPTIONCALLBACK(temperature_toggle, visible_cols.temperature)
|
2012-08-07 18:24:40 +00:00
|
|
|
OPTIONCALLBACK(totalweight_toggle, visible_cols.totalweight)
|
2012-08-14 23:07:25 +00:00
|
|
|
OPTIONCALLBACK(suit_toggle, visible_cols.suit)
|
2011-10-23 20:36:37 +00:00
|
|
|
OPTIONCALLBACK(cylinder_toggle, visible_cols.cylinder)
|
2012-08-22 05:04:24 +00:00
|
|
|
OPTIONCALLBACK(autogroup_toggle, autogroup)
|
2011-09-27 17:16:40 +00:00
|
|
|
|
2011-10-25 09:51:16 +00:00
|
|
|
static void event_toggle(GtkWidget *w, gpointer _data)
|
|
|
|
{
|
|
|
|
gboolean *plot_ev = _data;
|
|
|
|
|
|
|
|
*plot_ev = GTK_TOGGLE_BUTTON(w)->active;
|
|
|
|
}
|
|
|
|
|
2012-09-09 16:06:44 +00:00
|
|
|
static void pick_default_file(GtkWidget *w, GtkButton *button)
|
|
|
|
{
|
2012-09-21 19:09:48 +00:00
|
|
|
GtkWidget *fs_dialog, *parent;
|
2012-09-12 20:40:22 +00:00
|
|
|
const char *current_default;
|
2012-09-09 16:06:44 +00:00
|
|
|
char *current_def_file, *current_def_dir;
|
|
|
|
GtkFileFilter *filter;
|
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
fs_dialog = gtk_file_chooser_dialog_new("Choose Default XML File",
|
|
|
|
GTK_WINDOW(main_window),
|
|
|
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
|
|
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
|
|
|
NULL);
|
2012-09-21 19:09:48 +00:00
|
|
|
parent = gtk_widget_get_ancestor(w, GTK_TYPE_DIALOG);
|
|
|
|
gtk_widget_set_sensitive(parent, FALSE);
|
|
|
|
gtk_window_set_decorated(GTK_WINDOW(parent), FALSE);
|
|
|
|
gtk_window_set_transient_for(GTK_WINDOW(fs_dialog), GTK_WINDOW(parent));
|
2012-09-13 17:53:30 +00:00
|
|
|
|
2012-09-09 16:06:44 +00:00
|
|
|
current_default = subsurface_default_filename();
|
2012-09-13 18:17:38 +00:00
|
|
|
current_def_dir = g_path_get_dirname(current_default);
|
|
|
|
current_def_file = g_path_get_basename(current_default);
|
2012-09-12 20:40:22 +00:00
|
|
|
|
2012-09-09 16:06:44 +00:00
|
|
|
/* it's possible that the directory doesn't exist (especially for the default)
|
2012-09-12 20:40:22 +00:00
|
|
|
* For gtk's file select box to make sense we create it */
|
|
|
|
if (stat(current_def_dir, &sb) != 0)
|
|
|
|
g_mkdir(current_def_dir, S_IRWXU);
|
|
|
|
|
2012-09-09 16:06:44 +00:00
|
|
|
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fs_dialog), current_def_dir);
|
|
|
|
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fs_dialog), current_def_file);
|
|
|
|
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(fs_dialog), FALSE);
|
2012-09-15 22:22:36 +00:00
|
|
|
filter = setup_filter();
|
2012-09-09 16:06:44 +00:00
|
|
|
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fs_dialog), filter);
|
|
|
|
gtk_widget_show_all(fs_dialog);
|
|
|
|
if (gtk_dialog_run(GTK_DIALOG(fs_dialog)) == GTK_RESPONSE_ACCEPT) {
|
|
|
|
GSList *list;
|
|
|
|
|
|
|
|
list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(fs_dialog));
|
2012-09-12 20:40:22 +00:00
|
|
|
if (g_slist_length(list) == 1)
|
|
|
|
gtk_button_set_label(button, list->data);
|
2012-09-09 16:06:44 +00:00
|
|
|
g_slist_free(list);
|
|
|
|
}
|
2012-09-12 20:40:22 +00:00
|
|
|
|
2012-09-09 16:06:44 +00:00
|
|
|
free(current_def_dir);
|
|
|
|
free(current_def_file);
|
2012-09-18 11:24:54 +00:00
|
|
|
free((void *)current_default);
|
2012-09-09 16:06:44 +00:00
|
|
|
gtk_widget_destroy(fs_dialog);
|
2012-09-21 19:09:48 +00:00
|
|
|
|
|
|
|
gtk_widget_set_sensitive(parent, TRUE);
|
|
|
|
gtk_window_set_decorated(GTK_WINDOW(parent), TRUE);
|
2012-09-09 16:06:44 +00:00
|
|
|
}
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
static void preferences_dialog(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
int result;
|
2011-09-27 18:05:39 +00:00
|
|
|
GtkWidget *dialog, *font, *frame, *box, *vbox, *button;
|
2012-09-09 16:06:44 +00:00
|
|
|
const char *current_default, *new_default;
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
menu_units = output_units;
|
|
|
|
|
|
|
|
dialog = gtk_dialog_new_with_buttons("Preferences",
|
|
|
|
GTK_WINDOW(main_window),
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
frame = gtk_frame_new("Units");
|
2011-09-24 22:26:37 +00:00
|
|
|
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
box = gtk_vbox_new(FALSE, 6);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), box);
|
|
|
|
|
|
|
|
create_radio(box, "Depth:",
|
|
|
|
"Meter", set_meter, (output_units.length == METERS),
|
|
|
|
"Feet", set_feet, (output_units.length == FEET),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
create_radio(box, "Pressure:",
|
|
|
|
"Bar", set_bar, (output_units.pressure == BAR),
|
|
|
|
"PSI", set_psi, (output_units.pressure == PSI),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
create_radio(box, "Volume:",
|
|
|
|
"Liter", set_liter, (output_units.volume == LITER),
|
|
|
|
"CuFt", set_cuft, (output_units.volume == CUFT),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
create_radio(box, "Temperature:",
|
|
|
|
"Celsius", set_celsius, (output_units.temperature == CELSIUS),
|
|
|
|
"Fahrenheit", set_fahrenheit, (output_units.temperature == FAHRENHEIT),
|
|
|
|
NULL);
|
|
|
|
|
2011-12-24 03:41:16 +00:00
|
|
|
create_radio(box, "Weight:",
|
|
|
|
"kg", set_kg, (output_units.weight == KG),
|
|
|
|
"lbs", set_lbs, (output_units.weight == LBS),
|
|
|
|
NULL);
|
|
|
|
|
2012-08-17 06:56:03 +00:00
|
|
|
frame = gtk_frame_new("Show Columns");
|
2011-09-27 17:16:40 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
|
|
|
|
|
|
|
|
box = gtk_hbox_new(FALSE, 6);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), box);
|
|
|
|
|
2012-08-17 06:56:03 +00:00
|
|
|
button = gtk_check_button_new_with_label("Temp");
|
2011-10-23 20:36:37 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.temperature);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
|
|
|
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(temperature_toggle), NULL);
|
|
|
|
|
2012-08-17 06:56:03 +00:00
|
|
|
button = gtk_check_button_new_with_label("Cyl");
|
2011-10-23 20:36:37 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.cylinder);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
|
|
|
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(cylinder_toggle), NULL);
|
|
|
|
|
2012-08-17 06:56:03 +00:00
|
|
|
button = gtk_check_button_new_with_label("O" UTF8_SUBSCRIPT_2 "%");
|
2011-10-23 20:36:37 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.nitrox);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
|
|
|
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(nitrox_toggle), NULL);
|
|
|
|
|
2012-08-17 06:56:03 +00:00
|
|
|
button = gtk_check_button_new_with_label("SAC");
|
2011-09-27 17:16:40 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.sac);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
|
|
|
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(sac_toggle), NULL);
|
|
|
|
|
2012-08-17 06:56:03 +00:00
|
|
|
button = gtk_check_button_new_with_label("OTU");
|
2011-09-27 17:16:40 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.otu);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
|
|
|
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(otu_toggle), NULL);
|
|
|
|
|
2012-08-17 06:56:03 +00:00
|
|
|
button = gtk_check_button_new_with_label("Weight");
|
2012-08-07 18:24:40 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.totalweight);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
|
|
|
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(totalweight_toggle), NULL);
|
|
|
|
|
2012-08-17 06:56:03 +00:00
|
|
|
button = gtk_check_button_new_with_label("Suit");
|
2012-08-14 23:07:25 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.suit);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
|
|
|
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(suit_toggle), NULL);
|
|
|
|
|
2012-08-22 05:04:24 +00:00
|
|
|
frame = gtk_frame_new("Divelist Font");
|
|
|
|
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
font = gtk_font_button_new_with_font(divelist_font);
|
2012-08-22 05:04:24 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(frame),font);
|
|
|
|
|
|
|
|
frame = gtk_frame_new("Misc. Options");
|
|
|
|
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
|
|
|
|
|
|
|
|
box = gtk_hbox_new(FALSE, 6);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), box);
|
|
|
|
|
|
|
|
button = gtk_check_button_new_with_label("Automatically group dives in trips");
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), autogroup);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
|
|
|
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(autogroup_toggle), NULL);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2012-09-09 16:06:44 +00:00
|
|
|
frame = gtk_frame_new("Default XML Data File");
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
|
|
|
|
box = gtk_hbox_new(FALSE, 6);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), box);
|
|
|
|
current_default = subsurface_default_filename();
|
|
|
|
button = gtk_button_new_with_label(current_default);
|
|
|
|
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(pick_default_file), button);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
gtk_widget_show_all(dialog);
|
|
|
|
result = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
|
|
if (result == GTK_RESPONSE_ACCEPT) {
|
|
|
|
/* Make sure to flush any modified old dive data with old units */
|
|
|
|
update_dive(NULL);
|
|
|
|
|
|
|
|
divelist_font = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON(font)));
|
|
|
|
set_divelist_font(divelist_font);
|
|
|
|
|
|
|
|
output_units = menu_units;
|
|
|
|
update_dive_list_units();
|
|
|
|
repaint_dive();
|
2011-09-27 17:16:40 +00:00
|
|
|
update_dive_list_col_visibility();
|
2011-10-29 01:46:53 +00:00
|
|
|
|
2011-11-24 06:56:57 +00:00
|
|
|
subsurface_set_conf("feet", PREF_BOOL, BOOL_TO_PTR(output_units.length == FEET));
|
|
|
|
subsurface_set_conf("psi", PREF_BOOL, BOOL_TO_PTR(output_units.pressure == PSI));
|
|
|
|
subsurface_set_conf("cuft", PREF_BOOL, BOOL_TO_PTR(output_units.volume == CUFT));
|
|
|
|
subsurface_set_conf("fahrenheit", PREF_BOOL, BOOL_TO_PTR(output_units.temperature == FAHRENHEIT));
|
2011-12-24 03:41:16 +00:00
|
|
|
subsurface_set_conf("lbs", PREF_BOOL, BOOL_TO_PTR(output_units.weight == LBS));
|
2011-11-24 06:56:57 +00:00
|
|
|
subsurface_set_conf("TEMPERATURE", PREF_BOOL, BOOL_TO_PTR(visible_cols.temperature));
|
2012-08-07 18:24:40 +00:00
|
|
|
subsurface_set_conf("TOTALWEIGHT", PREF_BOOL, BOOL_TO_PTR(visible_cols.totalweight));
|
2012-08-14 23:07:25 +00:00
|
|
|
subsurface_set_conf("SUIT", PREF_BOOL, BOOL_TO_PTR(visible_cols.suit));
|
2011-11-24 06:56:57 +00:00
|
|
|
subsurface_set_conf("CYLINDER", PREF_BOOL, BOOL_TO_PTR(visible_cols.cylinder));
|
|
|
|
subsurface_set_conf("NITROX", PREF_BOOL, BOOL_TO_PTR(visible_cols.nitrox));
|
|
|
|
subsurface_set_conf("SAC", PREF_BOOL, BOOL_TO_PTR(visible_cols.sac));
|
|
|
|
subsurface_set_conf("OTU", PREF_BOOL, BOOL_TO_PTR(visible_cols.otu));
|
|
|
|
subsurface_set_conf("divelist_font", PREF_STRING, divelist_font);
|
2012-08-22 05:04:24 +00:00
|
|
|
subsurface_set_conf("autogroup", PREF_BOOL, BOOL_TO_PTR(autogroup));
|
2012-09-09 16:06:44 +00:00
|
|
|
new_default = strdup(gtk_button_get_label(GTK_BUTTON(button)));
|
2012-09-12 20:40:22 +00:00
|
|
|
|
|
|
|
/* if we opened the default file and are changing its name,
|
|
|
|
* update existing_filename */
|
2012-09-13 17:46:09 +00:00
|
|
|
if (existing_filename) {
|
|
|
|
if (strcmp(current_default, existing_filename) == 0) {
|
2012-09-16 03:51:06 +00:00
|
|
|
free((void *)existing_filename);
|
2012-09-13 17:46:09 +00:00
|
|
|
existing_filename = strdup(new_default);
|
|
|
|
}
|
|
|
|
}
|
2012-09-12 20:40:22 +00:00
|
|
|
|
2012-09-09 16:06:44 +00:00
|
|
|
if (strcmp(current_default, new_default)) {
|
|
|
|
subsurface_set_conf("default_filename", PREF_STRING, new_default);
|
|
|
|
free((void *)default_filename);
|
|
|
|
default_filename = new_default;
|
|
|
|
}
|
2012-05-02 17:03:48 +00:00
|
|
|
|
|
|
|
/* Flush the changes out to the system */
|
|
|
|
subsurface_flush_conf();
|
2011-09-20 19:40:34 +00:00
|
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
}
|
|
|
|
|
2011-10-25 09:51:16 +00:00
|
|
|
static void create_toggle(const char* label, int *on, void *_data)
|
|
|
|
{
|
2011-10-25 11:18:31 +00:00
|
|
|
GtkWidget *button, *table = _data;
|
|
|
|
int rows, cols, x, y;
|
|
|
|
static int count;
|
|
|
|
|
|
|
|
if (table == NULL) {
|
|
|
|
/* magic way to reset the number of toggle buttons
|
|
|
|
* that we have already added - call this before you
|
|
|
|
* create the dialog */
|
|
|
|
count = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
g_object_get(G_OBJECT(table), "n-columns", &cols, "n-rows", &rows, NULL);
|
|
|
|
if (count > rows * cols) {
|
|
|
|
gtk_table_resize(GTK_TABLE(table),rows+1,cols);
|
|
|
|
rows++;
|
|
|
|
}
|
|
|
|
x = count % cols;
|
|
|
|
y = count / cols;
|
2011-10-25 09:51:16 +00:00
|
|
|
button = gtk_check_button_new_with_label(label);
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *on);
|
2011-10-25 11:18:31 +00:00
|
|
|
gtk_table_attach_defaults(GTK_TABLE(table), button, x, x+1, y, y+1);
|
2011-10-25 09:51:16 +00:00
|
|
|
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(event_toggle), on);
|
2011-10-25 11:18:31 +00:00
|
|
|
count++;
|
2011-10-25 09:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void selectevents_dialog(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
int result;
|
2011-10-25 11:18:31 +00:00
|
|
|
GtkWidget *dialog, *frame, *vbox, *table;
|
2011-10-25 09:51:16 +00:00
|
|
|
|
|
|
|
dialog = gtk_dialog_new_with_buttons("SelectEvents",
|
|
|
|
GTK_WINDOW(main_window),
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
|
|
|
|
NULL);
|
2011-10-25 11:18:31 +00:00
|
|
|
/* initialize the function that fills the table */
|
|
|
|
create_toggle(NULL, NULL, NULL);
|
2011-10-25 09:51:16 +00:00
|
|
|
|
|
|
|
frame = gtk_frame_new("Enable / Disable Events");
|
|
|
|
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
|
|
|
|
|
2011-10-25 11:18:31 +00:00
|
|
|
table = gtk_table_new(1, 4, TRUE);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), table);
|
2011-10-25 09:51:16 +00:00
|
|
|
|
2011-10-25 11:18:31 +00:00
|
|
|
evn_foreach(&create_toggle, table);
|
2011-10-25 09:51:16 +00:00
|
|
|
|
|
|
|
gtk_widget_show_all(dialog);
|
|
|
|
result = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
|
|
if (result == GTK_RESPONSE_ACCEPT) {
|
|
|
|
repaint_dive();
|
|
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
}
|
|
|
|
|
2012-09-03 04:48:30 +00:00
|
|
|
static void autogroup_cb(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
autogroup = !autogroup;
|
|
|
|
if (! autogroup)
|
|
|
|
remove_autogen_trips();
|
|
|
|
dive_list_update_dives();
|
|
|
|
}
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
static void renumber_dialog(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
int result;
|
2011-10-05 15:37:14 +00:00
|
|
|
struct dive *dive;
|
2011-09-24 22:26:37 +00:00
|
|
|
GtkWidget *dialog, *frame, *button, *vbox;
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
dialog = gtk_dialog_new_with_buttons("Renumber",
|
|
|
|
GTK_WINDOW(main_window),
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
|
|
|
|
NULL);
|
|
|
|
|
2011-09-24 22:26:37 +00:00
|
|
|
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
frame = gtk_frame_new("New starting number");
|
2011-09-24 22:26:37 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
button = gtk_spin_button_new_with_range(1, 50000, 1);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), button);
|
|
|
|
|
2011-10-05 15:37:14 +00:00
|
|
|
/*
|
|
|
|
* Do we have a number for the first dive already? Use that
|
|
|
|
* as the default.
|
|
|
|
*/
|
|
|
|
dive = get_dive(0);
|
|
|
|
if (dive && dive->number)
|
|
|
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), dive->number);
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
gtk_widget_show_all(dialog);
|
|
|
|
result = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
|
|
if (result == GTK_RESPONSE_ACCEPT) {
|
|
|
|
int nr = gtk_spin_button_get_value(GTK_SPIN_BUTTON(button));
|
|
|
|
renumber_dives(nr);
|
|
|
|
repaint_dive();
|
|
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
}
|
|
|
|
|
2011-09-24 22:48:13 +00:00
|
|
|
static void about_dialog(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
const char *logo_property = NULL;
|
|
|
|
GdkPixbuf *logo = NULL;
|
|
|
|
|
2011-10-11 22:58:38 +00:00
|
|
|
if (need_icon) {
|
2011-12-28 23:57:36 +00:00
|
|
|
GtkWidget *image = gtk_image_new_from_file(subsurface_icon_name());
|
2011-10-11 22:58:38 +00:00
|
|
|
|
|
|
|
if (image) {
|
|
|
|
logo = gtk_image_get_pixbuf(GTK_IMAGE(image));
|
|
|
|
logo_property = "logo";
|
|
|
|
}
|
2011-09-24 22:48:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gtk_show_about_dialog(NULL,
|
|
|
|
"program-name", "SubSurface",
|
2012-09-06 21:27:34 +00:00
|
|
|
"comments", "Multi-platform divelog software in C",
|
2011-09-24 22:48:13 +00:00
|
|
|
"license", "GPLv2",
|
2011-09-26 18:04:50 +00:00
|
|
|
"version", VERSION_STRING,
|
2012-09-06 21:27:34 +00:00
|
|
|
"copyright", "Linus Torvalds, Dirk Hohndel, and others, 2011, 2012",
|
2011-10-11 22:58:38 +00:00
|
|
|
"logo-icon-name", "subsurface",
|
2011-09-24 22:48:13 +00:00
|
|
|
/* Must be last: */
|
|
|
|
logo_property, logo,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2011-12-06 21:00:01 +00:00
|
|
|
static void view_list(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
gtk_paned_set_position(GTK_PANED(vpane), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void view_profile(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
gtk_paned_set_position(GTK_PANED(hpane), 0);
|
|
|
|
gtk_paned_set_position(GTK_PANED(vpane), 65535);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void view_info(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
gtk_paned_set_position(GTK_PANED(vpane), 65535);
|
|
|
|
gtk_paned_set_position(GTK_PANED(hpane), 65535);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void view_three(GtkWidget *w, gpointer data)
|
|
|
|
{
|
2012-07-29 09:13:36 +00:00
|
|
|
GtkAllocation alloc;
|
2012-08-19 01:06:32 +00:00
|
|
|
GtkRequisition requisition;
|
|
|
|
|
2012-07-29 09:13:36 +00:00
|
|
|
gtk_widget_get_allocation(hpane, &alloc);
|
|
|
|
gtk_paned_set_position(GTK_PANED(hpane), alloc.width/2);
|
|
|
|
gtk_widget_get_allocation(vpane, &alloc);
|
2012-08-19 01:06:32 +00:00
|
|
|
gtk_widget_size_request(notebook, &requisition);
|
|
|
|
/* pick the requested size for the notebook plus 6 pixels for frame */
|
|
|
|
gtk_paned_set_position(GTK_PANED(vpane), requisition.height + 6);
|
2011-12-06 21:00:01 +00:00
|
|
|
}
|
|
|
|
|
2012-06-11 00:45:36 +00:00
|
|
|
static void toggle_zoom(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
zoomed_plot = (zoomed_plot)?0 : 1;
|
|
|
|
/*Update dive*/
|
|
|
|
repaint_dive();
|
|
|
|
}
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
static GtkActionEntry menu_items[] = {
|
2012-07-29 10:15:04 +00:00
|
|
|
{ "FileMenuAction", NULL, "File", NULL, NULL, NULL},
|
|
|
|
{ "LogMenuAction", NULL, "Log", NULL, NULL, NULL},
|
|
|
|
{ "ViewMenuAction", NULL, "View", NULL, NULL, NULL},
|
|
|
|
{ "FilterMenuAction", NULL, "Filter", NULL, NULL, NULL},
|
|
|
|
{ "HelpMenuAction", NULL, "Help", NULL, NULL, NULL},
|
2012-09-16 23:23:02 +00:00
|
|
|
{ "NewFile", GTK_STOCK_NEW, NULL, CTRLCHAR "N", NULL, G_CALLBACK(file_close) },
|
2012-01-03 04:49:10 +00:00
|
|
|
{ "OpenFile", GTK_STOCK_OPEN, NULL, CTRLCHAR "O", NULL, G_CALLBACK(file_open) },
|
|
|
|
{ "SaveFile", GTK_STOCK_SAVE, NULL, CTRLCHAR "S", NULL, G_CALLBACK(file_save) },
|
2012-07-17 14:49:27 +00:00
|
|
|
{ "SaveAsFile", GTK_STOCK_SAVE_AS, NULL, SHIFTCHAR CTRLCHAR "S", NULL, G_CALLBACK(file_save_as) },
|
2012-09-10 21:32:55 +00:00
|
|
|
{ "CloseFile", GTK_STOCK_CLOSE, NULL, NULL, NULL, G_CALLBACK(file_close) },
|
2012-01-03 04:49:10 +00:00
|
|
|
{ "Print", GTK_STOCK_PRINT, NULL, CTRLCHAR "P", NULL, G_CALLBACK(do_print) },
|
2012-09-16 22:29:45 +00:00
|
|
|
{ "Import", GTK_STOCK_GO_BACK, "Import", SHIFTCHAR CTRLCHAR "O", NULL, G_CALLBACK(import_dialog) },
|
2012-07-29 10:15:04 +00:00
|
|
|
{ "AddDive", GTK_STOCK_ADD, "Add Dive", NULL, NULL, G_CALLBACK(add_dive_cb) },
|
|
|
|
{ "Preferences", GTK_STOCK_PREFERENCES, "Preferences", PREFERENCE_ACCEL, NULL, G_CALLBACK(preferences_dialog) },
|
2011-09-20 19:40:34 +00:00
|
|
|
{ "Renumber", NULL, "Renumber", NULL, NULL, G_CALLBACK(renumber_dialog) },
|
2012-09-10 19:17:28 +00:00
|
|
|
{ "YearlyStats", NULL, "Yearly Statistics", NULL, NULL, G_CALLBACK(show_yearly_stats) },
|
2011-10-25 09:51:16 +00:00
|
|
|
{ "SelectEvents", NULL, "SelectEvents", NULL, NULL, G_CALLBACK(selectevents_dialog) },
|
2012-01-03 04:49:10 +00:00
|
|
|
{ "Quit", GTK_STOCK_QUIT, NULL, CTRLCHAR "Q", NULL, G_CALLBACK(quit) },
|
2011-10-25 09:51:16 +00:00
|
|
|
{ "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK(about_dialog) },
|
2012-01-03 04:49:10 +00:00
|
|
|
{ "ViewList", NULL, "List", CTRLCHAR "1", NULL, G_CALLBACK(view_list) },
|
|
|
|
{ "ViewProfile", NULL, "Profile", CTRLCHAR "2", NULL, G_CALLBACK(view_profile) },
|
|
|
|
{ "ViewInfo", NULL, "Info", CTRLCHAR "3", NULL, G_CALLBACK(view_info) },
|
2012-06-11 00:45:36 +00:00
|
|
|
{ "ViewThree", NULL, "Three", CTRLCHAR "4", NULL, G_CALLBACK(view_three) },
|
2011-09-20 19:40:34 +00:00
|
|
|
};
|
|
|
|
static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
|
|
|
|
|
2012-09-03 04:48:30 +00:00
|
|
|
static GtkToggleActionEntry toggle_items[] = {
|
|
|
|
{ "Autogroup", NULL, "Autogroup", NULL, NULL, G_CALLBACK(autogroup_cb), FALSE },
|
|
|
|
{ "ToggleZoom", NULL, "Toggle Zoom", CTRLCHAR "0", NULL, G_CALLBACK(toggle_zoom), FALSE },
|
|
|
|
};
|
|
|
|
static gint ntoggle_items = sizeof (toggle_items) / sizeof (toggle_items[0]);
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
static const gchar* ui_string = " \
|
|
|
|
<ui> \
|
|
|
|
<menubar name=\"MainMenu\"> \
|
|
|
|
<menu name=\"FileMenu\" action=\"FileMenuAction\"> \
|
2012-09-16 23:23:02 +00:00
|
|
|
<menuitem name=\"New\" action=\"NewFile\" /> \
|
2011-09-20 19:40:34 +00:00
|
|
|
<menuitem name=\"Open\" action=\"OpenFile\" /> \
|
|
|
|
<menuitem name=\"Save\" action=\"SaveFile\" /> \
|
2012-07-17 14:49:27 +00:00
|
|
|
<menuitem name=\"Save As\" action=\"SaveAsFile\" /> \
|
2012-09-10 21:32:55 +00:00
|
|
|
<menuitem name=\"Close\" action=\"CloseFile\" /> \
|
2011-09-20 19:40:34 +00:00
|
|
|
<separator name=\"Separator1\"/> \
|
2012-09-16 22:29:45 +00:00
|
|
|
<menuitem name=\"Import\" action=\"Import\" /> \
|
2012-05-02 19:56:01 +00:00
|
|
|
<separator name=\"Separator2\"/> \
|
2012-09-16 22:29:45 +00:00
|
|
|
<menuitem name=\"Print\" action=\"Print\" /> \
|
|
|
|
<separator name=\"Separator3\"/> \
|
|
|
|
<menuitem name=\"Preferences\" action=\"Preferences\" /> \
|
|
|
|
<separator name=\"Separator4\"/> \
|
2011-09-20 19:40:34 +00:00
|
|
|
<menuitem name=\"Quit\" action=\"Quit\" /> \
|
|
|
|
</menu> \
|
|
|
|
<menu name=\"LogMenu\" action=\"LogMenuAction\"> \
|
2012-06-28 01:09:26 +00:00
|
|
|
<menuitem name=\"Add Dive\" action=\"AddDive\" /> \
|
2012-05-02 19:56:01 +00:00
|
|
|
<separator name=\"Separator\"/> \
|
2011-09-20 19:40:34 +00:00
|
|
|
<menuitem name=\"Renumber\" action=\"Renumber\" /> \
|
2012-09-03 04:48:30 +00:00
|
|
|
<menuitem name=\"Autogroup\" action=\"Autogroup\" /> \
|
2012-06-11 00:45:36 +00:00
|
|
|
<menuitem name=\"Toggle Zoom\" action=\"ToggleZoom\" /> \
|
2012-09-10 19:17:28 +00:00
|
|
|
<menuitem name=\"YearlyStats\" action=\"YearlyStats\" /> \
|
2011-12-06 21:00:01 +00:00
|
|
|
<menu name=\"View\" action=\"ViewMenuAction\"> \
|
|
|
|
<menuitem name=\"List\" action=\"ViewList\" /> \
|
|
|
|
<menuitem name=\"Profile\" action=\"ViewProfile\" /> \
|
|
|
|
<menuitem name=\"Info\" action=\"ViewInfo\" /> \
|
|
|
|
<menuitem name=\"Paned\" action=\"ViewThree\" /> \
|
|
|
|
</menu> \
|
2011-09-20 19:40:34 +00:00
|
|
|
</menu> \
|
2011-10-25 09:51:16 +00:00
|
|
|
<menu name=\"FilterMenu\" action=\"FilterMenuAction\"> \
|
|
|
|
<menuitem name=\"SelectEvents\" action=\"SelectEvents\" /> \
|
|
|
|
</menu> \
|
2011-09-24 22:48:13 +00:00
|
|
|
<menu name=\"Help\" action=\"HelpMenuAction\"> \
|
|
|
|
<menuitem name=\"About\" action=\"About\" /> \
|
|
|
|
</menu> \
|
2011-09-20 19:40:34 +00:00
|
|
|
</menubar> \
|
|
|
|
</ui> \
|
|
|
|
";
|
|
|
|
|
2012-01-03 04:49:10 +00:00
|
|
|
static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager)
|
2011-09-20 19:40:34 +00:00
|
|
|
{
|
|
|
|
GtkActionGroup *action_group = gtk_action_group_new("Menu");
|
|
|
|
gtk_action_group_add_actions(action_group, menu_items, nmenu_items, 0);
|
2012-09-03 15:01:21 +00:00
|
|
|
toggle_items[0].is_active = autogroup;
|
2012-09-03 04:48:30 +00:00
|
|
|
gtk_action_group_add_toggle_actions(action_group, toggle_items, ntoggle_items, 0);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
|
|
|
|
GError* error = 0;
|
|
|
|
gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error);
|
|
|
|
|
|
|
|
gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
|
|
|
|
GtkWidget* menu = gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
|
|
|
|
|
|
|
|
return menu;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void switch_page(GtkNotebook *notebook, gint arg1, gpointer user_data)
|
|
|
|
{
|
|
|
|
repaint_dive();
|
|
|
|
}
|
|
|
|
|
2011-11-02 00:09:15 +00:00
|
|
|
void init_ui(int *argcp, char ***argvp)
|
2011-09-20 19:40:34 +00:00
|
|
|
{
|
|
|
|
GtkWidget *win;
|
2012-01-15 22:29:08 +00:00
|
|
|
GtkWidget *nb_page;
|
2011-09-20 19:40:34 +00:00
|
|
|
GtkWidget *dive_list;
|
|
|
|
GtkWidget *menubar;
|
|
|
|
GtkWidget *vbox;
|
Make the notebook portion (dive notes/equipment/info) a scrollable window
This makes things start up with the wrong size, which is somewhat
annoying, but by doing so avoids a bigger annoyance, namely that the
three panes move around when moving between dives.
In particular, if the initial dive didn't have much of an equipment
list, the initial size allocated for the notebook is fairly small and
determined mainly by the size of the the Dive Notes page. However, when
you then scroll around in the dive list, you might hit a dive with lots
of equipment, and suddenly the panes dividing the different parts of the
subsurface application window will jump around to make room.
That's horribly annoying, and actually makes things like double-clicking
dives in the dive list not work right, because the first click will
select it, and cause the dive to move around (so the second click will
hit a totally different dive).
Now, making the notebook be in a scrollable window means that if the
size of the notebook changes, it might get a scrollbar, but the panes
themselves do not move around.
The initial sizing of that thing being wrong is annoying, though. We
need to figure out a separate solution to that.
[ Side note: currently it uses GTK_POLICY_NEVER for the horizontal
scroll-bar, just to avoid the horizontal size also starting out wrong,
which is *really* nasty. If we can solve the initial size issue, we
should make the horizontal scroll-bar be GTK_POLICY_AUTOMATIC too. ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-08-18 21:37:43 +00:00
|
|
|
GtkWidget *scrolled;
|
2011-10-11 22:58:38 +00:00
|
|
|
GdkScreen *screen;
|
|
|
|
GtkIconTheme *icon_theme=NULL;
|
2011-10-04 23:06:27 +00:00
|
|
|
GtkSettings *settings;
|
2012-01-03 04:49:10 +00:00
|
|
|
GtkUIManager *ui_manager;
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2011-11-02 00:09:15 +00:00
|
|
|
gtk_init(argcp, argvp);
|
2011-10-04 23:06:27 +00:00
|
|
|
settings = gtk_settings_get_default();
|
|
|
|
gtk_settings_set_long_property(settings, "gtk_tooltip_timeout", 10, "subsurface setting");
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
g_type_init();
|
2011-10-28 05:10:35 +00:00
|
|
|
|
2011-11-24 06:56:57 +00:00
|
|
|
subsurface_open_conf();
|
|
|
|
if (subsurface_get_conf("feet", PREF_BOOL))
|
2011-09-20 19:40:34 +00:00
|
|
|
output_units.length = FEET;
|
2011-11-24 06:56:57 +00:00
|
|
|
if (subsurface_get_conf("psi", PREF_BOOL))
|
2011-09-20 19:40:34 +00:00
|
|
|
output_units.pressure = PSI;
|
2011-11-24 06:56:57 +00:00
|
|
|
if (subsurface_get_conf("cuft", PREF_BOOL))
|
2011-09-20 19:40:34 +00:00
|
|
|
output_units.volume = CUFT;
|
2011-11-24 06:56:57 +00:00
|
|
|
if (subsurface_get_conf("fahrenheit", PREF_BOOL))
|
2011-09-20 19:40:34 +00:00
|
|
|
output_units.temperature = FAHRENHEIT;
|
2011-12-24 03:41:16 +00:00
|
|
|
if (subsurface_get_conf("lbs", PREF_BOOL))
|
|
|
|
output_units.weight = LBS;
|
2011-10-23 20:36:37 +00:00
|
|
|
/* an unset key is FALSE - all these are hidden by default */
|
2011-11-24 06:56:57 +00:00
|
|
|
visible_cols.cylinder = PTR_TO_BOOL(subsurface_get_conf("CYLINDER", PREF_BOOL));
|
|
|
|
visible_cols.temperature = PTR_TO_BOOL(subsurface_get_conf("TEMPERATURE", PREF_BOOL));
|
2012-08-07 18:24:40 +00:00
|
|
|
visible_cols.totalweight = PTR_TO_BOOL(subsurface_get_conf("TOTALWEIGHT", PREF_BOOL));
|
2012-08-14 23:07:25 +00:00
|
|
|
visible_cols.suit = PTR_TO_BOOL(subsurface_get_conf("SUIT", PREF_BOOL));
|
2011-11-24 06:56:57 +00:00
|
|
|
visible_cols.nitrox = PTR_TO_BOOL(subsurface_get_conf("NITROX", PREF_BOOL));
|
|
|
|
visible_cols.otu = PTR_TO_BOOL(subsurface_get_conf("OTU", PREF_BOOL));
|
|
|
|
visible_cols.sac = PTR_TO_BOOL(subsurface_get_conf("SAC", PREF_BOOL));
|
|
|
|
|
|
|
|
divelist_font = subsurface_get_conf("divelist_font", PREF_STRING);
|
2012-08-22 05:04:24 +00:00
|
|
|
autogroup = PTR_TO_BOOL(subsurface_get_conf("autogroup", PREF_BOOL));
|
2012-09-09 16:06:44 +00:00
|
|
|
default_filename = subsurface_get_conf("default_filename", PREF_STRING);
|
2012-08-22 05:04:24 +00:00
|
|
|
|
2012-06-22 20:37:39 +00:00
|
|
|
default_dive_computer_vendor = subsurface_get_conf("dive_computer_vendor", PREF_STRING);
|
|
|
|
default_dive_computer_product = subsurface_get_conf("dive_computer_product", PREF_STRING);
|
2012-05-30 04:54:09 +00:00
|
|
|
default_dive_computer_device = subsurface_get_conf("dive_computer_device", PREF_STRING);
|
2012-05-02 17:26:34 +00:00
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
error_info_bar = NULL;
|
|
|
|
win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
2011-10-11 22:58:38 +00:00
|
|
|
g_set_application_name ("subsurface");
|
|
|
|
/* Let's check if the subsurface icon has been installed or if
|
|
|
|
* we need to try to load it from the current directory */
|
|
|
|
screen = gdk_screen_get_default();
|
|
|
|
if (screen)
|
|
|
|
icon_theme = gtk_icon_theme_get_for_screen(screen);
|
|
|
|
if (icon_theme) {
|
|
|
|
if (gtk_icon_theme_has_icon(icon_theme, "subsurface")) {
|
|
|
|
need_icon = FALSE;
|
|
|
|
gtk_window_set_default_icon_name ("subsurface");
|
|
|
|
}
|
|
|
|
}
|
2012-01-03 04:15:24 +00:00
|
|
|
if (need_icon) {
|
|
|
|
const char *icon_name = subsurface_icon_name();
|
|
|
|
if (!access(icon_name, R_OK))
|
|
|
|
gtk_window_set_icon_from_file(GTK_WINDOW(win), icon_name, NULL);
|
|
|
|
}
|
2011-09-27 17:38:07 +00:00
|
|
|
g_signal_connect(G_OBJECT(win), "delete-event", G_CALLBACK(on_delete), NULL);
|
2011-09-20 19:40:34 +00:00
|
|
|
g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(on_destroy), NULL);
|
|
|
|
main_window = win;
|
|
|
|
|
|
|
|
vbox = gtk_vbox_new(FALSE, 0);
|
|
|
|
gtk_container_add(GTK_CONTAINER(win), vbox);
|
|
|
|
main_vbox = vbox;
|
|
|
|
|
2012-01-03 04:49:10 +00:00
|
|
|
ui_manager = gtk_ui_manager_new();
|
|
|
|
menubar = get_menubar_menu(win, ui_manager);
|
2012-01-01 21:41:47 +00:00
|
|
|
|
2012-01-03 04:49:10 +00:00
|
|
|
subsurface_ui_setup(settings, menubar, vbox, ui_manager);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2011-11-19 20:54:58 +00:00
|
|
|
vpane = gtk_vpaned_new();
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), vpane, TRUE, TRUE, 3);
|
|
|
|
hpane = gtk_hpaned_new();
|
|
|
|
gtk_paned_add1(GTK_PANED(vpane), hpane);
|
Make the notebook portion (dive notes/equipment/info) a scrollable window
This makes things start up with the wrong size, which is somewhat
annoying, but by doing so avoids a bigger annoyance, namely that the
three panes move around when moving between dives.
In particular, if the initial dive didn't have much of an equipment
list, the initial size allocated for the notebook is fairly small and
determined mainly by the size of the the Dive Notes page. However, when
you then scroll around in the dive list, you might hit a dive with lots
of equipment, and suddenly the panes dividing the different parts of the
subsurface application window will jump around to make room.
That's horribly annoying, and actually makes things like double-clicking
dives in the dive list not work right, because the first click will
select it, and cause the dive to move around (so the second click will
hit a totally different dive).
Now, making the notebook be in a scrollable window means that if the
size of the notebook changes, it might get a scrollbar, but the panes
themselves do not move around.
The initial sizing of that thing being wrong is annoying, though. We
need to figure out a separate solution to that.
[ Side note: currently it uses GTK_POLICY_NEVER for the horizontal
scroll-bar, just to avoid the horizontal size also starting out wrong,
which is *really* nasty. If we can solve the initial size issue, we
should make the horizontal scroll-bar be GTK_POLICY_AUTOMATIC too. ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-08-18 21:37:43 +00:00
|
|
|
g_signal_connect_after(G_OBJECT(vbox), "realize", G_CALLBACK(view_three), NULL);
|
2011-11-19 20:54:58 +00:00
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
/* Notebook for dive info vs profile vs .. */
|
|
|
|
notebook = gtk_notebook_new();
|
Make the notebook portion (dive notes/equipment/info) a scrollable window
This makes things start up with the wrong size, which is somewhat
annoying, but by doing so avoids a bigger annoyance, namely that the
three panes move around when moving between dives.
In particular, if the initial dive didn't have much of an equipment
list, the initial size allocated for the notebook is fairly small and
determined mainly by the size of the the Dive Notes page. However, when
you then scroll around in the dive list, you might hit a dive with lots
of equipment, and suddenly the panes dividing the different parts of the
subsurface application window will jump around to make room.
That's horribly annoying, and actually makes things like double-clicking
dives in the dive list not work right, because the first click will
select it, and cause the dive to move around (so the second click will
hit a totally different dive).
Now, making the notebook be in a scrollable window means that if the
size of the notebook changes, it might get a scrollbar, but the panes
themselves do not move around.
The initial sizing of that thing being wrong is annoying, though. We
need to figure out a separate solution to that.
[ Side note: currently it uses GTK_POLICY_NEVER for the horizontal
scroll-bar, just to avoid the horizontal size also starting out wrong,
which is *really* nasty. If we can solve the initial size issue, we
should make the horizontal scroll-bar be GTK_POLICY_AUTOMATIC too. ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-08-18 21:37:43 +00:00
|
|
|
scrolled = gtk_scrolled_window_new(NULL, NULL);
|
|
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
|
|
|
gtk_paned_add1(GTK_PANED(hpane), scrolled);
|
|
|
|
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), notebook);
|
2011-09-20 19:40:34 +00:00
|
|
|
g_signal_connect(notebook, "switch-page", G_CALLBACK(switch_page), NULL);
|
2011-09-27 17:38:07 +00:00
|
|
|
|
|
|
|
/* Create the actual divelist */
|
|
|
|
dive_list = dive_list_create();
|
2011-09-27 23:23:59 +00:00
|
|
|
gtk_widget_set_name(dive_list, "Dive List");
|
2011-11-19 20:54:58 +00:00
|
|
|
gtk_paned_add2(GTK_PANED(vpane), dive_list);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
/* Frame for dive profile */
|
|
|
|
dive_profile = dive_profile_widget();
|
2011-09-27 23:23:59 +00:00
|
|
|
gtk_widget_set_name(dive_profile, "Dive Profile");
|
2011-11-19 20:54:58 +00:00
|
|
|
gtk_paned_add2(GTK_PANED(hpane), dive_profile);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
/* Frame for extended dive info */
|
2012-01-15 22:29:08 +00:00
|
|
|
nb_page = extended_dive_info_widget();
|
|
|
|
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), nb_page, gtk_label_new("Dive Notes"));
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
/* Frame for dive equipment */
|
2012-08-15 22:21:34 +00:00
|
|
|
nb_page = equipment_widget(W_IDX_PRIMARY);
|
2012-01-15 22:29:08 +00:00
|
|
|
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), nb_page, gtk_label_new("Equipment"));
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2012-01-15 22:29:08 +00:00
|
|
|
/* Frame for single dive statistics */
|
|
|
|
nb_page = single_stats_widget();
|
|
|
|
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), nb_page, gtk_label_new("Dive Info"));
|
|
|
|
|
|
|
|
/* Frame for total dive statistics */
|
|
|
|
nb_page = total_stats_widget();
|
2012-03-14 17:01:34 +00:00
|
|
|
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), nb_page, gtk_label_new("Stats"));
|
2011-11-02 16:10:57 +00:00
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
gtk_widget_set_app_paintable(win, TRUE);
|
|
|
|
gtk_widget_show_all(win);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void run_ui(void)
|
|
|
|
{
|
|
|
|
gtk_main();
|
|
|
|
}
|
|
|
|
|
2012-05-02 17:03:48 +00:00
|
|
|
void exit_ui(void)
|
|
|
|
{
|
|
|
|
subsurface_close_conf();
|
2012-09-12 20:40:22 +00:00
|
|
|
if (default_filename)
|
|
|
|
free((char *)default_filename);
|
2012-09-13 17:46:09 +00:00
|
|
|
if (existing_filename)
|
2012-09-16 03:51:06 +00:00
|
|
|
free((void *)existing_filename);
|
2012-05-02 17:03:48 +00:00
|
|
|
}
|
|
|
|
|
2011-10-04 19:27:55 +00:00
|
|
|
typedef struct {
|
2012-09-10 22:31:01 +00:00
|
|
|
cairo_rectangle_t rect;
|
2011-10-04 19:27:55 +00:00
|
|
|
const char *text;
|
|
|
|
} tooltip_record_t;
|
|
|
|
|
|
|
|
static tooltip_record_t *tooltip_rects;
|
|
|
|
static int tooltips;
|
|
|
|
|
|
|
|
void attach_tooltip(int x, int y, int w, int h, const char *text)
|
|
|
|
{
|
2012-09-10 22:31:01 +00:00
|
|
|
cairo_rectangle_t *rect;
|
2011-10-04 19:27:55 +00:00
|
|
|
tooltip_rects = realloc(tooltip_rects, (tooltips + 1) * sizeof(tooltip_record_t));
|
|
|
|
rect = &tooltip_rects[tooltips].rect;
|
|
|
|
rect->x = x;
|
|
|
|
rect->y = y;
|
|
|
|
rect->width = w;
|
|
|
|
rect->height = h;
|
|
|
|
tooltip_rects[tooltips].text = text;
|
|
|
|
tooltips++;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define INSIDE_RECT(_r,_x,_y) ((_r.x <= _x) && (_r.x + _r.width >= _x) && \
|
|
|
|
(_r.y <= _y) && (_r.y + _r.height >= _y))
|
|
|
|
|
|
|
|
static gboolean profile_tooltip (GtkWidget *widget, gint x, gint y,
|
|
|
|
gboolean keyboard_mode, GtkTooltip *tooltip, gpointer user_data)
|
|
|
|
{
|
|
|
|
int i;
|
2012-09-10 22:31:01 +00:00
|
|
|
cairo_rectangle_t *drawing_area = user_data;
|
2011-10-04 19:27:55 +00:00
|
|
|
gint tx = x - drawing_area->x; /* get transformed coordinates */
|
|
|
|
gint ty = y - drawing_area->y;
|
|
|
|
|
|
|
|
/* are we over an event marker ? */
|
|
|
|
for (i = 0; i < tooltips; i++) {
|
|
|
|
if (INSIDE_RECT(tooltip_rects[i].rect, tx, ty)) {
|
|
|
|
gtk_tooltip_set_text(tooltip,tooltip_rects[i].text);
|
|
|
|
return TRUE; /* show tooltip */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE; /* don't show tooltip */
|
|
|
|
}
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
|
|
|
|
{
|
|
|
|
struct dive *dive = current_dive;
|
|
|
|
struct graphics_context gc = { .printer = 0 };
|
2012-09-11 08:16:34 +00:00
|
|
|
static cairo_rectangle_t drawing_area;
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2011-10-04 19:14:26 +00:00
|
|
|
/* the drawing area gives TOTAL width * height - x,y is used as the topx/topy offset
|
|
|
|
* so effective drawing area is width-2x * height-2y */
|
|
|
|
drawing_area.width = widget->allocation.width;
|
|
|
|
drawing_area.height = widget->allocation.height;
|
|
|
|
drawing_area.x = drawing_area.width / 20.0;
|
|
|
|
drawing_area.y = drawing_area.height / 20.0;
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
gc.cr = gdk_cairo_create(widget->window);
|
2011-10-04 19:27:55 +00:00
|
|
|
g_object_set(widget, "has-tooltip", TRUE, NULL);
|
|
|
|
g_signal_connect(widget, "query-tooltip", G_CALLBACK(profile_tooltip), &drawing_area);
|
2011-11-28 17:17:33 +00:00
|
|
|
init_profile_background(&gc);
|
2011-09-20 19:40:34 +00:00
|
|
|
cairo_paint(gc.cr);
|
|
|
|
|
2011-10-04 19:27:55 +00:00
|
|
|
if (dive) {
|
|
|
|
if (tooltip_rects) {
|
|
|
|
free(tooltip_rects);
|
|
|
|
tooltip_rects = NULL;
|
|
|
|
}
|
|
|
|
tooltips = 0;
|
2012-09-11 08:16:34 +00:00
|
|
|
plot(&gc, &drawing_area, dive, SC_SCREEN);
|
2011-10-04 19:27:55 +00:00
|
|
|
}
|
2011-09-20 19:40:34 +00:00
|
|
|
cairo_destroy(gc.cr);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GtkWidget *dive_profile_widget(void)
|
|
|
|
{
|
|
|
|
GtkWidget *da;
|
|
|
|
|
|
|
|
da = gtk_drawing_area_new();
|
|
|
|
gtk_widget_set_size_request(da, 350, 250);
|
|
|
|
g_signal_connect(da, "expose_event", G_CALLBACK(expose_event), NULL);
|
|
|
|
|
|
|
|
return da;
|
|
|
|
}
|
|
|
|
|
|
|
|
int process_ui_events(void)
|
|
|
|
{
|
|
|
|
int ret=0;
|
|
|
|
|
|
|
|
while (gtk_events_pending()) {
|
|
|
|
if (gtk_main_iteration_do(0)) {
|
|
|
|
ret = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-12-15 04:49:40 +00:00
|
|
|
return ret;
|
2011-09-20 19:40:34 +00:00
|
|
|
}
|
|
|
|
|
2012-05-02 17:26:34 +00:00
|
|
|
static int fill_computer_list(GtkListStore *store)
|
2011-09-20 19:40:34 +00:00
|
|
|
{
|
2012-05-02 17:26:34 +00:00
|
|
|
int index = -1, i;
|
2011-09-20 19:40:34 +00:00
|
|
|
GtkTreeIter iter;
|
2012-06-22 20:37:39 +00:00
|
|
|
dc_iterator_t *iterator = NULL;
|
|
|
|
dc_descriptor_t *descriptor = NULL;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
dc_descriptor_iterator(&iterator);
|
|
|
|
while (dc_iterator_next (iterator, &descriptor) == DC_STATUS_SUCCESS) {
|
|
|
|
const char *vendor = dc_descriptor_get_vendor(descriptor);
|
|
|
|
const char *product = dc_descriptor_get_product(descriptor);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
gtk_list_store_append(store, &iter);
|
|
|
|
gtk_list_store_set(store, &iter,
|
2012-06-22 20:37:39 +00:00
|
|
|
0, descriptor,
|
2011-09-20 19:40:34 +00:00
|
|
|
-1);
|
2012-06-22 20:37:39 +00:00
|
|
|
if (is_default_dive_computer(vendor, product))
|
2012-05-02 17:26:34 +00:00
|
|
|
index = i;
|
2012-06-22 20:37:39 +00:00
|
|
|
i++;
|
2011-09-20 19:40:34 +00:00
|
|
|
}
|
2012-06-22 20:37:39 +00:00
|
|
|
dc_iterator_free(iterator);
|
2012-05-02 17:26:34 +00:00
|
|
|
return index;
|
2011-09-20 19:40:34 +00:00
|
|
|
}
|
|
|
|
|
2012-06-22 20:37:39 +00:00
|
|
|
void render_dive_computer(GtkCellLayout *cell,
|
|
|
|
GtkCellRenderer *renderer,
|
|
|
|
GtkTreeModel *model,
|
|
|
|
GtkTreeIter *iter,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
char buffer[40];
|
|
|
|
dc_descriptor_t *descriptor = NULL;
|
|
|
|
const char *vendor, *product;
|
|
|
|
|
|
|
|
gtk_tree_model_get(model, iter, 0, &descriptor, -1);
|
|
|
|
vendor = dc_descriptor_get_vendor(descriptor);
|
|
|
|
product = dc_descriptor_get_product(descriptor);
|
|
|
|
snprintf(buffer, sizeof(buffer), "%s %s", vendor, product);
|
|
|
|
g_object_set(renderer, "text", buffer, NULL);
|
|
|
|
}
|
|
|
|
|
2012-09-21 18:32:12 +00:00
|
|
|
static void dive_computer_selector_changed(GtkWidget *combo, gpointer data)
|
|
|
|
{
|
|
|
|
GtkWidget *import, *button;
|
|
|
|
|
|
|
|
import = gtk_widget_get_ancestor(combo, GTK_TYPE_DIALOG);
|
|
|
|
button = gtk_dialog_get_widget_for_response(GTK_DIALOG(import), GTK_RESPONSE_ACCEPT);
|
|
|
|
gtk_widget_set_sensitive(button, TRUE);
|
|
|
|
}
|
2012-06-22 20:37:39 +00:00
|
|
|
|
2011-09-26 16:19:30 +00:00
|
|
|
static GtkComboBox *dive_computer_selector(GtkWidget *vbox)
|
2011-09-20 19:40:34 +00:00
|
|
|
{
|
2011-09-26 16:19:30 +00:00
|
|
|
GtkWidget *hbox, *combo_box, *frame;
|
2011-09-20 19:40:34 +00:00
|
|
|
GtkListStore *model;
|
|
|
|
GtkCellRenderer *renderer;
|
2012-05-02 17:26:34 +00:00
|
|
|
int default_index;
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
hbox = gtk_hbox_new(FALSE, 6);
|
2011-09-24 22:26:37 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2012-06-22 20:37:39 +00:00
|
|
|
model = gtk_list_store_new(1, G_TYPE_POINTER);
|
2012-05-02 17:26:34 +00:00
|
|
|
default_index = fill_computer_list(model);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2011-09-26 16:19:30 +00:00
|
|
|
frame = gtk_frame_new("Dive computer");
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 3);
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
|
2012-09-21 18:32:12 +00:00
|
|
|
g_signal_connect(G_OBJECT(combo_box), "changed", G_CALLBACK(dive_computer_selector_changed), NULL);
|
2011-09-26 16:19:30 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(frame), combo_box);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
|
|
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), renderer, TRUE);
|
2012-06-22 20:37:39 +00:00
|
|
|
gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(combo_box), renderer, render_dive_computer, NULL, NULL);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2012-05-02 17:26:34 +00:00
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), default_index);
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
return GTK_COMBO_BOX(combo_box);
|
|
|
|
}
|
|
|
|
|
2012-05-30 04:54:09 +00:00
|
|
|
const char *subsurface_device_name()
|
|
|
|
{
|
|
|
|
if (!default_dive_computer_device || !*default_dive_computer_device)
|
|
|
|
return subsurface_USB_name();
|
|
|
|
else
|
|
|
|
return default_dive_computer_device;
|
|
|
|
}
|
|
|
|
|
2011-09-26 16:44:27 +00:00
|
|
|
static GtkEntry *dive_computer_device(GtkWidget *vbox)
|
|
|
|
{
|
|
|
|
GtkWidget *hbox, *entry, *frame;
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new(FALSE, 6);
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
|
|
|
|
|
|
|
|
frame = gtk_frame_new("Device name");
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 3);
|
|
|
|
|
|
|
|
entry = gtk_entry_new();
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), entry);
|
2012-05-30 04:54:09 +00:00
|
|
|
gtk_entry_set_text(GTK_ENTRY(entry), subsurface_device_name());
|
2011-09-26 16:44:27 +00:00
|
|
|
|
|
|
|
return GTK_ENTRY(entry);
|
|
|
|
}
|
|
|
|
|
2012-09-15 22:12:30 +00:00
|
|
|
static void pick_import_files(GtkWidget *w, GSList **filelist)
|
2011-10-05 21:12:03 +00:00
|
|
|
{
|
2012-09-21 19:09:48 +00:00
|
|
|
GtkWidget *fs_dialog, *parent;
|
2012-09-15 22:12:30 +00:00
|
|
|
const char *current_default;
|
|
|
|
char *current_def_dir;
|
2011-10-05 18:36:15 +00:00
|
|
|
GtkFileFilter *filter;
|
2012-09-15 22:12:30 +00:00
|
|
|
struct stat sb;
|
2011-10-05 21:12:03 +00:00
|
|
|
|
2012-09-15 22:12:30 +00:00
|
|
|
*filelist = NULL;
|
2012-09-21 18:35:40 +00:00
|
|
|
fs_dialog = gtk_file_chooser_dialog_new("Choose Files To Import",
|
2011-10-05 18:36:15 +00:00
|
|
|
GTK_WINDOW(main_window),
|
|
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
|
|
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
|
|
|
NULL);
|
2012-09-21 19:09:48 +00:00
|
|
|
parent = gtk_widget_get_ancestor(w, GTK_TYPE_DIALOG);
|
|
|
|
gtk_widget_set_sensitive(parent, FALSE);
|
|
|
|
gtk_window_set_decorated(GTK_WINDOW(parent), FALSE);
|
|
|
|
gtk_window_set_transient_for(GTK_WINDOW(fs_dialog), GTK_WINDOW(parent));
|
2012-09-15 22:12:30 +00:00
|
|
|
|
|
|
|
/* I'm not sure what the best default path should be... */
|
|
|
|
if (existing_filename) {
|
|
|
|
current_def_dir = g_path_get_dirname(existing_filename);
|
|
|
|
} else {
|
|
|
|
current_default = subsurface_default_filename();
|
|
|
|
current_def_dir = g_path_get_dirname(current_default);
|
|
|
|
free((void *)current_default);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* it's possible that the directory doesn't exist (especially for the default)
|
|
|
|
* For gtk's file select box to make sense we create it */
|
|
|
|
if (stat(current_def_dir, &sb) != 0)
|
|
|
|
g_mkdir(current_def_dir, S_IRWXU);
|
2011-10-05 18:36:15 +00:00
|
|
|
|
2012-09-15 22:12:30 +00:00
|
|
|
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fs_dialog), current_def_dir);
|
|
|
|
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(fs_dialog), TRUE);
|
2012-09-15 22:22:36 +00:00
|
|
|
filter = setup_filter();
|
2012-09-15 22:12:30 +00:00
|
|
|
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fs_dialog), filter);
|
|
|
|
gtk_widget_show_all(fs_dialog);
|
|
|
|
if (gtk_dialog_run(GTK_DIALOG(fs_dialog)) == GTK_RESPONSE_ACCEPT)
|
|
|
|
*filelist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(fs_dialog));
|
|
|
|
free(current_def_dir);
|
|
|
|
gtk_widget_destroy(fs_dialog);
|
2012-09-21 19:09:48 +00:00
|
|
|
|
|
|
|
gtk_widget_set_sensitive(parent, TRUE);
|
|
|
|
gtk_window_set_decorated(GTK_WINDOW(parent), TRUE);
|
|
|
|
|
2012-09-15 22:12:30 +00:00
|
|
|
/* if we selected one or more files, pretent that we clicked OK in the import dialog */
|
|
|
|
if (*filelist != NULL)
|
2012-09-21 19:09:48 +00:00
|
|
|
gtk_dialog_response(GTK_DIALOG(parent), GTK_RESPONSE_ACCEPT);
|
2011-10-05 21:12:03 +00:00
|
|
|
}
|
|
|
|
|
2012-09-15 22:12:30 +00:00
|
|
|
static void xml_file_selector(GtkWidget *vbox, GtkWidget *main_dialog, GSList **list)
|
2011-10-05 18:36:15 +00:00
|
|
|
{
|
2012-09-15 22:12:30 +00:00
|
|
|
GtkWidget *hbox, *frame, *chooser, *box;
|
2011-10-05 18:36:15 +00:00
|
|
|
|
|
|
|
hbox = gtk_hbox_new(FALSE, 6);
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
|
|
|
|
|
2012-09-21 18:35:40 +00:00
|
|
|
frame = gtk_frame_new("XML files");
|
2011-10-05 18:36:15 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 3);
|
2011-10-05 21:12:03 +00:00
|
|
|
|
2012-09-15 22:12:30 +00:00
|
|
|
box = gtk_hbox_new(FALSE, 6);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), box);
|
2012-09-21 18:35:40 +00:00
|
|
|
chooser = gtk_button_new_with_label("Choose Files To Import");
|
2012-09-15 22:12:30 +00:00
|
|
|
g_signal_connect(G_OBJECT(chooser), "clicked", G_CALLBACK(pick_import_files), list);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), chooser, FALSE, FALSE, 6);
|
2011-10-05 18:36:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void do_import_file(gpointer data, gpointer user_data)
|
|
|
|
{
|
|
|
|
GError *error = NULL;
|
2012-01-26 21:00:45 +00:00
|
|
|
parse_file(data, &error);
|
2011-10-05 18:36:15 +00:00
|
|
|
|
|
|
|
if (error != NULL)
|
|
|
|
{
|
|
|
|
report_error(error);
|
|
|
|
g_error_free(error);
|
|
|
|
error = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-02 20:45:52 +00:00
|
|
|
static GtkWidget *import_dive_computer(device_data_t *data, GtkDialog *dialog)
|
2012-05-02 19:49:03 +00:00
|
|
|
{
|
|
|
|
GError *error;
|
2012-05-02 20:45:52 +00:00
|
|
|
GtkWidget *vbox, *info, *container, *label, *button;
|
2012-05-02 19:49:03 +00:00
|
|
|
|
|
|
|
error = do_import(data);
|
|
|
|
if (!error)
|
|
|
|
return NULL;
|
|
|
|
|
2012-05-02 20:45:52 +00:00
|
|
|
button = gtk_dialog_get_widget_for_response(dialog, GTK_RESPONSE_ACCEPT);
|
|
|
|
gtk_button_set_use_stock(GTK_BUTTON(button), 0);
|
|
|
|
gtk_button_set_label(GTK_BUTTON(button), "Retry");
|
|
|
|
|
|
|
|
vbox = gtk_dialog_get_content_area(dialog);
|
|
|
|
|
2012-05-02 19:49:03 +00:00
|
|
|
info = gtk_info_bar_new();
|
|
|
|
container = gtk_info_bar_get_content_area(GTK_INFO_BAR(info));
|
|
|
|
label = gtk_label_new(error->message);
|
|
|
|
gtk_container_add(GTK_CONTAINER(container), label);
|
2012-05-02 20:45:52 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), info, FALSE, FALSE, 0);
|
2012-05-02 19:49:03 +00:00
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
void import_dialog(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
int result;
|
2012-09-21 18:32:12 +00:00
|
|
|
GtkWidget *dialog, *button, *hbox, *vbox, *label, *info = NULL;
|
2012-09-18 11:17:55 +00:00
|
|
|
GSList *filenames = NULL;
|
2011-09-20 19:40:34 +00:00
|
|
|
GtkComboBox *computer;
|
2012-09-21 18:32:12 +00:00
|
|
|
GtkTreeIter iter;
|
2011-09-26 16:44:27 +00:00
|
|
|
GtkEntry *device;
|
2011-09-20 19:40:34 +00:00
|
|
|
device_data_t devicedata = {
|
2011-09-26 16:44:27 +00:00
|
|
|
.devname = NULL,
|
2011-09-20 19:40:34 +00:00
|
|
|
};
|
|
|
|
|
2012-09-16 22:37:09 +00:00
|
|
|
dialog = gtk_dialog_new_with_buttons("Import",
|
2011-09-20 19:40:34 +00:00
|
|
|
GTK_WINDOW(main_window),
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
|
|
|
|
NULL);
|
|
|
|
|
2011-09-26 16:19:30 +00:00
|
|
|
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
2012-09-21 18:35:40 +00:00
|
|
|
label = gtk_label_new("Choose what to import:");
|
2011-10-05 18:36:15 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3);
|
2012-09-15 22:12:30 +00:00
|
|
|
xml_file_selector(vbox, dialog, &filenames);
|
2011-09-26 16:19:30 +00:00
|
|
|
computer = dive_computer_selector(vbox);
|
2011-09-26 16:44:27 +00:00
|
|
|
device = dive_computer_device(vbox);
|
2011-09-20 19:40:34 +00:00
|
|
|
hbox = gtk_hbox_new(FALSE, 6);
|
2011-09-24 22:26:37 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 3);
|
2011-09-22 23:38:24 +00:00
|
|
|
devicedata.progress.bar = gtk_progress_bar_new();
|
|
|
|
gtk_container_add(GTK_CONTAINER(hbox), devicedata.progress.bar);
|
2011-09-20 19:40:34 +00:00
|
|
|
|
2012-09-21 18:32:12 +00:00
|
|
|
button = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
|
|
|
|
if (!gtk_combo_box_get_active_iter(computer, &iter))
|
|
|
|
gtk_widget_set_sensitive(button, FALSE);
|
|
|
|
|
2012-05-02 19:49:03 +00:00
|
|
|
repeat:
|
2011-09-20 19:40:34 +00:00
|
|
|
gtk_widget_show_all(dialog);
|
|
|
|
result = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
|
|
switch (result) {
|
2012-06-22 20:37:39 +00:00
|
|
|
dc_descriptor_t *descriptor;
|
2011-09-20 19:40:34 +00:00
|
|
|
GtkTreeModel *model;
|
2012-09-15 22:12:30 +00:00
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
case GTK_RESPONSE_ACCEPT:
|
2011-10-05 18:36:15 +00:00
|
|
|
/* what happened - did the user pick a file? In that case
|
|
|
|
* we ignore whether a dive computer model was picked */
|
2012-05-02 19:49:03 +00:00
|
|
|
if (info)
|
|
|
|
gtk_widget_destroy(info);
|
2012-09-18 11:17:55 +00:00
|
|
|
if (!filenames || g_slist_length(filenames) == 0) {
|
2012-06-22 20:37:39 +00:00
|
|
|
const char *vendor, *product;
|
|
|
|
|
2011-10-05 18:36:15 +00:00
|
|
|
if (!gtk_combo_box_get_active_iter(computer, &iter))
|
|
|
|
break;
|
2012-09-21 18:32:12 +00:00
|
|
|
|
2011-10-05 18:36:15 +00:00
|
|
|
model = gtk_combo_box_get_model(computer);
|
|
|
|
gtk_tree_model_get(model, &iter,
|
2012-06-22 20:37:39 +00:00
|
|
|
0, &descriptor,
|
2011-10-05 18:36:15 +00:00
|
|
|
-1);
|
2012-06-22 20:37:39 +00:00
|
|
|
|
|
|
|
vendor = dc_descriptor_get_vendor(descriptor);
|
|
|
|
product = dc_descriptor_get_product(descriptor);
|
|
|
|
|
|
|
|
devicedata.descriptor = descriptor;
|
|
|
|
devicedata.vendor = vendor;
|
|
|
|
devicedata.product = product;
|
2011-10-05 18:36:15 +00:00
|
|
|
devicedata.devname = gtk_entry_get_text(device);
|
2012-06-22 20:37:39 +00:00
|
|
|
set_default_dive_computer(vendor, product);
|
2012-05-30 04:54:09 +00:00
|
|
|
set_default_dive_computer_device(devicedata.devname);
|
2012-05-02 20:45:52 +00:00
|
|
|
info = import_dive_computer(&devicedata, GTK_DIALOG(dialog));
|
2012-05-02 19:49:03 +00:00
|
|
|
if (info)
|
|
|
|
goto repeat;
|
2012-09-18 11:17:55 +00:00
|
|
|
} else if (filenames) {
|
2012-09-15 22:12:30 +00:00
|
|
|
g_slist_foreach(filenames,do_import_file,NULL);
|
|
|
|
g_slist_free(filenames);
|
2011-10-05 18:36:15 +00:00
|
|
|
}
|
2012-09-21 18:32:12 +00:00
|
|
|
report_dives(TRUE);
|
2011-09-20 19:40:34 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
void update_progressbar(progressbar_t *progress, double value)
|
|
|
|
{
|
|
|
|
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress->bar), value);
|
|
|
|
}
|
2011-09-21 04:50:26 +00:00
|
|
|
|
2012-05-03 00:40:39 +00:00
|
|
|
void update_progressbar_text(progressbar_t *progress, const char *text)
|
|
|
|
{
|
|
|
|
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress->bar), text);
|
|
|
|
}
|
2011-09-21 04:50:26 +00:00
|
|
|
|
2012-09-10 19:27:00 +00:00
|
|
|
void set_filename(const char *filename, gboolean force)
|
2011-09-21 04:50:26 +00:00
|
|
|
{
|
2012-09-10 19:27:00 +00:00
|
|
|
if (!force && existing_filename)
|
|
|
|
return;
|
2012-09-16 03:51:06 +00:00
|
|
|
free((void *)existing_filename);
|
2012-07-31 17:55:41 +00:00
|
|
|
if (filename)
|
2011-09-21 04:50:26 +00:00
|
|
|
existing_filename = strdup(filename);
|
|
|
|
}
|