/* * Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic * * Xurses is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation. * And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version. * It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3. */ #ifndef XURSES_SOURCE #define XURSES_SOURCE #include int curses_active = 1; int curses_cursor = 0; char curses_signal = '\0'; int curses_screen_width = 0; int curses_screen_height = 0; int curses_screen_size = 0; char * curses_screen = NULL; char curses_format [CURSES_LENGTH + 1] = "\033[-;3-m-\033[0m"; void (* curses_action ['~' - ' ' + 1]) (void) = { 0 }; struct termios curses_old_terminal; struct termios curses_new_terminal; void curses_initialize (void) { struct winsize screen_dimension; char i = 0; fatal_failure (ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension) == -1, "ioctl: Failed to get terminal dimensions."); curses_screen_width = (int) screen_dimension.ws_col; curses_screen_height = (int) screen_dimension.ws_row; fatal_failure (tcgetattr (STDIN_FILENO, & curses_old_terminal) == -1, "tcgetattr: Failed to get default terminal attributes."); curses_new_terminal = curses_old_terminal; curses_new_terminal.c_cc [VMIN] = (unsigned char) 0; curses_new_terminal.c_cc [VTIME] = (unsigned char) 1; curses_new_terminal.c_iflag &= (unsigned int) ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); curses_new_terminal.c_oflag &= (unsigned int) ~(OPOST); curses_new_terminal.c_cflag |= (unsigned int) (CS8); curses_new_terminal.c_lflag &= (unsigned int) ~(ECHO | ICANON | IEXTEN | ISIG); fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_new_terminal) == -1, "tcsetattr: Failed to set reverse terminal attributes."); curses_screen = allocate (CURSES_OFFSET + CURSES_LENGTH * curses_screen_width * curses_screen_height + (curses_screen_height - 1) * CURSES_RETURN + 1); for (i = ' '; i != '~'; ++i) { curses_unbind ((char) i); } terminal_clear (); curses_screen_offset (); for (i = 0; i != curses_screen_height - 1; ++i) { string_copy_limit (& curses_screen [CURSES_LENGTH * curses_screen_width * i + CURSES_OFFSET], "\r\n", string_length ("\r\n")); } } void curses_deinitialize (void) { curses_screen = deallocate (curses_screen); terminal_clear (); fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_old_terminal) == -1, "tcsetattr: Failed to set default terminal attributes."); } void curses_synchronize (void) { curses_signal = '\0'; /* out (curses_screen, curses_screen_size); */ out (curses_screen, CURSES_OFFSET + CURSES_LENGTH * curses_screen_width * curses_screen_height); in (& curses_signal, 1); if ((curses_signal >= ' ') && (curses_signal <= '~')) { curses_action [curses_signal - ' '] (); } curses_screen_offset (); } void curses_screen_offset (void) { string_copy_limit (& curses_screen [0], "\033[H", CURSES_OFFSET); curses_screen_size = CURSES_OFFSET; } char * curses_screen_position (int x, int y) { fatal_failure (x <= -1, "curses_screen_position: X position is beyond the lower bound."); fatal_failure (y <= -1, "curses_screen_position: Y position is beyond the lower bound."); fatal_failure (x >= curses_screen_width, "curses_screen_position: X position is beyond the upper bound."); fatal_failure (y >= curses_screen_height, "curses_screen_position: Y position is beyond the upper bound."); return (& curses_screen [CURSES_LENGTH * (y * curses_screen_width + x) + y * CURSES_RETURN + CURSES_OFFSET]); } char * curses_format_character (char character, int colour, int effect) { fatal_failure (character_is_invisible (character), "curses_format_character: Can not format invisible characters."); fatal_failure (colour >= COLOUR_COUNT, "curses_format_character: Colour is invalid enumeration value."); fatal_failure (effect >= EFFECT_COUNT, "curses_format_character: Effect is invalid enumeration value."); curses_format [2] = (char) effect + '0'; curses_format [5] = (char) colour + '0'; curses_format [7] = character; return (curses_format); } void curses_output_character (char character, int colour, int effect) { out (curses_format_character (character, colour, effect), CURSES_LENGTH); } void curses_render_character (char character, int colour, int effect, int x, int y) { string_copy_limit (curses_screen_position (x, y), curses_format_character (character, colour, effect), CURSES_LENGTH); curses_screen_size += CURSES_LENGTH; } /* void curses_output_string (char * string, int colour, int effect) { char format [8] = "\033[ ;3 m"; format [2] = (char) effect + '0'; format [5] = (char) colour + '0'; string_copy_limit (& curses_screen [curses_screen_size], format, 7); string_copy_limit (& curses_screen [curses_screen_size], string, string_length (string)); string_copy_limit (& curses_screen [curses_screen_size], "\033[0m", 4); curses_screen_size += 7 + string_length (string) + 4; } void curses_render_string (char * string, int colour, int effect, int x, int y) { int offset = 0; int length = string_length (string); for (offset = 0; offset != length; (++offset, ++x)) { curses_render_character (string [offset], colour, effect, x, y); } } void curses_append_cursor (int cursor_x, int cursor_y) { char format [11] = "\033[000;000H"; format [4] = (char) (cursor_y / 1) % 10 + '0'; format [3] = (char) (cursor_y / 10) % 10 + '0'; format [2] = (char) (cursor_y / 100) % 10 + '0'; format [8] = (char) (cursor_x / 1) % 10 + '0'; format [7] = (char) (cursor_x / 10) % 10 + '0'; format [6] = (char) (cursor_x / 100) % 10 + '0'; string_copy_limit (& curses_screen [curses_screen_size], format, 10); curses_screen_size += 10; } */ void curses_blank (void) { int i, j; for (i = 0; i != curses_screen_height; ++i) { for (j = 0; j != curses_screen_width; ++j) { curses_render_character (' ', EFFECT_NORMAL, COLOUR_WHITE, j, i); } } } void curses_bind (char key, void (* action) (void)) { curses_action [key - ' '] = action; } void curses_unbind (char key) { curses_action [key - ' '] = curses_idle; } void curses_idle (void) { return; } void curses_exit (void) { curses_active = 0; } #endif