Explained more about curses...
This commit is contained in:
parent
cb619d884c
commit
59fd9b711b
@ -98,23 +98,71 @@ void (* hello_world [4]) (void) = {
|
||||
};
|
||||
|
||||
/*
|
||||
Now, we'll talk more about cursed functions! I broke code formatting rules for this, but it's worth it, time to learn.
|
||||
Now, we'll talk more about cursed functions! I broke code formatting rules for this, but it's worth it, time to learn. Function or variable with 'static' instead of 'extern'
|
||||
keyword before it is internal. That means it'll only be accessable in this file. That way, I can include file "chapter_2.h" in some other file, and know that I can't access or
|
||||
modify some internal variable within that other file. They can only be accessed or modified in this file! Lets show some formatting examples below:
|
||||
|
||||
@C
|
||||
static int my_size = 0;
|
||||
static char * my_name = "Name";
|
||||
static void * my_data = NULL;
|
||||
@
|
||||
|
||||
Unlike when declaring external variables (seen in previous header files), you need to initialize internal variables to some value, like you see above. You shouldn't initialize
|
||||
external variables, they have separate definition (initialization in this case). You can see them just below, they are initialized without 'extern' in front of them, and the same
|
||||
goes for functions declared in "chapter_2.h", but there's another trick to this... You can declare internal functions before defining them, so you have 2 options for them:
|
||||
|
||||
@C
|
||||
// Option A:
|
||||
static void * my_function (char * name, int size);
|
||||
|
||||
int my_function (char * name, int size) {
|
||||
int data = 0;
|
||||
|
||||
// Do some work involving function arguments and modify data.
|
||||
|
||||
return (data);
|
||||
}
|
||||
|
||||
// Option B:
|
||||
static int my_function (char * name, int size) {
|
||||
int data = 0;
|
||||
|
||||
// Do some work involving function arguments and modify data.
|
||||
|
||||
return (data);
|
||||
}
|
||||
@
|
||||
|
||||
Okay, external variables you see lower (without 'static') are all integers. Lets briefly see what types are the internal variables.
|
||||
|
||||
- curses_format / curses_format: Array of characters (also known as string!), and their size is already known at the compile time, it's inside square braces.
|
||||
- curses_screen: Pointer to character, we'll allocate memory for it later, so it'll be a dynamic array of characters, its' size can change.
|
||||
- curses_activator: Pointer to integer, we'll also allocate memory for it, so we can't use square braces for those. Remember that for later.
|
||||
- curses_action: Strictly speaking, pointer to another pointer to function of signature 'void SOMETHING (void);', but ignore it for now, don't get confused.
|
||||
*/
|
||||
|
||||
static char curses_format [CURSES_FORMAT + 1] = "\033[-;3-m-\033[0m";
|
||||
static char curses_cursor [CURSES_CURSOR + 1] = "\033[---;---H";
|
||||
static char curses_format [CURSES_FORMAT + 1] = "\033[-;3-m-\033[0m"; // Internal variable holding data for rendering single character, using ASCII escape sequences.
|
||||
static char curses_cursor [CURSES_CURSOR + 1] = "\033[---;---H"; // Internal variable holding data for rendering cursor at some position.
|
||||
|
||||
static char * curses_screen = NULL;
|
||||
static char * curses_screen = NULL; // We hold all terminal screen data here, you can think of it as an image, but better word is a framebuffer.
|
||||
|
||||
static int curses_action_count = 0;
|
||||
static int * curses_activator = NULL;
|
||||
static int curses_action_count = 0; // Count of defined actions, these are part of event handling system.
|
||||
static int * curses_activator = NULL; // Array of action signals, when they are active, action is executed.
|
||||
|
||||
static void (* * curses_action) (void) = NULL;
|
||||
static void (* * curses_action) (void) = NULL; // Array of function pointers, we use it to set event actions, so that user can interact with the terminal.
|
||||
|
||||
static struct termios curses_old_terminal;
|
||||
static struct termios curses_old_terminal; // This is <termios.h> magic for making terminal enter and exit the raw mode.
|
||||
static struct termios curses_new_terminal;
|
||||
|
||||
static void curses_free (void) {
|
||||
// We've explained these external variables in header file already.
|
||||
int curses_character = 0;
|
||||
int curses_signal = SIGNAL_NONE;
|
||||
int curses_screen_width = 0;
|
||||
int curses_screen_height = 0;
|
||||
int curses_active = 1;
|
||||
|
||||
static void curses_deinitialize (void) {
|
||||
curses_screen = deallocate (curses_screen);
|
||||
curses_activator = deallocate (curses_activator);
|
||||
curses_action = deallocate (curses_action);
|
||||
@ -170,15 +218,6 @@ static char * curses_format_character (char character, int colour, int effect) {
|
||||
static void curses_idle (void) { return; } // If you have a lot of short functions that are intended to be in array of function pointers, you can align them like this.
|
||||
static void curses_exit (void) { curses_active = 0; }
|
||||
|
||||
int curses_realign_x = 0;
|
||||
int curses_realign_y = 0;
|
||||
int curses_tab_width = 8;
|
||||
int curses_character = 0;
|
||||
int curses_signal = SIGNAL_NONE;
|
||||
int curses_screen_width = 0;
|
||||
int curses_screen_height = 0;
|
||||
int curses_active = 1;
|
||||
|
||||
/*
|
||||
External function definitions, those found in "chapter_2.h" header file.
|
||||
*/
|
||||
@ -186,7 +225,7 @@ External function definitions, those found in "chapter_2.h" header file.
|
||||
void curses_configure (void) {
|
||||
struct winsize screen_dimension;
|
||||
|
||||
atexit (curses_free);
|
||||
atexit (curses_deinitialize);
|
||||
|
||||
fatal_failure (ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension) == -1, "ioctl: Failed to get terminal dimensions.");
|
||||
|
||||
|
@ -86,21 +86,21 @@ you won't be able to see icons, you won't pass the Login text on your screen, yo
|
||||
#include "chapter_0.h" // We use functions declared in these two header files, so in order to make them visible, we included those files here.
|
||||
#include "chapter_1.h"
|
||||
|
||||
#define SIGNAL_ARROW_UP (0X415B1B) // Just hardcoding some arrow key ASCII escape sequences, we'll explain them in later chapters...
|
||||
#define SIGNAL_ARROW_UP (0X415B1B) // Just hardcoding some arrow key ASCII escape sequences, we'll explain them in later chapters.
|
||||
#define SIGNAL_ARROW_DOWN (0X425B1B)
|
||||
#define SIGNAL_ARROW_RIGHT (0X435B1B)
|
||||
#define SIGNAL_ARROW_LEFT (0X445B1B)
|
||||
|
||||
#define SIGNAL_CONTROL (0X1000000)
|
||||
#define SIGNAL_CONTROL (0X1000000) // We're also defining some signal masks, they'll be used later to mark which key combination is pressed.
|
||||
#define SIGNAL_SHIFT (0X2000000)
|
||||
#define SIGNAL_ALTERNATE (0X4000000)
|
||||
#define SIGNAL_SYSTEM (0X8000000)
|
||||
|
||||
#define CURSES_FORMAT ((int) sizeof ("\033[-;3-m-\033[0m") - 1) // We'll use these three macros through-out cursed functions, I'm following formatting rules, so it's here...
|
||||
#define CURSES_FORMAT ((int) sizeof ("\033[-;3-m-\033[0m") - 1) // We'll use these three macros through-out cursed functions.
|
||||
#define CURSES_REVERT ((int) sizeof ("\033[H") - 1)
|
||||
#define CURSES_CURSOR ((int) sizeof ("\033[---;---H") - 1)
|
||||
|
||||
enum {
|
||||
enum { // This enumeration will be used for signal processing.
|
||||
SIGNAL_NONE,
|
||||
SIGNAL_ANY,
|
||||
SIGNAL_A, SIGNAL_B, SIGNAL_C, SIGNAL_D, SIGNAL_E, SIGNAL_F, SIGNAL_G, SIGNAL_H,
|
||||
@ -109,31 +109,40 @@ enum {
|
||||
SIGNAL_Y, SIGNAL_Z, SIGNAL_0, SIGNAL_1, SIGNAL_2, SIGNAL_3, SIGNAL_4, SIGNAL_5,
|
||||
SIGNAL_6, SIGNAL_7, SIGNAL_8, SIGNAL_9, SIGNAL_ESCAPE, SIGNAL_TABULATOR, SIGNAL_RETURN, SIGNAL_NEW_LINE,
|
||||
SIGNAL_SLASH, SIGNAL_BACKSLASH, SIGNAL_QUOTE, SIGNAL_BACKQUOTE, SIGNAL_SPACE, SIGNAL_BACKSPACE, SIGNAL_DOT, SIGNAL_COMMA,
|
||||
SIGNAL_CITE, SIGNAL_CAPS_LOCK, SIGNAL_L_BRACKET, SIGNAL_R_BRACKET, SIGNAL_MINUS, SIGNAL_EQUAL,
|
||||
SIGNAL_QUOTATION, SIGNAL_CAPS_LOCK, SIGNAL_L_BRACKET, SIGNAL_R_BRACKET, SIGNAL_MINUS, SIGNAL_EQUAL,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
extern int curses_character;
|
||||
extern int curses_signal;
|
||||
extern int curses_screen_width;
|
||||
extern int curses_screen_height;
|
||||
extern int curses_active;
|
||||
/*
|
||||
These below are external variables, they can be accessed and modified in any file where they're (re)declared. We're compiling C source files (.c) separately, so the compiler will
|
||||
output object files (.o), and then we can link them together (most compilers are also linkers, this is nothing out of ordinary) into final executable. We can, for example, use
|
||||
functions declared in "chapter_2.h" and defined in "chapter_2.c" in completely separate file "chapter_3.c", if we have included it with '#include "chapter_2.h". Keep in mind that
|
||||
header files can be included recursively, that's why we use those header guards, '#ifndef SOMETHING', '#define SOMETHING' and '#endif' at the end. That way, they'll be included
|
||||
only once, so compiler won't be confused and spit out errors.
|
||||
*/
|
||||
|
||||
extern void curses_configure (void);
|
||||
extern void curses_synchronize (void);
|
||||
extern int curses_character; // Literal character (integer) that user has pressed, some of them are more than single byte, like arrow keys defined above.
|
||||
extern int curses_signal; // Converted value of 'curses_character' into values of macros and enumeration values named as 'SIGNAL_*'.
|
||||
extern int curses_screen_width; // Width of terminal window in which we're rendering.
|
||||
extern int curses_screen_height; // Height of terminal window in which we're rendering.
|
||||
extern int curses_active; // As long as there's no termination signal, this variable will be different from zero. We use it to exit the program.
|
||||
|
||||
extern void curses_bind (int signal, void (* action) (void));
|
||||
extern void curses_unbind (int signal);
|
||||
extern void curses_configure (void); // I like using the approach of "just do it" instead of "begin" and "end", due to that we'll see more internal functions and variables.
|
||||
extern void curses_synchronize (void); // This function needs to be explained in more details, that'll be done in file "chapter_2.c".
|
||||
|
||||
extern void curses_render_cursor (int x, int y);
|
||||
extern void curses_bind (int signal, void (* action) (void)); // Binding specific function pointer to some key, so each time key is pressed, function is executed.
|
||||
extern void curses_unbind (int signal); // Unbinding any function that was bound to value of 'signal'.
|
||||
|
||||
extern void curses_render_character (char character, int colour, int effect, int x, int y);
|
||||
extern void curses_render_background (char character, int colour, int effect);
|
||||
extern void curses_render_cursor (int x, int y); // Render terminal cursor at position X and Y.
|
||||
|
||||
extern void curses_render_character (char character, int colour, int effect, int x, int y); // Render single character at position X and Y.
|
||||
extern void curses_render_background (char character, int colour, int effect); // Render entire buffer with the same character.
|
||||
|
||||
// Remember that in chapter zero, I've separated 'string_*' and 'string_*_limit' functions. Now, there's always more ways to logically organize your code, for example, as below:
|
||||
extern int curses_render_string (char * string, int colour, int effect, int x, int y);
|
||||
extern int curses_render_number (int number, int colour, int effect, int x, int y);
|
||||
extern int curses_render_string_limit (char * string, int limit, int colour, int effect, int x, int y);
|
||||
extern int curses_render_number_limit (int number, int limit, int colour, int effect, int x, int y);
|
||||
// I really hope that you already know what these functions do just by looking at the names of the arguments...
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user