Pro tip: Never put everything in the main.c or the main() funtion itself!
Code always need to be clean and well structured
After structuring the whole project, including all required libraries and defining all used functions and structs, now we must keep only the important things in the main.c
Our main.c only contains the most important things
main.c head:
In the head file we include all the required headers, libraries and macros to use 'em in our project:
#include"headers/includes.h"//? The file wchich includes all required libraries to work.#include"headers/functions.h"//? Local library contains many functions for this project.#defineNUMBUTTONS6
main.c body:
in a well-strucured C project, the main.c body must only contains the main() function which itself only contains other functions calls, exactly like our code
Our main() function can be parted into 4 parts:
intmain() {// Part 1: Windows and buttons// Part 2: Keys Listener// Part 3: Preforming Actions// Part 4: Cleaning Up}
Part 1: Defining Windows and Buttons for our UI
//PART 1: Windows and Buttons setlocale(LC_ALL, ""); //? Support Non-Ascii characters for most Unix-Like terminals (source: includes.h => locale.h)
//* Initialize ncurses screen (Source: includes.h => ncurses.h)initscr(); cbreak();keypad(stdscr,TRUE);curs_set(0);//* Initialize color pairsstart_color();init_pair(1, COLOR_BLACK, COLOR_WHITE);init_pair(2, COLOR_BLACK, COLOR_GREEN);//* Create welcome windowint max_y, max_x;getmaxyx(stdscr, max_y, max_x); WINDOW* welcome_win =newwin(max_y, max_x,0,0);box(welcome_win,0,0);refresh();//* Print welcome message and descriptionconstchar* title =" Welcome to Etudiants Management Program ";constchar* btn ="Press Enter to Continue";int title_len =strlen(title);int btn_len =strlen(btn);//? Print an ASCII Art as a logo mvwprintw(welcome_win, max_y/2 - 6, max_x/2 - 45, "███████╗████████╗██╗ ██╗ ███╗ ███╗ █████╗ ███╗ ██╗ █████╗ ██████╗ ███████╗██████╗ \n");
mvwprintw(welcome_win, max_y/2 - 5, max_x/2 - 45, "██╔════╝╚══██╔══╝██║ ██║ ████╗ ████║██╔══██╗████╗ ██║██╔══██╗██╔════╝ ██╔════╝██╔══██╗\n");
mvwprintw(welcome_win, max_y/2 - 4, max_x/2 - 45, "█████╗ ██║ ██║ ██║ ██╔████╔██║███████║██╔██╗██║███████║██║ ██╗ █████╗ ██████╔╝\n");
mvwprintw(welcome_win, max_y/2 - 3, max_x/2 - 45, "██╔══╝ ██║ ██║ ██║ ██║╚██╔╝██║██╔══██║██║╚████║██╔══██║██║ ╚██╗██╔══╝ ██╔══██╗\n");
mvwprintw(welcome_win, max_y/2 - 2, max_x/2 - 45, "███████╗ ██║ ╚██████╔╝ ██║ ╚═╝ ██║██║ ██║██║ ╚███║██║ ██║╚██████╔╝███████╗██║ ██║\n");
mvwprintw(welcome_win, max_y/2 - 1, max_x/2 - 45, "╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚══╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝\n");
//? Pint the Title with bold and reversed formatwattron(welcome_win, A_BOLD | A_REVERSE); //turns on bold and reverse fromatmvwprintw(welcome_win, max_y/2+3, max_x/2- title_len/2,"%s", title);wattroff(welcome_win, A_BOLD | A_REVERSE); //turns off bold and reverse fromat//? Pint the Description with bold and blink effectwattron(welcome_win, A_BOLD | A_BLINK); //turn on bold and blink effectmvwprintw(welcome_win, max_y/2+5, max_x/2- btn_len/2,"%s", btn);wattroff(welcome_win, A_BOLD | A_BLINK); //turn on bold and blink effect//* Refresh welcome screenwrefresh(welcome_win); //! A key listener: Wait for user to click Enter to continueint ch =getch();while (ch !='\n') { ch =getch(); }//* Delete welcome screendelwin(welcome_win);MAIN://* Create main windowgetmaxyx(stdscr, max_y, max_x); WINDOW* mainwin =newwin(max_y, max_x,0,0);box(mainwin,0,0);refresh();//* Create buttonsconstchar*ttl ="Students Management:";int ttl_len =strlen(ttl);char*button_labels[6] = {"Add Students","Display Students","Search Students","Modify Students","Delete Students","Average Calculator" };int current_button =0;wattron(mainwin, A_BOLD);mvwprintw(mainwin, max_y/2-11, max_x/2- ttl_len/2,"%s", ttl);wattroff(mainwin, A_BOLD);mvprintw(LINES-2,2,"Press Q key to exit..."); WINDOW* button_wins[NUMBUTTONS];for (int i =0; i < NUMBUTTONS; i++) { button_wins[i] =subwin(mainwin,3,20, max_y/2+ i*3- NUMBUTTONS*3/2, max_x/2-10);wbkgd(button_wins[i], COLOR_PAIR(1));box(button_wins[i],0,0);mvwprintw(button_wins[i],1,1, button_labels[i]); }wbkgd(button_wins[current_button],COLOR_PAIR(2));wrefresh(mainwin);...
Part 2: Keys Listener
setting up a keys listener to record keyboard clicks, we actually have only 3 cases:
Key Up, Key Down: to browse through the options.
Enter Key: to confirm/access to an option.
Q key: to quite the program.
//Part 2: Keys Listener// Main loopbool quit =false;while (!quit) {int ch =getch();switch (ch) {case KEY_DOWN: // case key down clicked /* Here we switch the colors pairs from white to green to make button appears like it's active (the selected one)
So used can knows which button possition he's on */wbkgd(button_wins[current_button],COLOR_PAIR(1));wrefresh(button_wins[current_button]); current_button = (current_button +1) % NUMBUTTONS;wbkgd(button_wins[current_button],COLOR_PAIR(2));wrefresh(button_wins[current_button]);break;case KEY_UP: // case of key up clickedwbkgd(button_wins[current_button],COLOR_PAIR(1));wrefresh(button_wins[current_button]); current_button = (current_button -1+ NUMBUTTONS) % NUMBUTTONS;wbkgd(button_wins[current_button],COLOR_PAIR(2));wrefresh(button_wins[current_button]);break;case'\n': // case of Enter clicked//Part 3: Preforming Actions break;case'q': // case of lowercase qcase'Q': // case of uppercase Q quit =true; // break the loop and exit programbreak; } }
Part 3: Preforming actions
Here we give each button it's function using if else cases and button index variable we called "current_button":
//Part 3: Preforming Actions if (current_button ==0) {addStudent(); } elseif (current_button ==1) {display_students(); } elseif (current_button ==2) {searchStudent(); } elseif (current_button ==3) {update_student(); } elseif (current_button ==4) {delete_student(); } elseif (current_button ==5) {calculateAverage(); }// Cleaning up after finishing the function jobmvprintw(LINES-2,2,"Press any key to continue...");getch(); //* Wait for user inputclear(); //! Clear the screenbox(mainwin,0,0); //* Redraw main window borderwrefresh(mainwin); //* Refresh main windowgoto MAIN; //* Go back to main loop