diff options
author | Antony Kellermann | 2018-06-17 20:41:10 -0400 |
---|---|---|
committer | Antony Kellermann | 2018-06-17 20:41:10 -0400 |
commit | cc6d8b9c302fd8babba9eeb42de9933dd61451c8 (patch) | |
tree | 067be195e421be83f1e8f2f149da6b930ec8d267 | |
parent | 9b7ef358cb19dd264e967e06fae2e81f9fc43ea6 (diff) | |
download | aur-cc6d8b9c302fd8babba9eeb42de9933dd61451c8.tar.gz |
Implemented basic GTK+ check window
-rw-r--r-- | gtk_win.c | 132 | ||||
-rw-r--r-- | gtk_win.h | 43 | ||||
-rw-r--r-- | main.c | 24 | ||||
-rw-r--r-- | window_main.glade | 344 |
4 files changed, 533 insertions, 10 deletions
diff --git a/gtk_win.c b/gtk_win.c new file mode 100644 index 000000000000..307952c48285 --- /dev/null +++ b/gtk_win.c @@ -0,0 +1,132 @@ +#include "gtk_win.h" + +char column_names[16][NUM_COLS]; + +void window_main(void) { + gtk_init(NULL, NULL); + GtkBuilder* builder = gtk_builder_new(); + + // Read glade XML config file + gtk_builder_add_from_file(builder, "/usr/share/tick/window_main.glade", NULL); + + // Get widgets + GtkWidget* window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main")); + GtkListStore* list = GTK_LIST_STORE(gtk_builder_get_object(builder, "check_list")); + GtkTreeView* tree_view = GTK_TREE_VIEW(gtk_builder_get_object(builder, "check_tree_view")); + for (gint i = 0; i < NUM_COLS; i++) // Copy names of columns into array + strcpy(column_names[i], gtk_tree_view_column_get_title(gtk_tree_view_get_column( + tree_view, i))); + + Info_Array* portfolio_data = portfolio_get_info_array(); // Portfolio data + format_cells(portfolio_data); // Format portfolio data to strings + + Info* idx; // Append list store with portfolio data + for (size_t i = 0; i < portfolio_data->length; i++) { + GtkTreeIter iter; + idx = portfolio_data->array[i]; + gtk_list_store_append(list, &iter); + gtk_list_store_set(list, &iter, AMOUNT, idx->famount, SYMBOL, idx->symbol, VALUE, + idx->fcurrent_value, SPENT, idx->ftotal_spent, PROFIT, + idx->fprofit_total, PROFIT_PERCENT, idx->fprofit_total_percent, + PROFIT_24H, idx->fprofit_last_close, PROFIT_24H_PERCENT, + idx->fprofit_last_close_percent, PROFIT_7D, idx->fprofit_7d, + PROFIT_7D_PERCENT, idx->fprofit_7d_percent, PROFIT_30D, idx->fprofit_30d, + PROFIT_30D_PERCENT, idx->fprofit_30d_percent, -1); + } + + GtkTreeIter iter; + gtk_list_store_append(list, &iter); // Add totals + gtk_list_store_set(list, &iter, SYMBOL, "TOTALS", VALUE, portfolio_data->fcurrent_value, SPENT, + portfolio_data->ftotal_spent, PROFIT, portfolio_data->fprofit_total, + PROFIT_PERCENT, portfolio_data->fprofit_total_percent, PROFIT_24H, + portfolio_data->fprofit_last_close, PROFIT_24H_PERCENT, + portfolio_data->fprofit_last_close_percent, PROFIT_7D, + portfolio_data->fprofit_7d, PROFIT_7D_PERCENT, + portfolio_data->fprofit_7d_percent, PROFIT_30D, portfolio_data->fprofit_30d, + PROFIT_30D_PERCENT, portfolio_data->fprofit_30d_percent, -1); + + gtk_builder_connect_signals(builder, NULL); // Connect signals + g_object_unref(builder); + gtk_widget_show_all(window); + gtk_main(); // Main loop + api_info_array_destroy(&portfolio_data); +} + +void format_cells(Info_Array* portfolio_data) { + Info* idx; + for (size_t i = 0; i < portfolio_data->length; i++) { + idx = portfolio_data->array[i]; + sprintf(idx->famount, "%.2lf", idx->amount); + sprintf(idx->ftotal_spent, "%.2lf", idx->total_spent); + sprintf(idx->fcurrent_value, "%.2lf", idx->current_value); + sprintf(idx->fprofit_total, "%.2lf", idx->profit_total); + sprintf(idx->fprofit_total_percent, "%.2lf", idx->profit_total_percent); + sprintf(idx->fprofit_last_close, "%.2lf", idx->profit_last_close); + sprintf(idx->fprofit_last_close_percent, "%.2lf", idx->profit_last_close_percent); + sprintf(idx->fprofit_7d, "%.2lf", idx->profit_7d); + sprintf(idx->fprofit_7d_percent, "%.2lf", idx->profit_7d_percent); + sprintf(idx->fprofit_30d, "%.2lf", idx->profit_30d); + sprintf(idx->fprofit_30d_percent, "%.2lf", idx->profit_30d_percent); + } + sprintf(portfolio_data->ftotal_spent, "%.2lf", portfolio_data->total_spent); + sprintf(portfolio_data->fcurrent_value, "%.2lf", portfolio_data->current_value); + sprintf(portfolio_data->fprofit_total, "%.2lf", portfolio_data->profit_total); + sprintf(portfolio_data->fprofit_total_percent, "%.2lf", portfolio_data->profit_total_percent); + sprintf(portfolio_data->fprofit_last_close, "%.2lf", portfolio_data->profit_last_close); + sprintf(portfolio_data->fprofit_last_close_percent, "%.2lf", + portfolio_data->profit_last_close_percent); + sprintf(portfolio_data->fprofit_7d, "%.2lf", portfolio_data->profit_7d); + sprintf(portfolio_data->fprofit_7d_percent, "%.2lf", portfolio_data->profit_7d_percent); + sprintf(portfolio_data->fprofit_30d, "%.2lf", portfolio_data->profit_30d); + sprintf(portfolio_data->fprofit_30d_percent, "%.2lf", + portfolio_data->profit_30d_percent); +} + +void on_main_win_destroy(void) { + gtk_main_quit(); +} + +void on_column_clicked(GtkTreeViewColumn* column, GtkListStore* list_store) { + int idx = -1; + for (int i = 0; i < NUM_COLS; i++) + if (strcmp(gtk_tree_view_column_get_title(column), column_names[i]) == 0) + idx = i; + + list_store_sort(list_store, (Col_Index) idx); +} + +void list_store_sort(GtkListStore* list_store, Col_Index idx) { + GtkTreeModel* model = (GtkTreeModel*) list_store; + int loop_flag = 1; + gchar* str1, * str2, * sym1, * sym2; + while (loop_flag) { // Bubble sort + loop_flag = 0; + GtkTreeIter iter1, iter2; + gtk_tree_model_get_iter_first(model, &iter1); + gtk_tree_model_get_iter_first(model, &iter2); + if (!gtk_tree_model_iter_next(model, &iter2)) // List length 1 + return; + do { + gtk_tree_model_get(model, &iter1, SYMBOL, &sym1, -1); + gtk_tree_model_get(model, &iter2, SYMBOL, &sym2, -1); + + // Don't sort TOTALS + if (strcmp(sym1, "TOTALS") != 0 && strcmp(sym2, "TOTALS") != 0) { + gtk_tree_model_get(model, &iter1, idx, &str1, -1); + gtk_tree_model_get(model, &iter2, idx, &str2, -1); + + // Compare doubles + if ((idx != SYMBOL && strtod(str1, NULL) < strtod(str2, NULL)) || + (idx == SYMBOL && strcmp(str1, str2) > 0)) { // Compare strings + gtk_list_store_swap(list_store, &iter1, &iter2); + loop_flag = 1; + } + g_free(str1); + g_free(str2); + } + g_free(sym1); + g_free(sym2); + } while (gtk_tree_model_iter_next(model, &iter1) && + gtk_tree_model_iter_next(model, &iter2)); + } +}
\ No newline at end of file diff --git a/gtk_win.h b/gtk_win.h new file mode 100644 index 000000000000..dcb1e7a7c416 --- /dev/null +++ b/gtk_win.h @@ -0,0 +1,43 @@ +#ifndef TICK_GTK_WIN_H +#define TICK_GTK_WIN_H + +#include <gtk/gtk.h> +#include "portfolio.h" + +typedef enum column_index { + AMOUNT, SYMBOL, VALUE, SPENT, PROFIT, PROFIT_PERCENT, PROFIT_24H, PROFIT_24H_PERCENT, PROFIT_7D, + PROFIT_7D_PERCENT, PROFIT_30D, PROFIT_30D_PERCENT, NUM_COLS +} Col_Index; + +/** + * Opens GTK+ Window and prints portfolio data to it. Currently cannot handle encrypted portfolios. + */ +void window_main(void); + +/** + * Formats text in Info structs for printing to window + * @param portfolio_data + */ +void format_cells(Info_Array* portfolio_data); + +/** + * Signal handler for destroying main window. Exits the program. + */ +void on_main_win_destroy(void); + +/** + * Signal handler for clicking column labels. Sorts the ListStore struct according to which + * column was clicked. + * @param column clicked column + * @param list_store portfolio data list + */ +void on_column_clicked(GtkTreeViewColumn* column, GtkListStore* list_store); + +/** + * Sorts a ListStore struct according to idx. + * @param list_store ListStore to sort + * @param idx column number + */ +void list_store_sort(GtkListStore* list_store, Col_Index idx); + +#endif
\ No newline at end of file @@ -1,16 +1,15 @@ #include "portfolio.h" #include "info.h" +#include "gtk_win.h" int main(int argc, char* argv[]) { - if (argc < 2) { - puts("Invalid arguments. Type \"man tick\" for help."); - return 0; + char* cmd = NULL, * sym = NULL; + if (argc > 1) { + cmd = malloc(strlen(argv[1]) + 1); + pointer_alloc_check(cmd); + strcpy(cmd, argv[1]); + strtolower(cmd); } - char cmd[strlen(argv[1]) + 1]; - strcpy(cmd, argv[1]); - strtolower(cmd); - - char* sym = NULL; if (argc > 2) { sym = malloc(strlen(argv[2]) + 1); pointer_alloc_check(sym); @@ -27,8 +26,12 @@ int main(int argc, char* argv[]) { // Portfolio modify operation int modop = -1; - // News - if (strcmp(cmd, "news") == 0 && (argc == 3 || argc == 4)) { + // GTK+ window + if (argc == 1) + window_main(); + + // News + else if (strcmp(cmd, "news") == 0 && (argc == 3 || argc == 4)) { int num_articles = 3; // Default if (argc == 4) num_articles = (int) strtol(argv[3], NULL, 10); @@ -103,6 +106,7 @@ int main(int argc, char* argv[]) { } free(portfolio_file); free(sym); + free(cmd); curl_global_cleanup(); return 0; }
\ No newline at end of file diff --git a/window_main.glade b/window_main.glade new file mode 100644 index 000000000000..fdde875888ed --- /dev/null +++ b/window_main.glade @@ -0,0 +1,344 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 + +The MIT License (MIT) + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Authors: +Antony Kellermann +https://github.com/aokellermann/ + +--> +<interface> + <requires lib="gtk+" version="3.20"/> + <!-- interface-license-type mit --> + <!-- interface-name Tick --> + <!-- interface-description Command line stock and cryptocurrency portfolio tracker. --> + <!-- interface-authors Antony Kellermann\nhttps://github.com/aokellermann/ --> + <object class="GtkListStore" id="check_list"> + <columns> + <!-- column-name Amount --> + <column type="gchararray"/> + <!-- column-name Symbol --> + <column type="gchararray"/> + <!-- column-name Value --> + <column type="gchararray"/> + <!-- column-name Spent --> + <column type="gchararray"/> + <!-- column-name Profit --> + <column type="gchararray"/> + <!-- column-name Profit1 --> + <column type="gchararray"/> + <!-- column-name Profit24H --> + <column type="gchararray"/> + <!-- column-name 24H% --> + <column type="gchararray"/> + <!-- column-name Profit7D --> + <column type="gchararray"/> + <!-- column-name 7D% --> + <column type="gchararray"/> + <!-- column-name Profit30D --> + <column type="gchararray"/> + <!-- column-name 30D% --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkApplicationWindow" id="window_main"> + <property name="can_focus">False</property> + <child> + <placeholder/> + </child> + <child> + <object class="GtkScrolledWindow" id="scroll_window"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="check_tree_view"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscroll_policy">natural</property> + <property name="vscroll_policy">natural</property> + <property name="model">check_list</property> + <property name="enable_search">False</property> + <property name="fixed_height_mode">True</property> + <property name="show_expanders">False</property> + <property name="enable_grid_lines">both</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="amount_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">100</property> + <property name="title" translatable="yes">Amount</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="amount_renderer"> + <property name="xalign">1</property> + </object> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="symbol_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">100</property> + <property name="title" translatable="yes">Symbol</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="symbol_renderer"> + <property name="xalign">0</property> + </object> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="value_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">100</property> + <property name="title" translatable="yes">Value</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="value_renderer"> + <property name="xalign">1</property> + <property name="alignment">right</property> + </object> + <attributes> + <attribute name="text">2</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="spent_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">100</property> + <property name="title" translatable="yes">Spent</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="spent_renderer"> + <property name="xalign">1</property> + <property name="alignment">right</property> + </object> + <attributes> + <attribute name="text">3</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="profit_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">100</property> + <property name="title" translatable="yes">Profit</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="profit_renderer"> + <property name="xalign">1</property> + <property name="alignment">right</property> + </object> + <attributes> + <attribute name="text">4</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="profit_percent_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">65</property> + <property name="title" translatable="yes">%</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="profit_percent_renderer"> + <property name="xalign">1</property> + <property name="alignment">right</property> + </object> + <attributes> + <attribute name="text">5</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="profit_24h_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">65</property> + <property name="title" translatable="yes">24H</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="profit_24h_renderer"> + <property name="xalign">1</property> + <property name="alignment">right</property> + </object> + <attributes> + <attribute name="text">6</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="profit_24h_percent_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">65</property> + <property name="title" translatable="yes">24H%</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="profit_24h_percent_renderer"> + <property name="xalign">1</property> + <property name="alignment">right</property> + </object> + <attributes> + <attribute name="text">7</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="profit_7d_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">65</property> + <property name="title" translatable="yes">7D</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="profit_7d_renderer"> + <property name="xalign">1</property> + <property name="alignment">right</property> + </object> + <attributes> + <attribute name="text">8</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="profit_7d_percent_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">65</property> + <property name="title" translatable="yes">7D%</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="profit_7d_percent_renderer"> + <property name="xalign">1</property> + <property name="alignment">right</property> + </object> + <attributes> + <attribute name="text">9</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="profit_30d_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">80</property> + <property name="title" translatable="yes">30D</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="profit_30d_renderer"> + <property name="xalign">1</property> + <property name="alignment">right</property> + </object> + <attributes> + <attribute name="text">10</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="profit_30d_percent_column"> + <property name="resizable">True</property> + <property name="sizing">fixed</property> + <property name="min_width">65</property> + <property name="title" translatable="yes">30D%</property> + <property name="expand">True</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <signal name="clicked" handler="on_column_clicked" object="check_list" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="profit_30d_percent_renderer"> + <property name="xalign">1</property> + <property name="alignment">right</property> + </object> + <attributes> + <attribute name="text">11</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </object> +</interface> |