/* * Copyright (c) 2006 * Morten Slot Kristensen, Århus, Denmark. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "matrix.hpp" #include "operations.hpp" #include "gtk.hpp" #include "defs.hpp" using namespace std; /* METHODS */ int id_in_use(int id); matrix get_by_id(int id); void do_trivial(matrix*); int get_input(int type, string msg); float get_input_f(int type, string msg); /* GTK METHODS */ void interactive_dialog(int); void define_matrix_dialog(); void build_menu(); void update_tree_view(); static void selection_changed (GtkTreeSelection*); void set_statusbar_text(string); void do_gtk_trivial(matrix*); /* GLOBAL VARIABLES */ vector matrix_vector; int global_preview_id = -1, global_rows = -1, global_columns = -1, global_order = -1, global_from = 0, global_to = 0, m1 = -1, m2 = -1; GtkWidget *window, *menubar, *menuitem, *menu, *menuMenu, *menuMatrices, *menuHelp, *scrolledwindow_m1, *scrolledwindow_m2, *scrolledwindow_pre, *scrolledwindow_res, *scrolledwindow_list, *vbox_1, *vbox_2, *hbox_1, *hpaned, *hpaned_2, *vpaned, *treeview, *textview_m1, *textview_m2, *textview_pre, *textview_res, *frame_list, *frame_pre, *frame_m1, *frame_m2, *frame_res, *vbox_2_1, *hbox_2, *hbox_3, *btn_sel_m1, *btn_sel_m2, *btn_del_m1, *btn_del_m2, *btn_del_chosen, *btn_del_all, *menuOperations, *statusbar; GtkTreeModel *list_model; GtkListStore *store; GtkTreeSelection *selection; GtkTextBuffer *textbuf_m1, *textbuf_m2, *textbuf_pre, *textbuf_res; int main(int argc, char *argv[]) { // If the option '-gui' is used then start up GUI if(argc == 2 && string(argv[1]) == "-gui") { cout << "Starting with gui.." << endl; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(destroy_app), NULL); gtk_window_set_default_size(GTK_WINDOW(window), WINWIDTH, WINHEIGHT); gtk_window_set_title(GTK_WINDOW(window), WINTITLE); gtk_container_border_width(GTK_CONTAINER(window), WINBORDER); vbox_1 = gtk_vbox_new(FALSE, 0); vbox_2 = gtk_vbox_new(FALSE, 0); vbox_2_1 = gtk_vbox_new(FALSE, 0); hbox_1 = gtk_hbox_new(FALSE, 0); hbox_2 = gtk_hbox_new(FALSE, 0); hbox_3 = gtk_hbox_new(FALSE, 0); hpaned = gtk_hpaned_new(); hpaned_2 = gtk_hpaned_new(); vpaned = gtk_vpaned_new(); frame_m1 = gtk_frame_new("[M1] Matrix 1:"); frame_m2 = gtk_frame_new("[M2] Matrix 2:"); frame_pre = gtk_frame_new("Preview Matrix:"); frame_res = gtk_frame_new("Result Matrix:"); frame_list = gtk_frame_new("Matrix list:"); scrolledwindow_list = gtk_scrolled_window_new(NULL, NULL); scrolledwindow_m1 = gtk_scrolled_window_new(NULL, NULL); scrolledwindow_m2 = gtk_scrolled_window_new(NULL, NULL); scrolledwindow_pre = gtk_scrolled_window_new(NULL, NULL); scrolledwindow_res = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow_m1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow_m2), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow_res), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow_pre), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow_list), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); textbuf_m1 = gtk_text_buffer_new(NULL); textbuf_m2 = gtk_text_buffer_new(NULL); textbuf_pre = gtk_text_buffer_new(NULL); textbuf_res = gtk_text_buffer_new(NULL); textview_m1 = gtk_text_view_new_with_buffer(textbuf_m1); textview_m2 = gtk_text_view_new_with_buffer(textbuf_m2); textview_pre = gtk_text_view_new_with_buffer(textbuf_pre); textview_res = gtk_text_view_new_with_buffer(textbuf_res); gtk_text_view_set_editable(GTK_TEXT_VIEW(textview_m1), FALSE); gtk_text_view_set_editable(GTK_TEXT_VIEW(textview_m2), FALSE); gtk_text_view_set_editable(GTK_TEXT_VIEW(textview_pre), FALSE); gtk_text_view_set_editable(GTK_TEXT_VIEW(textview_res), FALSE); gtk_container_add(GTK_CONTAINER(scrolledwindow_m1), textview_m1); gtk_container_add(GTK_CONTAINER(scrolledwindow_m2), textview_m2); gtk_container_add(GTK_CONTAINER(scrolledwindow_pre), textview_pre); gtk_container_add(GTK_CONTAINER(scrolledwindow_res), textview_res); gtk_container_add(GTK_CONTAINER(frame_m1), scrolledwindow_m1); gtk_container_add(GTK_CONTAINER(frame_m2), scrolledwindow_m2); gtk_container_add(GTK_CONTAINER(frame_res), scrolledwindow_res); gtk_container_add(GTK_CONTAINER(frame_pre), scrolledwindow_pre); gtk_container_add(GTK_CONTAINER(frame_list), scrolledwindow_list); menubar = gtk_menu_bar_new(); gtk_box_pack_start(GTK_BOX(vbox_1), menubar, FALSE, TRUE, 0); gtk_widget_show(menubar); build_menu(); // add and show it store = gtk_list_store_new(NUMBER_OF_COLUMNS, G_TYPE_INT, G_TYPE_STRING); list_model = GTK_TREE_MODEL(store); treeview = gtk_tree_view_new_with_model(list_model); gtk_container_add(GTK_CONTAINER(scrolledwindow_list), treeview); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); g_signal_connect (selection, "changed", G_CALLBACK (selection_changed), NULL); // add the columns add_columns_to_treeview(GTK_TREE_VIEW(treeview)); btn_sel_m1 = gtk_button_new_with_mnemonic("Select M_1"); btn_sel_m2 = gtk_button_new_with_mnemonic("Select M_2"); btn_del_m1 = gtk_button_new_with_mnemonic("U_nset M1"); btn_del_m2 = gtk_button_new_with_mnemonic("Un_set M2"); btn_del_all = gtk_button_new_with_mnemonic("Re_move all"); btn_del_chosen = gtk_button_new_with_mnemonic("Remove _chosen"); gtk_signal_connect(GTK_OBJECT(btn_sel_m1), "clicked", GTK_SIGNAL_FUNC(btn_sel_m1_clicked), NULL); gtk_signal_connect(GTK_OBJECT(btn_sel_m2), "clicked", GTK_SIGNAL_FUNC(btn_sel_m2_clicked), NULL); gtk_signal_connect(GTK_OBJECT(btn_del_m1), "clicked", GTK_SIGNAL_FUNC(btn_del_m1_clicked), NULL); gtk_signal_connect(GTK_OBJECT(btn_del_m2), "clicked", GTK_SIGNAL_FUNC(btn_del_m2_clicked), NULL); gtk_signal_connect(GTK_OBJECT(btn_del_all), "clicked", GTK_SIGNAL_FUNC(btn_del_all_clicked), NULL); gtk_signal_connect(GTK_OBJECT(btn_del_chosen), "clicked", GTK_SIGNAL_FUNC(btn_del_chosen_clicked), NULL); gtk_box_pack_start(GTK_BOX(hbox_1), btn_sel_m1, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox_1), btn_sel_m2, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox_2), btn_del_m1, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox_2), btn_del_m2, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox_3), btn_del_all, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox_3), btn_del_chosen, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox_2_1), hbox_1, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox_2_1), hbox_2, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox_2_1), hbox_3, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox_2), frame_list, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox_2), vbox_2_1, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox_2), frame_pre, TRUE, TRUE, 0); gtk_paned_pack1(GTK_PANED(hpaned_2), frame_m1, TRUE, TRUE); gtk_paned_pack2(GTK_PANED(hpaned_2), frame_m2, TRUE, TRUE); gtk_paned_pack1(GTK_PANED(vpaned), hpaned_2, TRUE, TRUE); gtk_paned_pack2(GTK_PANED(vpaned), frame_res, TRUE, TRUE); gtk_paned_pack1(GTK_PANED(hpaned), vbox_2, FALSE, FALSE); gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, TRUE); gtk_container_add(GTK_CONTAINER(vbox_1), hpaned); statusbar = gtk_statusbar_new(); gtk_box_pack_end(GTK_BOX(vbox_1), statusbar, FALSE, TRUE, 0); gtk_container_add(GTK_CONTAINER(window), vbox_1); gtk_widget_show(statusbar); gtk_widget_show(btn_sel_m1); gtk_widget_show(btn_sel_m2); gtk_widget_show(btn_del_m1); gtk_widget_show(btn_del_m2); gtk_widget_show(btn_del_all); gtk_widget_show(btn_del_chosen); gtk_widget_show(treeview); gtk_widget_show(hpaned); gtk_widget_show(hpaned_2); gtk_widget_show(vpaned); gtk_widget_show(scrolledwindow_list); gtk_widget_show(scrolledwindow_m1); gtk_widget_show(scrolledwindow_m2); gtk_widget_show(scrolledwindow_res); gtk_widget_show(scrolledwindow_pre); gtk_widget_show(frame_m1); gtk_widget_show(frame_m2); gtk_widget_show(frame_list); gtk_widget_show(frame_pre); gtk_widget_show(frame_res); gtk_widget_show(textview_m1); gtk_widget_show(textview_m2); gtk_widget_show(textview_res); gtk_widget_show(textview_pre); gtk_widget_show(menuitem); gtk_widget_show(menuMenu); gtk_widget_show(menuMatrices); gtk_widget_show(menuHelp); gtk_widget_show(vbox_1); gtk_widget_show(vbox_2); gtk_widget_show(vbox_2_1); gtk_widget_show(hbox_1); gtk_widget_show(hbox_2); gtk_widget_show(hbox_3); gtk_widget_show(window); gtk_main(); return 0; } // If not then run as normal cout << APPNAME << " " << VERSION << " - Matrix Calculator\n" << "Copyright (c) " << CRYEAR << " " << DEVNAME << "\n" << "<" << DEVMAIL << ">\n\n" << "NOTE: To run the GTK version of this program\n" << " you can execute with the following option:\n" << " % " << argv[0] << " -gui\n\n" << "Type 'help' for usage information!" << endl; string line = "", input = ""; while(1) { cout << "\n# "; getline(cin, line); if(line == "exit") exit(0); else if(line == "help") { cout << APPNAME << " is a program which can do calculations" << " on several matrices.\n\nBeneath is a list of" << " commands:\n" << " createm Create a matrix.\n" << " createrm Create a random matrix.\n" << " createum Create a unit-matrix.\n" << " delete Remove a given matrix.\n" << " deleteall Remove all matrices.\n\n" << " mul Multiplicate two matrices.\n" << " muln Multiplicate a matrix with a number.\n" << " add Add two matrices.\n" << " sub Subtract two matrices.\n" << " invert Invert a matrix.\n" << " trans Transpose a matrix.\n" << " det Get the determinant of a matrix.\n" << " show Print all matrices.\n\n" << " help Shows this information.\n" << " exit Exit the program." << endl; } else if(line == "createm" || line == "createrm") { int rows = get_input(2, "Define rows: "); int columns = get_input(2, "Define columns: "); matrix m(rows, columns); if(line == "createm") { cout << "\nCreating a " << rows << "x" << columns << " matrix:\n"; for(int i=0; i to) cout << "Error: 'from' has to be smaller than or equal to 'max'\n"; else break; } for(int i=0; i 0) { for(vector::iterator it = matrix_vector.begin(); it != matrix_vector.end(); it++) { cout << endl << "id: " << it->get_id() << endl; it->print(); } } else cout << "There are no matrices present!\nCreate one with the 'createm' command.\n"; } else if(line == "mul") { matrix m1 = get_by_id(get_input(0, "Id of the first matrix: ")); matrix m2 = get_by_id(get_input(0, "Id of the second matrix: ")); if(m1.get_columns() == m2.get_rows()) { matrix m = multiplicate(&m1, &m2); do_trivial(&m); } else cout << "Can't multiplicate two matrices when the first's number of columns is not equal to the second's number of rows!" << endl; } else if(line == "muln") { matrix tmp = get_by_id(get_input(0, "Id of matrix: ")); matrix m = multiplicate(&tmp, get_input_f(0, "Input the number to multiplicate with: ")); do_trivial(&m); } else if(line == "add") { matrix m1 = get_by_id(get_input(0, "Id of the first matrix: ")); matrix m2 = get_by_id(get_input(0, "Id of the second matrix: ")); if(m1.get_rows() == m2.get_rows() && m1.get_columns() == m2.get_columns()) { matrix m = add(&m1, &m2); do_trivial(&m); } else cout << "Can't add two matrices when their rows and columns are not the same!" << endl; } else if(line == "sub") { matrix m1 = get_by_id(get_input(0, "Id of the first matrix: ")); matrix m2 = get_by_id(get_input(0, "Id of the second matrix: ")); if(m1.get_rows() == m2.get_rows() && m1.get_columns() == m2.get_columns()) { matrix m = substract(&m1, &m2); do_trivial(&m); } else cout << "Can't substract two matrices when their rows and columns are not the same!" << endl; } else if(line == "delete") { int id = get_input(0, "Id to delete: "); vector::iterator loc; for(loc = matrix_vector.begin(); loc != matrix_vector.end(); loc++) { if(loc->get_id() == id) break; } matrix_vector.erase(loc); } else if(line == "deleteall") { matrix_vector.clear(); } else if(line == "invert") { matrix tmp = get_by_id(get_input(0, "Id to invert: ")); matrix m = invert(&tmp); do_trivial(&m); } else if(line == "trans") { matrix tmp = get_by_id(get_input(0, "Id to transpose: ")); matrix m = transpose(&tmp); do_trivial(&m); } else if(line == "det") { int id = get_input(0, "Id to get the determinant of: "); matrix tmp = get_by_id(id); if(tmp.get_rows() == tmp.get_columns()) { if(tmp.get_rows() == 1) cout << "Determinant is: " << tmp.get_value(0, 0) << "\n"; else cout << "Determinant is: " << determinant(&tmp) << "\n"; } else cout << "The matrix has to be square! 2x2, MxM etc.\n"; } else cout << "Command not recognized!\nTry 'help'.\n"; } return 0; } /* * Determines wether the id is in use or not */ int id_in_use(int id) { int exists = 0; for(vector::iterator it = matrix_vector.begin(); it != matrix_vector.end(); it++) { if(it->get_id() == id) exists = 1; } return exists; } /* * Retrieves the matrix of a given id */ matrix get_by_id(int id) { for(vector::iterator it = matrix_vector.begin(); it != matrix_vector.end(); it++) { if(it->get_id() == id) return *it; } } /* * Method to do trivial stuff.. Used often at the end of subrutines */ void do_trivial(matrix *m) { m->print(); m->set_id(); cout << "New matrix created, id: " << m->get_id() << endl; matrix_vector.push_back(*m); } /* * Gtk version of the above method */ void do_gtk_trivial(matrix *m) { m->set_id(); insert_matrix(textbuf_res, &(*m)); matrix_vector.push_back(*m); update_tree_view(); } /* * Gets the input of the user * Returns an integer */ int get_input(int type, string msg) { string input = ""; int res; while(1) { cout << msg; getline(cin, input); res = atoi(input.c_str()); if(type == 0) { if(res == NULL || !id_in_use(res)) cout << "Error: You have to choose a correct id!\n"; else break; } else if(type == 1) { if(res == NULL || res < 1) cout << "Error: You have to input an integer greater than or equal to 1!\n"; else break; } else if(type == 2) { if(res == NULL || res <= 0) cout << "Error: You need to input an integer greater than zero!\n"; else break; } else if(type == 3) { if(res == NULL && !isdigit((char)res)) cout << "Error: You have to input an integer!\n"; else break; } } return res; } /* * Gets the input of the user * Returns a float */ float get_input_f(int type, string msg) { string input = ""; float res; while(1) { cout << msg; getline(cin, input); res = atof(input.c_str()); if(type == 0) { if(res == NULL) cout << "Error: You have to input a non-zero number!\n"; else break; } } return res; } /* * Method for building the GUI menu */ void build_menu() { /* Exit menu */ menuMenu = gtk_menu_item_new_with_mnemonic("M_enu"); gtk_menu_bar_append(GTK_MENU_BAR(menubar), menuMenu); gtk_widget_show(menuMenu); menu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuMenu), menu); menuitem = gtk_menu_item_new_with_mnemonic("Import matrix"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_import_clicked), NULL); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_mnemonic("Export matrix"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_export_clicked), NULL); gtk_widget_show(menuitem); menuitem = gtk_separator_menu_item_new(); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_mnemonic("E_xit"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(destroy_app), NULL); gtk_widget_show(menuitem); /* Matrices menu */ menuMatrices = gtk_menu_item_new_with_mnemonic("M_atrices"); gtk_menu_bar_append(GTK_MENU_BAR(menubar), menuMatrices); gtk_widget_show(menuMatrices); menu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuMatrices), menu); menuitem = gtk_menu_item_new_with_mnemonic("Create _new matrix"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_new_matrix), NULL); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_mnemonic("Create new _random matrix"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_new_rnd_matrix), NULL); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_mnemonic("Create new _unit-matrix"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_new_unit_matrix), NULL); gtk_widget_show(menuitem); /* Operations menu */ menuOperations = gtk_menu_item_new_with_mnemonic("O_perations"); gtk_menu_bar_append(GTK_MENU_BAR(menubar), menuOperations); gtk_widget_show(menuOperations); menu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuOperations), menu); menuitem = gtk_menu_item_new_with_mnemonic("M_ultiplicate (M1*M2)"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_mul_clicked), NULL); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_mnemonic("A_dd (M1+M2)"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_add_clicked), NULL); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_mnemonic("S_ubstract (M1-M2)"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_sub_clicked), NULL); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_mnemonic("I_nvert (M1)"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_invert_clicked), NULL); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_mnemonic("T_ranspose (M1)"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_transpose_clicked), NULL); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_mnemonic("G_et determinant (M1)"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_det_clicked), NULL); gtk_widget_show(menuitem); /* Help menu */ menuHelp = gtk_menu_item_new_with_mnemonic("He_lp"); gtk_menu_bar_append(GTK_MENU_BAR(menubar), menuHelp); gtk_widget_show(menuHelp); menu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuHelp), menu); menuitem = gtk_menu_item_new_with_mnemonic(string("A_bout "+string(APPNAME)).c_str()); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(show_about), NULL); gtk_widget_show(menuitem); } /* * Executed when the list's selection changes */ static void selection_changed(GtkTreeSelection *selection) { GtkTreeModel *model; GtkTreeIter iter; if(gtk_tree_selection_get_selected(selection, &model, &iter)) { gtk_tree_model_get(model, &iter, 0, &global_preview_id, -1); // set the preview matrix matrix m = get_by_id(global_preview_id); insert_matrix(textbuf_pre, &m); } } gint btn_sel_m1_clicked(GtkWidget *widget, gpointer gdata) { if(global_preview_id != -1) { matrix m = get_by_id(global_preview_id); insert_matrix(textbuf_m1, &m); m1 = global_preview_id; gtk_frame_set_label(GTK_FRAME(frame_m1), to_string("[M1] Matrix 1: ID = "+to_string(m1)).c_str()); } else { m1 = -1; msgbox("Select a matrix first!", GTK_MESSAGE_INFO, GTK_BUTTONS_OK); } } gint btn_sel_m2_clicked(GtkWidget *widget, gpointer gdata) { if(global_preview_id != -1) { matrix m = get_by_id(global_preview_id); insert_matrix(textbuf_m2, &m); m2 = global_preview_id; gtk_frame_set_label(GTK_FRAME(frame_m2), to_string("[M2] Matrix 2: ID = "+to_string(m2)).c_str()); } else { m2 = -1; msgbox("Select a matrix first!", GTK_MESSAGE_INFO, GTK_BUTTONS_OK); } } gint btn_del_m1_clicked(GtkWidget *widget, gpointer gdata) { gtk_text_buffer_set_text(textbuf_m1, "", 0); gtk_frame_set_label(GTK_FRAME(frame_m1), "[M1] Matrix 1:"); } gint btn_del_m2_clicked(GtkWidget *widget, gpointer gdata) { gtk_text_buffer_set_text(textbuf_m2, "", 0); gtk_frame_set_label(GTK_FRAME(frame_m2), "[M2] Matrix 2:"); } gint btn_del_all_clicked(GtkWidget *widget, gpointer gdata) { matrix_vector.clear(); update_tree_view(); global_preview_id = -1; gtk_text_buffer_set_text(textbuf_pre, "", 0); gtk_text_buffer_set_text(textbuf_m1, "", 0); gtk_text_buffer_set_text(textbuf_m2, "", 0); gtk_text_buffer_set_text(textbuf_res, "", 0); gtk_frame_set_label(GTK_FRAME(frame_m1), "[M1] Matrix 1:"); gtk_frame_set_label(GTK_FRAME(frame_m2), "[M2] Matrix 2:"); gtk_frame_set_label(GTK_FRAME(frame_res), "Result Matrix:"); } gint btn_del_chosen_clicked(GtkWidget *widget, gpointer gdata) { if(global_preview_id != -1) { vector::iterator loc; for(loc = matrix_vector.begin(); loc != matrix_vector.end(); loc++) { if(loc->get_id() == global_preview_id) break; } matrix_vector.erase(loc); update_tree_view(); } else msgbox("Select a matrix first!", GTK_MESSAGE_INFO, GTK_BUTTONS_OK); } /* * Updates the treeview with the matrices * stored in the vector */ void update_tree_view() { gtk_list_store_clear(store); vector::iterator loc; for(loc = matrix_vector.begin(); loc != matrix_vector.end(); loc++) add_matrix_to_treeview(GTK_TREE_VIEW(treeview), &(*loc), GTK_LIST_STORE(store)); gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(store)); } /* * Shows a dialog for defining rows, columns and * orders of matrices to create. * * type: * 0 = rows + columns (matrix) * 1 = order (unit matrix) * 2 = random (matrix) */ void interactive_dialog(int type) { global_rows = global_columns = -1; GtkWidget *dialog, *hbox, *stock, *table, *local_entry1, *local_entry2, *label, *local_entry3, *local_entry4; gint response; dialog = gtk_dialog_new_with_buttons ("New matrix: Define dimensions.", GTK_WINDOW (window), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_OK, "_Cancel", GTK_RESPONSE_CANCEL, NULL); hbox = gtk_hbox_new (FALSE, 8); gtk_container_set_border_width (GTK_CONTAINER (hbox), 8); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0); stock = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG); gtk_box_pack_start (GTK_BOX (hbox), stock, FALSE, FALSE, 0); if(type == 0 || type == 1) table = gtk_table_new (2, 2, FALSE); else table = gtk_table_new (2, 4, FALSE); gtk_table_set_row_spacings (GTK_TABLE (table), 4); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); if(type == 0 || type == 2) { label = gtk_label_new_with_mnemonic ("Ro_ws"); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1); local_entry1 = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (local_entry1), to_string("1").c_str()); gtk_table_attach_defaults (GTK_TABLE (table), local_entry1, 1, 2, 0, 1); gtk_label_set_mnemonic_widget (GTK_LABEL (label), local_entry1); label = gtk_label_new_with_mnemonic ("Co_lmns"); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2); local_entry2 = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (local_entry2), to_string("1").c_str()); gtk_table_attach_defaults (GTK_TABLE (table), local_entry2, 1, 2, 1, 2); gtk_label_set_mnemonic_widget (GTK_LABEL (label), local_entry2); if(type == 2) { label = gtk_label_new_with_mnemonic ("R_andom from:"); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 2, 3); local_entry3 = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (local_entry3), to_string("1").c_str()); gtk_table_attach_defaults (GTK_TABLE (table), local_entry3, 1, 2, 2, 3); gtk_label_set_mnemonic_widget (GTK_LABEL (label), local_entry3); label = gtk_label_new_with_mnemonic ("T_o max:"); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 3, 4); local_entry4 = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (local_entry4), to_string("100").c_str()); gtk_table_attach_defaults (GTK_TABLE (table), local_entry4, 1, 2, 3, 4); gtk_label_set_mnemonic_widget (GTK_LABEL (label), local_entry4); } } else if(type == 1) { label = gtk_label_new_with_mnemonic ("O_rder"); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1); local_entry1 = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (local_entry1), to_string("1").c_str()); gtk_table_attach_defaults (GTK_TABLE (table), local_entry1, 1, 2, 0, 1); gtk_label_set_mnemonic_widget (GTK_LABEL (label), local_entry1); } gtk_widget_show_all(hbox); response = gtk_dialog_run(GTK_DIALOG (dialog)); if(response == GTK_RESPONSE_OK) { if(type == 0) { string rows = gtk_entry_get_text(GTK_ENTRY (local_entry1)); string cols = gtk_entry_get_text(GTK_ENTRY (local_entry2)); global_rows = atoi(rows.c_str()); global_columns = atoi(cols.c_str()); if(global_rows == NULL || global_columns == NULL) { global_columns = global_rows = -1; msgbox("You have to input integers greater than zero!", GTK_MESSAGE_INFO, GTK_BUTTONS_OK); } } else if(type == 1) { string order = gtk_entry_get_text(GTK_ENTRY(local_entry1)); global_order = atoi(order.c_str()); if(global_order == NULL) { global_order = -1; msgbox("You have to input an integer greater than zero!", GTK_MESSAGE_INFO, GTK_BUTTONS_OK); } } else if(type == 2) { string rows = gtk_entry_get_text(GTK_ENTRY (local_entry1)); string cols = gtk_entry_get_text(GTK_ENTRY (local_entry2)); string from = gtk_entry_get_text(GTK_ENTRY (local_entry3)); string to = gtk_entry_get_text(GTK_ENTRY (local_entry4)); global_rows = atoi(rows.c_str()); global_columns = atoi(cols.c_str()); global_from = atoi(from.c_str()); global_to = atoi(to.c_str()); if(global_rows == NULL || global_columns == NULL || (!isdigit((char)from.c_str()[0]) && to_string(from.c_str()[0]) != "-") || (!isdigit((char)to.c_str()[0]) && to_string(to.c_str()[0]) != "-")) { global_rows = global_columns = -1; msgbox("You have to input an integer greater than zero for rows and columns. And for random 'from' to 'max' needs to be a valid integer!", GTK_MESSAGE_INFO, GTK_BUTTONS_OK); } } } else global_rows = global_columns = -1; gtk_widget_destroy(dialog); } gint menu_new_matrix(GtkWidget *widget, gpointer gdata) { interactive_dialog(0); if(global_rows > 0 && global_columns > 0) define_matrix_dialog(); } /* * Shows a dialog to fill in the contents of the matrix */ void define_matrix_dialog() { if((global_rows * global_columns) > 1000) { msgbox(to_string("You're trying to create "+to_string(global_rows*global_columns)+" fields which will take up quite a bit of memory! The limit is set to a 1000 fields which is also very many to fill out manually; It is better to import matrices of that size from the menu.\n\nThe format of these matrices is as follows:\n\nnumber of rows\nnumber of columns\nall data chronically separated by commas and with no whitespace\n\nExample:\n2\n2\n1,2,3,4\n\nWill represent:\n\t1\t2\n\t3\t4\n\nRemember that there can only be ONE matrix in each file!"), GTK_MESSAGE_INFO, GTK_BUTTONS_OK); return; } GtkWidget *dialog, *table, *sw; gint response; vector entries; int w, h; dialog = gtk_dialog_new_with_buttons ("New matrix: Fill in the context.", GTK_WINDOW (window), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_OK, "_Cancel", GTK_RESPONSE_CANCEL, NULL); w = global_columns*53; if(w > 800) w = 800; h = global_rows*27; if(h > 600) h = 600; gtk_window_set_default_size(GTK_WINDOW(dialog), w, h); table = gtk_table_new(global_rows, global_columns, TRUE); sw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), table); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), sw, TRUE, TRUE, 0); for(int i=0; i::iterator it = entries.begin(); it != entries.end(); it++) { string input = to_string(gtk_entry_get_text(GTK_ENTRY(*it))).c_str(); float value = strtod(input.c_str(), 0); if(value == NULL && !isdigit((char)input.c_str()[0])) { msgbox("Everything you input has to be floats! (fx.: 11.2)", GTK_MESSAGE_INFO, GTK_BUTTONS_OK); break; } else { response_matrix.set_value_t(i, value); i++; } } if(i == entries.size()) { response_matrix.set_id(); matrix_vector.push_back(response_matrix); update_tree_view(); } } gtk_widget_destroy(dialog); } gint menu_new_rnd_matrix(GtkWidget *widget, gpointer gdata) { interactive_dialog(2); if(global_rows > 0 && global_columns > 0) { matrix m(global_rows, global_columns); for(int i=0; i 0) { matrix m(global_order, global_order); int checker = 0, cnt = 0; for(int i=0; imessage), GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE); return 1; } ifstream reader(utf8_filename); string line, contents = ""; if(reader.is_open()) { int r, c, i = 0; while(!reader.eof()) { getline(reader, line); if(i == 0) r = atoi(line.c_str()); else if(i == 1) c = atoi(line.c_str()); else contents += line; i++; } reader.close(); if(contents != "") { // convert the contents to UTF-8 gchar *utf8_data = g_convert(contents.c_str(), contents.length(), "UTF-8", "", NULL, NULL, NULL); // create matrix if(r == NULL || c == NULL) { msgbox("Error while importing matrix! The contents of the file is not valid!", GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE); } else { string dat = to_string(utf8_data); matrix m = gen_matrix_from_text(r, c, dat); m.set_id(); matrix_vector.push_back(m); update_tree_view(); set_statusbar_text("Imported matrix, id: "+to_string(m.get_id())); } } } else msgbox("An error occurred while trying to read from: " + string(filename), GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE); } gtk_widget_destroy(filechooser); } gint menu_export_clicked(GtkWidget *widget, gpointer gdata) { GtkWidget *filechooser; if(global_preview_id != -1) { filechooser = gtk_file_chooser_dialog_new("Save file", GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); // ask for confirmation when overwriting a file in the dialog gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(filechooser), TRUE); if(gtk_dialog_run(GTK_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT) { string filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser)); GError *err = NULL; gchar *utf8_filename = g_filename_to_utf8(filename.c_str(), filename.length(), NULL, NULL, &err); if(utf8_filename == NULL) { msgbox("Error: " + string(err->message), GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE); return 1; } matrix ex = get_by_id(global_preview_id); ofstream writer(utf8_filename); if(writer.is_open()) { writer << export_matrix(&ex); writer.close(); set_statusbar_text("Exported matrix (id="+to_string(global_preview_id)+") to: "+filename); } else msgbox("An error occurred while trying to write to: " + string(utf8_filename), GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE); } gtk_widget_destroy(filechooser); } else msgbox("You have to select the matrix in the list to export!", GTK_MESSAGE_INFO, GTK_BUTTONS_OK); }