瀏覽代碼

Added anti-word-wrap in curses and changed program 2...

master
父節點
當前提交
8517bae33a
共有 2 個文件被更改,包括 47 次插入31 次删除
  1. +33
    -20
      chapter/chapter_2.c
  2. +14
    -11
      program/program_2.c

+ 33
- 20
chapter/chapter_2.c 查看文件

@@ -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...
}
}
}


+ 14
- 11
program/program_2.c 查看文件

@@ -28,18 +28,21 @@ int main (void) {
curses_bind (SIGNAL_ARROW_LEFT, player_move_left);
curses_bind (SIGNAL_ARROW_RIGHT, player_move_right);

curses_bind (SIGNAL_W, player_move_up);
curses_bind (SIGNAL_S, player_move_down);
curses_bind (SIGNAL_A, player_move_left);
curses_bind (SIGNAL_D, player_move_right);

while (curses_active) {
curses_render_background (' ', COLOUR_WHITE, EFFECT_NORMAL);
curses_render_rectangle ('.', COLOUR_GREY, EFFECT_BOLD, 0, 0, 80, 24);
curses_render_character ('@', COLOUR_CYAN, EFFECT_BOLD, player_x, player_y);

//~switch (curses_character) {
//~case 'w': player_move_up (); break;
//~case 's': player_move_down (); break;
//~case 'a': player_move_left (); break;
//~case 'd': player_move_right (); break;
//~default: break;
//~}
curses_render_background ('.', COLOUR_GREY, EFFECT_BOLD);

curses_render_rectangle (',', COLOUR_GREEN, EFFECT_NORMAL, 10, 10, 80, 24);

curses_render_character ('@', COLOUR_CYAN, EFFECT_BOLD, player_x, player_y);

for (int i = 0; i < 50; ++i) {
curses_render_character ('#', COLOUR_BLUE, EFFECT_BOLD, i, i);
}

curses_synchronize ();
}


Loading…
取消
儲存