From 41cdf4b851a973cf93acb41b0cc6afb3e62c62f3 Mon Sep 17 00:00:00 2001 From: "David C. Rankin" Date: Mon, 8 Apr 2019 20:18:55 -0500 Subject: [PATCH] Add traditional menu and toolbar, remove bottom button-bar from default interface, accept command-line option '-b' to turn bottom bar on and '-t' to disable toolbar and add img/gtksolver.png icon for 'About' dialog. --- README.md | 8 + img/gtksolver.png | Bin 0 -> 23081 bytes src/msolvtextview.c | 583 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 520 insertions(+), 71 deletions(-) create mode 100644 img/gtksolver.png diff --git a/README.md b/README.md index 3e4f462..9aec9a4 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,10 @@ Taking the contents of the second example above as the contents of the textview (where the formatted solution vector is simply written back to the same GtkTextBuffer and displayed in the textview below the coefficent matrix) +### Interface Command Line Options + +The button bar on the bottom has been removed from the default interface and replace with a standard menu and toolbar. If you liked the old button bar you can enable it simply by passing the `'-b'` option on the command line to turn the bottom button bar on. If you don't like the new toolbar, you can turn the toolbar off by passing the `'-t'` option on the command line. The static label across the top basically duplicating the titlebar text. + ### Compiling For Linux, all that is needed is `gcc/make/pkg-config` and `Gtk+2`. (note: some distributions package the headers and development files in separate packages, for instance `Gtk+2-dev`). You may want to create an out-of-source directory for building to prevent cluttering your sources with the object and executable files. Simply create a separate directory (e.g. `gtksolver.build`) and then symlink the `Makefile`, `src` and `include` directories within your build directory. All that is needed then is to change to the build directory and type: @@ -78,6 +82,10 @@ TDM-MinGW is often installed as part of the Code::Blocks IDE. The only addition $ mingw32-make CC=mingw32-gcc os=windows +### Installation + +There is nothing required for the solver to run other than invoking the executable. The solver and interface is fully funciton without more. However, for it to find and display the GtkSolver icon, currently the `img/` directory must be installed below the current working path for the executable. The `LICENSE` file should be in the working directory. Eventually there will be additions to determine the system and user paths and to set a standard install location for the image and license files when gtksolver is packaged for the various distributions. + ### Development Status As mentioned at the beginning, this project is basically a quick GtkTextView wrapper around a linear system solver. The Gtk+2 interface and forwarding of the textview contents to the solver has minimal validations. This basically grew out of finding a convenient way to help students with physics and engineering problems. The acceptable input format is flexible enough to allow pasting of a `.csv` (*comma separated values* file) into the editor window or any other delimited set of numbers that make up the coefficent matrix for a system of equations. The underlying solver and parsing code is much more robust. diff --git a/img/gtksolver.png b/img/gtksolver.png new file mode 100644 index 0000000000000000000000000000000000000000..9ecb95a8f6f648e65bb6d2edb6806bc7d2cd940f GIT binary patch literal 23081 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 IM6N<$g36)RB>(^b literal 0 HcmV?d00001 diff --git a/src/msolvtextview.c b/src/msolvtextview.c index afe256a..3382bc4 100644 --- a/src/msolvtextview.c +++ b/src/msolvtextview.c @@ -1,5 +1,7 @@ +#include #include #include +#include /* for GDK key values */ #include "mtrx_t.h" #define PACKAGE "gtksolver" @@ -7,6 +9,23 @@ #define IMGDIR "img" #define LOGO "gtksolver.png" #define ICON "gtksolver.ico" +#define LICENSE "LICENSE" +#define SITE "https://www.rankinlawfirm.com" + +#define APPNAME "GtkSolver" +#define APPSTR "Linear System Solver" +// #define APPSTR "Linear System of Equations Solver" + +/* default window width and height */ +#define WWIDTH 640 +#define WHEIGHT 450 + +/* set default font string */ +#define FONTSTR "DejaVu Sans Mono 8" + +#if defined (_WIN32) || defined (_WIN64) || defined (_WINNT) + #define HAVEMSWIN 1 +#endif /* size_t format specifier for older MinGW compiler versions */ #if defined (_WIN32) @@ -18,13 +37,28 @@ #endif typedef struct app { - GtkWidget *text_view, /* text view */ - *btnsolv; /* solve button */ + GtkWidget *window, /* main window */ + *toolbar, /* main toolbar */ + *text_view, /* text view */ + *btnsolv, /* solve button */ + *menusolv, /* solve menu entry */ + *toolsolv; /* solve toolbar entry */ GtkTextTag *tagblue, /* Deep sky blue tag */ *tagroyal, /* Royal blue tag */ *tagred; /* Red tag */ + gboolean showtoolbar, /* show toolbar */ + bottombuttons; /* display bottom buttons */ } app_t; +/* set sensitivity of solver widgets */ +void setsolvsensitive (gpointer data, gboolean state) +{ + app_t *inst = data; + gtk_widget_set_sensitive (inst->btnsolv, state); + gtk_widget_set_sensitive (inst->menusolv, state); + gtk_widget_set_sensitive (inst->toolsolv, state); +} + /* Solve... button callback */ void btnsolv_activate (GtkWidget *widget, gpointer data) { @@ -104,7 +138,8 @@ void btnsolv_activate (GtkWidget *widget, gpointer data) /* set buffer modified false, set [Solve...] sensitivity */ gtk_text_buffer_set_modified (buffer, FALSE); - gtk_widget_set_sensitive (inst->btnsolv, FALSE); + // gtk_widget_set_sensitive (inst->btnsolv, FALSE); + setsolvsensitive (data, FALSE); if(widget) {} } @@ -120,7 +155,8 @@ void btnclear_activate (GtkWidget *widget, gpointer data) /* set buffer modified false, set [Solve...] sensitivity */ gtk_text_buffer_set_modified (buffer, FALSE); - gtk_widget_set_sensitive (inst->btnsolv, FALSE); + // gtk_widget_set_sensitive (inst->btnsolv, FALSE); + setsolvsensitive (data, FALSE); if (widget || data) {} } @@ -133,6 +169,7 @@ void btnexit_activate (GtkWidget *widget, gpointer data) if (widget || data) {} } +/* create tag table for text colors */ static void settagtable (gpointer data) { app_t *inst = data; @@ -152,6 +189,7 @@ static void settagtable (gpointer data) "foreground", "red", NULL); } +/** set intro help on initial window display and help menu/toolbar */ static void intro (gpointer data) { app_t *inst = data; @@ -191,7 +229,8 @@ static void intro (gpointer data) gtk_text_buffer_apply_tag (buffer, tagblue, &iter, &end); gtk_text_buffer_set_modified (buffer, FALSE); - gtk_widget_set_sensitive (inst->btnsolv, FALSE); + // gtk_widget_set_sensitive (inst->btnsolv, FALSE); + setsolvsensitive (data, FALSE); } /* Help... button callback */ @@ -213,12 +252,11 @@ void btnhelp_activate (GtkWidget *widget, gpointer data) */ void on_buffer_changed (GtkTextBuffer *buffer, gpointer data) { - app_t *inst = data; - // gboolean modified = gtk_text_buffer_get_modified (buffer); + // app_t *inst = data; - /* set [Solve...] button sensitivity */ - // gtk_widget_set_sensitive (inst->btnsolv, modified); - gtk_widget_set_sensitive (inst->btnsolv, TRUE); + /* set [Solve...] button(s) sensitivity */ + // gtk_widget_set_sensitive (inst->btnsolv, TRUE); + setsolvsensitive (data, TRUE); if (buffer) {} } @@ -241,51 +279,343 @@ GdkPixbuf *create_pixbuf_from_file (const gchar *filename) return pixbuf; } -static void activate (app_t *inst) +/* + * menu callback functions + * + * _File menu + */ +void menu_file_clear_activate (GtkMenuItem *menuitem, gpointer data) { - GtkWidget *window, - *scrolled_window, - *vbox, - *hbox; + btnclear_activate (NULL, data); + if (menuitem || data) {} +} +void menu_file_solv_activate (GtkMenuItem *menuitem, gpointer data) +{ + btnsolv_activate (NULL, data); + if (menuitem || data) {} +} +void menu_file_quit_activate (GtkMenuItem *menuitem, gpointer data) +{ + gtk_main_quit (); + if (menuitem || data) {} +} - GtkWidget *btnclear, - *btnexit, - *btnhelp; +/* + * _Help menu functions + */ +void help_about (gpointer data) +{ + app_t *app = data; + gchar *buf, *logofn, *license; + gsize fsize; + GdkPixbuf *logo = NULL; + + static const gchar *const authors[] = { + "David C. Rankin, J.D,P.E. ", + NULL + }; + + static const gchar copyright[] = \ + "Copyright \xc2\xa9 2019 David C. Rankin"; + + static const gchar comments[] = APPSTR; + + /* create pixbuf from logofn to pass to show_about_dialog */ + // if ((logofn = g_strdup_printf ("%s/%s", app->imgdir, LOGO))) { + if ((logofn = g_strdup_printf ("%s/%s", IMGDIR, LOGO))) { + // g_print ("logofn : '%s'\n", logofn); + logo = create_pixbuf_from_file (logofn); + g_free (logofn); + } - GtkWidget *toplabel; +/* TODO; get system and user directories based on OS and distribution */ +// #ifndef HAVEMSWIN +// /* Archlinux */ +// license = g_strdup_printf ("%s/%s/%s", "/usr/share/licenses", CFGDIR, LICENSE); +// if (g_file_test (license, G_FILE_TEST_EXISTS)) +// goto gotnixlic; +// +// /* openSuSE */ +// g_free (license); +// license = NULL; +// license = g_strdup_printf ("%s/%s/%s", "/usr/share/doc/packages", CFGDIR, LICENSE); +// if (g_file_test (license, G_FILE_TEST_EXISTS)) +// goto gotnixlic; +// +// /* generic */ +// g_free (license); +// license = NULL; +// license = g_strdup_printf ("%s/%s", app->sysdatadir, LICENSE); +// +// gotnixlic:; +// #else +// /* win32/win64 */ +// license = g_strdup_printf ("%s\\%s", app->sysdatadir, LICENSE); +// #endif + + license = g_strdup (LICENSE); + + /* check if license read into buf */ +// if (g_file_get_contents (license, &buf, &fsize, NULL)) { + if (g_file_get_contents (LICENSE, &buf, &fsize, NULL)) { + + if (logo) /* show logo */ + gtk_show_about_dialog (GTK_WINDOW (app->window), + "authors", authors, + "comments", comments, + "copyright", copyright, + "version", VERSION, + "website", SITE, + "program-name", APPNAME, + "logo", logo, + "license", buf, + NULL); + else /* show stock GTK_STOCK_EDIT */ + gtk_show_about_dialog (GTK_WINDOW (app->window), + "authors", authors, + "comments", comments, + "copyright", copyright, + "version", VERSION, + "website", SITE, + "program-name", APPNAME, + "logo-icon-name", GTK_STOCK_EDIT, + "license", buf, + NULL); + g_free (buf); + } + else { +#ifdef DEBUG + g_warning ("error: load of license file %s failed.\n", LICENSE); +#endif + if (logo) /* show logo */ + gtk_show_about_dialog (GTK_WINDOW (app->window), + "authors", authors, + "comments", comments, + "copyright", copyright, + "version", VERSION, + "website", SITE, + "program-name", APPNAME, + "logo", logo, + NULL); + else /* show stock GTK_STOCK_EDIT */ + gtk_show_about_dialog (GTK_WINDOW (app->window), + "authors", authors, + "comments", comments, + "copyright", copyright, + "version", VERSION, + "website", SITE, + "program-name", APPNAME, + "logo-icon-name", GTK_STOCK_EDIT, + NULL); + } - gchar *iconfile; - GtkTextBuffer *buffer; - PangoFontDescription *font_desc; + if (logo) + g_object_unref (logo); + if (license) + g_free (license); +} - /* Create a window with a title, and a default size (win, w, h) */ - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (window), "Linear System Solver"); - gtk_window_set_default_size (GTK_WINDOW (window), 640, 450); +/* + * _Help menu + */ +void menu_help_help_activate (GtkMenuItem *menuitem, gpointer data) +{ + btnhelp_activate (NULL, data); + if (menuitem || data) {} +} +void menu_help_about_activate (GtkMenuItem *menuitem, gpointer data) +{ + help_about (data); + if (menuitem || data) {} +} - /* create icon filename and set icon */ - if ((iconfile = g_strdup_printf ("%s/%s", IMGDIR, ICON))) { - GdkPixbuf *pixbuf = create_pixbuf_from_file (iconfile); - if (pixbuf) { - gtk_window_set_icon(GTK_WINDOW(window), pixbuf); - g_object_unref (pixbuf); - } - g_free (iconfile); - } +/* create menubar and return pointer to caller */ +GtkWidget *create_menubar (gpointer data, GtkAccelGroup *mainaccel) +{ + app_t *inst = data; - /* create vbox and add as main container in window */ - vbox = gtk_vbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (window), vbox); + GtkWidget *menubar, /* menu container */ + *fileMenu, /* file menu */ + *fileMi, + *clearMi, + *solvMi, + *sep, + *quitMi; + + GtkWidget *helpMenu, /* help menu */ + *helpMi, + *helpI, + *aboutMi; + + /* create menubar, menus and submenus */ + menubar = gtk_menu_bar_new (); + fileMenu = gtk_menu_new (); + helpMenu = gtk_menu_new (); + + /* define file menu */ + fileMi = gtk_menu_item_new_with_mnemonic ("_File"); + sep = gtk_separator_menu_item_new (); + clearMi = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLEAR, + NULL); + solvMi = gtk_image_menu_item_new_from_stock (GTK_STOCK_PREFERENCES, + NULL); + gtk_menu_item_set_label (GTK_MENU_ITEM (solvMi), "_Solve"); + // gtk_menu_item_set_label (GTK_MENU_ITEM (solvMi), "_Solve System"); + quitMi = gtk_image_menu_item_new_from_stock (GTK_STOCK_QUIT, NULL); + + inst->menusolv = solvMi; /* set widget in struct */ + + /* create entries under 'File' then add to menubar */ + gtk_menu_item_set_submenu (GTK_MENU_ITEM (fileMi), fileMenu); + gtk_menu_shell_append (GTK_MENU_SHELL (fileMenu), sep); + gtk_menu_shell_append (GTK_MENU_SHELL (fileMenu), clearMi); + gtk_menu_shell_append (GTK_MENU_SHELL (fileMenu), solvMi); + gtk_menu_shell_append (GTK_MENU_SHELL (fileMenu), + gtk_separator_menu_item_new()); + gtk_menu_shell_append (GTK_MENU_SHELL (fileMenu), quitMi); + gtk_menu_shell_append (GTK_MENU_SHELL (menubar), fileMi); + + gtk_widget_add_accelerator (clearMi, "activate", mainaccel, + GDK_KEY_e, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); + gtk_widget_add_accelerator (solvMi, "activate", mainaccel, + GDK_KEY_s, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); + gtk_widget_add_accelerator (quitMi, "activate", mainaccel, + GDK_KEY_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); + + /*define help menu */ + helpMi = gtk_menu_item_new_with_mnemonic ("_Help"); + // gtk_menu_item_set_right_justified ((GtkMenuItem *)helpMi, TRUE); + sep = gtk_separator_menu_item_new (); + helpI = gtk_image_menu_item_new_from_stock (GTK_STOCK_HELP, + NULL); + aboutMi = gtk_image_menu_item_new_from_stock (GTK_STOCK_ABOUT, + NULL); + + /* create entries under 'Help' then add to menubar */ + gtk_menu_item_set_submenu (GTK_MENU_ITEM (helpMi), helpMenu); + gtk_menu_shell_append (GTK_MENU_SHELL (helpMenu), sep); + gtk_menu_shell_append (GTK_MENU_SHELL (helpMenu), helpI); + gtk_menu_shell_append (GTK_MENU_SHELL (helpMenu), aboutMi); + gtk_menu_shell_append (GTK_MENU_SHELL (menubar), helpMi); + + gtk_widget_add_accelerator (helpI, "activate", mainaccel, + GDK_KEY_h, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); + gtk_widget_add_accelerator (aboutMi, "activate", mainaccel, + GDK_KEY_a, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE); + + /* File Menu */ + g_signal_connect (G_OBJECT (clearMi), "activate", /* file Clear */ + G_CALLBACK (menu_file_clear_activate), data); + + g_signal_connect (G_OBJECT (solvMi), "activate", /* file Solv */ + G_CALLBACK (menu_file_solv_activate), data); + + g_signal_connect (G_OBJECT (quitMi), "activate", /* file Quit */ + G_CALLBACK (menu_file_quit_activate), data); + + /* Help Menu */ + g_signal_connect (G_OBJECT (helpI), "activate", /* help Info */ + G_CALLBACK (menu_help_help_activate), data); + + g_signal_connect (G_OBJECT (aboutMi), "activate", /* help About */ + G_CALLBACK (menu_help_about_activate), data); + + gtk_widget_show_all (menubar); + + return menubar; +} - /* top label for title */ - toplabel = gtk_label_new (NULL); - gtk_label_set_markup (GTK_LABEL (toplabel), - "Matrix Solver for Linear System of Equations"); - gtk_misc_set_padding (GTK_MISC(toplabel), 0, 10); - gtk_box_pack_start (GTK_BOX (vbox), toplabel, FALSE, FALSE, 0); - gtk_widget_show (toplabel); +GtkWidget *create_toolbar (GtkAccelGroup *mainaccel, gpointer data) +{ + app_t *inst = data; + + GtkWidget *toolbar; + + GtkToolItem *clear, /* clear, solv, quit, help */ + *solv, + *quit, + *help; + + /* create toolbar, set overflow arrow on */ + toolbar = gtk_toolbar_new (); + gtk_toolbar_set_show_arrow (GTK_TOOLBAR(toolbar), TRUE); + + /* toolbar styles + * GTK_TOOLBAR_ICONS, + * GTK_TOOLBAR_TEXT, + * GTK_TOOLBAR_BOTH, + * GTK_TOOLBAR_BOTH_HORIZ (text only shown when is_important set) + */ + // gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); + // gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_TEXT); + // gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH); + gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ); + + clear = gtk_tool_button_new_from_stock(GTK_STOCK_CLEAR); + gtk_tool_item_set_is_important (clear, TRUE); + // gtk_tool_item_set_homogeneous (clear, FALSE); + gtk_tool_item_set_homogeneous (clear, TRUE); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), clear, -1); + gtk_widget_set_tooltip_text (GTK_WIDGET(clear), "Clear Content "); + + solv = gtk_tool_button_new_from_stock(GTK_STOCK_PREFERENCES); + gtk_tool_item_set_is_important (solv, TRUE); + // gtk_tool_item_set_homogeneous (solv, FALSE); + gtk_tool_item_set_homogeneous (solv, TRUE); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), solv, -1); + gtk_tool_button_set_label (GTK_TOOL_BUTTON(solv), "Solve"); + gtk_widget_set_tooltip_text (GTK_WIDGET(solv), "Solve Shown System "); + + inst->toolsolv = GTK_WIDGET(solv); /* set inst struct member */ + + quit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT); + gtk_tool_item_set_is_important (quit, TRUE); + // gtk_tool_item_set_homogeneous (quit, FALSE); + gtk_tool_item_set_homogeneous (quit, TRUE); + // gtk_toolbar_insert(GTK_TOOLBAR(toolbar), quit, -1); + gtk_widget_set_tooltip_text (GTK_WIDGET(quit), "Quit "); + + help = gtk_tool_button_new_from_stock(GTK_STOCK_HELP); + gtk_tool_item_set_is_important (help, TRUE); + // gtk_tool_item_set_homogeneous (help, FALSE); + gtk_tool_item_set_homogeneous (help, TRUE); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), help, -1); + gtk_widget_set_tooltip_text (GTK_WIDGET(help), "Display Initial Help "); + + /* test putting quit after help */ + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), quit, -1); + + /* File Menu */ + g_signal_connect (G_OBJECT (clear), "clicked", /* file Clear */ + G_CALLBACK (menu_file_clear_activate), data); + + g_signal_connect (G_OBJECT (solv), "clicked", /* file Solv */ + G_CALLBACK (menu_file_solv_activate), data); + + g_signal_connect (G_OBJECT (quit), "clicked", /* file Quit */ + G_CALLBACK (menu_file_quit_activate), data); + + /* Help Menu */ + g_signal_connect (G_OBJECT (help), "clicked", /* help Info */ + G_CALLBACK (menu_help_help_activate), data); + + gtk_widget_show_all (toolbar); + + return toolbar; + + if (mainaccel) {} /* stub to prevent [-Wunused-parameter] */ +} + +/* create scrolled window containing textview with Fixed Font */ +GtkWidget *create_scrolled_view (gpointer data) +{ + app_t *inst = data; - /* Create the scrolled window. NULL is passed for both parameters to + GtkWidget *scrolled_window; + GtkTextBuffer *buffer; + PangoFontDescription *font_desc; + + /* create the scrolled window. NULL is passed for both parameters to * size horizontal/vertical adjustments automatically. Setting the * scrollbar policy to automatic show scrollbars when needed. */ @@ -294,40 +624,51 @@ static void activate (app_t *inst) GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 5); - gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0); /* The text buffer represents for textview */ buffer = gtk_text_buffer_new (NULL); - /* Create text_view to display editable text buffer. - * Line wrapping is set to break lines in between words. + /* create text_view to display editable text buffer. + * line wrapping is set to NONE so coefficient matrix lines do not wrap. */ inst->text_view = gtk_text_view_new_with_buffer (buffer); - // gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (inst->text_view), GTK_WRAP_WORD); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (inst->text_view), GTK_WRAP_NONE); - /* Set default font throughout the widget */ - font_desc = pango_font_description_from_string ("DejaVu Sans Mono 8"); + /* set default font throughout the widget */ + font_desc = pango_font_description_from_string (FONTSTR); gtk_widget_modify_font (inst->text_view, font_desc); pango_font_description_free (font_desc); - /* Change left margin throughout the widget */ + /* change left margin throughout the widget */ gtk_text_view_set_left_margin (GTK_TEXT_VIEW (inst->text_view), 10); - /* Initialize tag table for text_view buffer */ + /* initialize tag table for text_view buffer */ settagtable (inst); - /* Add text_view to scrolled_window */ + /* add text_view to scrolled_window */ gtk_container_add (GTK_CONTAINER (scrolled_window), inst->text_view); + /* connect textview callbacks */ + g_signal_connect (buffer, "changed", + G_CALLBACK (on_buffer_changed), inst); + + return scrolled_window; +} + +GtkWidget *create_bottombtnbar (gpointer data) +{ + app_t *inst = data; + + GtkWidget *hbox, + *btnclear, + *btnexit, + *btnhelp; + /* Create hbox to hold horizontal row of buttons at bottom of window */ hbox = gtk_hbox_new (FALSE, 0); gtk_box_set_spacing (GTK_BOX (hbox), 5); gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - /* Pack the hbox at the end of the vbox */ - gtk_box_pack_end (GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - /* define the buttons and pack into hbox */ inst->btnsolv = gtk_button_new_with_mnemonic ("_Solve..."); gtk_widget_set_size_request (inst->btnsolv, 80, 24); @@ -337,7 +678,7 @@ static void activate (app_t *inst) gtk_widget_set_size_request (btnclear, 80, 24); gtk_box_pack_start (GTK_BOX (hbox), btnclear, FALSE, FALSE, 0); - btnexit = gtk_button_new_with_mnemonic ("_Exit"); + btnexit = gtk_button_new_with_mnemonic ("_Quit"); gtk_widget_set_size_request (btnexit, 80, 24); gtk_box_pack_end (GTK_BOX (hbox), btnexit, FALSE, FALSE, 0); @@ -345,14 +686,6 @@ static void activate (app_t *inst) gtk_widget_set_size_request (btnhelp, 80, 24); gtk_box_pack_end (GTK_BOX (hbox), btnhelp, FALSE, FALSE, 0); - /* connect window close callback */ - g_signal_connect (window, "destroy", - G_CALLBACK (gtk_main_quit), NULL); - - /* connect textview callbacks */ - g_signal_connect (buffer, "changed", - G_CALLBACK (on_buffer_changed), inst); - /* connect button callbacks */ g_signal_connect (inst->btnsolv, "clicked", G_CALLBACK (btnsolv_activate), inst); @@ -366,22 +699,130 @@ static void activate (app_t *inst) g_signal_connect (btnexit, "clicked", G_CALLBACK (btnexit_activate), inst); + gtk_widget_show_all (hbox); + + return hbox; +} + +/** create application main window, returning pointer to + * main window on success, NULL otherwise. + */ +GtkWidget *create_window (app_t *inst) +{ + GtkWidget *window, /* main window & layout containers */ + *scrolled_window, + *vbox, + *hbox; + + GtkWidget *menubar, + *toolbar; + + gchar *iconfile; + GtkAccelGroup *mainaccel; + + /* Create a window with a title, and a default size (win, w, h) */ + if (!(window = gtk_window_new(GTK_WINDOW_TOPLEVEL))) + return NULL; + inst->window = window; + gtk_window_set_title (GTK_WINDOW (window), "Linear System Solver"); + gtk_window_set_default_size (GTK_WINDOW (window), WWIDTH, WHEIGHT); + + /* create icon filename and set icon */ + if ((iconfile = g_strdup_printf ("%s/%s", IMGDIR, ICON))) { + GdkPixbuf *pixbuf = create_pixbuf_from_file (iconfile); + if (pixbuf) { + gtk_window_set_icon(GTK_WINDOW(window), pixbuf); + g_object_unref (pixbuf); + } + g_free (iconfile); + } + + /* create & attach keyboard accelerator group */ + mainaccel = gtk_accel_group_new (); + gtk_window_add_accel_group (GTK_WINDOW (window), mainaccel); + + /* create vbox and add as main container in window */ + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), vbox); + + /* create menubar and menus to add */ + menubar = create_menubar (inst, mainaccel); + gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0); + gtk_widget_show (menubar); + + /* create toolbar + * GTK_TOOLBAR_ICONS, GTK_TOOLBAR_TEXT, GTK_TOOLBAR_BOTH, GTK_TOOLBAR_BOTH_HORIZ + */ + toolbar = create_toolbar (mainaccel, inst); + inst->toolbar = toolbar; + gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0); + gtk_widget_show (toolbar); + + /* Create the scrolled window containning text_view with fixed font */ + if (!(scrolled_window = create_scrolled_view (inst))) + return NULL; + + /* pack scrolled_window into vbox */ + gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0); + + /* Create hbox to hold horizontal row of buttons at bottom of window */ + hbox = create_bottombtnbar (inst); + /* Pack the hbox at the end of the vbox */ + gtk_box_pack_end (GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + /* connect window close callback */ + g_signal_connect (window, "destroy", + G_CALLBACK (gtk_main_quit), NULL); + /* Show intro text */ intro (inst); gtk_widget_show_all (window); -} + /* enable/disable toolbar or bottom button bar based on CLI arguments */ + gtk_widget_set_visible (toolbar, inst->showtoolbar); + gtk_widget_set_visible (hbox, inst->bottombuttons); + gtk_widget_grab_focus (inst->text_view); /* set focus on text_view */ + + return window; +} + +/* check & process command line options */ +void init_iface (app_t *inst, int argc, char **argv) +{ + int i = 1; + + /* set default TRUE for default interface widgets */ + inst->showtoolbar = TRUE; + + /* iterate over command line options */ + for (; i < argc; i++) { + if (*argv[i] == '-') { + switch (argv[i][1]) { + case 'b': + inst->bottombuttons = TRUE; + break; + case 't': + inst->showtoolbar = FALSE; + break; + } + } + } +} int main (int argc, char **argv) { app_t inst = { .text_view = NULL }; - gtk_init(&argc, &argv); + gtk_init (&argc, &argv); - activate (&inst); + init_iface (&inst, argc, argv); + if (!create_window (&inst)) { + g_error ("failed to create window.\n"); + return 1; + } gtk_main(); return 0; -} \ No newline at end of file +}