diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/commands.c | 21 | ||||
-rw-r--r-- | client/errcatch.c | 27 | ||||
-rw-r--r-- | client/errcatch.h | 8 | ||||
-rw-r--r-- | client/i18n/en_us.h | 96 | ||||
-rw-r--r-- | client/main.c | 6 | ||||
-rw-r--r-- | client/main.h | 4 | ||||
-rw-r--r-- | client/serial.c | 9 | ||||
-rw-r--r-- | client/serial_win32.c | 16 | ||||
-rw-r--r-- | client/setup.c | 11 | ||||
-rw-r--r-- | client/strings.c | 81 | ||||
-rw-r--r-- | client/strings.h | 7 | ||||
-rw-r--r-- | client/time_windows.c | 4 | ||||
-rw-r--r-- | client/ui.c | 85 | ||||
-rw-r--r-- | client/ui.h | 43 | ||||
-rw-r--r-- | client/ui_dirc.c | 68 | ||||
-rw-r--r-- | client/ui_errcatch.c | 49 | ||||
-rw-r--r-- | client/ui_modes.c | 16 | ||||
-rw-r--r-- | client/ui_orders.c | 112 | ||||
-rw-r--r-- | client/ui_start.c | 8 | ||||
-rw-r--r-- | client/ui_tabbar.c | 33 |
20 files changed, 601 insertions, 103 deletions
diff --git a/client/commands.c b/client/commands.c index 778e9c1..d2e53c8 100644 --- a/client/commands.c +++ b/client/commands.c @@ -46,10 +46,21 @@ void w2_send_ping() { } void w2_send_mode(w2_e_mode mode) { - W2_CREATE_MSG_BIN(w2_s_cmd_mode_rx, msg, msg_bin); - msg->opcode = W2_CMD_MODE | W2_CMDDIR_RX; - msg->mode = mode; + if (mode == W2_M_PREV) { + W2_CREATE_MSG_BIN(w2_s_cmd_sres_rx, msg, msg_bin); - w2_send_bin(msg_bin); - free(msg_bin); + msg->opcode = W2_CMD_SRES | W2_CMDDIR_RX; + msg->type = W2_CMD_SRES_RX_TYPE_PREVMODE; + + w2_send_bin(msg_bin); + free(msg_bin); + } else { + W2_CREATE_MSG_BIN(w2_s_cmd_mode_rx, msg, msg_bin); + + msg->opcode = W2_CMD_MODE | W2_CMDDIR_RX; + msg->mode = mode; + + w2_send_bin(msg_bin); + free(msg_bin); + } } diff --git a/client/errcatch.c b/client/errcatch.c index 5e39b00..c39544c 100644 --- a/client/errcatch.c +++ b/client/errcatch.c @@ -1,18 +1,15 @@ -#include "../shared/errcatch.h" +#include <stdlib.h> -void w2_errcatch_handle_error(w2_s_error *error) { - // TODO: handle more error types - switch (error->code) { - case W2_E_WARN_UNCAUGHT_ERROR: { - break; - } - default: { - g_w2_error_uncaught = true; -#ifdef W2_SIM - simwarn("Uncaught/unhandled error found with code 0x%02x\n", error->code); -#endif - } - } +#include "errcatch.h" - return; +w2_s_error *g_w2_error_log[W2_ERRCATCH_LOG_SIZE] = {NULL}; +unsigned int g_w2_error_log_index = 0; + +void w2_errcatch_log_error(w2_s_error *error) { + if (g_w2_error_log[g_w2_error_log_index] != NULL) free(g_w2_error_log[g_w2_error_log_index]); + g_w2_error_log[g_w2_error_log_index] = + w2_alloc_error(error->code, error->message_length, error->message); + g_w2_error_log_index = (g_w2_error_log_index + 1) % W2_ERRCATCH_LOG_SIZE; } + +void w2_errcatch_handle_error(w2_s_error *error) { w2_errcatch_log_error(error); } diff --git a/client/errcatch.h b/client/errcatch.h new file mode 100644 index 0000000..71eb56d --- /dev/null +++ b/client/errcatch.h @@ -0,0 +1,8 @@ +#pragma once + +#include "../shared/errcatch.h" + +#define W2_ERRCATCH_LOG_SIZE 256 + +extern w2_s_error *g_w2_error_log[W2_ERRCATCH_LOG_SIZE]; +extern unsigned int g_w2_error_log_index; diff --git a/client/i18n/en_us.h b/client/i18n/en_us.h index 5547db5..d198296 100644 --- a/client/i18n/en_us.h +++ b/client/i18n/en_us.h @@ -9,6 +9,7 @@ #define W2_UI_BATT_STAT_BATTERY "battery" #define W2_UI_EXPT_STAT_WARNINGS "warning(s)" #define W2_UI_EXPT_STAT_ERRORS "error(s)" + #define W2_UI_MODE_CHRG "charging station" #define W2_UI_MODE_DIRC "direct control" #define W2_UI_MODE_GRID "grid" @@ -17,3 +18,98 @@ #define W2_UI_MODE_MAZE "maze" #define W2_UI_MODE_SCAL "sensor calibration" #define W2_UI_MODE_SPIN "wet floor simulation" + +#define W2_UI_TAB_LABEL_START "info" +#define W2_UI_TAB_LABEL_DIRC "direct control" +#define W2_UI_TAB_LABEL_ERRCATCH "logs" +#define W2_UI_TAB_LABEL_MCFG "map" +#define W2_UI_TAB_LABEL_ORDERS "orders" +#define W2_UI_TAB_LABEL_MODES "set mode" + +#define W2_UI_TAB_START_MESSAGE "" \ + "welcome to the wall-e2 console application!\n" \ + "this is client version " W2_BUILD_STR "\n" \ + "\n" \ + "this application is functionally similar to a BIOS.\n" \ + "here's a brief summary of keyboard commands:\n" \ + "\n" \ + "<tab> switch to next tab\n" \ + "<ctrl-c> exit\n" \ + "\n" \ + +#define W2_UI_ERROR_SEVERITY_CRIT "CRIT" +#define W2_UI_ERROR_SEVERITY_WARN "WARN" +#define W2_UI_ERROR_SEVERITY_INFO "INFO" +#define W2_UI_ERROR_SEVERITY_VERB "VERB" + +#define W2_UI_ERROR_INT_W2_E_UNKNOWN "W2_E_UNKNOWN" +#define W2_UI_ERROR_INT_W2_E_CRIT_CONN_LOST "W2_E_CRIT_CONN_LOST" +#define W2_UI_ERROR_INT_W2_E_CRIT_COM_UNAVAILABLE "W2_E_CRIT_COM_UNAVAILABLE" +#define W2_UI_ERROR_INT_W2_E_CRIT_LINE_LOST "W2_E_CRIT_LINE_LOST" +#define W2_UI_ERROR_INT_W2_E_CRIT_OBSTACLE_STUCK "W2_E_CRIT_OBSTACLE_STUCK" +#define W2_UI_ERROR_INT_W2_E_CRIT_VERSION_INCOMPATIBLE "W2_E_CRIT_VERSION_INCOMPATIBLE" +#define W2_UI_ERROR_INT_W2_E_WARN_BATTERY_LOW "W2_E_WARN_BATTERY_LOW" +#define W2_UI_ERROR_INT_W2_E_WARN_OBSTACLE_DETECTED "W2_E_WARN_OBSTACLE_DETECTED" +#define W2_UI_ERROR_INT_W2_E_WARN_CYCLE_EXPIRED "W2_E_WARN_CYCLE_EXPIRED" +#define W2_UI_ERROR_INT_W2_E_WARN_UNCAUGHT_ERROR "W2_E_WARN_UNCAUGHT_ERROR" +#define W2_UI_ERROR_INT_W2_E_WARN_ERR_BUFFER_FULL "W2_E_WARN_ERR_BUFFER_FULL" +#define W2_UI_ERROR_INT_W2_E_WARN_LINE_LOST "W2_E_WARN_LINE_LOST" +#define W2_UI_ERROR_INT_W2_E_WARN_SERCOMM_BUFFER_FULL "W2_E_WARN_SERCOMM_BUFFER_FULL" +#define W2_UI_ERROR_INT_W2_E_WARN_VERSION_INCOMPATIBLE "W2_E_WARN_VERSION_INCOMPATIBLE" +#define W2_UI_ERROR_INT_W2_E_WARN_SERIAL_NOISY "W2_E_WARN_SERIAL_NOISY" +#define W2_UI_ERROR_INT_W2_E_WARN_MODE_HISTORY_BUFFER_IOB "W2_E_WARN_MODE_HISTORY_BUFFER_IOB" +#define W2_UI_ERROR_INT_W2_E_WARN_PING_TIMEOUT "W2_E_WARN_PING_TIMEOUT" + +#define W2_UI_ERROR_USR_W2_E_UNKNOWN "unknown error code" +#define W2_UI_ERROR_USR_W2_E_CRIT_CONN_LOST "connection to robot lost" +#define W2_UI_ERROR_USR_W2_E_CRIT_COM_UNAVAILABLE "COM-port unavailable" +#define W2_UI_ERROR_USR_W2_E_CRIT_LINE_LOST "line lost and unable to be found automatically" +#define W2_UI_ERROR_USR_W2_E_CRIT_OBSTACLE_STUCK "obstacle detected, robot stuck" +#define W2_UI_ERROR_USR_W2_E_CRIT_VERSION_INCOMPATIBLE "major version mismatch detected, please update robot" +#define W2_UI_ERROR_USR_W2_E_WARN_BATTERY_LOW "battery low, going to charging station" +#define W2_UI_ERROR_USR_W2_E_WARN_OBSTACLE_DETECTED "obstacle detected, waiting" +#define W2_UI_ERROR_USR_W2_E_WARN_CYCLE_EXPIRED "maximum logic module cycle time exceeded" +#define W2_UI_ERROR_USR_W2_E_WARN_UNCAUGHT_ERROR "uncaught error occurred" +#define W2_UI_ERROR_USR_W2_E_WARN_ERR_BUFFER_FULL "error buffer full" +#define W2_UI_ERROR_USR_W2_E_WARN_LINE_LOST "line lost, trying to find line automatically" +#define W2_UI_ERROR_USR_W2_E_WARN_SERCOMM_BUFFER_FULL "serial communication buffer full" +#define W2_UI_ERROR_USR_W2_E_WARN_VERSION_INCOMPATIBLE "minor version mismatch detected, this might cause problems" +#define W2_UI_ERROR_USR_W2_E_WARN_SERIAL_NOISY "invalid serial data received (noisy channel / check connection?)" +#define W2_UI_ERROR_USR_W2_E_WARN_MODE_HISTORY_BUFFER_IOB "mode history buffer index out of bounds" +#define W2_UI_ERROR_USR_W2_E_WARN_PING_TIMEOUT "ping timed out" + +#define W2_UI_ORDER_CMD_HELP "help" +#define W2_UI_ORDER_CMD_START "start" +#define W2_UI_ORDER_CMD_COORDINATE "coordinate" +#define W2_UI_ORDER_CMD_DONE "done" +#define W2_UI_ORDER_CMD_SEND "send" + +#define W2_UI_ORDER_MSG_ERROR "unknown command, type 'help' to see a list of valid commands\n\n" +#define W2_UI_ORDER_MSG_HELP \ + "commands:\n" \ + "\n" \ + W2_UI_ORDER_CMD_HELP ": print this list\n" \ + W2_UI_ORDER_CMD_START ": start an order\n" \ + W2_UI_ORDER_CMD_COORDINATE " <x> <y>: add a coordinate to the current order\n" \ + W2_UI_ORDER_CMD_DONE ": finish the current order\n" \ + W2_UI_ORDER_CMD_SEND ": send the latest completed order to robot\n\n" +#define W2_UI_ORDER_MSG_ORDER_START_OK "order started\n\n" +#define W2_UI_ORDER_MSG_ORDER_START_ERR "order already started\n\n" +#define W2_UI_ORDER_MSG_ORDER_APPEND_OK "appended coordinate to order\n\n" +#define W2_UI_ORDER_MSG_ORDER_APPEND_ERR "no order active\n\n" +#define W2_UI_ORDER_MSG_ORDER_DONE_OK "order saved\n\n" +#define W2_UI_ORDER_MSG_ORDER_DONE_ERR "no order active\n\n" +#define W2_UI_ORDER_MSG_ORDER_SENT "order sent to robot\n\n" + +#define W2_UI_MODES_INFO \ + "press keys (0-9) for:\n" \ + "\n" \ + "1 - set to maze mode\n" \ + "2 - set to grid mode\n" \ + "3 - halt (emergency stop)\n" \ + "4 - set to charging station mode\n" \ + "5 - set to spinning mode (wet floor simulation)\n" \ + "6 - calibrate sensors\n" \ + "\n" \ + "0 - previous\n" \ + diff --git a/client/main.c b/client/main.c index b5af0e8..4d7f484 100644 --- a/client/main.c +++ b/client/main.c @@ -7,7 +7,11 @@ #include "time.h" #include "ui.h" -w2_s_client_state g_w2_state = {.ping_received = true}; +w2_s_client_state g_w2_state = { + .ping_received = true, + .map_height = W2_MAP_DEFAULT_HEIGHT, + .map_width = W2_MAP_DEFAULT_WIDTH, +}; int main(int argc, char **argv) { w2_client_setup(argc, argv); diff --git a/client/main.h b/client/main.h index cc4c728..b72b507 100644 --- a/client/main.h +++ b/client/main.h @@ -13,8 +13,10 @@ typedef struct { uint8_t mode; + uint8_t map_width; + uint8_t map_height; + w2_s_cmd_info_tx info; - w2_s_cmd_sens_tx io; } w2_s_client_state; extern w2_s_client_state g_w2_state; diff --git a/client/serial.c b/client/serial.c index 112fd81..2a4d26f 100644 --- a/client/serial.c +++ b/client/serial.c @@ -3,6 +3,7 @@ #include "../shared/protocol.h" #include "../shared/serial_parse.h" #include "commands.h" +#include "errcatch.h" #include "main.h" #include "serial.h" #include "time.h" @@ -26,14 +27,17 @@ void w2_cmd_ping_rx(w2_s_bin *data) { void w2_cmd_ping_tx(w2_s_bin *data) { w2_send_bin(data); } -void w2_cmd_expt_tx(w2_s_bin *data) {} +void w2_cmd_expt_tx(w2_s_bin *data) { + W2_CAST_BIN(w2_s_cmd_expt_tx, data, cast); + w2_errcatch_throw_msg(cast->error, cast->length, (char *)cast->message); +} + void w2_cmd_mode_tx(w2_s_bin *data) { W2_CAST_BIN(w2_s_cmd_mode_tx, data, cast); g_w2_state.mode = cast->mode; } void w2_cmd_cord_tx(w2_s_bin *data) {} void w2_cmd_bomd_tx(w2_s_bin *data) {} -void w2_cmd_sens_tx(w2_s_bin *data) {} void w2_cmd_info_tx(w2_s_bin *data) { memcpy(&g_w2_state.info, data->data, sizeof(w2_s_cmd_info_tx)); @@ -46,7 +50,6 @@ void w2_cmd_cord_rx(w2_s_bin *data) { return; } void w2_cmd_bomd_rx(w2_s_bin *data) { return; } void w2_cmd_sres_rx(w2_s_bin *data) { return; } void w2_cmd_mcfg_rx(w2_s_bin *data) { return; } -void w2_cmd_sens_rx(w2_s_bin *data) { return; } void w2_cmd_info_rx(w2_s_bin *data) { return; } void w2_cmd_disp_rx(w2_s_bin *data) { return; } void w2_cmd_play_rx(w2_s_bin *data) { return; } diff --git a/client/serial_win32.c b/client/serial_win32.c index edc9db1..99f4160 100644 --- a/client/serial_win32.c +++ b/client/serial_win32.c @@ -2,20 +2,12 @@ #include "serial.h" -int w2_serial_read() { - return 0x00; -} +int w2_serial_read() { return 0x00; } -bool w2_serial_write(char *data, uint8_t length) { - return true; -} +bool w2_serial_write(char *data, uint8_t length) { return true; } -bool w2_serial_open(const char *port_name) { - return true; -} +bool w2_serial_open(const char *port_name) { return true; } -void w2_serial_close() { - return; -} +void w2_serial_close() { return; } #endif diff --git a/client/setup.c b/client/setup.c index fd37c13..43ed135 100644 --- a/client/setup.c +++ b/client/setup.c @@ -33,12 +33,23 @@ void w2_client_setup(int argc, char **argv) { noecho(); curs_set(false); nodelay(g_w2_ui_win, true); + keypad(g_w2_ui_win, true); w2_strings_init(); w2_cmd_setup_handlers(); + w2_ui_tabbar_init(); w2_send_info(); + g_w2_ui_width = getmaxx(g_w2_ui_win); + g_w2_ui_height = getmaxy(g_w2_ui_win); + + g_w2_ui_pad_tabbar = newpad(1, g_w2_ui_width); + g_w2_ui_pad_body = newpad(g_w2_ui_height - 5, g_w2_ui_width); + g_w2_ui_pad_statusbar = newpad(2, g_w2_ui_width); + g_w2_ui_pad_seperator = newpad(1, g_w2_ui_width + 1); + scrollok(g_w2_ui_pad_body, true); + // check endianness g_w2_endianness = *_ptest; } diff --git a/client/strings.c b/client/strings.c index b97d4b2..1354653 100644 --- a/client/strings.c +++ b/client/strings.c @@ -1,16 +1,93 @@ #include "strings.h" +#include "../shared/errcatch.h" char *g_w2_mode_strings[W2_MODE_COUNT]; +char *g_w2_tab_strings[W2_UI_TAB_COUNT]; +char *g_w2_error_type_strings[4]; +char *g_w2_error_internal_strings[0x100]; +char *g_w2_error_user_strings[0x100]; void w2_strings_modes_init() { g_w2_mode_strings[W2_M_CHRG] = W2_UI_MODE_CHRG; g_w2_mode_strings[W2_M_DIRC] = W2_UI_MODE_DIRC; g_w2_mode_strings[W2_M_GRID] = W2_UI_MODE_GRID; g_w2_mode_strings[W2_M_HALT] = W2_UI_MODE_HALT; - g_w2_mode_strings[W2_M_LCAL] = W2_UI_MODE_LCAL; g_w2_mode_strings[W2_M_MAZE] = W2_UI_MODE_MAZE; g_w2_mode_strings[W2_M_SCAL] = W2_UI_MODE_SCAL; g_w2_mode_strings[W2_M_SPIN] = W2_UI_MODE_SPIN; } -void w2_strings_init() { w2_strings_modes_init(); } +void w2_strings_tabs_init() { + g_w2_tab_strings[W2_UI_TAB_START] = W2_UI_TAB_LABEL_START; + g_w2_tab_strings[W2_UI_TAB_ERRCATCH] = W2_UI_TAB_LABEL_ERRCATCH; + g_w2_tab_strings[W2_UI_TAB_DIRC] = W2_UI_TAB_LABEL_DIRC; + g_w2_tab_strings[W2_UI_TAB_ORDERS] = W2_UI_TAB_LABEL_ORDERS; + g_w2_tab_strings[W2_UI_TAB_MODES] = W2_UI_TAB_LABEL_MODES; +} + +void w2_strings_errors_types() { + g_w2_error_type_strings[0b00] = W2_UI_ERROR_SEVERITY_CRIT; + g_w2_error_type_strings[0b01] = W2_UI_ERROR_SEVERITY_WARN; + g_w2_error_type_strings[0b10] = W2_UI_ERROR_SEVERITY_INFO; + g_w2_error_type_strings[0b11] = W2_UI_ERROR_SEVERITY_VERB; +} + +void w2_strings_errors_internal() { + g_w2_error_internal_strings[W2_E_CRIT_CONN_LOST] = W2_UI_ERROR_INT_W2_E_CRIT_CONN_LOST; + g_w2_error_internal_strings[W2_E_CRIT_COM_UNAVAILABLE] = + W2_UI_ERROR_INT_W2_E_CRIT_COM_UNAVAILABLE; + g_w2_error_internal_strings[W2_E_CRIT_LINE_LOST] = W2_UI_ERROR_INT_W2_E_CRIT_LINE_LOST; + g_w2_error_internal_strings[W2_E_CRIT_OBSTACLE_STUCK] = + W2_UI_ERROR_INT_W2_E_CRIT_OBSTACLE_STUCK; + g_w2_error_internal_strings[W2_E_CRIT_VERSION_INCOMPATIBLE] = + W2_UI_ERROR_INT_W2_E_CRIT_VERSION_INCOMPATIBLE; + g_w2_error_internal_strings[W2_E_WARN_BATTERY_LOW] = W2_UI_ERROR_INT_W2_E_WARN_BATTERY_LOW; + g_w2_error_internal_strings[W2_E_WARN_OBSTACLE_DETECTED] = + W2_UI_ERROR_INT_W2_E_WARN_OBSTACLE_DETECTED; + g_w2_error_internal_strings[W2_E_WARN_CYCLE_EXPIRED] = W2_UI_ERROR_INT_W2_E_WARN_CYCLE_EXPIRED; + g_w2_error_internal_strings[W2_E_WARN_UNCAUGHT_ERROR] = + W2_UI_ERROR_INT_W2_E_WARN_UNCAUGHT_ERROR; + g_w2_error_internal_strings[W2_E_WARN_ERR_BUFFER_FULL] = + W2_UI_ERROR_INT_W2_E_WARN_ERR_BUFFER_FULL; + g_w2_error_internal_strings[W2_E_WARN_LINE_LOST] = W2_UI_ERROR_INT_W2_E_WARN_LINE_LOST; + g_w2_error_internal_strings[W2_E_WARN_SERCOMM_BUFFER_FULL] = + W2_UI_ERROR_INT_W2_E_WARN_SERCOMM_BUFFER_FULL; + g_w2_error_internal_strings[W2_E_WARN_VERSION_INCOMPATIBLE] = + W2_UI_ERROR_INT_W2_E_WARN_VERSION_INCOMPATIBLE; + g_w2_error_internal_strings[W2_E_WARN_SERIAL_NOISY] = W2_UI_ERROR_INT_W2_E_WARN_SERIAL_NOISY; + g_w2_error_internal_strings[W2_E_WARN_MODE_HISTORY_BUFFER_IOB] = + W2_UI_ERROR_INT_W2_E_WARN_MODE_HISTORY_BUFFER_IOB; + g_w2_error_internal_strings[W2_E_WARN_PING_TIMEOUT] = W2_UI_ERROR_INT_W2_E_WARN_PING_TIMEOUT; +} + +void w2_strings_errors_user() { + g_w2_error_user_strings[W2_E_CRIT_CONN_LOST] = W2_UI_ERROR_USR_W2_E_CRIT_CONN_LOST; + g_w2_error_user_strings[W2_E_CRIT_COM_UNAVAILABLE] = W2_UI_ERROR_USR_W2_E_CRIT_COM_UNAVAILABLE; + g_w2_error_user_strings[W2_E_CRIT_LINE_LOST] = W2_UI_ERROR_USR_W2_E_CRIT_LINE_LOST; + g_w2_error_user_strings[W2_E_CRIT_OBSTACLE_STUCK] = W2_UI_ERROR_USR_W2_E_CRIT_OBSTACLE_STUCK; + g_w2_error_user_strings[W2_E_CRIT_VERSION_INCOMPATIBLE] = + W2_UI_ERROR_USR_W2_E_CRIT_VERSION_INCOMPATIBLE; + g_w2_error_user_strings[W2_E_WARN_BATTERY_LOW] = W2_UI_ERROR_USR_W2_E_WARN_BATTERY_LOW; + g_w2_error_user_strings[W2_E_WARN_OBSTACLE_DETECTED] = + W2_UI_ERROR_USR_W2_E_WARN_OBSTACLE_DETECTED; + g_w2_error_user_strings[W2_E_WARN_CYCLE_EXPIRED] = W2_UI_ERROR_USR_W2_E_WARN_CYCLE_EXPIRED; + g_w2_error_user_strings[W2_E_WARN_UNCAUGHT_ERROR] = W2_UI_ERROR_USR_W2_E_WARN_UNCAUGHT_ERROR; + g_w2_error_user_strings[W2_E_WARN_ERR_BUFFER_FULL] = W2_UI_ERROR_USR_W2_E_WARN_ERR_BUFFER_FULL; + g_w2_error_user_strings[W2_E_WARN_LINE_LOST] = W2_UI_ERROR_USR_W2_E_WARN_LINE_LOST; + g_w2_error_user_strings[W2_E_WARN_SERCOMM_BUFFER_FULL] = + W2_UI_ERROR_USR_W2_E_WARN_SERCOMM_BUFFER_FULL; + g_w2_error_user_strings[W2_E_WARN_VERSION_INCOMPATIBLE] = + W2_UI_ERROR_USR_W2_E_WARN_VERSION_INCOMPATIBLE; + g_w2_error_user_strings[W2_E_WARN_SERIAL_NOISY] = W2_UI_ERROR_USR_W2_E_WARN_SERIAL_NOISY; + g_w2_error_user_strings[W2_E_WARN_MODE_HISTORY_BUFFER_IOB] = + W2_UI_ERROR_USR_W2_E_WARN_MODE_HISTORY_BUFFER_IOB; + g_w2_error_user_strings[W2_E_WARN_PING_TIMEOUT] = W2_UI_ERROR_USR_W2_E_WARN_PING_TIMEOUT; +} + +void w2_strings_init() { + w2_strings_errors_types(); + w2_strings_errors_internal(); + w2_strings_errors_user(); + w2_strings_modes_init(); + w2_strings_tabs_init(); +} diff --git a/client/strings.h b/client/strings.h index 0085228..5d20b8e 100644 --- a/client/strings.h +++ b/client/strings.h @@ -2,9 +2,12 @@ #include "../shared/modes.h" #include "i18n.h" - -#define W2_STRINGS_MODE_MAP_BUFFER_SIZE 32 +#include "ui.h" extern char *g_w2_mode_strings[W2_MODE_COUNT]; +extern char *g_w2_tab_strings[W2_UI_TAB_COUNT]; +extern char *g_w2_error_type_strings[4]; +extern char *g_w2_error_internal_strings[0x100]; +extern char *g_w2_error_user_strings[0x100]; void w2_strings_init(); diff --git a/client/time_windows.c b/client/time_windows.c index f9082d6..76d1879 100644 --- a/client/time_windows.c +++ b/client/time_windows.c @@ -2,9 +2,7 @@ #include "time.h" -unsigned long w2_get_time() { - return 0; -} +unsigned long w2_get_time() { return 0; } void w2_timer_start(w2_e_client_timers label) { g_w2_client_timers[label] = w2_get_time(); } diff --git a/client/ui.c b/client/ui.c index f636501..cdf2f3b 100644 --- a/client/ui.c +++ b/client/ui.c @@ -11,61 +11,94 @@ #include "ui.h" WINDOW *g_w2_ui_win; -unsigned int g_w2_ui_width = 0; -unsigned int g_w2_ui_height = 0; -void (*g_w2_ui_current_tab)(bool first) = &w2_ui_dirc; -void (*g_w2_ui_last_tab)(bool first) = NULL; +WINDOW *g_w2_ui_pad_tabbar; +WINDOW *g_w2_ui_pad_statusbar; +WINDOW *g_w2_ui_pad_seperator; +WINDOW *g_w2_ui_pad_body; +int g_w2_ui_pad_body_scroll = 0; +unsigned int g_w2_ui_width = 0; +unsigned int g_w2_ui_height = 0; +w2_e_ui_tabs g_w2_ui_current_tab = W2_UI_TAB_START; +w2_e_ui_tabs g_w2_ui_last_tab; + +void w2_wmvaddstr(WINDOW *win, unsigned int y, unsigned int x, char *str) { + wmove(win, y, x); + waddstr(win, str); +} + +void w2_wmvaddnstr(WINDOW *win, unsigned int y, unsigned int x, char *str, unsigned int len) { + wmove(win, y, x); + waddnstr(win, str, len); +} + +void w2_ui_switch_tab(w2_e_ui_tabs next_tab) { + g_w2_ui_current_tab = next_tab % W2_UI_TAB_COUNT; + wclear(g_w2_ui_pad_body); + curs_set(false); +} + +void w2_ui_key_handler() { + int ch; + void (*current_mode_key_handler)() = g_w2_keyhndl_ptrs[g_w2_ui_current_tab]; + while ((ch = getch()) != -1) { + if (ch == '\t') + w2_ui_switch_tab(g_w2_ui_current_tab + 1); + else if (current_mode_key_handler != NULL) + (*current_mode_key_handler)(ch); + } +} void w2_ui_main() { g_w2_ui_width = getmaxx(g_w2_ui_win); g_w2_ui_height = getmaxy(g_w2_ui_win); + w2_ui_key_handler(); w2_ui_paint(); } void w2_ui_paint() { w2_ui_paint_statusbar(); + w2_ui_paint_tabbar(); + w2_ui_paint_seperator(); if (w2_timer_end(W2_TIMER_UPDATE) >= (1000 / W2_UI_UPDATE_FPS)) { - (*g_w2_ui_current_tab)(g_w2_ui_last_tab != g_w2_ui_current_tab); + (*g_w2_tab_ptrs[g_w2_ui_current_tab])(g_w2_ui_last_tab != g_w2_ui_current_tab); g_w2_ui_last_tab = g_w2_ui_current_tab; w2_timer_start(W2_TIMER_UPDATE); } - refresh(); + prefresh(g_w2_ui_pad_statusbar, 0, 0, 0, 0, 1, g_w2_ui_width - 1); + prefresh(g_w2_ui_pad_tabbar, 0, 0, 2, 0, 2, g_w2_ui_width - 1); + prefresh(g_w2_ui_pad_seperator, 0, 0, 3, 0, 3, g_w2_ui_width - 1); + prefresh(g_w2_ui_pad_body, W2_MAX(0, g_w2_ui_pad_body_scroll), 0, + 4 - W2_MIN(0, g_w2_ui_pad_body_scroll), 0, g_w2_ui_height - 2, g_w2_ui_width - 1); } void w2_ui_paint_statusbar() { char temp[g_w2_ui_width]; - for (unsigned int i = 0; i < g_w2_ui_width; i++) temp[i] = ' '; - mvaddnstr(0, 0, temp, g_w2_ui_width); - mvaddnstr(1, 0, temp, g_w2_ui_width); - mvaddnstr(2, 0, temp, g_w2_ui_width); + for (int i = 0; i < g_w2_ui_width; i++) temp[i] = ' '; + w2_wmvaddnstr(g_w2_ui_pad_statusbar, 0, 0, temp, g_w2_ui_width); + w2_wmvaddnstr(g_w2_ui_pad_statusbar, 1, 0, temp, g_w2_ui_width); - g_w2_state.connected - ? sprintf(temp, W2_UI_CONN_STAT_CONNECTED ", %ims %s", g_w2_state.ping, W2_UI_CONN_STAT_PING) - : sprintf(temp, W2_UI_CONN_STAT_DISCONNECTED); - mvaddstr(0, 0, temp); + g_w2_state.connected ? sprintf(temp, W2_UI_CONN_STAT_CONNECTED ", %ims %s", g_w2_state.ping, + W2_UI_CONN_STAT_PING) + : sprintf(temp, W2_UI_CONN_STAT_DISCONNECTED); + w2_wmvaddstr(g_w2_ui_pad_statusbar, 0, 0, temp); sprintf(temp, "(%s)", g_w2_state.info.build_str); - mvaddstr(0, g_w2_ui_width / 2 - strlen(temp) / 2, temp); + w2_wmvaddstr(g_w2_ui_pad_statusbar, 0, g_w2_ui_width / 2 - strlen(temp) / 2, temp); sprintf(temp, "%s %i%%", W2_UI_BATT_STAT_BATTERY, g_w2_state.battery_level); - mvaddstr(0, g_w2_ui_width - strlen(temp), temp); + w2_wmvaddstr(g_w2_ui_pad_statusbar, 0, g_w2_ui_width - strlen(temp), temp); sprintf(temp, "[%s]", g_w2_mode_strings[g_w2_state.mode]); - mvaddstr(1, 0, temp); + w2_wmvaddstr(g_w2_ui_pad_statusbar, 1, 0, temp); sprintf(temp, "%i %s, %i %s", 0, W2_UI_EXPT_STAT_WARNINGS, 0, W2_UI_EXPT_STAT_ERRORS); - mvaddstr(1, g_w2_ui_width - strlen(temp), temp); - - w2_ui_paint_tabbar(); - - for (unsigned int i = 0; i < g_w2_ui_width; i++) temp[i] = '-'; - mvaddnstr(3, 0, temp, g_w2_ui_width); + w2_wmvaddstr(g_w2_ui_pad_statusbar, 1, g_w2_ui_width - strlen(temp), temp); } -void w2_ui_paint_tabbar() { +void w2_ui_paint_seperator() { char temp[g_w2_ui_width]; - sprintf(temp, "-- tab bar here --"); - mvaddstr(2, g_w2_ui_width / 2 - strlen(temp) / 2, temp); + for (unsigned int i = 0; i < g_w2_ui_width; i++) temp[i] = '-'; + w2_wmvaddnstr(g_w2_ui_pad_seperator, 0, 0, temp, g_w2_ui_width - 1); } diff --git a/client/ui.h b/client/ui.h index 0d375de..c169401 100644 --- a/client/ui.h +++ b/client/ui.h @@ -3,12 +3,34 @@ #include <ncurses.h> #include <stdint.h> -#define W2_UI_UPDATE_FPS (60) +#define W2_UI_UPDATE_FPS 60 +/** order tab current command buffer (char[]) */ +#define W2_UI_ORDER_CMD_BUFFER_SIZE 80 +/** order tab current command buffer (uint16_t[]) */ +#define W2_UI_ORDER_BUFFER_SIZE 16 + +#define W2_UI_TAB_COUNT 5 +typedef enum { + W2_UI_TAB_START = 0, + W2_UI_TAB_ERRCATCH = 1, + W2_UI_TAB_DIRC = 2, + W2_UI_TAB_ORDERS = 3, + W2_UI_TAB_MODES = 4, +} w2_e_ui_tabs; extern WINDOW *g_w2_ui_win; +extern WINDOW *g_w2_ui_pad_tabbar; +extern WINDOW *g_w2_ui_pad_statusbar; +extern WINDOW *g_w2_ui_pad_seperator; +extern WINDOW *g_w2_ui_pad_body; +extern int g_w2_ui_pad_body_scroll; extern unsigned int g_w2_ui_width; extern unsigned int g_w2_ui_height; -extern void (*g_w2_ui_current_tab)(bool first); +extern void (*g_w2_tab_ptrs[W2_UI_TAB_COUNT])(bool first); +extern void (*g_w2_keyhndl_ptrs[W2_UI_TAB_COUNT])(int key); +extern w2_e_ui_tabs g_w2_ui_current_tab; + +void w2_ui_switch_tab(w2_e_ui_tabs next_tab); /** update terminal props */ void w2_ui_update(); @@ -23,5 +45,20 @@ void w2_ui_main(); void w2_ui_paint_statusbar(); /** draw tab bar */ void w2_ui_paint_tabbar(); +/** draw seperator under tab bar */ +void w2_ui_paint_seperator(); + +void w2_ui_tabbar_init(); + +void w2_ui_tab_dirc(bool first); +void w2_ui_tab_start(bool first); +void w2_ui_tab_errcatch(bool first); +void w2_ui_tab_modes(bool first); +void w2_ui_tab_orders(bool first); +void w2_ui_onkey_dirc(int ch); +void w2_ui_onkey_errcatch(int ch); +void w2_ui_onkey_modes(int ch); +void w2_ui_onkey_orders(int ch); -void w2_ui_dirc(bool first); +void w2_wmvaddstr(WINDOW *win, unsigned int y, unsigned int x, char *str); +void w2_wmvaddnstr(WINDOW *win, unsigned int y, unsigned int x, char *str, unsigned int len); diff --git a/client/ui_dirc.c b/client/ui_dirc.c index ed69cd2..db91661 100644 --- a/client/ui_dirc.c +++ b/client/ui_dirc.c @@ -1,8 +1,14 @@ #include "../shared/protocol.h" #include "../shared/util.h" #include "commands.h" +#include "errcatch.h" #include "ui.h" +unsigned int g_w2_lb = 0; +unsigned int g_w2_lf = 0; +unsigned int g_w2_rb = 0; +unsigned int g_w2_rf = 0; + /** decay modifier */ #define W2_DIRC_MOD ((double)0.95) /** add value per key press */ @@ -50,7 +56,7 @@ void w2_ui_bar_graph(unsigned int y, unsigned int x, unsigned int width, double temp[width - 1] = '|'; for (unsigned int i = 0; i < width - 2; i++) temp[i + 1] = i < width * value ? '*' : ' '; - mvaddnstr(y, x, temp, width); + w2_wmvaddnstr(g_w2_ui_pad_body, y, x, temp, width); } void w2_ui_bar_graph_pm(unsigned int y, unsigned int x, unsigned int width, double value) { @@ -67,46 +73,48 @@ void w2_ui_bar_graph_pm(unsigned int y, unsigned int x, unsigned int width, doub temp[i + 1] = i > hw ? ' ' : (hw - i) < -(hw * value) ? '*' : ' '; } - mvaddnstr(y, x, temp, width + 2); + w2_wmvaddnstr(g_w2_ui_pad_body, y, x, temp, width + 2); } void w2_ui_dirc_paint(int left, int right) { - mvaddstr(4, 0, "left drive: "); - w2_ui_bar_graph_pm(4, 13, g_w2_ui_width - 13, (double)left / 255); - mvaddstr(5, 0, "right drive: "); - w2_ui_bar_graph_pm(5, 13, g_w2_ui_width - 13, (double)right / 255); - - mvaddstr(7, 0, - " controls:\n" - "\n" - " <q> <w> <e> forward\n" - " <a> <s> <d> backward\n" - "left both right\n" - "\n" - "<space> send dirc mode command"); + w2_wmvaddstr(g_w2_ui_pad_body, 0, 0, "left drive: "); + w2_ui_bar_graph_pm(0, 13, g_w2_ui_width - 13, (double)left / 255); + w2_wmvaddstr(g_w2_ui_pad_body, 1, 0, "right drive: "); + w2_ui_bar_graph_pm(1, 13, g_w2_ui_width - 13, (double)right / 255); + + w2_wmvaddstr(g_w2_ui_pad_body, 3, 0, + " controls:\n" + "\n" + " <q> <w> <e> forward\n" + " <a> <s> <d> backward\n" + "left both right\n" + "\n" + "<space> send dirc mode command"); +} + +void w2_ui_onkey_dirc(int ch) { + if (ch == 'e' || ch == 'w') g_w2_lf++; + if (ch == 'd' || ch == 's') g_w2_lb++; + if (ch == 'q' || ch == 'w') g_w2_rf++; + if (ch == 'a' || ch == 's') g_w2_rb++; + if (ch == ' ') w2_send_mode(W2_M_DIRC); } -void w2_ui_dirc(bool first) { +void w2_ui_tab_dirc(bool first) { + g_w2_ui_pad_body_scroll = 0; if (first) w2_ui_dirc_init(); - int ch = 0; - unsigned int lb = 0; - unsigned int lf = 0; - unsigned int rb = 0; - unsigned int rf = 0; - while ((ch = getch()) != -1) { - if (ch == 'e' || ch == 'w') lf++; - if (ch == 'd' || ch == 's') lb++; - if (ch == 'q' || ch == 'w') rf++; - if (ch == 'a' || ch == 's') rb++; - if (ch == ' ') w2_send_mode(W2_M_DIRC); - } - int drive_l = w2_dirc_motor_l(lf, lb); - int drive_r = w2_dirc_motor_r(rf, rb); + int drive_l = w2_dirc_motor_l(g_w2_lf, g_w2_lb); + int drive_r = w2_dirc_motor_r(g_w2_rf, g_w2_rb); drive_l += drive_r * W2_DIRC_STP; drive_r += drive_l * W2_DIRC_STP; w2_send_dirc(drive_l, drive_r); w2_ui_dirc_paint(drive_l, drive_r); + + g_w2_lb = 0; + g_w2_lf = 0; + g_w2_rb = 0; + g_w2_rf = 0; } diff --git a/client/ui_errcatch.c b/client/ui_errcatch.c new file mode 100644 index 0000000..5d5365f --- /dev/null +++ b/client/ui_errcatch.c @@ -0,0 +1,49 @@ +#include <stdlib.h> +#include <string.h> + +#include "../shared/util.h" +#include "errcatch.h" +#include "i18n.h" +#include "strings.h" +#include "ui.h" + +unsigned int g_w2_errcatch_log_line = 0; + +char *w2_err_format(w2_s_error *error) { + const char *type = g_w2_error_type_strings[error->code >> 6]; + const char *internal = g_w2_error_internal_strings[error->code]; + const char *user = g_w2_error_user_strings[error->code]; + if (internal == NULL || user == NULL) { + internal = W2_UI_ERROR_INT_W2_E_UNKNOWN; + user = W2_UI_ERROR_USR_W2_E_UNKNOWN; + } + size_t errdesc_len = strlen(type) + strlen(internal) + strlen(user) + 8; + size_t msg_indent = strlen(type) + 3; + char *ret_str = malloc( + errdesc_len + (error->message_length > 0 ? error->message_length + msg_indent : 0) + 1); + sprintf(ret_str, "[%s] %02x#%s: %s", type, error->code, internal, user); + if (error->message_length > 0) { + sprintf(ret_str + errdesc_len, "\n%*c%s", (int)msg_indent, ' ', error->message); + g_w2_errcatch_log_line += 1 + w2_newline_count(error->message, error->message_length); + } + return ret_str; +} + +void w2_ui_onkey_errcatch(int ch) {} + +void w2_ui_tab_errcatch(bool first) { + g_w2_errcatch_log_line = 0; + g_w2_ui_pad_body_scroll = 5 - g_w2_ui_height; + for (unsigned int x = 0; x < W2_ERRCATCH_LOG_SIZE; x++) { + unsigned int i = (x + g_w2_error_log_index) % W2_ERRCATCH_LOG_SIZE; + if (g_w2_error_log[i] == NULL) continue; + + wmove(g_w2_ui_pad_body, g_w2_errcatch_log_line, 0); + char *err_str = w2_err_format(g_w2_error_log[i]); + waddstr(g_w2_ui_pad_body, err_str); + free(err_str); + + g_w2_errcatch_log_line++; + } + g_w2_ui_pad_body_scroll += g_w2_errcatch_log_line; +} diff --git a/client/ui_modes.c b/client/ui_modes.c new file mode 100644 index 0000000..3048ba9 --- /dev/null +++ b/client/ui_modes.c @@ -0,0 +1,16 @@ +#include "commands.h" +#include "i18n.h" +#include "ui.h" + +void w2_ui_onkey_modes(int ch) { + if (ch == '1') w2_send_mode(W2_M_MAZE); + if (ch == '2') w2_send_mode(W2_M_GRID); + if (ch == '3') w2_send_mode(W2_M_HALT); + if (ch == '4') w2_send_mode(W2_M_CHRG); + if (ch == '5') w2_send_mode(W2_M_SPIN); + if (ch == '6') w2_send_mode(W2_M_SCAL); + + if (ch == '0') w2_send_mode(W2_M_PREV); +} + +void w2_ui_tab_modes(bool first) { w2_wmvaddstr(g_w2_ui_pad_body, 0, 0, W2_UI_MODES_INFO); } diff --git a/client/ui_orders.c b/client/ui_orders.c new file mode 100644 index 0000000..6c5de27 --- /dev/null +++ b/client/ui_orders.c @@ -0,0 +1,112 @@ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "../shared/bin.h" +#include "../shared/protocol.h" +#include "../shared/util.h" +#include "commands.h" +#include "errcatch.h" +#include "i18n.h" +#include "main.h" +#include "ui.h" + +#define W2_IS_CMD(cmd) strncmp(g_w2_command_buffer, cmd, sizeof(cmd) - 1) == 0 +#define W2_UI_ORDERS_PRINT_CONST(text) \ + w2_wmvaddstr(g_w2_ui_pad_body, g_w2_order_line, 0, text); \ + g_w2_order_line += w2_newline_count(text, sizeof(text)); + +char g_w2_command_buffer[W2_UI_ORDER_CMD_BUFFER_SIZE] = {0x00}; +int g_w2_command_buffer_index = 0; +int g_w2_order_line = 0; +bool g_w2_order_recording = false; +bool g_w2_order_saved = false; +uint16_t g_w2_order_buffer[W2_UI_ORDER_BUFFER_SIZE] = {0}; +int g_w2_order_buffer_index = 0; + +void w2_ui_orders_cmd_error() { W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ERROR); } + +void w2_ui_orders_cmd_help() { W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_HELP); } + +void w2_ui_orders_cmd_start() { + if (g_w2_order_recording) { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_START_ERR); + } else { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_START_OK); + g_w2_order_buffer_index = 0; + } + g_w2_order_recording = true; +} + +void w2_ui_orders_cmd_coordinate() { + if (!g_w2_order_recording) { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_APPEND_ERR); + return; + } + unsigned int x, y; + if (sscanf(g_w2_command_buffer, W2_UI_ORDER_CMD_COORDINATE " %u %u", &x, &y) != 2) + return w2_ui_orders_cmd_error(); + g_w2_order_buffer[g_w2_order_buffer_index++] = y * g_w2_state.map_width + x; + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_APPEND_OK); +} + +void w2_ui_orders_cmd_done() { + if (g_w2_order_recording) { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_DONE_OK); + } else { + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_DONE_ERR); + } + g_w2_order_saved = true; + g_w2_order_recording = false; +} + +void w2_ui_orders_cmd_send() { + for (int i = 0; i < g_w2_order_buffer_index; i++) { + W2_CREATE_MSG_BIN(w2_s_cmd_bomd_rx, msg, bin); + + msg->position = w2_bin_hton16(g_w2_order_buffer[i]); + msg->id = rand(); + + w2_send_bin(bin); + free(bin); + } + W2_UI_ORDERS_PRINT_CONST(W2_UI_ORDER_MSG_ORDER_SENT); +} + +void w2_ui_orders_process_cmd() { + if (g_w2_command_buffer_index == 0) return w2_ui_orders_cmd_error(); + if (W2_IS_CMD(W2_UI_ORDER_CMD_HELP)) return w2_ui_orders_cmd_help(); + if (W2_IS_CMD(W2_UI_ORDER_CMD_START)) return w2_ui_orders_cmd_start(); + if (W2_IS_CMD(W2_UI_ORDER_CMD_COORDINATE)) return w2_ui_orders_cmd_coordinate(); + if (W2_IS_CMD(W2_UI_ORDER_CMD_DONE)) return w2_ui_orders_cmd_done(); + if (W2_IS_CMD(W2_UI_ORDER_CMD_SEND)) return w2_ui_orders_cmd_send(); + return w2_ui_orders_cmd_error(); +} + +void w2_ui_onkey_orders(int ch) { + if (ch >= 'A' && ch <= 'Z') ch += 0x20; // convert uppercase to lowercase + if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || (ch == ' ')) { + g_w2_command_buffer[g_w2_command_buffer_index] = ch; + g_w2_command_buffer_index = + W2_MIN(g_w2_command_buffer_index + 1, W2_UI_ORDER_CMD_BUFFER_SIZE - 1); + } else if (ch == KEY_BACKSPACE) { + g_w2_command_buffer_index = W2_MAX(g_w2_command_buffer_index - 1, 0); + g_w2_command_buffer[g_w2_command_buffer_index] = 0x00; + } else if (ch == 0x0a) { + // clear cursor + wmove(g_w2_ui_pad_body, g_w2_order_line, g_w2_command_buffer_index + 2); + waddstr(g_w2_ui_pad_body, " "); + + g_w2_order_line += 1; + w2_ui_orders_process_cmd(); + memset(g_w2_command_buffer, 0x00, W2_UI_ORDER_CMD_BUFFER_SIZE); + g_w2_command_buffer_index = 0; + } +} + +void w2_ui_tab_orders(bool first) { + if (first) g_w2_order_line = 0; + char temp[100]; + sprintf(temp, "> %s_ ", g_w2_command_buffer); + w2_wmvaddstr(g_w2_ui_pad_body, g_w2_order_line, 0, temp); +} diff --git a/client/ui_start.c b/client/ui_start.c new file mode 100644 index 0000000..118bc01 --- /dev/null +++ b/client/ui_start.c @@ -0,0 +1,8 @@ +#include "i18n.h" +#include "ui.h" + +void w2_ui_tab_start(bool first) { + g_w2_ui_pad_body_scroll = 0; + refresh(); + w2_wmvaddstr(g_w2_ui_pad_body, 0, 0, W2_UI_TAB_START_MESSAGE); +} diff --git a/client/ui_tabbar.c b/client/ui_tabbar.c new file mode 100644 index 0000000..637d2f3 --- /dev/null +++ b/client/ui_tabbar.c @@ -0,0 +1,33 @@ +#include <stdlib.h> +#include <string.h> + +#include "strings.h" +#include "ui.h" + +unsigned int g_w2_ui_tabbar_scroll = 0; +unsigned int g_w2_ui_tabbar_lengths[W2_UI_TAB_COUNT]; +void (*g_w2_tab_ptrs[W2_UI_TAB_COUNT])(bool first); +void (*g_w2_keyhndl_ptrs[W2_UI_TAB_COUNT])(int key); + +void w2_ui_tabbar_init() { + g_w2_tab_ptrs[W2_UI_TAB_START] = &w2_ui_tab_start; + g_w2_tab_ptrs[W2_UI_TAB_ERRCATCH] = &w2_ui_tab_errcatch; + g_w2_keyhndl_ptrs[W2_UI_TAB_START] = &w2_ui_onkey_errcatch; + g_w2_tab_ptrs[W2_UI_TAB_DIRC] = &w2_ui_tab_dirc; + g_w2_keyhndl_ptrs[W2_UI_TAB_DIRC] = &w2_ui_onkey_dirc; + g_w2_tab_ptrs[W2_UI_TAB_ORDERS] = &w2_ui_tab_orders; + g_w2_keyhndl_ptrs[W2_UI_TAB_ORDERS] = &w2_ui_onkey_orders; + g_w2_tab_ptrs[W2_UI_TAB_MODES] = &w2_ui_tab_modes; + g_w2_keyhndl_ptrs[W2_UI_TAB_MODES] = &w2_ui_onkey_modes; +} + +void w2_ui_paint_tabbar() { + wmove(g_w2_ui_pad_tabbar, 0, 0); + for (unsigned int i = 0; i < W2_UI_TAB_COUNT; i++) { + g_w2_ui_tabbar_lengths[i] += 2 + strlen(g_w2_tab_strings[i]); + + wprintw(g_w2_ui_pad_tabbar, " %c%s%c", g_w2_ui_current_tab == i ? '[' : ' ', + g_w2_tab_strings[i], g_w2_ui_current_tab == i ? ']' : ' '); + } + wprintw(g_w2_ui_pad_tabbar, " "); +} |