aboutsummaryrefslogtreecommitdiff
path: root/src/crystfel_gui.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/crystfel_gui.c')
-rw-r--r--src/crystfel_gui.c280
1 files changed, 280 insertions, 0 deletions
diff --git a/src/crystfel_gui.c b/src/crystfel_gui.c
new file mode 100644
index 00000000..fbb8d0e2
--- /dev/null
+++ b/src/crystfel_gui.c
@@ -0,0 +1,280 @@
+/*
+ * crystfel_gui.c
+ *
+ * CrystFEL's main graphical user interface
+ *
+ * Copyright © 2020 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
+ *
+ * Authors:
+ * 2020 Thomas White <taw@physics.org>
+ *
+ * This file is part of CrystFEL.
+ *
+ * CrystFEL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * CrystFEL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CrystFEL. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms-compat.h>
+#include <assert.h>
+
+#include "crystfelimageview.h"
+
+
+static void show_help(const char *s)
+{
+ printf("Syntax: %s\n\n", s);
+ printf(
+"CrystFEL graphical user interface.\n"
+"\n"
+" -h, --help Display this help message.\n"
+" --version Print CrystFEL version number and exit.\n"
+
+);
+}
+
+
+struct crystfelproject {
+
+ GtkWidget *window;
+ GtkUIManager *ui;
+ GtkActionGroup *action_group;
+
+ GtkWidget *imageview;
+ GtkWidget *icons; /* Drawing area for task icons */
+ GtkWidget *report; /* Text view at the bottom for messages */
+
+};
+
+
+static void error_box(struct crystfelproject *proj, const char *message)
+{
+ GtkWidget *window;
+
+ window = gtk_message_dialog_new(GTK_WINDOW(proj->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CLOSE, "%s", message);
+ gtk_window_set_title(GTK_WINDOW(window), "Error");
+
+ g_signal_connect_swapped(window, "response",
+ G_CALLBACK(gtk_widget_destroy), window);
+ gtk_widget_show(window);
+}
+
+
+static gboolean destroy_sig(GtkWidget *da, struct crystfelproject *proj)
+{
+ gtk_main_quit();
+ return FALSE;
+}
+
+
+static void add_ui_sig(GtkUIManager *ui, GtkWidget *widget,
+ GtkContainer *container)
+{
+ gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 0);
+ if ( GTK_IS_TOOLBAR(widget) ) {
+ gtk_toolbar_set_show_arrow(GTK_TOOLBAR(widget), TRUE);
+ }
+}
+
+
+static gint quit_sig(GtkWidget *widget, struct crystfelproject *proj)
+{
+ gtk_main_quit();
+ return FALSE;
+}
+
+
+static gint about_sig(GtkWidget *widget, struct crystfelproject *proj)
+{
+ GtkWidget *window;
+
+ const gchar *authors[] = {
+ "Thomas White <taw@physics.org>",
+ NULL
+ };
+
+ window = gtk_about_dialog_new();
+ gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(proj->window));
+
+ gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(window),
+ "CrystFEL graphical user interface");
+ gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(window), CRYSTFEL_VERSIONSTRING);
+ gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(window),
+ "© 2020 Deutsches Elektronen-Synchrotron DESY, "
+ "a research centre of the Helmholtz Association.");
+ gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(window),
+ "https://www.desy.de/~twhite/crystfel");
+ gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(window), authors);
+
+ g_signal_connect(window, "response", G_CALLBACK(gtk_widget_destroy),
+ NULL);
+
+ gtk_widget_show_all(window);
+
+ return 0;
+}
+
+
+static void add_menu_bar(struct crystfelproject *proj, GtkWidget *vbox)
+{
+ GError *error = NULL;
+
+ const char *ui = "<ui> <menubar name=\"cellwindow\">"
+ "<menu name=\"file\" action=\"FileAction\">"
+ " <menuitem name=\"quit\" action=\"QuitAction\" />"
+ "</menu>"
+ "<menu name=\"tools\" action=\"ToolsAction\" >"
+ "</menu>"
+ "<menu name=\"help\" action=\"HelpAction\">"
+ " <menuitem name=\"about\" action=\"AboutAction\" />"
+ "</menu>"
+ "</menubar></ui>";
+
+ GtkActionEntry entries[] = {
+
+ { "FileAction", NULL, "_File", NULL, NULL, NULL },
+ { "QuitAction", GTK_STOCK_QUIT, "_Quit", NULL, NULL,
+ G_CALLBACK(quit_sig) },
+
+ { "ToolsAction", NULL, "_Tools", NULL, NULL, NULL },
+
+ { "HelpAction", NULL, "_Help", NULL, NULL, NULL },
+ { "AboutAction", GTK_STOCK_ABOUT, "_About", NULL, NULL,
+ G_CALLBACK(about_sig) },
+
+ };
+ guint n_entries = G_N_ELEMENTS(entries);
+
+ proj->action_group = gtk_action_group_new("cellwindow");
+ gtk_action_group_add_actions(proj->action_group, entries, n_entries, proj);
+
+ proj->ui = gtk_ui_manager_new();
+ gtk_ui_manager_insert_action_group(proj->ui, proj->action_group, 0);
+ g_signal_connect(proj->ui, "add_widget", G_CALLBACK(add_ui_sig), vbox);
+ if ( gtk_ui_manager_add_ui_from_string(proj->ui, ui, -1, &error) == 0 )
+ {
+ fprintf(stderr, "Error loading message window menu bar: %s\n",
+ error->message);
+ return;
+ }
+
+ gtk_window_add_accel_group(GTK_WINDOW(proj->window),
+ gtk_ui_manager_get_accel_group(proj->ui));
+ gtk_ui_manager_ensure_update(proj->ui);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int c;
+ struct crystfelproject proj;
+ GtkWidget *vbox;
+ GtkWidget *vpaned;
+ GtkWidget *hpaned;
+ GtkWidget *scroll;
+ GtkWidget *frame;
+
+ /* Long options */
+ const struct option longopts[] = {
+ {"help", 0, NULL, 'h'},
+ {"version", 0, NULL, 1 },
+ {0, 0, NULL, 0}
+ };
+
+ /* Short options */
+ while ((c = getopt_long(argc, argv, "h",
+ longopts, NULL)) != -1) {
+
+ switch (c) {
+
+ case 'h' :
+ show_help(argv[0]);
+ return 0;
+
+ case 1 :
+ printf("CrystFEL: " CRYSTFEL_VERSIONSTRING "\n");
+ printf(CRYSTFEL_BOILERPLATE"\n");
+ return 0;
+
+ default :
+ return 1;
+
+ }
+
+ }
+
+ /* This isn't great, but necessary to make the command-line UI and file
+ * formats consistent with the other programs, which all use the C
+ * locale. Better would be to have all the programs call
+ * setlocale(LC_ALL, "") and use the C locale temporarily when reading
+ * or writing a stream, reflection file, geometry file etc. */
+ gtk_disable_setlocale();
+
+ gtk_init(&argc, &argv);
+
+ proj.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(proj.window), "CrystFEL");
+ g_signal_connect(G_OBJECT(proj.window), "destroy", G_CALLBACK(destroy_sig),
+ &proj);
+
+ vbox = gtk_vbox_new(FALSE, 0.0);
+ gtk_container_add(GTK_CONTAINER(proj.window), vbox);
+ add_menu_bar(&proj, vbox);
+
+ vpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
+ gtk_box_pack_end(GTK_BOX(vbox), vpaned, TRUE, TRUE, 0.0);
+
+ hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
+ gtk_paned_pack1(GTK_PANED(vpaned), hpaned, TRUE, TRUE);
+
+ proj.imageview = crystfel_image_view_new();
+ frame = gtk_frame_new(NULL);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
+ GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
+ gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(proj.imageview));
+ gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(scroll));
+ gtk_paned_pack2(GTK_PANED(hpaned), GTK_WIDGET(frame), TRUE, TRUE);
+
+ proj.icons = gtk_drawing_area_new();
+ frame = gtk_frame_new(NULL);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+ gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(proj.icons));
+ gtk_paned_pack1(GTK_PANED(hpaned), GTK_WIDGET(frame), FALSE, FALSE);
+
+ proj.report = gtk_text_view_new();
+ frame = gtk_frame_new(NULL);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+ gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(proj.report));
+ gtk_paned_pack2(GTK_PANED(vpaned), GTK_WIDGET(frame), FALSE, FALSE);
+
+ gtk_widget_show_all(proj.window);
+ gtk_main();
+
+ return 0;
+}