aboutsummaryrefslogtreecommitdiff
path: root/data/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'data/client.c')
-rw-r--r--data/client.c449
1 files changed, 447 insertions, 2 deletions
diff --git a/data/client.c b/data/client.c
index 31e18b8..d5e8e56 100644
--- a/data/client.c
+++ b/data/client.c
@@ -1,23 +1,410 @@
#include <curses.h>
#include <locale.h>
#include <stdlib.h>
+#include <string.h>
#include "logger.c"
+#include "plots.c"
#include "tui.c"
+#define UI_AVAIL_PLOTS_COL PANE_AND_MARGIN_WIDTH
+#define UI_WINDOWS_COL (PANE_AND_MARGIN_WIDTH * 2)
+#define UI_PLOTS_COL (PANE_AND_MARGIN_WIDTH * 3)
+
+#define MAX_WINDOW_ROWS 4
+#define MAX_WINDOW_COLS 4
+#define MAX_WINDOW_PLOTS (MAX_WINDOW_ROWS * MAX_WINDOW_COLS)
+
#define CTRL(x) (x & 0x1f)
enum {
PAIR_HEADER = 1,
+ PAIR_SELECTED = 2,
+ PAIR_TO_BE_CREATED = 3,
+ PAIR_TO_BE_UPDATED = 4,
+ PAIR_TO_BE_REMOVED = 5,
+};
+
+enum UIColumn {
+ UICOL_AVAIL_PLOTS,
+ UICOL_WINDOWS,
+ UICOL_PLOTS,
+ UICOL_COUNT,
+};
+
+enum WindowState {
+ WINDOW_TO_BE_CREATED,
+ WINDOW_TO_BE_UPDATED,
+ WINDOW_IS_LIVE,
+ WINDOW_TO_BE_REMOVED,
+};
+
+enum WindowPlotState {
+ PLOT_TO_BE_CREATED,
+ PLOT_IS_LIVE,
+ PLOT_TO_BE_REMOVED,
+};
+
+struct WindowHandle {
+ size_t wid;
+ size_t rows;
+ size_t cols;
+ size_t rows_update;
+ size_t cols_update;
+ enum WindowState state;
+ size_t plot_count;
+ size_t plot_sel;
+ enum WindowPlotState plot_states[MAX_WINDOW_PLOTS];
+ struct PlotDef *plot_defs[MAX_WINDOW_PLOTS];
};
// Globals
bool g_exit;
+enum UIColumn g_col_sel;
+size_t g_apsel;
+size_t g_wsel;
+size_t g_apscroll;
+size_t g_wscroll;
+size_t g_pscroll;
+size_t g_wid_count;
+struct WindowHandle *g_window_handles;
+size_t g_window_count;
+size_t g_window_cap;
-void ui_print(void) {
+// ----------------------------------------------------------------------------
+// UI functions
+// ----------------------------------------------------------------------------
+void ui_print_sim_description(void) {
+ // Simulation desciption
int l = 1;
tui_line(false, l++, PAIR_HEADER, A_BOLD, "SALIS DATA CLIENT");
+ tui_str_field(l++, "name", NAME);
+ tui_ulx_field(l++, "seed", SEED);
+ tui_str_field(l++, "conn", IP ":" PORT_STR);
+ tui_str_field(l++, "anc", ANC);
+ tui_str_field(l++, "arch", ARCH);
+ tui_ulx_field(l++, "asav", AUTOSAVE_INTERVAL);
+ tui_ulx_field(l++, "cres", CORES);
+#if defined(MUTA_FLIP)
+ tui_str_field(l++, "mflp", "true");
+#else
+ tui_str_field(l++, "mflp", "false");
+#endif
+ tui_ulx_field(l++, "mrng", MUTA_RANGE);
+ tui_ulx_field(l++, "size", MVEC_SIZE);
+#if defined(MVEC_LOOP)
+ tui_str_field(l++, "loop", "true");
+#else
+ tui_str_field(l++, "loop", "false");
+#endif
+#if defined(COMPRESS)
+ tui_str_field(l++, "xsav", "enabled");
+#else
+ tui_str_field(l++, "xsav", "disabled");
+#endif
+ tui_ulx_field(l++, "dpsi", DATA_PUSH_INTERVAL);
+
+ // Window summary
+ l++;
+
+ tui_line(false, l++, PAIR_HEADER, A_BOLD, "SUMMARY");
+ tui_uld_field(l++, "wcnt", g_window_count);
+ tui_uld_field(l++, "wcap", g_window_cap);
+ tui_uld_field(l++, "widc", g_wid_count);
+}
+
+void ui_print_avail_plots(void) {
+ int l = 1;
+ int pair = g_col_sel == UICOL_AVAIL_PLOTS ? PAIR_SELECTED : PAIR_HEADER;
+
+ tui_field(l++, UI_AVAIL_PLOTS_COL, pair, A_BOLD, "AVAIL PLOTS [%ld:%ld]", g_apsel, g_apscroll);
+
+ for (size_t i = g_apscroll; i < g_general_plots_count; i++) {
+ pair = i == g_apsel ? PAIR_SELECTED : PAIR_NORMAL;
+ tui_field(l++, UI_AVAIL_PLOTS_COL, pair, A_NORMAL, g_general_plots_def[i].name);
+ }
+}
+
+void ui_print_windows(void) {
+ int l = 1;
+ int pair = g_col_sel == UICOL_WINDOWS ? PAIR_SELECTED : PAIR_HEADER;
+
+ struct WindowHandle *whdl = &g_window_handles[g_wsel];
+ tui_field(l++, UI_WINDOWS_COL, pair, A_BOLD, "WINDOWS [%ld:%ld]", whdl->wid, g_wscroll);
+
+ for (size_t i = g_wscroll; i < g_window_count; i++) {
+ whdl = &g_window_handles[i];
+ char mark = ' ';
+
+ switch (whdl->state) {
+ case WINDOW_TO_BE_CREATED:
+ pair = PAIR_TO_BE_CREATED;
+ mark = '+';
+ break;
+ case WINDOW_TO_BE_UPDATED:
+ pair = PAIR_TO_BE_UPDATED;
+ mark = 'u';
+ break;
+ case WINDOW_IS_LIVE:
+ pair = PAIR_NORMAL;
+ break;
+ case WINDOW_TO_BE_REMOVED:
+ pair = PAIR_TO_BE_REMOVED;
+ mark = 'd';
+ break;
+ }
+
+ pair = i == g_wsel ? PAIR_SELECTED : pair;
+ tui_field(l++, UI_WINDOWS_COL, pair, A_NORMAL, "wid:%ld [%dx%d] %c", whdl->wid, whdl->rows_update, whdl->cols_update, mark);
+ }
+}
+
+void ui_print_plots(void) {
+ int l = 1;
+ int pair = g_col_sel == UICOL_PLOTS ? PAIR_SELECTED : PAIR_HEADER;
+
+ struct WindowHandle *whdl = &g_window_handles[g_wsel];
+ tui_field(l++, UI_PLOTS_COL, pair, A_BOLD, "PLOTS [%ld:%ld]", whdl->plot_sel, g_pscroll);
+
+ if (!g_window_count) return;
+
+ for (size_t i = g_pscroll; i < whdl->plot_count; i++) {
+ struct PlotDef *plot_def = whdl->plot_defs[i];
+ enum WindowPlotState plot_state = whdl->plot_states[i];
+ char mark = ' ';
+
+ switch (plot_state) {
+ case PLOT_TO_BE_CREATED:
+ pair = PAIR_TO_BE_CREATED;
+ mark = '+';
+ break;
+ case PLOT_IS_LIVE:
+ pair = PAIR_NORMAL;
+ break;
+ case PLOT_TO_BE_REMOVED:
+ pair = PAIR_TO_BE_REMOVED;
+ mark = 'd';
+ break;
+ }
+
+ pair = i == whdl->plot_sel ? PAIR_SELECTED : pair;
+ tui_field(l++, UI_PLOTS_COL, pair, A_NORMAL, "%s %c", plot_def->name, mark);
+ plot_def++;
+ }
+}
+
+void ui_print_footer(void) {
+ tui_field(LINES - 1, 1, PAIR_NORMAL, A_NORMAL, "[+] new window | [enter] add plot | [x] delete elem | [ctrl+c] quit");
+}
+
+void ui_print(void) {
+ ui_print_sim_description();
+ ui_print_avail_plots();
+ ui_print_windows();
+ ui_print_plots();
+ ui_print_footer();
+}
+
+// ----------------------------------------------------------------------------
+// Control function
+// ----------------------------------------------------------------------------
+void ev_scroll(int ev) {
+ size_t *scroll_var = NULL;
+
+ switch (g_col_sel) {
+ case UICOL_AVAIL_PLOTS:
+ scroll_var = &g_apscroll;
+ break;
+ case UICOL_WINDOWS:
+ scroll_var = &g_wscroll;
+ break;
+ case UICOL_PLOTS:
+ scroll_var = &g_pscroll;
+ break;
+ default:;
+ }
+
+ assert(scroll_var);
+
+ switch (ev) {
+ case 'w':
+ *scroll_var += 1;
+ break;
+ case 's':
+ *scroll_var -= (*scroll_var ? 1 : 0);
+ break;
+ case 'q':
+ *scroll_var = 0;
+ break;
+ }
+}
+
+void ev_new_window(void) {
+ if (g_window_count == g_window_cap) {
+ // Reallocate dynamic array
+ size_t new_window_cap = g_window_cap * 2;
+ struct WindowHandle *new_window_handles = calloc(new_window_cap, sizeof(struct WindowHandle));
+ memcpy(new_window_handles, g_window_handles, sizeof(struct WindowHandle) * g_window_count);
+ free(g_window_handles);
+ g_window_cap = new_window_cap;
+ g_window_handles = new_window_handles;
+ }
+
+ g_window_count++;
+ g_window_handles[g_window_count - 1] = (struct WindowHandle){
+ .wid = g_wid_count++,
+ .rows = 2,
+ .cols = 2,
+ .rows_update = 2,
+ .cols_update = 2,
+ .state = WINDOW_TO_BE_CREATED,
+ };
+}
+
+void ev_delete_window_handle(size_t widx) {
+ assert(g_window_count);
+ assert(widx < g_window_count);
+ assert(g_window_handles[widx].state == WINDOW_TO_BE_CREATED);
+
+ for (size_t i = widx; i < g_window_count - 1; i++) {
+ memcpy(&g_window_handles[i], &g_window_handles[i + 1], sizeof(struct WindowHandle));
+ }
+
+ g_window_handles[g_window_count - 1] = (struct WindowHandle){ 0 };
+ g_window_count--;
+ g_wsel -= (g_window_count && g_wsel == g_window_count) ? 1 : 0;
+}
+
+void ev_add_plot(void) {
+ assert(g_col_sel == UICOL_AVAIL_PLOTS);
+ assert(g_window_count);
+
+ struct WindowHandle *whdl = &g_window_handles[g_wsel];
+ size_t max_plots = whdl->rows_update * whdl->cols_update;
+ size_t pidx = 0;
+
+ do {
+ if (!whdl->plot_defs[pidx]) break;
+ pidx++;
+ } while (pidx < max_plots);
+
+ if (pidx == max_plots) return;
+
+ whdl->plot_count++;
+ whdl->plot_states[pidx] = PLOT_TO_BE_CREATED;
+ whdl->plot_defs[pidx] = &g_general_plots_def[g_apsel];
+}
+
+void ev_delete_plot(size_t widx) {
+ assert(g_window_count);
+ assert(widx < g_window_count);
+
+ struct WindowHandle *whdl = &g_window_handles[g_wsel];
+ assert(whdl->plot_count);
+ assert(whdl->plot_sel < whdl->plot_count);
+ assert(whdl->plot_states[whdl->plot_sel] == PLOT_TO_BE_CREATED);
+
+ for (size_t i = whdl->plot_sel; i < whdl->plot_count - 1; i++) {
+ whdl->plot_states[i] = whdl->plot_states[i + 1];
+ whdl->plot_defs[i] = whdl->plot_defs[i + 1];
+ }
+
+ whdl->plot_states[whdl->plot_count - 1] = 0;
+ whdl->plot_defs[whdl->plot_count - 1] = NULL;
+ whdl->plot_count--;
+
+ if (!whdl->plot_count) {
+ whdl->plot_sel = 0;
+ } else if (whdl->plot_sel >= whdl->plot_count) {
+ whdl->plot_sel = whdl->plot_count - 1;
+ }
+}
+
+void ev_delete_elem(void) {
+ if (g_col_sel == UICOL_WINDOWS && g_window_count) {
+ struct WindowHandle *whdl = &g_window_handles[g_wsel];
+
+ switch (whdl->state) {
+ case WINDOW_TO_BE_CREATED:
+ ev_delete_window_handle(g_wsel);
+ break;
+ case WINDOW_TO_BE_UPDATED:
+ break;
+ case WINDOW_IS_LIVE:
+ break;
+ case WINDOW_TO_BE_REMOVED:
+ break;
+ }
+ }
+
+ if (g_col_sel == UICOL_PLOTS && g_window_count && g_window_handles[g_wsel].plot_count) {
+ struct WindowHandle *whdl = &g_window_handles[g_wsel];
+
+ switch (whdl->plot_states[whdl->plot_sel]) {
+ case PLOT_TO_BE_CREATED:
+ ev_delete_plot(g_wsel);
+ break;
+ case PLOT_IS_LIVE:
+ break;
+ case PLOT_TO_BE_REMOVED:
+ break;
+ }
+ }
+}
+
+void ev_resize_window(int ev) {
+ assert(g_col_sel == UICOL_WINDOWS);
+ assert(g_window_count);
+
+ struct WindowHandle *whdl = &g_window_handles[g_wsel];
+
+ switch (ev) {
+ case 'A':
+ if (whdl->cols_update > 1 && (whdl->rows_update * (whdl->cols_update - 1)) >= whdl->plot_count) whdl->cols_update--;
+ break;
+ case 'D':
+ whdl->cols_update += whdl->cols_update < MAX_WINDOW_COLS ? 1 : 0;
+ break;
+ case 'W':
+ if (whdl->rows_update > 1 && (whdl->cols_update * (whdl->rows_update - 1)) >= whdl->plot_count) whdl->rows_update--;
+ break;
+ case 'S':
+ whdl->rows_update += whdl->rows_update < MAX_WINDOW_ROWS ? 1 : 0;
+ break;
+ }
+}
+
+void ev_swap_plots(int ev) {
+ assert(g_col_sel == UICOL_PLOTS);
+ assert(g_window_count);
+
+ struct WindowHandle *whdl = &g_window_handles[g_wsel];
+ size_t pidx1;
+ size_t pidx2;
+
+ switch (ev) {
+ case 'W':
+ if (!whdl->plot_count || !whdl->plot_sel) return;
+ pidx1 = whdl->plot_sel;
+ pidx2 = whdl->plot_sel - 1;
+ whdl->plot_sel--;
+ break;
+ case 'S':
+ if (!whdl->plot_count || whdl->plot_sel >= whdl->plot_count - 1) return;
+ pidx1 = whdl->plot_sel;
+ pidx2 = whdl->plot_sel + 1;
+ whdl->plot_sel++;
+ break;
+ }
+
+ enum WindowPlotState tmp_state = whdl->plot_states[pidx1];
+ whdl->plot_states[pidx1] = whdl->plot_states[pidx2];
+ whdl->plot_states[pidx2] = tmp_state;
+
+ struct PlotDef *tmp_def = whdl->plot_defs[pidx1];
+ whdl->plot_defs[pidx1] = whdl->plot_defs[pidx2];
+ whdl->plot_defs[pidx2] = tmp_def;
}
void ev_handle(void) {
@@ -28,13 +415,58 @@ void ev_handle(void) {
g_exit = true;
break;
case KEY_RESIZE:
- clear();
tui_line_buff_resize();
+ break;
+ case 'w':
+ case 's':
+ case 'q':
+ ev_scroll(ev);
+ break;
+ case 'Q':
+ g_apscroll = 0;
+ g_wscroll = 0;
+ g_pscroll = 0;
+ break;
+ case KEY_LEFT:
+ g_col_sel -= g_col_sel ? 1 : 0;
+ break;
+ case KEY_RIGHT:
+ g_col_sel += g_col_sel < UICOL_COUNT - 1 ? 1 : 0;
+ break;
+ case KEY_UP:
+ if (g_col_sel == UICOL_AVAIL_PLOTS && g_apsel) g_apsel--;
+ if (g_col_sel == UICOL_WINDOWS && g_wsel) g_wsel--;
+ if (g_col_sel == UICOL_PLOTS && g_window_count && g_window_handles[g_wsel].plot_sel) g_window_handles[g_wsel].plot_sel--;
+ break;
+ case KEY_DOWN:
+ if (g_col_sel == UICOL_AVAIL_PLOTS && g_apsel < g_general_plots_count - 1) g_apsel++;
+ if (g_col_sel == UICOL_WINDOWS && g_window_count && g_wsel < g_window_count - 1) g_wsel++;
+ if (g_col_sel == UICOL_PLOTS && g_window_count && g_window_handles[g_wsel].plot_count && g_window_handles[g_wsel].plot_sel < g_window_handles[g_wsel].plot_count - 1) g_window_handles[g_wsel].plot_sel++;
+ break;
+ case '+':
+ ev_new_window();
+ break;
+ case '\n':
+ if (g_col_sel == UICOL_AVAIL_PLOTS && g_window_count) ev_add_plot();
+ break;
+ case 'x':
+ ev_delete_elem();
+ break;
+ case 'A':
+ case 'D':
+ case 'W':
+ case 'S':
+ if (g_col_sel == UICOL_WINDOWS && g_window_count) ev_resize_window(ev);
+ if (g_col_sel == UICOL_PLOTS && g_window_count) ev_swap_plots(ev);
+ break;
default:
break;
}
}
+// ----------------------------------------------------------------------------
+// Main functions
+// ----------------------------------------------------------------------------
void init(void) {
log_info("Initializing salis data client");
@@ -51,14 +483,23 @@ void init(void) {
init_pair(PAIR_NORMAL, COLOR_WHITE, COLOR_BLACK);
init_pair(PAIR_HEADER, COLOR_BLUE, COLOR_BLACK);
+ init_pair(PAIR_SELECTED, COLOR_YELLOW, COLOR_BLACK);
+ init_pair(PAIR_TO_BE_CREATED, COLOR_GREEN, COLOR_BLACK);
+ init_pair(PAIR_TO_BE_UPDATED, COLOR_GREEN, COLOR_BLACK);
+ init_pair(PAIR_TO_BE_REMOVED, COLOR_RED, COLOR_BLACK);
tui_line_buff_resize();
+
+ g_window_count = 0;
+ g_window_cap = 1;
+ g_window_handles = calloc(g_window_cap, sizeof(struct WindowHandle));
}
void exec(void) {
while (!g_exit) {
ui_print();
ev_handle();
+ clear();
}
}
@@ -73,5 +514,9 @@ int main(void) {
exec();
quit();
+ free(g_window_handles);
+ g_window_count = 0;
+ g_window_cap = 0;
+
return 0;
}