summaryrefslogtreecommitdiff
path: root/app/wlib/gtklib/ixhelp.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/wlib/gtklib/ixhelp.c')
-rw-r--r--app/wlib/gtklib/ixhelp.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/app/wlib/gtklib/ixhelp.c b/app/wlib/gtklib/ixhelp.c
new file mode 100644
index 0000000..6d85b2b
--- /dev/null
+++ b/app/wlib/gtklib/ixhelp.c
@@ -0,0 +1,441 @@
+/** \file ixhelp.c
+ * use the Webkit2-based help system
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2015 Martin Fischer
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <stdint.h>
+
+#include "gtkint.h"
+#include "i18n.h"
+
+#include <webkit/webkit.h>
+
+#include "gtkint.h"
+#include "i18n.h"
+
+void load_into_view(char *file,
+ int requested_view); // Prototype to please clang.
+
+/* globals and defines related to the HTML help window */
+
+#define HTMLERRORTEXT "<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=US-ASCII\">" \
+ "<title>Help Error</title><body><h1>Error - help information can not be found.</h1><p>" \
+ "The help information you requested cannot be found on this system.<br><pre>%s: %s</pre><p>" \
+ "Usually this is an installation problem, Make sure that XTrackCAD and the included " \
+ "HTML files are installed properly and can be found via the XTRKCADLIB environment " \
+ "variable. Also make sure that the user has sufficient access rights to read these" \
+ "files.</p></body></html>"
+
+
+#define SLIDERPOSDEFAULT 180 /**< default value for slider position */
+
+#define HTMLHELPSECTION "gtklib html help" /**< section name for html help window preferences */
+#define SLIDERPREFNAME "sliderpos" /**< name for the slider position preference */
+#define WINDOWPOSPREFNAME "position" /**< name for the window position preference */
+#define WINDOWSIZEPREFNAME "size" /**< name for the window size preference */
+
+#define BACKBUTTON "back"
+#define FORWARDBUTTON "forward"
+#define HOMEBUTTON "home"
+#define CONTENTBUTTON "contents"
+#define TOCDOC "tocDoc"
+#define CONTENTSDOC "contentsDoc"
+#define TOCVIEW "viewLeft"
+#define CONTENTSVIEW "viewRight"
+#define PANED "hpane"
+
+enum pane_views { MAIN_VIEW, CONTENTS_VIEW };
+
+static char *directory; /**< base directory for HTML files */
+
+static GtkWidget *wHelpWindow; /**< handle for the help window */
+static GtkWidget *main_view; /** handle for the help main data pane */
+static GtkWidget *contents_view; /** handle for the help contents pane */
+
+#define GLADE_HOOKUP_OBJECT(component,widget,name) \
+ g_object_set_data_full (G_OBJECT (component), name, \
+ gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
+
+#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
+ g_object_set_data (G_OBJECT (component), name, widget)
+
+static GtkWidget*
+lookup_widget(GtkWidget *widget, const gchar *widget_name)
+{
+ GtkWidget *parent, *found_widget;
+
+ for (;;) {
+ if (GTK_IS_MENU(widget)) {
+ parent = gtk_menu_get_attach_widget(GTK_MENU(widget));
+ } else {
+ parent = widget->parent;
+ }
+
+ if (!parent) {
+ parent = (GtkWidget*) g_object_get_data(G_OBJECT(widget), "GladeParentKey");
+ }
+
+ if (parent == NULL) {
+ break;
+ }
+
+ widget = parent;
+ }
+
+ found_widget = (GtkWidget*) g_object_get_data(G_OBJECT(widget),
+ widget_name);
+
+ if (!found_widget) {
+ g_warning("Widget not found: %s", widget_name);
+ }
+
+ return found_widget;
+}
+
+
+
+
+/**
+ * create a new horizontal pane and place it into container.
+ * The separator position is read from the resource configuration and set accordingly.
+ * Also a callback is specified that will be executed when the slider has been moved.
+ *
+ * \PARAM container IN the container into which the pane will be stuffed.
+ * \PARAM property IN the name of the property for the slider position
+ *
+ * \return the HPaned handle
+ */
+
+GtkWidget *
+CreateHPaned(GtkBox *container, char *property)
+{
+ GtkWidget *hpaned;
+ long posSlider;
+
+ /* the horizontal slider */
+ hpaned = gtk_hpaned_new();
+ gtk_container_set_border_width(GTK_CONTAINER(hpaned), 6);
+
+ wPrefGetInteger(HTMLHELPSECTION, SLIDERPREFNAME, &posSlider, SLIDERPOSDEFAULT);
+ gtk_paned_set_position(GTK_PANED(hpaned), (int)posSlider);
+
+ /* pack the horizontal slider into the main window */
+ gtk_box_pack_start(container, hpaned, TRUE, TRUE, 0);
+ gtk_widget_show(hpaned);
+
+ return (hpaned);
+}
+
+/**
+ * Handler for the delete-event issued on the help window.We are saving window
+ * information (eg. position) and are hiding the window instead of closing it.
+ *
+ * \PARAM win IN the window to be destroyed
+ * \PARAM event IN unused
+ * \PARAM ptr IN unused
+ *
+ * \RETURN FALSE
+ */
+
+static gboolean
+DestroyHelpWindow(GtkWidget *win, GdkEvent *event, void *ptr)
+{
+ int i;
+ GtkWidget *widget;
+ char tmp[ 20 ];
+
+ gint x, y;
+
+ /* get the slider position and save it */
+ widget = lookup_widget(win, PANED);
+ i = gtk_paned_get_position(GTK_PANED(widget));
+ wPrefSetInteger(HTMLHELPSECTION, SLIDERPREFNAME, i);
+
+ /* get the window position */
+ gtk_window_get_position((GtkWindow *)win, &x, &y);
+ sprintf(tmp, "%d %d", x, y);
+ wPrefSetString(HTMLHELPSECTION, WINDOWPOSPREFNAME, tmp);
+
+ /* get the window size */
+ gtk_window_get_size((GtkWindow *)win , &x, &y);
+ sprintf(tmp, "%d %d", x, y);
+ wPrefSetString(HTMLHELPSECTION, WINDOWSIZEPREFNAME, tmp);
+
+ gtk_widget_hide(win);
+ return TRUE;
+}
+
+void back_button_clicked(GtkWidget *widget, gpointer data)
+{
+ webkit_web_view_go_back(WEBKIT_WEB_VIEW(data));
+}
+
+void forward_button_clicked(GtkWidget *widget, gpointer data)
+{
+ webkit_web_view_go_forward(WEBKIT_WEB_VIEW(data));
+}
+
+void home_button_clicked(GtkWidget *widget, gpointer data)
+{
+ load_into_view("index.html", MAIN_VIEW);
+}
+
+/* Toggles the contents pane */
+void contents_button_clicked(GtkWidget *widget, gpointer data)
+{
+ if (gtk_paned_get_position(GTK_PANED(data)) < 50) {
+ gtk_paned_set_position(GTK_PANED(data), 370);
+ } else {
+ gtk_paned_set_position(GTK_PANED(data), 0);
+ }
+}
+
+gboolean contents_click_handler(
+ WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ WebKitWebNavigationAction *navigation_action,
+ WebKitWebPolicyDecision *policy_decision,
+ gpointer data)
+{
+
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(data),
+ webkit_network_request_get_uri(request));
+
+ return TRUE;
+}
+
+/**
+ * Initialize the buttons for the help window
+ */
+void initialize_buttons(GtkWidget *main_vbox, GtkWidget *content_hpane)
+{
+ GtkWidget *buttons_hbuttonbox;
+ GtkWidget *back_button;
+ GtkWidget *forward_button;
+ GtkWidget *home_button;
+ GtkWidget *contents_button;
+
+ // define and attach signals to buttons
+ back_button = gtk_button_new_with_label(_("Back"));
+ g_signal_connect(back_button, "clicked", G_CALLBACK(back_button_clicked),
+ G_OBJECT(main_view));
+
+ forward_button = gtk_button_new_with_label(_("Forward"));
+ g_signal_connect(forward_button, "clicked", G_CALLBACK(forward_button_clicked),
+ G_OBJECT(main_view));
+
+ home_button = gtk_button_new_with_label(_("Home"));
+ g_signal_connect(home_button, "clicked", G_CALLBACK(home_button_clicked),
+ G_OBJECT(main_view));
+
+ contents_button = gtk_button_new_with_label(_("Contents"));
+ g_signal_connect(contents_button, "clicked",
+ G_CALLBACK(contents_button_clicked), G_OBJECT(content_hpane));
+
+ // button layout
+ buttons_hbuttonbox = gtk_hbutton_box_new();
+ gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), back_button);
+ gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), forward_button);
+ gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), home_button);
+ gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), contents_button);
+ gtk_box_pack_start(GTK_BOX(main_vbox), buttons_hbuttonbox, FALSE, TRUE, 0);
+ gtk_box_set_spacing(GTK_BOX(buttons_hbuttonbox), 6);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(buttons_hbuttonbox),
+ GTK_BUTTONBOX_START);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT(main_view, back_button, BACKBUTTON);
+ GLADE_HOOKUP_OBJECT(main_view, forward_button, FORWARDBUTTON);
+ GLADE_HOOKUP_OBJECT(main_view, home_button, HOMEBUTTON);
+ GLADE_HOOKUP_OBJECT(main_view, contents_button, CONTENTBUTTON);
+}
+
+/**
+ * Create the help windows including all contained widgets and the needed HTML documents.
+ *
+ * \RETURN handle of the created window.
+ */
+
+GtkWidget*
+CreateHelpWindow(void)
+{
+ GtkWidget *main_vbox;
+ GtkWidget *main_view_scroller;
+ GtkWidget *contents_view_scroller;
+ GtkWidget *content_hpane;
+
+ int width;
+ int height;
+ int x, y;
+ int w = 0, h = 0;
+ const char *pref;
+
+ wHelpWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ width = gdk_screen_get_width(gtk_window_get_screen((GtkWindow *)wHelpWindow));
+ height = gdk_screen_get_height(gtk_window_get_screen((GtkWindow *)wHelpWindow));
+
+ pref = wPrefGetString(HTMLHELPSECTION, WINDOWSIZEPREFNAME);
+
+ if (pref) {
+ sscanf(pref, "%d %d", &w, &h);
+
+ if (w > width) {
+ w = width;
+ }
+
+ if (h > height) {
+ h = height;
+ }
+ } else {
+ w = (width * 2)/ 5;
+ h = height - 100;
+ }
+
+ pref = wPrefGetString(HTMLHELPSECTION, WINDOWPOSPREFNAME);
+
+ if (pref) {
+ sscanf(pref, "%d %d", &x, &y);
+
+ if (y > height - h) {
+ y = height - h;
+ }
+
+ if (x > width - w) {
+ x = width - w;
+ }
+ } else {
+ x = (width * 3) / 5 - 10;
+ y = 70;
+ }
+
+ gtk_window_resize((GtkWindow *)wHelpWindow, w, h);
+ gtk_window_move((GtkWindow *)wHelpWindow, x, y);
+
+ gtk_window_set_title(GTK_WINDOW(wHelpWindow), "XTrkCad Help");
+
+ g_signal_connect(G_OBJECT(wHelpWindow), "delete-event",
+ G_CALLBACK(DestroyHelpWindow), NULL);
+
+ main_view_scroller = gtk_scrolled_window_new(NULL, NULL);
+ contents_view_scroller = gtk_scrolled_window_new(NULL, NULL);
+ main_view = webkit_web_view_new();
+ contents_view = webkit_web_view_new();
+ // must be done here as it gets locked down later
+ load_into_view("contents.html", CONTENTS_VIEW);
+ gtk_widget_set_size_request(GTK_WIDGET(wHelpWindow), x, y);
+
+ main_vbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(wHelpWindow), main_vbox);
+
+ gtk_container_add(GTK_CONTAINER(main_view_scroller), main_view);
+
+ gtk_container_add(GTK_CONTAINER(contents_view_scroller), contents_view);
+
+ content_hpane = gtk_hpaned_new();
+ initialize_buttons(main_vbox, content_hpane);
+ gtk_container_add(GTK_CONTAINER(content_hpane), contents_view_scroller);
+ gtk_container_add(GTK_CONTAINER(content_hpane), main_view_scroller);
+ gtk_box_pack_start(GTK_BOX(main_vbox), content_hpane, TRUE, TRUE, 0);
+
+ gtk_paned_set_position(GTK_PANED(content_hpane), 370);
+
+ g_signal_connect(contents_view, "navigation-policy-decision-requested",
+ G_CALLBACK(contents_click_handler), G_OBJECT(main_view));
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF(wHelpWindow, wHelpWindow, "wHelpWindow");
+ GLADE_HOOKUP_OBJECT(wHelpWindow, content_hpane, PANED);
+ GLADE_HOOKUP_OBJECT(wHelpWindow, contents_view, TOCVIEW);
+ GLADE_HOOKUP_OBJECT(wHelpWindow, main_view, CONTENTSVIEW);
+
+ return wHelpWindow;
+}
+
+void load_into_view(char *file, int requested_view)
+{
+ GtkWidget *view;
+
+ switch (requested_view) {
+ case MAIN_VIEW:
+ view = main_view;
+ break;
+
+ case CONTENTS_VIEW:
+ view = contents_view;
+ break;
+
+ default:
+ printf("*** error, could not find view");
+ break;
+ }
+
+ char fileToLoad[250] = "file://";
+ strcat(fileToLoad,directory);
+ strcat(fileToLoad,file);
+
+ //debug printf("*** loading %s into pane %d.\n", fileToLoad, requested_view);
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(view), fileToLoad);
+}
+
+/**
+ * Invoke the help system to display help for <topic>.
+ *
+ * \param topic IN topic string
+ */
+
+void wHelp(const char * topic)
+{
+ char *htmlFile;
+
+ if (!wHelpWindow) {
+ directory = malloc(BUFSIZ);
+ assert(directory != NULL);
+
+ sprintf(directory, "%s/html/", wGetAppLibDir());
+
+ wHelpWindow = CreateHelpWindow();
+ /* load the default content */
+ load_into_view("index.html", MAIN_VIEW);
+ }
+
+ /* need space for the 'html' extension plus dot plus \0 */
+ htmlFile = malloc(strlen(topic) + 6);
+ assert(htmlFile != NULL);
+
+ sprintf(htmlFile, "%s.html", topic);
+
+ load_into_view(htmlFile, MAIN_VIEW);
+ gtk_widget_show_all(wHelpWindow);
+ gtk_window_present(GTK_WINDOW(wHelpWindow));
+}