|
|
@@ -195,7 +195,7 @@ static void curses_exit (void) { curses_active = 0; } // And this is our main fu |
|
|
|
|
|
|
|
static void curses_initialize (void) { // This function will be called when 'curses_configure' is called, automatically. |
|
|
|
struct winsize screen_dimension; // We need this ugly structure for our 'ioctl' function to get the dimensions. |
|
|
|
int screen_memory; // And you can use local variables to shorten some lines of code if you want. |
|
|
|
int screen_memory, lines; // And you can use local variables to shorten some lines of code if you want. |
|
|
|
|
|
|
|
fatal_failure (ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension) == -1, // If function 'ioctl' failed, we immediately aborting the entire program. |
|
|
|
"ioctl: Failed to get terminal dimensions."); // I split those error messages, you can find your own formatting style. |
|
|
@@ -220,13 +220,20 @@ static void curses_initialize (void) { |
|
|
|
"tcsetattr: Failed to set reverse terminal attributes."); |
|
|
|
|
|
|
|
screen_memory = CURSES_FORMAT * curses_screen_width * curses_screen_height; // This is square area of our terminal, and multiplied by 12, size of FORMAT. |
|
|
|
lines = (curses_screen_height - 1) * 2; // This is size of line feed and carriage return to avoid word-wrapping. |
|
|
|
|
|
|
|
curses_screen = allocate (CURSES_REVERT + screen_memory + CURSES_CURSOR + 1); // We're requesting new memory for framebuffer. |
|
|
|
curses_screen = allocate (CURSES_REVERT + screen_memory + lines + CURSES_CURSOR + 1); // We're requesting new memory for framebuffer. |
|
|
|
|
|
|
|
curses_bind (SIGNAL_ESCAPE, curses_exit); // Binding universal exit key (signal). |
|
|
|
|
|
|
|
string_copy (& curses_screen [0], "\033[H"); // ASCII black magic to always clear screen. |
|
|
|
|
|
|
|
for (lines = 1; lines < curses_screen_height; ++lines) { // Now it's time to put forced line breaks in raw terminal, without the last one. |
|
|
|
int skip = CURSES_REVERT + 2 * (lines - 1); // We skip first 3 bytes and previously copied amount of line breaks. |
|
|
|
int next = lines * CURSES_FORMAT * curses_screen_width; // And now we offset full width of our terminal, this makes it faster... |
|
|
|
string_copy_limit (curses_screen + skip + next, "\r\n", string_length ("\r\n")); // And lastly, we copy those line breaks at this offset into our screen buffer. |
|
|
|
} // Keep in mind that word-wrapping is slow on some terminals, hence I use this. |
|
|
|
|
|
|
|
terminal_clear (); |
|
|
|
} |
|
|
|
|
|
|
@@ -235,8 +242,8 @@ static void curses_deinitialize (void) { |
|
|
|
curses_activator = deallocate (curses_activator); |
|
|
|
curses_action = deallocate (curses_action); |
|
|
|
|
|
|
|
curses_action_count = 0; |
|
|
|
curses_character = 0; |
|
|
|
curses_action_count = 0; // I just set everthing into default state, so we can use curses multiple times. |
|
|
|
curses_character = 0; // This way, it's all safe and clean, even with (de)initializing it twice. |
|
|
|
curses_signal = SIGNAL_NONE; |
|
|
|
curses_screen_width = 0; |
|
|
|
curses_screen_height = 0; |
|
|
@@ -290,10 +297,10 @@ static char * curses_screen_offset (int x, int y) { |
|
|
|
// log_in (LOG_FAILURE, x >= curses_screen_width, "curses_screen_offset: X position is above the upper bound."); |
|
|
|
// log_in (LOG_FAILURE, y >= curses_screen_height, "curses_screen_offset: Y position is above the upper bound."); |
|
|
|
|
|
|
|
limit (& x, 0, curses_screen_width - 1); // We're limiting the values of X and Y coordinates to screen dimensions. |
|
|
|
limit (& y, 0, curses_screen_height - 1); // Function 'limit' uses inclusive values for minimum and maximum. |
|
|
|
limit (& x, 0, curses_screen_width - 1); // We're limiting the values of X and Y coordinates to screen dimensions. |
|
|
|
limit (& y, 0, curses_screen_height - 1); // Function 'limit' uses inclusive values for minimum and maximum. |
|
|
|
|
|
|
|
return (& curses_screen [CURSES_REVERT + CURSES_FORMAT * (y * curses_screen_width + x)]); // And returning the offset of the screen buffer. |
|
|
|
return (& curses_screen [CURSES_REVERT + 2 * y + CURSES_FORMAT * (y * curses_screen_width + x)]); // And returning the offset of the screen buffer. |
|
|
|
} |
|
|
|
|
|
|
|
static char * curses_format_character (char character, int colour, int effect) { |
|
|
@@ -344,11 +351,13 @@ void curses_configure (void) { |
|
|
|
} |
|
|
|
|
|
|
|
void curses_synchronize (void) { |
|
|
|
int signal; |
|
|
|
int signal, length; |
|
|
|
|
|
|
|
curses_signal = curses_character = signal = 0; // Reassigning signals to 0. |
|
|
|
|
|
|
|
out (curses_screen, CURSES_REVERT + CURSES_FORMAT * curses_screen_width * curses_screen_height + CURSES_CURSOR); // We output the entire framebuffer to terminal (present). |
|
|
|
length = CURSES_REVERT + CURSES_FORMAT * curses_screen_width * curses_screen_height + 2 * (curses_screen_height - 1) + CURSES_CURSOR; |
|
|
|
|
|
|
|
out (curses_screen, length); // We output the entire framebuffer to terminal (present). |
|
|
|
|
|
|
|
in (& signal, (int) sizeof (signal)); // We're now checking for user input to modify it. |
|
|
|
|
|
|
@@ -420,20 +429,20 @@ void curses_render_cursor (int x, int y) { |
|
|
|
// We're adding one because ASCII uses 1 ... 1000, and we use 0 ... 999, so it doesn't causes hidden bugs, and realign them to be prefixed with '0' characters. |
|
|
|
// If we have set of values (x = 31, y = 37), then the copied string would look like "\033[031;037H". It's not complex as it may sound. |
|
|
|
// And remember our ASCII table, thing scary thing (\033) is just octal value for number 27, which is CHARACTER_ESCAPE, hence the escape sequences start with it. |
|
|
|
x %= 1000; |
|
|
|
int offset; |
|
|
|
|
|
|
|
x %= 1000; // I don't care for terminals bigger than this... |
|
|
|
y %= 1000; |
|
|
|
|
|
|
|
string_copy_limit (curses_cursor + 2, string_realign (number_to_string (y + 1), 3, '0'), 3); |
|
|
|
string_copy_limit (curses_cursor + 6, string_realign (number_to_string (x + 1), 3, '0'), 3); |
|
|
|
string_copy_limit (curses_cursor + 2, string_realign (number_to_string (y + 1), 3, '0'), 3); // We're copying 0...999 number as string, with 0s. |
|
|
|
string_copy_limit (curses_cursor + 6, string_realign (number_to_string (x + 1), 3, '0'), 3); // Those prefix 0s must be used with this. |
|
|
|
|
|
|
|
string_copy_limit (& curses_screen [CURSES_REVERT + CURSES_FORMAT * curses_screen_width * curses_screen_height], curses_cursor, CURSES_CURSOR); // Actual rendering. |
|
|
|
offset = CURSES_REVERT + 2 * (curses_screen_height - 1) + CURSES_FORMAT * curses_screen_width * curses_screen_height; // We need to offset it at the end of our screen. |
|
|
|
|
|
|
|
string_copy_limit (& curses_screen [offset], curses_cursor, CURSES_CURSOR); // And only then copy cursor data into screen. |
|
|
|
} |
|
|
|
|
|
|
|
void curses_render_character (char character, int colour, int effect, int x, int y) { |
|
|
|
if ((x < 0) || (x > curses_screen_width - 1) || (y < 0) || (y > curses_screen_height - 1)) { // If any of these are true, we don't render. |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Again, lets show some code formatting examples: |
|
|
|
// if ((x < 0) |
|
|
|
// || (y < 0) |
|
|
@@ -451,6 +460,10 @@ void curses_render_character (char character, int colour, int effect, int x, int |
|
|
|
// Or if you really hate adding 2 more lines of code and curly braces: |
|
|
|
// if ((x < 0) || (x > curses_screen_width - 1) || (y < 0) || (y > curses_screen_height - 1)) return; |
|
|
|
|
|
|
|
if ((x < 0) || (x > curses_screen_width - 1) || (y < 0) || (y > curses_screen_height - 1)) { // If any of these are true, we don't render. |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
string_copy_limit (curses_screen_offset (x, y), curses_format_character (character, colour, effect), CURSES_FORMAT); // Again, actual rendering, copying a value to offset. |
|
|
|
} |
|
|
|
|
|
|
@@ -465,9 +478,9 @@ void curses_render_background (char character, int colour, int effect) { |
|
|
|
} |
|
|
|
|
|
|
|
void curses_render_rectangle (char character, int colour, int effect, int x, int y, int width, int height) { |
|
|
|
for (int j = 0; j < height; ++j) { // Iterating through rows (by height) of our framebuffer ('curses_screen'). |
|
|
|
for (int i = 0; i < width; ++i) { // Iterating through columns (by width) of our framebuffer. |
|
|
|
curses_render_character (character, colour, effect, x + i, y + j); // Now, we can use function 'curses_render_character' to simplify our life... |
|
|
|
for (int j = 0; j < height; ++j) { // You can declare type of those iterators in for loops. |
|
|
|
for (int i = 0; i < width; ++i) { // This only works if you're not using ANSI C (C89 / C90) standard. |
|
|
|
curses_render_character (character, colour, effect, x + i, y + j); // Now, we render character by character again... |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|