gol

Implementation of Conway's Game of Life writen in C
git clone git://git.dimitrijedobrota.com/gol.git
Log | Files | Refs | README

commit 53d6b402cb20183b6506084fcc0feacf27ce9518
parent dab783effb48ad69fb178f8f00a0dc915a58a585
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Thu,  9 Jun 2022 14:44:05 +0200

Documentation for window.c and general improvement

Diffstat:
Minclude/window.h | 34++++++++++++++++++++--------------
Msrc/display.c | 6++++++
Msrc/game.c | 10+++++-----
Msrc/window.c | 204++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
4 files changed, 196 insertions(+), 58 deletions(-)

diff --git a/include/window.h b/include/window.h @@ -6,29 +6,35 @@ #define window_T T typedef struct T *T; -T window_new(void); -void window_free(T self); -T window_init(T self); -T window_split(T self, int hor, int a, int b, char *name1, char *name2); -void window_unsplit(T self); -T window_center(T self, int h, int w, char *name); -void window_update_children(T self); +// General -WINDOW *WINDOW_new(T self); +T window_new(void); +T window_init(T self); +T window_split(T self, int hor, int a, int b, char *name1, char *name2); +T window_center(T self, int h, int w, char *name); + +WINDOW *window_win_new(T self); + +void window_clear(T self); +void window_clear_noRefresh(T self); +void window_free(T self); +void window_settings(WINDOW *win); +void window_unsplit(T self); +void window_update_children(T self); + +// Setters and Gettern T window_sibiling(T self); +WINDOW *window_win(T self); int window_height(T self); int window_wight(T self); -WINDOW *window_win(T self); -void window_settings(WINDOW *win); -void window_clear(T self); -void window_clear_noRefresh(T self); +void window_set_title(T self, char *title); -void window_set_title(T self, char *title); +// Help -void wcenter_horizontal(T window, int y, int n); int wcenter_vertical(T window, int n); void cursor_offset(WINDOW *win, int oy, int ox); +void wcenter_horizontal(T window, int y, int n); #undef T #endif diff --git a/src/display.c b/src/display.c @@ -11,6 +11,12 @@ window_T MAIN_w = NULL; +void cursor_offset(WINDOW *win, int oy, int ox) { + int y, x; + getyx(win, y, x); + wmove(win, y + oy, x + ox); +} + void print_pattern(WINDOW *win, pattern_T pattern, int *y, int x, int indent) { (*y)++; wmove(win, (*y)++, x + indent); diff --git a/src/game.c b/src/game.c @@ -128,7 +128,7 @@ int display_select(window_T wind) { WINDOW *new; if (UNICODE) { - new = WINDOW_new(wind); + new = window_win_new(wind); overlay(win, new); wrefresh(new); } else { @@ -244,12 +244,12 @@ reset_screen: wrap = (s_w > 0 && s_h > 0); - if (!wrap) { - width = window_wight(screen_w) / 2; - height = window_height(screen_w); - } else { + if (wrap) { width = s_w; height = s_h; + } else { + width = 0; + height = 0; } logic_init(wrap, mode_index); diff --git a/src/window.c b/src/window.c @@ -1,3 +1,17 @@ +/** + * @file window.c + * @author Dimitrije Dobrota + * @date 9 June 2022 + * @brief This file contains the implementation of the window interface + * + * This file handles the creation and deletion process of nodes in the binary + * tree of windows used for recalculating the ncurses WINDOW position in + * dimension when the terminal has been resized. It's possible to "split" the + * current window in two using a given ration or fixed size, as well as create + * a centered subwindow. It makes some of the tree data accessible via function + * so that other functions can know about the sizes and adapt to them. + */ + #include <curses.h> #include <stdlib.h> #include <string.h> @@ -13,33 +27,44 @@ #define window_T T typedef struct T *T; +/** + * @brief A node in a binary tree of windows + * + * window_T contains all of the information about the size and dimensions of + * ncurses WINDOW, as well as all the information on how to recalculate + * children when a terminal resize occurs. + */ struct window_T { - WINDOW *win; - T c1; - T c2; - T sibiling; + WINDOW + *win; ///< ncurses WINDOW* that represents current window_T on the screen + T c1; ///< left child, NULL if none + T c2; ///< right child, NULL if none + T sibling; ///< sibling, NULL if none - int param[4]; - int mod[3]; + int param[4]; ///< windows size and dimension, refer to macros + int mod[3]; ///< Information an recreating children - char *title; + char *title; ///< Window title to display, NULL if none }; +/** + * @breif Apply settings, draw a border, print title for a give window + * + * @param title: title to be prinded unless NULL + */ void WINDOW_init(WINDOW *win, char *title) { window_settings(win); - wattrset(win, COLOR_PAIR(0)); box(win, ACS_VLINE, ACS_HLINE); if (title) - mvwprintw(win, 0, 1, "%s", title); - wrefresh(win); -} - -WINDOW *WINDOW_new(T self) { - WINDOW *win = newwin(H(self), W(self), Y(self), X(self)); - WINDOW_init(win, self->title); - return win; + mvwprintw(win, 0, 1, " %s ", title); } +/** + * @brief create new window_T + * + * Allocate the memory for a new window_T and set its fields to the default + * value. Should be the only way new window_T objects are created + */ T window_new(void) { T self; @@ -47,7 +72,7 @@ T window_new(void) { self->win = NULL; self->c1 = NULL; self->c2 = NULL; - self->sibiling = NULL; + self->sibling = NULL; self->title = NULL; H(self) = 0; W(self) = 0; @@ -56,21 +81,59 @@ T window_new(void) { return self; } -T window_sibiling(T self) { return self->sibiling; } -int window_height(T self) { return H(self) - 2; } -int window_wight(T self) { return W(self) - 2; } +/// Getter: return the sibling of the current window +T window_sibiling(T self) { return self->sibling; } + +/// Getter: return the height of the current window +int window_height(T self) { return H(self) - 2; } + +/// Getter: return the width of a current window +int window_wight(T self) { return W(self) - 2; } + +/// Getter: return the ncurses WINDOW* of the current window WINDOW *window_win(T self) { return self->win; } +/// Setter: set the title of the current window void window_set_title(T self, char *title) { self->title = title; } +/** + * @brief create new ncurses WINDOW to the specification with default settings + * + * New ncruses WINDOW is created with newwin and it should be deleted with + * delwin. Setting are applied with the call to WINDOW_INIT + */ +WINDOW *window_win_new(T self) { + WINDOW *win = newwin(H(self), W(self), Y(self), X(self)); + WINDOW_init(win, self->title); + wrefresh(win); + return win; +} + +/** + * @brief Initialize the window to be used as main + * + * This function will use the ncurses interface directly to set the screen size + * to match the whole terminal. This window object should always be used as a + * root of the tree and under no condition should it be used as a child of + * other window. + * + * There can be multiple instances of windows initialized with this function + */ T window_init(T self) { self->win = stdscr; WINDOW_init(stdscr, self->title); + wrefresh(self->win); H(self) = LINES; W(self) = COLS; return self; } +/** + * @brief Free the window and it's children recursively + * + * Free the object itself and ncurses WINDOW* with delwin + */ + void window_free(T self) { if (self == NULL) return; @@ -80,6 +143,10 @@ void window_free(T self) { free(self); } +/** + * @brief Delete all children and subchildren of a window + */ + void window_unsplit(T self) { window_free(self->c1); window_free(self->c2); @@ -87,6 +154,22 @@ void window_unsplit(T self) { self->c2 = NULL; } +/** + * @brief Given the window calculate the position and dimensions of it's + * children + * + * This function takes care of calculation for two windows in a given ration or + * fixed size, and single subwindow. + * If a given windows has 2 children then they are split with the following + * rule: + * - If mod[0] is 0, two created windows will be side by side + * - If mod[0] is not 0, two created windows will be one on top of the other + * - If mod[1] and mod[2] are 0, nothing happens + * - If mod[1] or mod[2] is 0, the window with a non zero value will be of a + * fixed size, while the other will fill the rest of the screen + * If a given windows has 1 child then: + * - Child dimensions will be mod[1] x mod[2] or made to fit in it's parent + */ void window_calc_children(T self) { T c1, c2, f, nf; c1 = self->c1; @@ -145,6 +228,17 @@ void window_calc_children(T self) { } } +/** + * @brief Split the window in a given ration into two windows with a name + * + * @param hor: should the split line be horizontal or verical + * @param a: ration of the first window + * @param b: ration of the second window + * @param name1: name of the first window + * @param name2: name of the second window + * + * @see window_calc_children to see how the ratios are used + */ T window_split(T self, int hor, int a, int b, char *name1, char *name2) { if (self->c1) window_free(self->c1); @@ -154,8 +248,8 @@ T window_split(T self, int hor, int a, int b, char *name1, char *name2) { self->c1 = window_new(); self->c2 = window_new(); - self->c1->sibiling = self->c2; - self->c2->sibiling = self->c1; + self->c1->sibling = self->c2; + self->c2->sibling = self->c1; self->mod[0] = hor; self->mod[1] = a; @@ -166,12 +260,20 @@ T window_split(T self, int hor, int a, int b, char *name1, char *name2) { self->c1->title = name1; self->c2->title = name2; - self->c1->win = WINDOW_new(self->c1); - self->c2->win = WINDOW_new(self->c2); + self->c1->win = window_win_new(self->c1); + self->c2->win = window_win_new(self->c2); return self->c1; } +/** + * @brief Create a subwindow that will be of a given size or made to fit it's + * parent + * + * @param h: desired height of a new window_T + * @param w: desired width of a new window_T + * @param name: name of the new window_T + */ T window_center(T self, int h, int w, char *name) { self->c1 = window_new(); self->c2 = NULL; @@ -183,11 +285,15 @@ T window_center(T self, int h, int w, char *name) { window_calc_children(self); self->c1->title = name; - self->c1->win = WINDOW_new(self->c1); + self->c1->win = window_win_new(self->c1); return self->c1; } +/** + * @brief Recursevly recalculate the size of each child and make new ncurses + * WINDOW + */ void window_update_children(T self) { if (self == NULL || self->c1 == NULL) return; @@ -195,41 +301,61 @@ void window_update_children(T self) { window_calc_children(self); delwin(self->c1->win); - self->c1->win = WINDOW_new(self->c1); + self->c1->win = window_win_new(self->c1); window_update_children(self->c1); if (self->c2 != NULL) { delwin(self->c2->win); - self->c2->win = WINDOW_new(self->c2); + self->c2->win = window_win_new(self->c2); window_update_children(self->c2); } } +/** + * @brief Clear the current window, reset the setting, keep the border call + * ncurses refresh() + */ + void window_clear(T self) { werase(self->win); WINDOW_init(self->win, self->title); + wrefresh(self->win); } +/** + * @brief Same as window_clear but without calling ncurses refresh() + * + * @see window_clear + */ void window_clear_noRefresh(T self) { werase(self->win); - wattrset(self->win, COLOR_PAIR(0)); - box(self->win, ACS_VLINE, ACS_HLINE); - if (self->title) - mvwprintw(self->win, 0, 1, "%s", self->title); + WINDOW_init(self->win, self->title); } -void window_settings(WINDOW *win) { keypad(win, TRUE); } +/** + * @brief Default setting for each window + */ +void window_settings(WINDOW *win) { + keypad(win, TRUE); + wattrset(win, COLOR_PAIR(0)); +} +/** + * @brief Move the cursor to the given why position and x position so that the + * text of len n will be centered + * + * @param y: y position + * @n lenfth of the text to be centered + */ void wcenter_horizontal(T window, int y, int n) { - wmove(window_win(window), y, (W(window) - n - 2) / 2 + 1); + wmove(window->win, y, (W(window) - n - 2) / 2 + 1); } +/** + * @brief Return the y position of the cursor so that n lines will be centered + * + * @param n: number of lines to be centered + */ int wcenter_vertical(T window, int n) { return (H(window) - n - 2) / 2 + 1; } -void cursor_offset(WINDOW *win, int oy, int ox) { - int y, x; - getyx(win, y, x); - wmove(win, y + oy, x + ox); -} - #undef T