├── LICENSE ├── README.md ├── TODO ├── TODO.md ├── cedit3.jpg ├── cedit4.jpg └── src ├── Makefile ├── TODO.md ├── edbuf.c ├── edbuf.h ├── editor.c ├── editor.h ├── fileb.c ├── fileb.h ├── global.c ├── global.h ├── keyb.c ├── keyb.h ├── listbox.c ├── listbox.h ├── main.c ├── menu.c ├── menu.h ├── opfile.c ├── opfile.h ├── rterm.c ├── rterm.h ├── scbuf.c ├── scbuf.h ├── t.txt ├── tm.c ├── tm.h ├── ui.c └── ui.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Velorek1 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | C-EDIT Project in C language (NO NCURSES) 2 | ========================================= 3 | C-EDIT for linux - ALPHA - A linux text editor in the style of the MSDOS EDIT - WITHOUT USING NCURSES 4 | Works well with Termux! :) 5 | * WARNING: DO NOT EDIT YOUR PRECIOUS FILES WITH THIS EDITOR!! 6 | 7 | **If you want to support this project: 8 | bitcoin:bc1qn8hzf7f07afcyasym434e9a7sflf8mpjflhg4w** 9 | 10 | Contact me at: velorek1@gmail.com 11 | 12 | **NEW: AUGUST 2025** 13 | - Fixed flickering issues in status bar 14 | - Added pageup/down home/end keys 15 | 16 | History: 17 | - 2024 -> Dynamyc buffer added (vector of lineS) 18 | - 2023 -> Previous demo version kept in https://github.com/velorek1/C-editold 19 | - 2022 -> I have rewritten the screenbuffer and fixed polling issues (lynx: https://github.com/velorek1/lynx). 20 | Ideally, a keyboard library abstraction would be nice to expand the editor's possibilities.** 21 | - 2018 -> Start of the project; basic demo concepts developed (https://oldstuff286.blogspot.com/2018/03/c-edit-in-progress.html) 22 | 23 | TO INSTALL: 24 | 25 | * Download or clone repository. 26 | * Type "cd src", "make" and "./cedit" to execute. 27 | 28 | So far I have implemented: 29 | 30 | * A very simple Double Screen Buffer with a simple linked list in memory for greater display control. 31 | * Rudimentary Text User Interface with Windows, Textbox, Keyboard handling, Color schemes, etc. 32 | * Automatic display resizing. 33 | * Open file dialog with a Listbox and SCROLL capabilities to navigate and find the file to open. 34 | * Rudimentary Edit buffer with vertical and horizontal scroll (vector of lines). 35 | * A millisecond timer for animations. 36 | * Timers and kbhit with no polling for optimate CPU usage. 37 | * Greater modularity than Demo version 38 | * Rudimentary syntax highlighting 39 | 40 | Files in /src/: 41 | =============== 42 | * rterm.c -> code for the library that handles output with Ansi Functions and kbhit() in linux console (with its header file) 43 | * listbox.c -> code for the circular linked list responsible for handling menus 44 | * scbuf.c -> code for controlling display with a double screen buffer (with its header file) 45 | * keyb.c -> module to control keyboard input. 46 | * opfile.c -> module that list files with scroll capabilities to select the file to open. 47 | * ui.c -> module with user interface widgets: alert windows, confirmation windows, textbox, etc. 48 | * fileb.c -> module for single file operations. 49 | * tm.c -> module for a millisecond timer for animations (C11) 50 | * main.c -> Editor in C in the style of MSDOS EDIT (In progress). 51 | * global.c -> Global variables and main animation 52 | * menu.c -> Drop-down menu 53 | * editor.c -> Code for the editor section 54 | * edbuf.c -> Buffer - vector of lines 55 | 56 | 57 | As a screen buffer I have implemented a dynamic structure in memory that allows to save the current screen so that you can display new things on top and then go back to the previous (saved) screen. (simple linked list) 58 | 59 | TO-DO: 60 | * Clean code 61 | * Complete menus / dialogs 62 | * READ MODE 63 | * FULL UTF 8! - SUPPORT change from char to win_t/wchar in editor buffer 64 | * Copy/Paste/Cut routines / Highlight text 65 | * Create Keyboard abstraction to make it more portable (bottom-up fashion!) 66 | * Address glitches/bugs 67 | 68 | ![Alt text](cedit3.jpg?raw=true "Demo") 69 | ![Alt text](cedit4.jpg?raw=true "Demo") 70 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * Top Priority: 2 | Check https://github.com/velorek1/ceditbuf/ for latest development implementations (2024( 3 | 4 | - Code a more backward compatible timer : tm.c (done!) 5 | - Create Keyboard abstraction to make it more portable (bottom-up fashion!) 6 | - Rewrite screen buffer (in progress). 7 | - Rewrite and merge listbox with openfiledialog and menus. 8 | - Turn fw into a library to display long text with scroll. 9 | - Change editBuffer from static array to dynamic structure (in progress) 10 | - Expand behaviour of ENTER and BACKSPACE and REAL TAB SUPPORT! (in progress) 11 | - Add horizontal scroll (in progress) 12 | 13 | 14 | * Less Priority: 15 | - Highlight text and copy/paste function 16 | - Find text 17 | - Full UTF8 support? 18 | 19 | 20 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | * Top Priority: (2025) 2 | - Complete menus / dialogs 3 | - READ MODE 4 | - FULL UTF 8 - SUPPORT change char to win_t/wchar in editor buffer 5 | - Copy/Paste/Cut routines / Highlight text 6 | - Create Keyboard abstraction to make it more portable (bottom-up fashion!) 7 | - Address glitches/bugs 8 | -------------------------------------------------------------------------------- /cedit3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/velorek1/c-edit/4515137f6d35d4b512dc7244431df303427adaa4/cedit3.jpg -------------------------------------------------------------------------------- /cedit4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/velorek1/c-edit/4515137f6d35d4b512dc7244431df303427adaa4/cedit4.jpg -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | TARGET = cedit 3 | CC = cc 4 | CFLAGS = -Wall -Wextra -fsigned-char 5 | LDFLAGS = 6 | LDLIBS = 7 | 8 | # The list of object files. 9 | OBJS = main.o rterm.o listbox.o scbuf.o 10 | OBJS += ui.o fileb.o global.o menu.o editor.o 11 | OBJS += keyb.o tm.o edbuf.o opfile.o 12 | 13 | # the list of files to clean 14 | TOCLEAN = cedit $(OBJS) 15 | 16 | RM ?= rm -f 17 | 18 | all: $(TARGET) 19 | clean: 20 | $(RM) $(TOCLEAN) 21 | 22 | cedit: $(OBJS) 23 | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) 24 | 25 | # INCLUDE DEPENDENCIES to compile depending on which 26 | # source has been touched. 27 | main.o: main.c rterm.h listbox.h scbuf.h keyb.h ui.h fileb.h tm.h 28 | fileb.o: fileb.c fileb.h 29 | keyb.o: keyb.c rterm.h keyb.h 30 | listbox.o: listbox.c scbuf.h keyb.h 31 | editor.o: scbuf.h keyb.h rterm.h 32 | rterm.o: rterm.c 33 | menu.o: listbox.c scbuf.h ui.h keyb.h rterm.h 34 | tm.o: tm.c tm.h 35 | global.o: global.c global.h 36 | scbuf.o: scbuf.c rterm.h keyb.h scbuf.h 37 | ui.o: ui.c scbuf.h rterm.h keyb.h 38 | opfile.o: opfile.c scbuf.h rterm.h listbox.h keyb.h tm.h global.h ui.h 39 | -------------------------------------------------------------------------------- /src/TODO.md: -------------------------------------------------------------------------------- 1 | # ceditbuf 2 | C-edit with dynamic buffer (in development) 3 | -------------------------------------------------------------------------------- /src/edbuf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "edbuf.h" 5 | 6 | 7 | // create new list element of type VLINES from the supplied text string 8 | VLINES *_newline(VLINES temp) 9 | { 10 | VLINES *newp; 11 | newp = (VLINES *) malloc (sizeof(VLINES)); 12 | newp->index = temp.index; 13 | memcpy(newp->linea,temp.linea,sizeof(temp.linea)+1); 14 | newp->next = NULL; 15 | return newp; 16 | } 17 | 18 | // Delete first element on list whose item field matches the given text 19 | // NOTE!! delete requests for elements not in the list are silently ignored :-) 20 | void _RemoveThing(VLINES **head, int index) 21 | { 22 | BOOL present = FALSE; 23 | VLINES *old; 24 | VLINES **tracer = head; 25 | if ((*tracer)->index==index) present=TRUE; 26 | while((*tracer) && !(present)){ 27 | if ((*tracer)->index==index) present=TRUE; 28 | tracer = &(*tracer)->next; 29 | } 30 | 31 | if(present) 32 | { 33 | old = *tracer; 34 | *tracer = (*tracer)->next; 35 | free(old); // free up remainder of list element 36 | } 37 | } 38 | void _hardupdateLINE(VLINES **head, int index, VLINES temp) 39 | { 40 | int i=0; 41 | BOOL present = FALSE; 42 | VLINES **tracer = head; 43 | if ((*tracer)->index==index) present=TRUE; 44 | while((*tracer) && !(present)){ 45 | if ((*tracer)->index==index) {present=TRUE; break;} 46 | tracer = &(*tracer)->next; 47 | } 48 | 49 | if(present) 50 | { 51 | for (i=0; ilinea[i].ch = temp.linea[i].ch; 54 | (*tracer)->linea[i].attrib = temp.linea[i].attrib; 55 | (*tracer)->linea[i].specialChar = temp.linea[i].specialChar; 56 | } 57 | 58 | } 59 | } 60 | void _deletetheList(VLINES **head) 61 | { 62 | /* deref head_ref to get the real head */ 63 | VLINES *current = *head; 64 | VLINES *next = NULL; 65 | VLINES **tracer=head; 66 | while (current != NULL) 67 | { 68 | next = current->next; 69 | free(current); 70 | current = next; 71 | } 72 | 73 | /* deref head_ref to affect the real head back 74 | in the caller. */ 75 | 76 | *tracer = NULL; 77 | } 78 | 79 | 80 | // updatelement: remove from list the first instance of an element 81 | VLINES *_update(VLINES *head, int index, VLINES temp) 82 | { 83 | VLINES *p; 84 | for (p = head; p != NULL; p = p -> next) { 85 | if (p -> index == index) { 86 | break; 87 | } 88 | } 89 | p-> index = temp.index; 90 | return head; 91 | 92 | } 93 | 94 | // getObject 95 | VLINES *_getObject(VLINES *head, int index) 96 | { 97 | VLINES *p; 98 | for (p = head; p != NULL; p = p -> next) { 99 | if (p -> index == index) { 100 | break; 101 | } 102 | } 103 | //p-> index = temp.index; 104 | return p; 105 | 106 | } 107 | // deleteline: remove from list the first instance of an element 108 | // containing a given text string 109 | // NOTE!! delete requests for elements not in the list are silently ignored 110 | VLINES *_deleteline(VLINES *head, int index) 111 | { 112 | VLINES *p, *prev; 113 | prev = NULL; 114 | for (p = head; p != NULL; p = p -> next) { 115 | if (p -> index == index) { 116 | if(prev == NULL) 117 | head = p-> next; 118 | else 119 | prev -> next = p -> next; 120 | free(p); // remove rest of VLINES 121 | return head; 122 | } 123 | prev = p; 124 | } 125 | return NULL; 126 | } 127 | /* addfront: add new VLINES to front of list */ 128 | /* example usage: start = (addfront(start, newelement("burgers")); */ 129 | 130 | VLINES *_addfront(VLINES *head, VLINES *newp) 131 | { 132 | newp -> next = head; 133 | return newp; 134 | } 135 | 136 | /* addend: add new VLINES to the end of a list */ 137 | /* usage example: start = (addend(start, newelement("wine")); */ 138 | 139 | VLINES *_addatend (VLINES *head, VLINES *newp) 140 | { 141 | VLINES *p2; 142 | if (head == NULL) 143 | return newp; 144 | // now find the end of list 145 | for (p2 = head; p2 -> next != NULL; p2 = p2 -> next) 146 | ; 147 | p2 -> next = newp; 148 | return head; 149 | } 150 | 151 | void _printlist(VLINES **head) 152 | // this routine uses pointer-to-pointer techniques :-) 153 | { 154 | VLINES **tracer = head; 155 | int index=0, i = 0; 156 | while ((*tracer) != NULL) { 157 | index = (*tracer)->index; 158 | printf("LINE %d | ", index); 159 | for (i=0; i < MAX_LINE_SIZE; i++) 160 | printf("%c",(*tracer)->linea[i].ch); 161 | printf("\n"); 162 | tracer = &(*tracer)->next; 163 | } 164 | } 165 | 166 | int _length(VLINES **head) 167 | // this routine uses pointer-to-pointer techniques :-) 168 | { 169 | 170 | int count=0; 171 | VLINES **tracer = head; 172 | if (*head == NULL) return -1; 173 | while ((*tracer) != NULL) { 174 | count = count +1; 175 | tracer = &(*tracer)->next; 176 | } 177 | return count; 178 | } 179 | void _reindex(VLINES **head) 180 | { 181 | int count=0; 182 | VLINES *p=NULL; 183 | VLINES **tracer = head; 184 | while ((*tracer) != NULL) { 185 | p = *tracer; 186 | p->index=count; 187 | count = count +1; 188 | tracer = &(*tracer)->next; 189 | } 190 | } 191 | 192 | void _deleteObject(VLINES **head,int index, BOOL sort){ 193 | VLINES *p=*head; 194 | if (index == 0 || _length(head) <=1 || p->index == index ) 195 | _RemoveThing(head,index); 196 | else 197 | _deleteline(*head,index); 198 | if (sort == TRUE) _reindex(head); 199 | } 200 | 201 | int _dumpLine(VLINES *head, long index, VLINES *line){ 202 | //Dumps contents of desired line from buffer into temporary line 203 | int i=-1; char ch=0; char attrib = 0; char specialChar = 0; 204 | VLINES *aux = NULL; //auxiliary pointer 205 | aux = _getObject(head, index); 206 | memset(line, '\0',sizeof(&line)); //Clear memory for temporary line 207 | //Does the line exist? 208 | if (aux != NULL) { 209 | for (i=0; ilinea[i].ch; 212 | attrib = aux->linea[i].attrib; 213 | specialChar = aux->linea[i].specialChar; 214 | line->linea[i].ch = ch; 215 | line->linea[i].attrib = attrib; 216 | line->linea[i].specialChar = specialChar; 217 | } 218 | i = aux->index; 219 | } 220 | return i; 221 | } 222 | int _updateLine(VLINES *head, long index, VLINES *line){ 223 | //Copies contents of desired line from temporary line to buffer 224 | int i=0; char ch=0; char specialChar = 0; 225 | char attrib = 0; 226 | VLINES *aux = NULL; //auxiliary pointer 227 | aux = _getObject(head, index); 228 | //Does the line exist? 229 | if (aux != NULL) { 230 | for (i=0; ilinea[i].ch; 233 | specialChar = line->linea[i].specialChar; 234 | attrib = line->linea[i].attrib; 235 | aux->linea[i].ch = ch; 236 | aux->linea[i].specialChar = specialChar; 237 | aux->linea[i].attrib = attrib; 238 | } 239 | i = aux->index; 240 | } 241 | return i; 242 | } 243 | 244 | CHARBUF _getSingleChar(VLINES *head, long X, long Y ){ 245 | //Dumps contents of desired line from buffer into temporary line 246 | char ch=0; char attrib = 0; char specialChar = 0; 247 | CHARBUF retvalues; 248 | VLINES *aux = NULL; //auxiliary pointer 249 | aux = _getObject(head, Y); 250 | //Does the line exist? 251 | if (aux != NULL) { 252 | ch = aux->linea[X].ch; 253 | specialChar = aux->linea[X].specialChar; 254 | attrib = aux->linea[X].attrib; 255 | 256 | } else 257 | { 258 | ch = '\0'; 259 | specialChar = '\0'; 260 | attrib = '\0'; 261 | } 262 | retvalues.ch = ch; 263 | retvalues.attrib = attrib; 264 | retvalues.specialChar = specialChar; 265 | return retvalues; 266 | } 267 | 268 | int findEndline(VLINES line) { 269 | char ch = 0; 270 | int i=0; 271 | int result = 0; 272 | 273 | do { 274 | ch = line.linea[i].ch; 275 | //write_ch(i,1,ch,F_RED,B_WHITE); 276 | if(ch == 0x00 || ch == 0x10 || ch == 0x0A) //ch = 00 277 | break; 278 | i++; 279 | } while(i < MAX_LINE_SIZE); 280 | result = i; 281 | ch = 0; 282 | return result; 283 | } 284 | 285 | BOOL isLineTerminated(VLINES line) { 286 | BOOL flag=FALSE; 287 | char ch=0; 288 | int i = 0; 289 | for (i=0; i< MAX_LINE_SIZE; i++){ 290 | ch = line.linea[i].ch; 291 | if(ch == 0x10 || ch == 0x0A) 292 | flag = TRUE; 293 | } 294 | return flag; 295 | } 296 | 297 | 298 | -------------------------------------------------------------------------------- /src/edbuf.h: -------------------------------------------------------------------------------- 1 | #ifndef _EDBUF_H_ 2 | #define _EDBUF_H_ 3 | 4 | #include 5 | #include 6 | #define MAX_LINE_SIZE 512 7 | #define TRUE 1 8 | #define FALSE 0 9 | typedef int BOOL; 10 | 11 | typedef struct _charbuf 12 | { 13 | char ch; 14 | char specialChar; 15 | char attrib; 16 | }CHARBUF; 17 | 18 | typedef struct _vlines 19 | { 20 | int index; 21 | CHARBUF linea[MAX_LINE_SIZE]; 22 | struct _vlines *next; 23 | } VLINES; 24 | 25 | /* Adapted from Kernighan and Pike's "The Practice of Programming" pp.46 et 26 | seq. (Addison-Wesley 1999) */ 27 | 28 | // create new list element of type VLINES from the supplied text string 29 | VLINES *_newline(VLINES temp); 30 | VLINES *_addfront(VLINES *head, VLINES *newp); 31 | VLINES *_addatend (VLINES *head, VLINES *newp); 32 | VLINES *_addmiddle (VLINES *head, VLINES *newp); 33 | VLINES *_update(VLINES *head, int index, VLINES temp); 34 | VLINES *_getObject(VLINES *head, int index); 35 | void _hardupdateLINE(VLINES **head, int index, VLINES temp); 36 | void _RemoveThing(VLINES **head, int index); 37 | void _deletetheList(VLINES **head); 38 | VLINES *_deleteline(VLINES *head, int index); 39 | void _deleteObject(VLINES **head,int index, BOOL sort); 40 | int _length(VLINES **head); 41 | void _printlist(VLINES **head); 42 | void _reindex(VLINES **head); 43 | int _dumpLine(VLINES *head, long index, VLINES *line); 44 | int _updateLine(VLINES *head, long index, VLINES *line); 45 | CHARBUF _getSingleChar(VLINES *head, long X, long Y ); 46 | int findEndline(VLINES line); 47 | BOOL isLineTerminated(VLINES line); 48 | #endif 49 | -------------------------------------------------------------------------------- /src/editor.c: -------------------------------------------------------------------------------- 1 | /* Main editor section C·edit 2 | * for a Text User Interface 3 | * Last modified: 6/04/2024 4 | * @author:velorek 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "rterm.h" 12 | #include "scbuf.h" 13 | #include "ui.h" 14 | #include "tm.h" 15 | #include "keyb.h" 16 | #include "global.h" 17 | #include "editor.h" 18 | #include "fileb.h" 19 | #include "edbuf.h" 20 | int oldEndLine= 0; 21 | 22 | wchar_t convertChar(char c1, char c2) { 23 | // Given the two-byte representation for a Char get the wchar convrsion 24 | setlocale(LC_ALL, ""); 25 | 26 | // Combine the bytes into a single string 27 | char temp[3]; 28 | temp[0] = c1; 29 | temp[1] = c2; 30 | temp[2] = '\0'; 31 | 32 | wchar_t wchar; 33 | 34 | mbstowcs(&wchar, temp, 1); 35 | 36 | return wchar; 37 | } 38 | void linetoScreenRAW(long whereY, VLINES tempLine){ 39 | //dump temporary Line to screen buffer - RAW MODE 40 | int i=0; 41 | int attrib = EDIT_FORECOLOR; 42 | int tempEndLine = findEndline(tempLine); 43 | //if (tempEndLine <0) return; 44 | for (i=0; i 31 && ch < 127) || ch < 0) { 183 | 184 | // A KEY IS PRESSED AND ADDED TO EDIT BUFFER 185 | // FIRST check for negative chars and special characters 186 | newch=ch; 187 | accentchar[0] = 0; 188 | accentchar[1] = newch; 189 | //Check whether we are on Readmode 190 | // if (fileModified != FILE_READMODE) { 191 | //Process normal printable chars first 192 | if (ch == 27) return 0; 193 | 194 | if ((ch > 31 && ch < 127) || ch < 0) { 195 | if (ch < 0) { 196 | read_accent(&newch, accentchar); 197 | newch = accentchar[1]; 198 | } 199 | //if ((posBufX != endLine) && (shiftH>0)) return 0; 200 | //check if we are at the limit of our display to print chars 201 | if (cursorX < new_columns-2) cursorX++; 202 | if (posBufX < MAX_LINE_SIZE && cursorX == new_columns-2) {shiftH++;} 203 | //write_num(screen1,20,2,currentLine,B_CYAN,F_WHITE,1); 204 | //SYNTAX HIGHLIGHTING DEMO 205 | //Highlight numbers in GREEN 206 | if ((accentchar[1] >= 48) && (accentchar[1] <=57)) attrib = FH_GREEN; 207 | //Highlight special characters in CYAN 208 | 209 | if ((accentchar[1] >= 33) && (accentchar[1] <=47)) attrib = FH_CYAN; 210 | aux = _getObject(edBuf1, posBufY); 211 | if ((accentchar[1] >= 58) && (accentchar[1] <=64)) attrib = FH_CYAN; 212 | aux = _getObject(edBuf1, posBufY); 213 | if ((accentchar[1] >= 91) && (accentchar[1] <=96)) attrib = FH_CYAN; 214 | aux = _getObject(edBuf1, posBufY); 215 | if ((accentchar[1] >= 123) && (accentchar[1] <=126)) attrib = FH_CYAN; 216 | aux = _getObject(edBuf1, posBufY); 217 | 218 | //FIRST TIME -> CREATE LINES IN BUFFER 219 | if (aux == NULL) { 220 | //FIRST CHAR - if not we create a new line in buffer 221 | 222 | tempLine.index = posBufY; 223 | //Add spaces if cursor is not at (0,0) 224 | if (posBufX != 0) { 225 | for (i=0; i posBufX) { 250 | 251 | tempLine.index = posBufY; //with every line index is incremented 252 | if (insertMode == FALSE){ 253 | for (i=endLine; i>=posBufX; i--){ 254 | tempLine.linea[i+1].ch = tempLine.linea[i].ch; 255 | tempLine.linea[i+1].specialChar = tempLine.linea[i].specialChar; 256 | tempLine.linea[i+1].attrib = tempLine.linea[i].attrib; 257 | } 258 | } 259 | tempLine.linea[posBufX].ch = accentchar[1]; 260 | tempLine.linea[posBufX].specialChar = accentchar[0]; 261 | tempLine.linea[posBufX].attrib = attrib; 262 | posBufX = posBufX + 1; 263 | _updateLine(edBuf1, posBufY, &tempLine); 264 | linetoScreenRAW(cursorY,tempLine); 265 | 266 | } 267 | 268 | else { 269 | // POSBUFX >= ENDLINE: Cursor is at the end or further away from latest text 270 | //ADD SPACES IF CURSOR IS NOT AT THE END OF THE LINE AND LINE ALREADY EXISTS 271 | if(posBufX > endLine) { 272 | for(i = endLine; i < posBufX; i++) { 273 | tempLine.linea[i].ch = FILL_CHAR; 274 | tempLine.linea[i].specialChar = 0; 275 | tempLine.linea[i].attrib = EDIT_FORECOLOR; 276 | } 277 | } 278 | tempLine.linea[posBufX].ch = accentchar[1]; 279 | tempLine.linea[posBufX].specialChar = accentchar[0]; 280 | tempLine.linea[posBufX].attrib = attrib; 281 | posBufX = posBufX + 1; 282 | tempLine.linea[posBufX].ch = END_LINE_CHAR; 283 | tempLine.linea[posBufX].specialChar = 0; 284 | tempLine.linea[posBufX].attrib = attrib; 285 | _updateLine(edBuf1, posBufY, &tempLine); 286 | linetoScreenRAW(cursorY,tempLine); 287 | //the cursor returns to its place when scrolling horizontally 288 | if (posBufX < MAX_LINE_SIZE && cursorX == new_columns-2) {cursorX--;} 289 | } 290 | } 291 | if (shiftH>0){ 292 | buffertoScreen(1); 293 | } 294 | 295 | } 296 | //record previous values 297 | old_cursorX = cursorX; 298 | old_cursorY = cursorY; 299 | oldposBufX = posBufX; 300 | oldposBufY = posBufY; 301 | oldEndLine = endLine; 302 | //HANDLE ENTER KEY 303 | 304 | if (ch == K_ENTER) { 305 | // ENTER key 306 | update_ch(cursorX, cursorY, ' ', EDITAREACOL, EDITAREACOL); 307 | 308 | // Move cursor down if not at the bottom of the screen 309 | if (cursorY < new_rows - 3) { 310 | cursorY++; 311 | } 312 | cursorX = START_CURSOR_X; 313 | 314 | // If the buffer pointer is at the end, create a new empty line 315 | if (_length(&edBuf1) <= posBufY) { 316 | // Create a new line without characters in the current line in the edit buffer 317 | memset(&tempLine, '\0', sizeof(tempLine)); 318 | tempLine.index = _length(&edBuf1); 319 | tempLine.linea[0].ch = END_LINE_CHAR; 320 | tempLine.linea[0].specialChar = 0; 321 | tempLine.linea[0].attrib = 0; 322 | edBuf1 = _addatend(edBuf1, _newline(tempLine)); 323 | } else { 324 | // SPLIT LINE INTO TWO 325 | _dumpLine(edBuf1, posBufY, &tempLine); 326 | endLine = findEndline(tempLine); 327 | 328 | // Create a new line to insert the split content 329 | memset(&splitLine, '\0', sizeof(splitLine)); 330 | memset(&tempLine, '\0', sizeof(tempLine)); 331 | tempLine.index = _length(&edBuf1); 332 | edBuf1 = _addatend(edBuf1, _newline(tempLine)); 333 | 334 | // Move lines below the current line down by one 335 | for (j = _length(&edBuf1) - 1; j > posBufY; j--) { 336 | _dumpLine(edBuf1, j, &tempLine); 337 | _updateLine(edBuf1, j + 1, &tempLine); 338 | if (j + START_CURSOR_Y < new_rows - 3) { 339 | cleanSection(j + START_CURSOR_Y, 0, findEndline(tempLine)); 340 | } 341 | } 342 | 343 | // Split the current line at the cursor position 344 | _dumpLine(edBuf1, posBufY, &tempLine); 345 | memset(&splitLine, '\0', sizeof(splitLine)); 346 | 347 | // Copy characters before the cursor to the current line 348 | for (i = 0; i < posBufX; i++) { 349 | splitLine.linea[i].ch = tempLine.linea[i].ch; 350 | splitLine.linea[i].specialChar = tempLine.linea[i].specialChar; 351 | splitLine.linea[i].attrib = tempLine.linea[i].attrib; 352 | } 353 | if (isLineTerminated(splitLine) == FALSE) { 354 | splitLine.linea[i].ch = END_LINE_CHAR; 355 | } 356 | _updateLine(edBuf1, posBufY, &splitLine); 357 | 358 | // Move characters after the cursor to the next line 359 | memset(&splitLine, '\0', sizeof(splitLine)); 360 | j = 0; 361 | for (i = posBufX; i < endLine; i++) { 362 | splitLine.linea[j].ch = tempLine.linea[i].ch; 363 | splitLine.linea[j].specialChar = tempLine.linea[i].specialChar; 364 | splitLine.linea[j].attrib = tempLine.linea[i].attrib; 365 | j++; 366 | } 367 | if (isLineTerminated(splitLine) == FALSE) { 368 | splitLine.linea[j].ch = END_LINE_CHAR; 369 | } 370 | 371 | // Update the new line with the split content 372 | _updateLine(edBuf1, posBufY + 1, &splitLine); 373 | 374 | // Clean the screen for the current line and refresh the buffer 375 | cleanSection(cursorY - 1, 0, findEndline(tempLine)); 376 | buffertoScreen(TRUE); 377 | } 378 | 379 | // Scroll if needed when cursor is at the bottom of the screen 380 | if (_length(&edBuf1) > vdisplayArea && cursorY == new_rows - 3) { 381 | buffertoScreen(1); 382 | currentLine++; 383 | } 384 | 385 | // Move buffer pointer positions 386 | posBufY++; 387 | posBufX = 0; 388 | } 389 | 390 | if(ch == K_BACKSPACE) { 391 | // BACKSPACE key 392 | update_ch(cursorX, cursorY, ' ', EDITAREACOL, EDITAREACOL); 393 | 394 | if (posBufX == findEndline(tempLine)) { 395 | // Cursor is at the end of the line 396 | tempLine.linea[posBufX-1].ch = 0; 397 | tempLine.linea[posBufX-1].specialChar = 0; 398 | tempLine.linea[posBufX-1].attrib = 0; 399 | } else { 400 | // Shift characters to the left if we are not at the end of the line 401 | if (posBufX != 0) { 402 | for(i = posBufX - 1; i < findEndline(tempLine) - 1; i++) { 403 | tempLine.linea[i].ch = tempLine.linea[i + 1].ch; 404 | tempLine.linea[i].specialChar = tempLine.linea[i + 1].specialChar; 405 | tempLine.linea[i].attrib = tempLine.linea[i + 1].attrib; 406 | } 407 | // Clear the last character in the line 408 | tempLine.linea[i].ch = 0; 409 | tempLine.linea[i].specialChar = 0; 410 | tempLine.linea[i].attrib = 0; 411 | } 412 | } 413 | 414 | // Remove line if we continue pressing backspace at the beginning of a line 415 | if(cursorX == START_CURSOR_X && cursorY > START_CURSOR_Y) { 416 | if (posBufY > 0) { 417 | memset(&tempLine, '\0', sizeof(tempLine)); 418 | memset(&splitLine, '\0', sizeof(splitLine)); 419 | _dumpLine(edBuf1, posBufY - 1, &tempLine); 420 | 421 | if (findEndline(tempLine) < 1) { 422 | // Previous line is empty, remove it 423 | for (j = posBufY - 1; j < _length(&edBuf1) - 1; j++) { 424 | _dumpLine(edBuf1, j + 1, &tempLine); 425 | _hardupdateLINE(&edBuf1, j, tempLine); 426 | } 427 | _deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE); 428 | } else { 429 | // Merge two lines 430 | endLine = findEndline(tempLine); 431 | _dumpLine(edBuf1, posBufY, &splitLine); 432 | 433 | for (i = 0; i < findEndline(splitLine); i++) { 434 | tempLine.linea[endLine + i].ch = splitLine.linea[i].ch; 435 | tempLine.linea[endLine + i].attrib = splitLine.linea[i].attrib; 436 | tempLine.linea[endLine + i].specialChar = splitLine.linea[i].specialChar; 437 | } 438 | tempLine.linea[endLine + i].ch = END_LINE_CHAR; 439 | 440 | _hardupdateLINE(&edBuf1, posBufY - 1, tempLine); 441 | 442 | // Update subsequent lines 443 | for (j = posBufY; j < _length(&edBuf1) - 1; j++) { 444 | _dumpLine(edBuf1, j + 1, &tempLine); 445 | _hardupdateLINE(&edBuf1, j, tempLine); 446 | } 447 | _deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE); 448 | } 449 | 450 | posBufY--; 451 | cursorY--; 452 | if (cursorY == new_rows - 3 && currentLine > 0) currentLine--; 453 | buffertoScreen(1); 454 | _dumpLine(edBuf1, posBufY, &tempLine); 455 | 456 | // Adjust cursor position after merging lines 457 | if (findEndline(splitLine) != 0 && findEndline(splitLine) != findEndline(tempLine)) { 458 | posBufX = findEndline(tempLine) + 1; 459 | cursorX = posBufX + START_CURSOR_X; 460 | } else { 461 | if (endLine != findEndline(tempLine)) { 462 | cursorX = START_CURSOR_X; 463 | posBufX = cursorX - 1; 464 | } else { 465 | posBufX = findEndline(tempLine) + 1; 466 | cursorX = posBufX + START_CURSOR_X; 467 | } 468 | } 469 | } 470 | } 471 | 472 | // Normal backspace within a line 473 | if(cursorX > START_CURSOR_X) { 474 | cursorX--; 475 | posBufX--; 476 | _updateLine(edBuf1, posBufY, &tempLine); 477 | } 478 | 479 | // Clean up and refresh the line on screen 480 | cleanSection(cursorY, findEndline(tempLine), 2); 481 | linetoScreenRAW(cursorY, tempLine); 482 | } 483 | 484 | if (deleteKeyPressed == 1) { 485 | deleteKeyPressed = 0; 486 | // DEL key 487 | if (posBufX == findEndline(tempLine)) { 488 | // Cursor is at the end of the line 489 | if (posBufY < _length(&edBuf1) - 1) { 490 | // If there is a next line, merge it with the current line 491 | _dumpLine(edBuf1, posBufY + 1, &splitLine); 492 | endLine = findEndline(tempLine); 493 | 494 | // Copy the characters from the next line to the end of the current line 495 | for (i = 0; i < findEndline(splitLine); i++) { 496 | tempLine.linea[endLine + i].ch = splitLine.linea[i].ch; 497 | tempLine.linea[endLine + i].attrib = splitLine.linea[i].attrib; 498 | tempLine.linea[endLine + i].specialChar = splitLine.linea[i].specialChar; 499 | } 500 | tempLine.linea[endLine + i].ch = END_LINE_CHAR; 501 | 502 | // Update the buffer with the modified line 503 | _hardupdateLINE(&edBuf1, posBufY, tempLine); 504 | 505 | // Remove the next line from the buffer 506 | for (j = posBufY + 1; j < _length(&edBuf1); j++) { 507 | _dumpLine(edBuf1, j + 1, &tempLine); 508 | _hardupdateLINE(&edBuf1, j, tempLine); 509 | } 510 | _deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE); 511 | 512 | // Update the screen 513 | buffertoScreen(1); 514 | } 515 | } else { 516 | // Cursor is in the middle of the line, so delete the character at the cursor position 517 | for (i = posBufX; i < findEndline(tempLine); i++) { 518 | tempLine.linea[i].ch = tempLine.linea[i + 1].ch; 519 | tempLine.linea[i].specialChar = tempLine.linea[i + 1].specialChar; 520 | tempLine.linea[i].attrib = tempLine.linea[i + 1].attrib; 521 | } 522 | tempLine.linea[i].ch = 0; // Nullify the last character 523 | 524 | // Update the buffer with the modified line 525 | _updateLine(edBuf1, posBufY, &tempLine); 526 | 527 | // Update the screen 528 | cleanSection(cursorY, findEndline(tempLine), 2); 529 | linetoScreenRAW(cursorY, tempLine); 530 | } 531 | } 532 | 533 | if(ch == K_TAB) { 534 | //TAB key sends spaces for convenience 535 | for (i=posBufX; i 0) 587 | tempLine.linea[inlineChar].ch = ch; 588 | } 589 | //SYNTAX HIGHLIGHTING DEMO 590 | //Highlight numbers in GREEN 591 | attrib = EDIT_FORECOLOR; 592 | if ((ch >= 48) && (ch <=57)) attrib = FH_GREEN; 593 | //Highlight special characters in CYAN 594 | 595 | if ((ch >= 33) && (ch <=47)) attrib = FH_CYAN; 596 | if ((ch >= 58) && (ch <=64)) attrib = FH_CYAN; 597 | if ((ch >= 91) && (ch <=96)) attrib = FH_CYAN; 598 | if ((ch >= 123) && (ch <=126)) attrib = FH_CYAN; 599 | 600 | 601 | tempLine.linea[inlineChar].attrib = attrib; 602 | //TABs are converted into spaces 603 | /* if(ch == K_TAB) { 604 | for (tabcount=0;tabcount', SCROLLBAR_ARR, SCROLLBAR_FORE,0); 685 | if (strlen(fileName) == 0) strcpy(fileName,"UNTITLED"); 686 | write_str(screen1,(new_columns / 2) - (strlen(fileName) / 2), 2, fileName, 687 | MENU_PANEL, MENU_FOREGROUND0,0); 688 | if (force_update) dump_screen(screen1); 689 | } 690 | -------------------------------------------------------------------------------- /src/editor.h: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | - HEADER - 4 | Module with main editor in C·edit 5 | @author : Velorek 6 | @version : 1.0 7 | Last modified: 06/04/2024 8 | ======================================================================== 9 | */ 10 | 11 | #ifndef _EDITOR_H_ 12 | #define _EDITOR_H_ 13 | 14 | #include "scbuf.h" 15 | #include "global.h" 16 | #include "edbuf.h" 17 | #include 18 | int process_input(char ch); 19 | int special_keys(); 20 | int control_keys(char ch); 21 | void linetoScreen(long whereY, VLINES tempLine); 22 | void linetoScreenRAW(long whereY, VLINES tempLine); 23 | void cleanScreenLine(long whereY); 24 | void cleanSection(long whereY, long start, int amount); 25 | void buffertoScreen(BOOL raw); 26 | int editor_section(char ch); 27 | wchar_t convertChar(char c1, char c2); 28 | //int filetoBuffer(FILE * filePtr); 29 | void buffertoFile(char *fileName); 30 | int filetoBuffer(char *fileName); 31 | void flush_editarea(int force_update); 32 | #endif 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/fileb.c: -------------------------------------------------------------------------------- 1 | /* 2 | ====================================================================== 3 | Module to describe basic file operations. 4 | 5 | @author : Velorek 6 | @version : 1.0 7 | 8 | LAST MODIFIED : 14/04/2019 - Rename headers 9 | ====================================================================== 10 | */ 11 | 12 | /*====================================================================*/ 13 | /* COMPILER DIRECTIVES AND INCLUDES */ 14 | /*====================================================================*/ 15 | 16 | #include 17 | #include "global.h" 18 | #include "fileb.h" 19 | /*====================================================================*/ 20 | /* FUNCTIONS - CODE */ 21 | /*====================================================================*/ 22 | 23 | /*----------------------*/ 24 | /* Check if file exists */ 25 | /*----------------------*/ 26 | 27 | int file_exists(char *fileName) { 28 | int ok=0; 29 | if(access(fileName, F_OK) != -1) { 30 | ok = 1; //File exists 31 | } else { 32 | ok = 0; 33 | } 34 | return ok; 35 | } 36 | 37 | /*---------------*/ 38 | /* Get file size */ 39 | /*---------------*/ 40 | 41 | long getfileSize(FILE * filePtr) { 42 | long sz=0; 43 | if(filePtr != NULL) { 44 | fseek(filePtr, 0L, SEEK_END); 45 | sz = ftell(filePtr); 46 | rewind(filePtr); 47 | } 48 | 49 | return sz; 50 | } 51 | 52 | /*---------------------*/ 53 | /* Count lines in File */ 54 | /*---------------------*/ 55 | 56 | long countLinesFile(FILE * filePtr) { 57 | char ch=0; 58 | long counterA = 0; 59 | if(filePtr != NULL) { 60 | rewind(filePtr); //Make sure we are at the beginning 61 | 62 | ch = getc(filePtr); //Peek ahead in the file 63 | while(!feof(filePtr)) { 64 | if(ch == END_LINE_CHAR) { 65 | counterA++; 66 | } 67 | ch = getc(filePtr); 68 | } 69 | } 70 | return counterA; 71 | } 72 | 73 | /*-----------------*/ 74 | /* Check file type */ 75 | /*-----------------*/ 76 | 77 | 78 | long checkFile(FILE * filePtr) { 79 | char ch=0; 80 | long counterA = 0; 81 | if(filePtr != NULL) { 82 | rewind(filePtr); //Make sure we are at the beginning 83 | 84 | ch = getc(filePtr); //Peek ahead in the file 85 | while(!feof(filePtr)) { 86 | if(ch < 9) { 87 | //discard accents 88 | if(ch > -60) 89 | counterA++; 90 | } 91 | ch = getc(filePtr); 92 | } 93 | } 94 | return counterA; 95 | } 96 | 97 | //check whether the file is a text file 98 | int openandcheckFile(char *fileName) { 99 | unsigned char ch=0; 100 | long counterA = 0; 101 | FILE *fp; 102 | 103 | openFile(&fp, fileName, "r"); 104 | if(fp != NULL) { 105 | rewind(fp); //Make sure we are at the beginning 106 | 107 | ch = getc(fp); //Peek ahead in the file 108 | while(!feof(fp)) { 109 | 110 | if (ch == 0x00) {closeFile(fp); fp = NULL; return 1;} 111 | if(ch < 9) { 112 | //discard accents 113 | if(ch > 196) 114 | counterA++; 115 | } 116 | ch = getc(fp); 117 | } 118 | } 119 | //If there are more strange characters than half the size of the file probably a binary file 120 | if (counterA > (getfileSize(fp)/2)) { 121 | if (fp != NULL) closeFile(fp); 122 | fp = NULL; 123 | return 1; 124 | } 125 | if (fp != NULL) closeFile(fp); 126 | fp = NULL; 127 | return 0; 128 | } 129 | /*-----------*/ 130 | /* Open file */ 131 | /*-----------*/ 132 | 133 | int openFile(FILE ** filePtr, char fileName[], char *mode) 134 | /* 135 | Open file. 136 | @return ok = 1 ? 0 Success! 137 | */ 138 | { 139 | int ok = 0; 140 | *filePtr = fopen(fileName, mode); 141 | 142 | if(*filePtr != NULL) { 143 | //File opened correctly. 144 | ok = 1; 145 | } else { 146 | //Error 147 | ok = 0; 148 | } 149 | return ok; 150 | } 151 | 152 | /*------------*/ 153 | /* Close file */ 154 | /*------------*/ 155 | 156 | int closeFile(FILE * filePtr) { 157 | /* 158 | Close file 159 | @return ok: 160 | */ 161 | int ok=0; 162 | 163 | if(filePtr != NULL) { 164 | ok = fclose(filePtr); 165 | } 166 | 167 | return ok; 168 | } 169 | 170 | -------------------------------------------------------------------------------- /src/fileb.h: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | - HEADER - 4 | Module to handle basic file operations 5 | @author : Velorek 6 | @version : 1.0 7 | Last modified: 31/08/2025 Open and check file 8 | ======================================================================== 9 | */ 10 | 11 | #ifndef _FILEB_H_ 12 | #define _FILEB_H_ 13 | 14 | /*====================================================================*/ 15 | /* COMPILER DIRECTIVES AND INCLUDES */ 16 | /*====================================================================*/ 17 | 18 | #include 19 | #include "scbuf.h" 20 | 21 | /*====================================================================*/ 22 | /* CONSTANTS */ 23 | /*====================================================================*/ 24 | #define CONFIGFILE "cedit.cfg" 25 | 26 | /*====================================================================*/ 27 | /* FUNCTION PROTOTYPES */ 28 | /*====================================================================*/ 29 | 30 | int openFile(FILE ** filePtr, char fileName[], char *mode); 31 | int closeFile(FILE * filePtr); 32 | long getfileSize(FILE * filePtr); 33 | long countLinesFile(FILE * filePtr); 34 | long checkFile(FILE * filePtr); 35 | int openandcheckFile(char *fileName); 36 | int file_exists(char *fileName); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/global.c: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | #include "rterm.h" 3 | #include "time.h" 4 | 5 | // GLOBALS : SCREEN1 : ANIMATED | SCREEN2 : BASE SCREEN 6 | LISTCHOICE *listBox1 = NULL; 7 | SCREENCELL *screen1=NULL; 8 | SCREENCELL *screen2=NULL; 9 | SCREENCELL *screen3=NULL; 10 | NTIMER cursor_timer1; 11 | NTIMER timer2; 12 | NTIMER timer3; 13 | //NTIMER timer4; 14 | SCROLLDATA scrollData; 15 | VLINES *edBuf1=NULL; //Buffer vector of lines(1022 chars) 16 | VLINES tempLine; 17 | 18 | //C-Edit Theme 19 | int EDITAREACOL= B_BLUE; 20 | int EDIT_FORECOLOR=FH_WHITE; 21 | int STATUSBAR =B_BLACK; 22 | int STATUSMSG =F_WHITE; 23 | int MENU_PANEL =B_WHITE; 24 | int MENU2_PANEL = B_BLACK; 25 | int MENU_SELECTOR =B_RED; 26 | int MENU_FOREGROUND0 =F_BLACK; 27 | int MENU2_FOREGROUND0 = F_WHITE; 28 | int MENU_FOREGROUND1= FH_WHITE; 29 | int EDITWINDOW_BACK= B_BLUE; 30 | int EDITWINDOW_FORE= F_WHITE; 31 | int SCROLLBAR_BACK= B_WHITE; 32 | int SCROLLBAR_FORE= FH_WHITE; 33 | int SCROLLBAR_SEL= B_CYAN; 34 | int SCROLLBAR_ARR= B_BLACK; 35 | int WINDOW_TITLEB = B_BLACK; 36 | int WINDOW_TITLEF = F_WHITE; 37 | 38 | int new_rows = 0, new_columns = 0, old_rows = 0, old_columns = 0; // Terminal dimensions 39 | int cursorX = START_CURSOR_X, cursorY = START_CURSOR_Y; 40 | int old_cursorX = START_CURSOR_X, old_cursorY = START_CURSOR_Y; 41 | long posBufX = 0, posBufY = 0; 42 | long oldposBufX = 0, oldposBufY = 0; 43 | long shiftH = 0; 44 | int unwantedChars = 0; //try to avoid printing unwanted characgters from cursor chars counter 45 | 46 | //TEXT BUFFER POINTERS 47 | int hdisplayLimit=0; //horizontal scroll, last char position in line that allows scroll 48 | int currentColumn=0; //horizontal scroll, pointer to current char position in line 49 | long linesinFile=0; //vertical scroll 50 | long vdisplayLimit=0; //vertical scroll, last line that allows scroll 51 | int vdisplayArea = 0; //size in lines of the allowed displayed area // calculated when screen resizes 52 | int hdisplayArea = 0; //size in lines of the allowed displayed area // calculated when screen resizes 53 | long currentLine=0; //verticall scroll, pointer to current top line in scroll 54 | int vscrollActive=0; //vertical scroll, vertical scroll is posible 55 | //extern int hscrollActive; //horizontal scroll, horizontal scroll is posible 56 | int programStatus = 0; //signal for overall program Status 57 | char fileName[MAXFILENAME]; 58 | char fullPath[MAXFILENAME]; 59 | 60 | FILE *filePointer; 61 | int fileModified=FILE_UNMODIFIED; 62 | int deleteKeyPressed = 0; 63 | 64 | char aboutMSG[7][MAXLINE] = {ABOUT_ASC_0,ABOUT_ASC_1,ABOUT_ASC_2,ABOUT_ASC_3,ABOUT_ASC_4,ABOUT_ASC_5}; 65 | char help[HELPLINES][MAXLINE] = { HELP0, 66 | HELP1, HELP2, HELP3, 67 | HELP4, HELP5, HELP6, 68 | HELP7, HELP8, HELP9, 69 | HELP10, HELP11, HELP12, 70 | HELP13, HELP14, HELP15, 71 | HELP16, HELP17, HELP18, 72 | HELP19, HELP20 73 | }; 74 | int initCEDIT(){ 75 | get_terminal_dimensions(&new_rows,&new_columns); 76 | //Init timer 77 | init_timer(&cursor_timer1,TIMER_SPEED); 78 | init_timer(&timer2,TIMER_SPEED2); 79 | init_timer(&timer3,TIMER_SPEED3); 80 | //init_timer(&timer4,ABOUT_SPEED); 81 | timer2.ticks=0; 82 | timer3.ticks=-1; 83 | //timer4.ticks=0; 84 | cursor_timer1.ticks=0; 85 | //Init Text buffer 86 | VLINES tempLine = {0}; 87 | 88 | memset(&fileName, '\0',sizeof(fileName)); //Clear fileName 89 | memset(&tempLine, '\0',sizeof(tempLine)); //Clear memory for temporary line 90 | //Create one screen in memory 91 | if (screen1 != NULL) deleteList(&screen1); 92 | if (screen2 != NULL) deleteList(&screen2); 93 | //Init 2 : Create 2 Screens for a double buffer approach 94 | old_rows=new_rows; 95 | old_columns=new_columns; 96 | create_screen(&screen1); 97 | create_screen(&screen2); 98 | //how many lines are vertical display area consists of 99 | vdisplayArea = new_rows - 4; 100 | hdisplayArea = new_columns - 2; 101 | shiftH=0; 102 | return 0; 103 | } 104 | 105 | int _animation(){ 106 | /* Timer for animations - Display time and clean cursor */ 107 | time_t mytime = time(NULL); 108 | char *time_str = ctime(&mytime); 109 | char temp[4]; 110 | 111 | temp[0] = '['; 112 | temp[1] = ANIMATION[timer2.ticks]; 113 | temp[2] = ']'; 114 | temp[3] = '\0'; 115 | get_terminal_dimensions(&new_rows,&new_columns); 116 | resetAnsi(0); 117 | time_str[strlen(time_str) - 1] = '\0'; 118 | //display system time 119 | update_str(new_columns - strlen(time_str) - 1, 0, time_str, MENU_PANEL, 120 | MENU_FOREGROUND0); 121 | update_str(new_columns - strlen(time_str) - 5, 0, temp, MENU_PANEL, 122 | MENU_FOREGROUND0); 123 | printf("\n"); 124 | //update only the screen bits that change 125 | if(timer2.ticks > 6) 126 | timer2.ticks = 0; 127 | //return a signal if screen size changes 128 | if (new_rows != old_rows || new_columns != old_columns) 129 | return -1; 130 | else 131 | return 0; 132 | 133 | 134 | 135 | } 136 | 137 | 138 | -------------------------------------------------------------------------------- /src/global.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Global variables are intented to be placed here 3 | * Last modified: 9/7/2022 4 | * @author: velorek 5 | * 6 | */ 7 | #ifndef _GLOBAL_H_ 8 | #define _GLOBAL_H_ 9 | #include "scbuf.h" 10 | #include "tm.h" 11 | #include "edbuf.h" 12 | #include "listbox.h" 13 | 14 | #define TIMER_SPEED 100 //animation 15 | #define TIMER_SPEED2 30 //cursor 16 | #define TIMER_SPEED3 100 //temporary messages 17 | //#define ABOUT_SPEED 300 //about animation 18 | #define END_LINE_CHAR 0x0A 19 | #define FILL_CHAR 0x20 20 | #define ENDSIGNAL -1 21 | #define ESC_KEY '\e' 22 | #define ROWS_FAILSAFE 25 23 | #define COLUMNS_FAILSAFE 80 24 | #define TRUE 1 25 | #define FALSE 0 26 | #define CURSOR_CHAR '|' 27 | typedef int BOOL; 28 | 29 | //USER-DEFINED MESSAGES 30 | extern SCREENCELL *screen1; 31 | extern SCREENCELL *screen2; 32 | extern NTIMER cursor_timer1; 33 | extern NTIMER timer2; 34 | extern NTIMER timer3; 35 | //extern NTIMER timer4; 36 | extern size_t animation; 37 | extern int centerX; 38 | //extern LISTCHOICE listBox1; 39 | extern SCROLLDATA scrollData; 40 | extern VLINES *edBuf1; //Buffer vector of lines(512 chars) 41 | extern VLINES tempLine; 42 | 43 | //COLOR SCHEME 44 | extern int EDITAREACOL; 45 | extern int EDIT_FORECOLOR; 46 | extern int STATUSBAR; 47 | extern int STATUSMSG; 48 | extern int MENU_PANEL; 49 | extern int MENU2_PANEL; 50 | extern int MENU_SELECTOR; 51 | extern int MENU_FOREGROUND0; 52 | extern int MENU2_FOREGROUND0; 53 | extern int MENU_FOREGROUND1; 54 | extern int EDITWINDOW_BACK; 55 | extern int EDITWINDOW_FORE; 56 | extern int SCROLLBAR_BACK; 57 | extern int SCROLLBAR_FORE; 58 | extern int SCROLLBAR_SEL; 59 | extern int SCROLLBAR_ARR; 60 | extern int WINDOW_TITLEB; // to be accessible from opfile.c 61 | extern int WINDOW_TITLEF; 62 | 63 | //GOODBYE MSG - ASCII ART 64 | #define cedit_ascii_1 " _____ ______ _ _ _ \n" 65 | #define cedit_ascii_2 " / ____| | ____| | (_) | \n" 66 | #define cedit_ascii_3 "| | ______| |__ __| |_| |_ \n" 67 | #define cedit_ascii_4 "| | |______| __| / _` | | __|\n" 68 | #define cedit_ascii_5 "| |____ | |___| (_| | | |_ \n" 69 | #define cedit_ascii_6 " \\_____| |______\\__,_|_|\\__|\n" 70 | #define TAB_SPACES 8 71 | 72 | //ABOUT - ASCII ART 73 | #define ABOUT_ASC_0 "______________________________" 74 | #define ABOUT_ASC_1 " _ __ " 75 | #define ABOUT_ASC_2 " / _|__ _|.___ " 76 | #define ABOUT_ASC_3 " \\_ |__(_]| | v0.1 " 77 | #define ABOUT_ASC_4 "______________________________" 78 | #define ABOUT_ASC_5 " Coded by V3l0rek " 79 | #define ANIMATION "||//--\\\\" 80 | 81 | #define HELP0 "C-EDIT \0" 82 | #define HELP1 "======= \0" 83 | #define HELP2 "C-EDIT is a terminal TUI curses text editor. \0" 84 | #define HELP3 "It offers both vertical and horizontal scroll \0" 85 | #define HELP4 "for file buffer navigation. It also features a \0" 86 | #define HELP5 "variety of animations and has a built-in open file \0" 87 | #define HELP6 "dialog to easily locate the files in directories. \0" 88 | #define HELP7 "___________________________________________________\0" 89 | #define HELP8 "[F1] or [ALT + H] -> Display help \0" 90 | #define HELP9 "[F2] or [CTRL + L] -> Activate menu \0" 91 | #define HELP10 "[Arrow Keys] -> Navigate file buffer \0" 92 | #define HELP11 "[CTRL + A] -> Quick Load | CTRL + N -> New file \0" 93 | #define HELP12 "[ALT + O] -> Open file | \0" 94 | #define HELP13 "[ALT + S] -> Save file \0" 95 | #define HELP14 "[ESC] or [CTRL + C] or [ALT+X] -> Exit program \0" 96 | #define HELP15 "[S] Hide/Show table | CTRL or ALT may be used. \0" 97 | #define HELP16 "___________________________________________________\0" 98 | #define HELP17 "This program was coded in C & Vim from 2018-2024. \0" 99 | #define HELP18 "Some of the techniques used can be found in my \0" 100 | #define HELP19 "personal blog : oldstuff286.blogspot.com \0" 101 | #define HELP20 "Peace! - by v3l0r3k \0" 102 | #define HELPLINES 21 103 | 104 | //USER-DEFINED MESSAGES 105 | #define UNKNOWN "UNTITLED" 106 | #define WINDOWMSG "DISPLAY IS TOO SMALL. PLEASE, RESIZE WINDOW" 107 | #define STATUS_BAR_MSG1 " [C-Edit] | F2,CTRL+L: MENU | F1: HELP" 108 | #define STATUS_BAR_MSG2 " [C-Edit] Press ESC to exit menu. " 109 | #define STATUS_BAR_MSG3 " ENTER: SELECT | <- -> ARROW KEYS " 110 | #define WLEAVE_MSG "\n Are you sure\n you want to quit?" 111 | #define WSAVE_MSG ":\nFile saved successfully!" 112 | #define WSAVELABEL_MSG "[-] File:" 113 | #define WINFO_NOPEN "Error:\nThere isn't any file open!" 114 | #define WINFO_SIZE "-File size: " 115 | #define WINFO_SIZE2 "\n-No. of lines: " 116 | #define WINFO_SIZE3 "\n-File name: " 117 | #define WCHECKFILE2_MSG " File does not exist! \n\n A new buffer will be created. \n" 118 | #define WCHECKFILE_MSG " This file isn't a|text file. Program may crash.|Open anyway?" 119 | #define WINFONOTYET_MSG "Not implemented yet!" 120 | #define WCHECKLINES_MSG " File longer than 3000 \n lines. You'll view those \n lines as read Mode! " 121 | #define WMODIFIED_MSG "File has been modified|Save current buffer?" 122 | #define WFILEEXISTS_MSG " File exists. \n Overwrite?" 123 | #define WFILEINREADMODE_MSG " File is on read mode. \n" 124 | 125 | #define START_CURSOR_X 1 126 | #define START_CURSOR_Y 2 127 | 128 | //MENU CONSTANTS 129 | #define HOR_MENU -1 130 | #define FILE_MENU 0 131 | #define OPT_MENU 1 132 | #define HELP_MENU 2 133 | #define YESNO_MENU 3 134 | #define OK_MENU 4 135 | #define MAX_FILENAME 255 136 | #define MAX_LINES 100000 137 | #define MAXLINE 255 138 | 139 | //DROP-DOWN MENUS 140 | #define OPTION_1 0 141 | #define OPTION_2 1 142 | #define OPTION_3 2 143 | #define OPTION_4 3 144 | #define OPTION_5 4 145 | #define OPTION_6 5 146 | #define OPTION_NIL -1 //Reset option 147 | #define CONFIRMATION 1 148 | #define K_LEFTMENU -1 //Left arrow key pressed while in menu 149 | #define K_RIGHTMENU -2 //Right arrow key pressed while in menu 150 | #define DONT_UPDATE -5 151 | //MENU CONSTANTS 152 | #define HOR_MENU -1 153 | #define FILE_MENU 0 154 | #define OPT_MENU 1 155 | #define HELP_MENU 2 156 | #define YESNO_MENU 3 157 | #define OK_MENU 4 158 | #define MAXFILENAME 100 159 | #define OK_MENU2 5 160 | #define COLORS_MENU 6 161 | 162 | //FILE CONSTANTS 163 | #define FILE_MODIFIED 1 164 | #define FILE_UNMODIFIED 0 165 | #define FILE_READMODE 2 166 | extern char aboutMSG[7][MAXLINE]; 167 | extern char help[HELPLINES][MAXLINE]; 168 | 169 | extern int new_rows, new_columns, old_rows, old_columns; // Terminal dimensions 170 | extern int cursorX, cursorY; //position on screen X:[0, columns -2] Y:[0, rows-3] 171 | extern int old_cursorX, old_cursorY; 172 | extern long posBufX, posBufY; //position in the edit buffer X:[0,1022] Y:[0,13000] 173 | extern long oldposBufX, oldposBufY; //position in the edit buffer X:[0,1022] Y:[0,13000] 174 | extern long shiftH; //for horizontal scroll 175 | extern int unwantedChars; 176 | int _animation(); 177 | int initCEDIT(); 178 | 179 | 180 | //TEXT BUFFER POINTERS 181 | extern VLINES *edBuf1; //Buffer vector of lines(1022 chars) 182 | extern VLINES tempLine; 183 | 184 | extern FILE *filePointer; 185 | extern int vdisplayArea; //size in lines of the allowed displayed area // calculated when screen resizes 186 | extern int hdisplayArea; //size in lines of the allowed displayed area // calculated when screen resizes 187 | extern int hdisplayLimit; //horizontal scroll, last char position in line that allows scroll 188 | extern int currentColumn; //horizontal scroll, pointer to current char position in line 189 | extern long linesinFile; //vertical scroll 190 | extern long vdisplayLimit; //vertical scroll, last line that allows scroll 191 | extern long currentLine; //verticall scroll, pointer to current top line in scroll 192 | extern int vscrollActive; //vertical scroll, vertical scroll is posible 193 | extern int programStatus; //signal for overall program status 194 | extern char fileName[MAXFILENAME]; 195 | extern char fullPath[MAXFILENAME]; 196 | extern int fileModified; 197 | extern int deleteKeyPressed; 198 | //extern int hscrollActive; //horizontal scroll, horizontal scroll is posible 199 | 200 | 201 | 202 | 203 | #endif 204 | -------------------------------------------------------------------------------- /src/keyb.c: -------------------------------------------------------------------------------- 1 | /* 2 | ====================================================================== 3 | Module to control keyboard input. 4 | 5 | @author : Velorek 6 | @version : 1.0 7 | 8 | LAST MODIFIED : 14/04/2019 Rename headers 9 | ====================================================================== 10 | */ 11 | 12 | /*====================================================================*/ 13 | /* COMPILER DIRECTIVES AND INCLUDES */ 14 | /*====================================================================*/ 15 | 16 | #include 17 | #include "rterm.h" 18 | #include "keyb.h" 19 | 20 | /*====================================================================*/ 21 | /* FUNCTIONS - CODE */ 22 | /*====================================================================*/ 23 | 24 | /*----------------------------------*/ 25 | /* Read ESC-key char with its trail */ 26 | /*----------------------------------*/ 27 | 28 | int read_keytrail(char chartrail[5]){ 29 | /* 30 | New implementation: Trail of chars found in keyboard.c 31 | If K_ESCAPE is captured read a trail up to 5 characters from the console. 32 | This is to control the fact that some keys may change 33 | according to the terminal and expand the editor's possibilities. 34 | Eg: F2 can be either 27 79 81 or 27 91 91 82. 35 | */ 36 | char ch; 37 | int i; 38 | chartrail[0] = K_ESCAPE; 39 | for(i = 1; i < 5; i++) { 40 | if(kbhit(1) == 1) { 41 | ch=readch(); 42 | chartrail[i] = ch; 43 | } else { 44 | chartrail[i] = 0; 45 | } 46 | } 47 | resetch(); 48 | return 1; 49 | } 50 | 51 | /*----------------------------------*/ 52 | /* Read Accents and Special Chars */ 53 | /*----------------------------------*/ 54 | 55 | 56 | int read_accent(char *ch, char accentchar[2]) 57 | { 58 | /* 59 | Input Ref: ch, accentchar 60 | @return : 1 - SET 1 | 2 - SET 2 | 0 - NO ACCENT CHAR 61 | */ 62 | int result; 63 | result = 0; 64 | //Accents and special chars 65 | accentchar[0] = 0; 66 | accentchar[1] = *ch; 67 | if(*ch == SPECIAL_CHARS_SET1) { 68 | accentchar[0] = SPECIAL_CHARS_SET1; //Accents and special chars SET1 69 | accentchar[1] = readch(); 70 | result = 1; 71 | resetch(); 72 | } 73 | if(*ch == SPECIAL_CHARS_SET2) { 74 | accentchar[0] = SPECIAL_CHARS_SET2; //Accents and special chars SET2 75 | accentchar[1] = readch(); 76 | result = 2; 77 | resetch(); 78 | } 79 | return result; 80 | } 81 | -------------------------------------------------------------------------------- /src/keyb.h: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | - HEADER - 4 | Module to handle keyboard input in Linux and create 5 | a further layer of abstraction. 6 | @author : Velorek 7 | @version : 1.0 8 | Last modified: 14/04/2019 Rename Headers 9 | ======================================================================== 10 | */ 11 | 12 | #ifndef _KEYB_H_ 13 | #define _KEYB_H_ 14 | 15 | /*====================================================================*/ 16 | /* COMPILER DIRECTIVES AND INCLUDES */ 17 | /*====================================================================*/ 18 | 19 | #include 20 | #include "rterm.h" 21 | 22 | /*====================================================================*/ 23 | /* KEYS - CONSTANTS */ 24 | /*====================================================================*/ 25 | 26 | #define K_ENTER 13 27 | #define K_CAPS 91 28 | #define K_BACKSPACE 127 29 | #define K_TAB 9 30 | #define K_ESCAPE 27 31 | 32 | #define K_F1_TRAIL "\eOP\0\0" 33 | #define K_F1_TRAIL2 "\e[[A\0" 34 | #define K_F2_TRAIL "\eOQ\0\0" 35 | #define K_F2_TRAIL2 "\e[[B\0" 36 | #define K_F3_TRAIL "\eOR\0\0" 37 | #define K_F3_TRAIL2 "\e[[C\0" 38 | #define K_F4_TRAIL "\eOS\0\0" 39 | #define K_F4_TRAIL2 "\e[[D\0" 40 | 41 | #define K_UP_TRAIL "\e[A\0\0" 42 | #define K_DOWN_TRAIL "\e[B\0\0" 43 | #define K_RIGHT_TRAIL "\e[C\0\0" 44 | #define K_LEFT_TRAIL "\e[D\0\0" 45 | 46 | #define K_PAGEDOWN_TRAIL "\e[6~" 47 | #define K_PAGEUP_TRAIL "\e[5~" 48 | #define K_HOME_TRAIL "\e[H" 49 | #define K_END_TRAIL "\e[F" 50 | #define K_HOME_TRAIL2 "\e[1~" 51 | #define K_END_TRAIL2 "\e[4~" 52 | 53 | 54 | #define K_DELETE "\e[3~" 55 | 56 | #define K_CTRL_A 0x01 57 | #define K_CTRL_B 0x02 58 | #define K_CTRL_C 0x03 59 | #define K_CTRL_D 0x04 60 | #define K_CTRL_E 0x05 61 | #define K_CTRL_J 0x0A 62 | #define K_CTRL_L 0x0C 63 | #define K_CTRL_H 0x08 64 | #define K_CTRL_M 0x0D 65 | #define K_CTRL_N 0x0E 66 | #define K_CTRL_O 0x0F 67 | #define K_CTRL_S 0x14 68 | 69 | #define K_ALT_X "\ex" 70 | #define K_ALT_L "\el" 71 | #define K_ALT_S "\es" 72 | #define K_ALT_W "\ew" 73 | #define K_ALT_H "\eh" 74 | #define K_ALT_N "\en" 75 | #define K_ALT_O "\eo" 76 | #define K_ALT_W "\ew" 77 | #define K_ALT_A "\ea" 78 | #define K_ALT_I "\ei" 79 | #define K_ALT_C "\ec" 80 | #define K_ALT_F "\ef" 81 | #define K_ALT_P "\ep" 82 | #define K_ALT_S "\es" 83 | #define K_ALT_V "\ev" 84 | #define K_ALT_D "\ed" 85 | #define ESC3X "\e\e\e" 86 | #define ESC2X "\e\e" 87 | #define SPECIAL_CHARS_SET1 -61 88 | #define SPECIAL_CHARS_SET2 -62 89 | 90 | /*====================================================================*/ 91 | /* FUNCTION PROTOTYPES */ 92 | /*====================================================================*/ 93 | 94 | int read_keytrail(char chartrail[5]); 95 | int read_accent(char *ch, char accentchar[2]); 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /src/listbox.c: -------------------------------------------------------------------------------- 1 | /*====================================================================*/ 2 | /* +ListBox with double linked list and selection menu in C with 3 | * horizontal scroll. 4 | +Scroll function added. 5 | Last modified : 01/04/2024 + Horizontal option implementation started 6 | + ESC_KEY added 7 | + X,Y option added for different options 8 | - Pending: horizontal scroll 9 | Coded by Velorek. Raw output 10 | Target OS: Linux. */ 11 | /*====================================================================*/ 12 | 13 | /*====================================================================*/ 14 | /* COMPILER DIRECTIVES AND INCLUDES */ 15 | /*====================================================================*/ 16 | #include 17 | #include 18 | #include 19 | #include "rterm.h" 20 | #include "listbox.h" 21 | #include "keyb.h" 22 | #include "tm.h" 23 | #include "global.h" 24 | 25 | /*====================================================================*/ 26 | /* CODE */ 27 | /*====================================================================*/ 28 | int double_escape=0; 29 | int selectorLimit = 15; //by default selectoLimit is 15 when spaces are added 30 | int newrows=0, newcolumns=0; 31 | int listrows=0, listcolumns=0; 32 | char KTRAIL0[5]={0}; 33 | char KTRAIL1[5]={0}; 34 | 35 | /* --------------------- */ 36 | /* Dynamic List routines */ 37 | /* --------------------- */ 38 | 39 | // create new list element of type LISTCHOICE from the supplied text string 40 | LISTCHOICE *newitem(char *text,unsigned setX, unsigned setY,unsigned foreColor, unsigned backColor) { 41 | LISTCHOICE *newp; 42 | newp = (LISTCHOICE *) malloc(sizeof(LISTCHOICE)); 43 | newp->item = (char *)malloc(strlen(text) + 1); 44 | strcpy(newp->item, text); 45 | newp->next = NULL; 46 | newp->back = NULL; 47 | newp->setX = setX; 48 | newp->setY = setY; 49 | newp->foreColor = foreColor; 50 | newp->backColor = backColor; 51 | 52 | return newp; 53 | } 54 | 55 | // deleleteList: remove list from memory 56 | void removeList(LISTCHOICE ** head) { 57 | LISTCHOICE *aux = *head; 58 | LISTCHOICE *next = NULL; 59 | while(aux != NULL) { 60 | next = aux->next; 61 | free(aux->item); 62 | free(aux); //remove item 63 | aux = next; 64 | } 65 | *head = NULL; 66 | } 67 | 68 | /* addatend: add new LISTCHOICE to the end of a list */ 69 | /* usage example: listBox1 = (addatend(listBox1, newitem("Item")); */ 70 | LISTCHOICE *addatend(LISTCHOICE * head, LISTCHOICE * newp) { 71 | LISTCHOICE *p2; 72 | if(head == NULL) { 73 | newp->index = 0; 74 | newp->back = NULL; 75 | return newp; 76 | } 77 | // now find the end of list 78 | for(p2 = head; p2->next != NULL; p2 = p2->next) ; 79 | p2->next = newp; 80 | newp->back = p2; 81 | newp->index = newp->back->index + 1; 82 | return head; 83 | } 84 | 85 | /* ---------------- */ 86 | /* Listbox routines */ 87 | /* ---------------- */ 88 | 89 | void gotoIndex(LISTCHOICE ** aux, SCROLLDATA * scrollData, 90 | unsigned indexAt) 91 | //Go to a specific location on the list. 92 | { 93 | LISTCHOICE *aux2; 94 | unsigned counter = 0; 95 | *aux = listBox1; 96 | aux2 = *aux; 97 | while(counter != indexAt) { 98 | aux2 = aux2->next; 99 | counter++; 100 | } 101 | //Highlight current item 102 | 103 | displayItem(aux2, scrollData, SELECT_ITEM); 104 | 105 | //Update pointer 106 | *aux = aux2; 107 | } 108 | void printlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned displayLimit) { 109 | /* 110 | Displays the items contained in the list with the properties specified 111 | in scrollData. 112 | */ 113 | 114 | LISTCHOICE *aux; 115 | unsigned wherey, counter = 0; 116 | 117 | aux = head; 118 | gotoIndex(&aux, scrollData, 0); 119 | /* Save values */ 120 | //wherex = scrollData->wherex; 121 | wherey = scrollData->wherey; 122 | do { 123 | displayItem(aux, scrollData, UNSELECT_ITEM); 124 | aux = aux->next; 125 | counter++; 126 | scrollData->selector++; // wherey++ 127 | } while(counter != displayLimit); 128 | scrollData->selector = wherey; //restore value 129 | } 130 | 131 | 132 | void loadlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned indexAt) { 133 | /* 134 | Displays the items contained in the list with the properties specified 135 | in scrollData. 136 | */ 137 | 138 | LISTCHOICE *aux; 139 | unsigned wherey, counter = 0; 140 | 141 | aux = head; 142 | gotoIndex(&aux, scrollData, indexAt); 143 | /* Save values */ 144 | //wherex = scrollData->wherex; 145 | wherey = scrollData->wherey; 146 | do { 147 | displayItem(aux, scrollData, UNSELECT_ITEM); 148 | aux = aux->next; 149 | counter++; 150 | scrollData->selector++; // wherey++ 151 | } while(counter != scrollData->displayLimit); 152 | scrollData->selector = wherey; //restore value 153 | } 154 | 155 | int query_length(LISTCHOICE ** head) { 156 | //Return no. items in a list. 157 | { 158 | LISTCHOICE *aux; 159 | 160 | unsigned itemCount = 0; 161 | aux = *head; 162 | while(aux->next != NULL) { 163 | aux = aux->next; 164 | itemCount++; 165 | } 166 | return itemCount; 167 | } 168 | 169 | } 170 | 171 | void displayItem(LISTCHOICE * aux, SCROLLDATA * scrollData, int select) 172 | //Select or unselect item animation 173 | { 174 | size_t i=0; 175 | wchar_t newchar=0; 176 | resetAnsi(0); 177 | switch (select) { 178 | 179 | case SELECT_ITEM: 180 | if ((aux->setX == -1) || (aux->setY== -1 )) 181 | gotoxy(scrollData->wherex, scrollData->selector); 182 | else 183 | gotoxy(aux-> setX, aux -> setY); 184 | 185 | if ((aux->foreColor == -1) || (aux->backColor== -1 )) 186 | outputcolor(scrollData->foreColor1, scrollData->backColor1); 187 | else 188 | outputcolor(aux->foreColor, aux->backColor); 189 | 190 | //printf("%s\n", aux->item); 191 | 192 | for (i=0;iselectorLimit;i++) { 193 | if(i < strlen(aux->item)){ 194 | newchar=aux->item[i]; 195 | printf("%lc", newchar); 196 | } 197 | else 198 | if (scrollData->addSpaces != 0) printf("%c", 0x20); 199 | } 200 | printf("\n"); 201 | break; 202 | 203 | case UNSELECT_ITEM: 204 | if ((aux->setX == -1) || (aux->setY== -1 )) 205 | gotoxy(scrollData->wherex, scrollData->selector); 206 | else 207 | gotoxy(aux -> setX, aux -> setY); 208 | 209 | outputcolor(scrollData->foreColor0, scrollData->backColor0); 210 | //printf("%s\n", aux->item); 211 | 212 | 213 | for (i=0;iselectorLimit;i++) { 214 | if(i < strlen(aux->item)){ 215 | newchar = aux->item[i]; 216 | printf("%lc", newchar); 217 | } 218 | else 219 | if (scrollData->addSpaces != 0) printf("%c", 0x20); 220 | 221 | } 222 | printf("\n"); 223 | break; 224 | } 225 | } 226 | 227 | int move_selector(LISTCHOICE ** selector, SCROLLDATA * scrollData) { 228 | /* 229 | Creates animation by moving a selector highlighting next item and 230 | unselecting previous item 231 | */ 232 | 233 | LISTCHOICE *aux; 234 | unsigned scrollControl = 0, continueScroll = 0, circular = 235 | CIRCULAR_INACTIVE; 236 | 237 | //Auxiliary pointer points to selector. 238 | aux = *selector; 239 | 240 | //Circular list animation when not scrolling. 241 | if(aux->index == scrollData->listLength - 1 242 | && scrollData->scrollActive == SCROLL_INACTIVE 243 | && scrollData->scrollDirection == DOWN_SCROLL) { 244 | //After last item go back to the top. 245 | displayItem(aux, scrollData, UNSELECT_ITEM); 246 | scrollData->selector = scrollData->wherey; 247 | gotoIndex(&aux, scrollData, 0); 248 | *selector = aux; 249 | circular = CIRCULAR_ACTIVE; 250 | } 251 | 252 | if(aux->index == 0 && scrollData->scrollActive == SCROLL_INACTIVE 253 | && scrollData->scrollDirection == UP_SCROLL) { 254 | //Before first item go back to the bottom. 255 | displayItem(aux, scrollData, UNSELECT_ITEM); 256 | scrollData->selector = scrollData->wherey + scrollData->listLength - 1; 257 | gotoIndex(&aux, scrollData, scrollData->listLength - 1); 258 | *selector = aux; 259 | circular = CIRCULAR_ACTIVE; 260 | } 261 | //Check if we do the circular list animation. 262 | //If active, we skip the code one time. 263 | 264 | if(circular == CIRCULAR_INACTIVE) { 265 | 266 | //Check if we are within boundaries. 267 | if((aux->next != NULL && scrollData->scrollDirection == DOWN_SCROLL) 268 | || (aux->back != NULL && scrollData->scrollDirection == UP_SCROLL)) { 269 | 270 | //Unselect previous item 271 | displayItem(aux, scrollData, UNSELECT_ITEM); 272 | 273 | //Check whether we move UP or Down 274 | switch (scrollData->scrollDirection) { 275 | 276 | case UP_SCROLL: 277 | //Calculate new top index if scroll is active 278 | //otherwise it defaults to 0 (top) 279 | if(scrollData->scrollActive == SCROLL_ACTIVE) 280 | scrollControl = scrollData->currentListIndex; 281 | else 282 | scrollControl = 0; 283 | 284 | //Move selector 285 | if(aux->back->index >= scrollControl) { 286 | scrollData->selector--; //whereY-- 287 | aux = aux->back; //Go to previous item 288 | } else { 289 | if(scrollData->scrollActive == SCROLL_ACTIVE) 290 | continueScroll = 1; 291 | else 292 | continueScroll = 0; 293 | } 294 | break; 295 | 296 | case DOWN_SCROLL: 297 | //Calculate bottom index limit if scroll is ACTIVE 298 | //Otherwise it defaults to scrollData->ListLength-1 299 | 300 | if(scrollData->scrollActive == SCROLL_ACTIVE) 301 | scrollControl = 302 | scrollData->currentListIndex + (scrollData->displayLimit - 303 | 1); 304 | else 305 | scrollControl = scrollData->listLength - 1; 306 | 307 | //Move selector 308 | if(aux->next->index <= scrollControl) { 309 | aux = aux->next; //Go to next item 310 | scrollData->selector++; //whereY++; 311 | } else { 312 | if(scrollData->scrollActive == SCROLL_ACTIVE) 313 | continueScroll = 1; 314 | else 315 | continueScroll = 0; 316 | } 317 | break; 318 | } 319 | 320 | /* //Metrics 321 | gotoxy(6, 5); 322 | printf("Length:%d|Index:%d|Memory addr:%p", 323 | scrollData->listLength, aux->index, aux); 324 | gotoxy(6, 6); 325 | printf("Scroll Limit: %d|IsScActive?:%d|ContinueScroll: %d", 326 | scrollControl, scrollData->scrollActive, continueScroll); 327 | */ 328 | //Highlight new item 329 | displayItem(aux, scrollData, SELECT_ITEM); 330 | // update_screen(screen1); 331 | //Update selector pointer 332 | *selector = aux; 333 | } 334 | } 335 | //update_screen(screen1); 336 | circular = CIRCULAR_INACTIVE; 337 | return continueScroll; 338 | } 339 | 340 | char selectorMenu(LISTCHOICE * aux, SCROLLDATA * scrollData) { 341 | char ch=0; 342 | int keypressed=0; 343 | int control = 0; 344 | int continueScroll=0; 345 | unsigned counter = 0; 346 | char chartrail[5]; 347 | 348 | //Go to and select expected item at the beginning 349 | 350 | gotoIndex(&aux, scrollData, scrollData->currentListIndex); 351 | 352 | if(scrollData->scrollDirection == DOWN_SCROLL 353 | && scrollData->currentListIndex != 0) { 354 | //If we are going down we'll select the last item 355 | //to create a better scrolling transition (animation) 356 | for(counter = 0; counter < scrollData->displayLimit; counter++) { 357 | scrollData->scrollDirection = DOWN_SCROLL; 358 | move_selector(&aux, scrollData); 359 | } 360 | } else { 361 | //Do nothing if we are going up. Selector is always at the top item. 362 | } 363 | 364 | //It break the loop everytime the boundaries are reached. 365 | //to reload a new list to show the scroll animation. 366 | while(control != CONTINUE_SCROLL) { 367 | if (timerC(&timer2) == TRUE){ 368 | //Animation in global.c 369 | if (_animation() == -1) {scrollData->itemIndex = -1;double_escape = 1; break;} 370 | } 371 | 372 | //check listbox orientation and change keys 373 | if (scrollData->orientation == VERTICAL || scrollData->orientation == VERTICALWITHBREAK){ 374 | strcpy(KTRAIL0, K_UP_TRAIL); 375 | strcpy(KTRAIL1, K_DOWN_TRAIL); 376 | } 377 | else 378 | { 379 | strcpy(KTRAIL1, K_RIGHT_TRAIL); 380 | strcpy(KTRAIL0, K_LEFT_TRAIL); 381 | } 382 | 383 | keypressed = kbhit(1); 384 | if (keypressed == 1) 385 | ch = readch(); 386 | else 387 | ch = 0; 388 | //if enter key pressed - break loop 389 | if(ch == K_ENTER) 390 | control = CONTINUE_SCROLL; //Break the loop 391 | 392 | if (ch == 'x' || ch == K_BACKSPACE || ch == K_CTRL_C){ 393 | double_escape=1; 394 | scrollData->itemIndex = -1; 395 | break; 396 | } 397 | 398 | 399 | if (ch == K_ESCAPE) // escape key 400 | { 401 | strcpy(chartrail, "\0"); 402 | read_keytrail(chartrail); 403 | //If mode VERTICALWITHBREAK is selected; selector menu is interrupted when left/right arrow keys are pressed 404 | if ((scrollData->orientation == VERTICALWITHBREAK) && (strcmp(chartrail,K_LEFT_TRAIL))==0) 405 | return K_LEFTMENU; 406 | if ((scrollData->orientation == VERTICALWITHBREAK) && (strcmp(chartrail,K_RIGHT_TRAIL))==0) 407 | return K_RIGHTMENU; 408 | 409 | if (chartrail[0] == K_ESCAPE && chartrail[1] == 0) { 410 | double_escape = 1; 411 | scrollData->itemIndex = -1; 412 | break; 413 | } 414 | if (strcmp(chartrail, K_ALT_X) == 0) { 415 | break; 416 | } 417 | if (strcmp(chartrail, KTRAIL0) == 0) { 418 | // escape key + A => arrow key up 419 | //Move selector up 420 | scrollData->scrollDirection = UP_SCROLL; 421 | continueScroll = 422 | move_selector(&aux, scrollData); 423 | //Break the loop if we are scrolling 424 | if (scrollData->scrollActive == SCROLL_ACTIVE 425 | && continueScroll == 1) { 426 | control = CONTINUE_SCROLL; 427 | //Update data 428 | scrollData->currentListIndex = 429 | scrollData->currentListIndex - 1; 430 | scrollData->selector = 431 | scrollData->wherey; 432 | scrollData->item = aux->item; 433 | scrollData->itemIndex = aux->index; 434 | //Return value 435 | ch = control; 436 | } 437 | } 438 | // escape key + B => arrow key down 439 | if (strcmp(chartrail, KTRAIL1) == 0) { 440 | //Move selector down 441 | scrollData->scrollDirection = DOWN_SCROLL; 442 | continueScroll = 443 | move_selector(&aux, scrollData); 444 | //Break the loop if we are scrolling 445 | if (scrollData->scrollActive == SCROLL_ACTIVE 446 | && continueScroll == 1) { 447 | control = CONTINUE_SCROLL; 448 | //Update data 449 | scrollData->currentListIndex = 450 | scrollData->currentListIndex + 1; 451 | scrollData->selector = 452 | scrollData->wherey; 453 | scrollData->item = aux->item; 454 | scrollData->itemIndex = aux->index; 455 | scrollData->scrollDirection = 456 | DOWN_SCROLL; 457 | } 458 | //Return value 459 | ch = control; 460 | } 461 | 462 | } 463 | } 464 | 465 | if (ch == K_ENTER || ch == K_ENTER2) // enter key 466 | { 467 | //Pass data of last item selected 468 | scrollData->item = aux->item; 469 | scrollData->itemIndex = aux->index; 470 | } 471 | return ch; 472 | } 473 | //method to change how wide the selector is 474 | void setselectorLimit(int num){ 475 | selectorLimit = num; 476 | } 477 | void resetScrollData(SCROLLDATA *scrollData) 478 | { 479 | scrollData->scrollActive = 0; //To know whether scroll is active or not. 480 | scrollData->scrollLimit = 0; //Last index for scroll. 481 | scrollData->listLength = 0; //Total no. of items in the list 482 | scrollData->currentListIndex = 0; //Pointer to new sublist of items when scrolling. 483 | scrollData->displayLimit = 0; //No. of elements to be displayed. 484 | scrollData->selectorLimit = selectorLimit; //No. of chars per item display 485 | scrollData->scrollDirection = 0; //To keep track of scrolling Direction. 486 | scrollData->selector = 0; //Y++ 487 | scrollData->wherex = 0; 488 | scrollData->wherey = 0; 489 | scrollData->backColor0 = 0; //0 unselected; 1 selected 490 | scrollData->foreColor0 = 0; 491 | scrollData->backColor1 = 0; 492 | scrollData->foreColor1 = 0; 493 | scrollData->itemIndex = 0; 494 | scrollData->addSpaces = 0; 495 | scrollData->orientation = VERTICAL; 496 | } 497 | char listBox(LISTCHOICE * head, 498 | unsigned whereX, unsigned whereY, 499 | SCROLLDATA * scrollData, unsigned bColor0, 500 | unsigned fColor0, unsigned bColor1, unsigned fColor1, 501 | unsigned displayLimit,unsigned listorientation, unsigned addSpaces, unsigned locked) { 502 | 503 | unsigned list_length = 0; 504 | //unsigned currentIndex = 0; 505 | int scrollLimit = 0; 506 | unsigned currentListIndex = 0; 507 | char ch=0; 508 | LISTCHOICE *aux=NULL; 509 | //Init values 510 | double_escape=0; 511 | resetScrollData(scrollData); 512 | scrollData->orientation = listorientation; 513 | // Query size of the list 514 | list_length = query_length(&head) + 1; 515 | 516 | //Save calculations for SCROLL and store DATA 517 | scrollData->displayLimit = displayLimit; 518 | scrollLimit = list_length - scrollData->displayLimit; //Careful with negative integers 519 | if(scrollLimit < 0 || displayLimit > list_length) 520 | scrollData->displayLimit = list_length; //Failsafe for overboard values 521 | 522 | scrollData->scrollLimit = scrollLimit; 523 | scrollData->listLength = list_length; 524 | scrollData->wherex = whereX; 525 | scrollData->wherey = whereY; 526 | scrollData->selector = whereY; 527 | scrollData->backColor0 = bColor0; 528 | scrollData->backColor1 = bColor1; 529 | scrollData->foreColor0 = fColor0; 530 | scrollData->foreColor1 = fColor1; 531 | scrollData->addSpaces = addSpaces; 532 | 533 | get_terminal_dimensions(&listrows,&listcolumns); 534 | //Check whether we have to activate scroll or not 535 | //and if we are within bounds. [1,list_length) 536 | ch=0; 537 | aux = head; 538 | printlist(aux, scrollData, scrollData->displayLimit); 539 | if (locked == LOCKED) { 540 | if(list_length > scrollData->displayLimit && scrollLimit > 0 541 | && displayLimit > 0) { 542 | //Scroll is possible 543 | 544 | scrollData->scrollActive = SCROLL_ACTIVE; 545 | 546 | currentListIndex = 0; //We listBox1 the scroll at the top index. 547 | scrollData->currentListIndex = currentListIndex; 548 | 549 | //Scroll loop animation. Finish with ENTER. 550 | loadlist(aux, scrollData, currentListIndex); 551 | do { 552 | currentListIndex = scrollData->currentListIndex; 553 | loadlist(aux, scrollData, currentListIndex); 554 | gotoIndex(&aux, scrollData, currentListIndex); 555 | /* gotoxy(6, 4); 556 | printf("Current List Index: %d:%d\n", scrollData->currentListIndex, 557 | aux->index); */ 558 | ch = selectorMenu(aux, scrollData); 559 | if (double_escape == 1) { 560 | scrollData->itemIndex = -1; 561 | locked = FALSE; 562 | ch= K_ESCAPE; 563 | break; 564 | } 565 | if (_animation() == -1) { 566 | scrollData->itemIndex = -1; 567 | double_escape = 1; 568 | ch = K_ESCAPE; 569 | locked = FALSE; 570 | break; 571 | } 572 | } while(ch != K_ENTER); 573 | 574 | } else { 575 | //Scroll is not possible. 576 | //Display all the elements and create selector 577 | // 578 | scrollData->scrollActive = SCROLL_INACTIVE; 579 | scrollData->currentListIndex = 0; 580 | scrollData->displayLimit = list_length; //Default to list_length 581 | loadlist(head, scrollData, 0); 582 | ch = selectorMenu(head, scrollData); 583 | if (double_escape == 1) { 584 | scrollData->itemIndex = -1; 585 | locked = FALSE; 586 | ch= K_ESCAPE; 587 | //break; 588 | } 589 | 590 | } 591 | } 592 | return ch; 593 | } 594 | 595 | 596 | -------------------------------------------------------------------------------- /src/listbox.h: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | - HEADER - 4 | Module to implement a listBox integrated with LYNX. 5 | @author : Velorek 6 | @version : 1.0 7 | Last modified: 26/12/2022 8 | ======================================================================== 9 | */ 10 | 11 | #ifndef _LISTBOX_H_ 12 | #define _LISTBOX_H_ 13 | 14 | /*====================================================================*/ 15 | /* COMPILER DIRECTIVES AND INCLUDES */ 16 | /*====================================================================*/ 17 | 18 | #include 19 | #include "scbuf.h" 20 | /*====================================================================*/ 21 | /* CONSTANTS */ 22 | /*====================================================================*/ 23 | //Scroll Control values. 24 | #define SCROLL_ACTIVE 1 25 | #define SCROLL_INACTIVE 0 26 | #define CONTINUE_SCROLL -1 27 | #define DOWN_SCROLL 1 28 | #define UP_SCROLL 0 29 | #define SELECT_ITEM 1 30 | #define UNSELECT_ITEM 0 31 | #define CIRCULAR_ACTIVE 1 32 | #define CIRCULAR_INACTIVE 0 33 | #define LOCKED 1 34 | #define NOT_LOCKED 0 35 | #define VERTICAL 0 36 | #define HORIZONTAL 1 37 | #define VERTICALWITHBREAK 2 38 | /*====================================================================*/ 39 | /* TYPEDEF STRUCTS DEFINITIONS */ 40 | /*====================================================================*/ 41 | 42 | typedef struct _listchoice { 43 | unsigned index; // Item number 44 | char *item; // Item string 45 | int setX; //X,Y position 46 | int setY; //-1 to ignore 47 | int foreColor; //-1 to ignore 48 | int backColor; //-1 to ignore 49 | struct _listchoice *next; // Pointer to next item 50 | struct _listchoice *back; // Pointer to previous item 51 | } LISTCHOICE; 52 | 53 | typedef struct _scrolldata { 54 | unsigned scrollActive; //To know whether scroll is active or not. 55 | unsigned scrollLimit; //Last index for scroll. 56 | unsigned listLength; //Total no. of items in the list 57 | unsigned currentListIndex; //Pointer to new sublist of items when scrolling. 58 | unsigned displayLimit; //No. of elements to be displayed. 59 | unsigned selectorLimit; //how many items of string item can be displayed 60 | unsigned scrollDirection; //To keep track of scrolling Direction. 61 | unsigned wherex; 62 | unsigned wherey; 63 | unsigned selector; //Y++ 64 | unsigned backColor0; //0 unselected; 1 selected 65 | unsigned foreColor0; 66 | unsigned backColor1; 67 | unsigned foreColor1; 68 | unsigned addSpaces; //whether to add spaces or not 69 | unsigned orientation; 70 | unsigned displayMetrics; //to show metrics on screen/reuse code for text viewing 71 | char *item; 72 | int itemIndex; //-1 means ESC was pressed 73 | LISTCHOICE *head; //store head of the list 74 | } SCROLLDATA; 75 | 76 | /*====================================================================*/ 77 | /* GLOBAL VARIABLES */ 78 | /*====================================================================*/ 79 | extern LISTCHOICE *listBox1; //Head pointer. 80 | 81 | 82 | /*====================================================================*/ 83 | /* PROTOTYPES OF FUNCTIONS */ 84 | /*====================================================================*/ 85 | 86 | //DYNAMIC LINKED LIST FUNCTIONS 87 | void removeList(LISTCHOICE ** head); 88 | LISTCHOICE *addatend(LISTCHOICE * head, LISTCHOICE * newp); 89 | LISTCHOICE *newitem(char *text,unsigned setX, unsigned setY,unsigned foreColor, unsigned backColor); 90 | 91 | //LISTBOX FUNCTIONS 92 | //void addItems(LISTCHOICE ** listBox1); 93 | char listBox(LISTCHOICE * selector, unsigned whereX, unsigned whereY, 94 | SCROLLDATA * scrollData, unsigned bColor0, 95 | unsigned fColor0, unsigned bColor1, unsigned fColor1, 96 | unsigned displayLimit,unsigned listorientation, unsigned addSpaces, unsigned locked); 97 | void loadlist(LISTCHOICE * head, SCROLLDATA * scrollData, 98 | unsigned indexAt); 99 | 100 | void printlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned displayLimit); 101 | 102 | void gotoIndex(LISTCHOICE ** aux, SCROLLDATA * scrollData, 103 | unsigned indexAt); 104 | int query_length(LISTCHOICE ** head); 105 | int move_selector(LISTCHOICE ** head, SCROLLDATA * scrollData); 106 | char selectorMenu(LISTCHOICE * aux, SCROLLDATA * scrollData); 107 | void displayItem(LISTCHOICE * aux, SCROLLDATA * scrollData, int select); 108 | void resetScrollData(SCROLLDATA *scrollData); 109 | void setselectorLimit(int num); 110 | 111 | /*====================================================================*/ 112 | /* FUNCTION PROTOTYPES */ 113 | /*====================================================================*/ 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* C-edit project 2 | * Last updated - 29/8/2024 3 | * New drop-down menu implementation 4 | * Added more modularisation: editor.c menu.c 5 | * Scrollbars added 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "listbox.h" 12 | #include "scbuf.h" 13 | #include "rterm.h" 14 | #include "tm.h" 15 | #include "global.h" 16 | #include "keyb.h" 17 | #include "edbuf.h" 18 | #include "ui.h" 19 | #include "menu.h" 20 | #include "editor.h" 21 | #include "opfile.h" 22 | #include "fileb.h" 23 | //Prototypes 24 | void draw_screen(); 25 | void cursor_tick(); 26 | int special_keys(); 27 | int control_keys(char ch); 28 | void _resizeScreen(); 29 | wchar_t currentChar = 0; 30 | char tempMessage[150]; 31 | int displayMessage(char *temporaryMessage, int x, int y, int fColor, int bColor, int timeDuration); 32 | void update_indicators(); 33 | int oldPositionY = 4; 34 | int oldPositionX = 2; 35 | void draw_screen(){ 36 | //BASE SCREEN IS STORED IN SCREEN 2 37 | int i=0; 38 | if (screen1 != NULL) deleteList(&screen1); 39 | //if (screen2 != NULL) deleteList(&screen2); 40 | //Init 2 : Create 2 Screens for a double buffer approach 41 | old_rows=new_rows; 42 | old_columns=new_columns; 43 | create_screen(&screen1); 44 | create_screen(&screen2); 45 | //SCREEN 2 46 | screen_color(screen1, EDITAREACOL, EDIT_FORECOLOR, FILL_CHAR); 47 | //Failsafe just in case it can't find the terminal dimensions 48 | if(old_rows == 0) 49 | old_rows = ROWS_FAILSAFE; 50 | if(old_columns == 0) 51 | old_columns = COLUMNS_FAILSAFE; 52 | 53 | //Draw upper and lower bars 54 | for(i = 0; i < old_columns; i++) { 55 | write_ch(screen1, i, 1, FILL_CHAR, MENU_PANEL, MENU_PANEL,0); 56 | } 57 | 58 | for(i = 0; i < old_columns; i++) { 59 | write_ch(screen1, i, old_rows, FILL_CHAR, STATUSBAR, STATUSMSG,1); 60 | } 61 | // Text messages 62 | write_str(screen1, 0, 1, "File Options Help", MENU_PANEL, MENU_FOREGROUND0,0); 63 | write_str(screen1, 0, 1, "F", MENU_PANEL, F_RED,0); 64 | write_str(screen1, 7, 1, "p", MENU_PANEL, F_RED,0); 65 | write_str(screen1, 15, 1, "H", MENU_PANEL, F_RED,0); 66 | write_str(screen1, 0, old_rows, STATUS_BAR_MSG1, STATUSBAR, STATUSMSG,0); 67 | 68 | /* Frames */ 69 | //window appearance and scroll bar 70 | for(i = 2; i < old_rows; i++) { 71 | write_ch(screen1,old_columns-1, i, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,0); //Scroll bar 72 | write_ch(screen1,0, i, VER_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //upper vertical line box-like char 73 | } 74 | for(i = 0; i < old_columns; i++) { 75 | write_ch(screen1,i, 2, HOR_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //horizontal line box-like char 76 | write_ch(screen1,i, old_rows - 1, ' ', EDITWINDOW_BACK, EDITWINDOW_FORE,0); 77 | } 78 | write_ch(screen1,0, 2, UPPER_LEFT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //upper-left box-like char 79 | //horizontal scroll bar 80 | for(i = 0; i < old_columns; i++) { 81 | write_ch(screen1,i, old_rows - 1, FILL_CHAR, SCROLLBAR_BACK, SCROLLBAR_FORE,0); 82 | } 83 | //Window-appearance 84 | write_ch(screen1,old_columns-1, 2, UPPER_RIGHT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //right window corner 85 | write_ch(screen1,old_columns-1, old_rows - 1, LOWER_RIGHT_CORNER, EDITWINDOW_BACK, 86 | EDITWINDOW_FORE,0); 87 | write_ch(screen1, 0, old_rows - 1, LOWER_LEFT_CORNER, EDITWINDOW_BACK, 88 | EDITWINDOW_FORE,0); 89 | 90 | //Scroll symbols 91 | write_ch(screen1,old_columns-1, 3, '^', SCROLLBAR_ARR, SCROLLBAR_FORE,0); 92 | write_ch(screen1, old_columns-1, old_rows - 2, 'v', SCROLLBAR_ARR, SCROLLBAR_FORE,0); 93 | write_ch(screen1, old_columns-1, 4, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0); 94 | write_ch(screen1, 2, old_rows - 1, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0); 95 | write_ch(screen1, 1, old_rows - 1, '<', SCROLLBAR_ARR, SCROLLBAR_FORE,0); 96 | write_ch(screen1, old_columns - 2, old_rows - 1, '>', SCROLLBAR_ARR, SCROLLBAR_FORE,0); 97 | if (strlen(fileName) == 0) strcpy(fileName, "UNTITLED"); 98 | write_str(screen1,(new_columns / 2) - (strlen(fileName) / 2), 2, fileName, 99 | MENU_PANEL, MENU_FOREGROUND0,0); 100 | 101 | dump_screen(screen1); 102 | //Save screen for later 103 | //copy_screen(screen2,screen1); 104 | } 105 | 106 | void cursor_tick(void){ 107 | //CURSOR ANIMATION 108 | char drawChar=FILL_CHAR; 109 | char drawChar0=FILL_CHAR; 110 | int attrib = 0; 111 | wchar_t code_point; 112 | //GET CHAR BEING POINTED AT FROM EDIT BUFFER 113 | if (edBuf1 != NULL)_dumpLine(edBuf1, posBufY, &tempLine); 114 | drawChar = tempLine.linea[posBufX].ch; 115 | drawChar0 = tempLine.linea[posBufX].specialChar; 116 | attrib = tempLine.linea[posBufX].attrib; 117 | //CHECK FOR SPECIAL CHARACTERS AND CONVERT THEM TO UNICODE TO PRINT 118 | //IF CURSOR IS ON A CHAR HIGHLIGHT IT IN YELLOW 119 | if (drawChar0 != 0 && drawChar != '\0') code_point = ((drawChar0 & 0x1F) << 6) | (drawChar & 0x3F); 120 | else { 121 | if (drawChar == 0 || drawChar == END_LINE_CHAR) drawChar = FILL_CHAR; 122 | code_point = drawChar; 123 | } 124 | if (cursor_timer1.ticks % 2 == 0) update_ch(cursorX, cursorY, CURSOR_CHAR, B_BLUE, F_WHITE); 125 | else update_ch(cursorX, cursorY, code_point, EDITAREACOL, FH_YELLOW); 126 | 127 | //REST ANSI VALUES TO HAVE HIGH INTENSITY COLORS 128 | resetAnsi(0); 129 | 130 | //CLEAR LAST POSITION OF CURSOR WITH FILL_CHAR OR GO BACK TO PREVIOUS CHAR 131 | if ((old_cursorX != cursorX) || (old_cursorY != cursorY)){ 132 | //old? 133 | if (edBuf1 != NULL)_dumpLine(edBuf1, oldposBufY, &tempLine); 134 | drawChar = tempLine.linea[oldposBufX].ch; 135 | drawChar0 = tempLine.linea[oldposBufX].specialChar; 136 | attrib = tempLine.linea[oldposBufX].attrib; 137 | //always clear cursor cell (avoids false misprints) 138 | update_ch(old_cursorX, old_cursorY, ' ', EDITAREACOL, EDIT_FORECOLOR); 139 | 140 | 141 | //then try to update to its previous state 142 | if (drawChar0 != 0 && drawChar != '\0') code_point = ((drawChar0 & 0x1F) << 6) | (drawChar & 0x3F); 143 | else { 144 | if (drawChar == 0 || drawChar == END_LINE_CHAR) drawChar = FILL_CHAR; 145 | code_point = drawChar; 146 | } 147 | update_ch(old_cursorX, old_cursorY, code_point, EDITAREACOL, attrib); 148 | } 149 | if (old_cursorY != cursorY) { 150 | //Point to line in buffer when Y position changes 151 | if (edBuf1 != NULL) _dumpLine(edBuf1, posBufY, &tempLine); 152 | } 153 | //printf("\n"); 154 | //write_num(screen1, 10,10, cursorX, B_GREEN, F_WHITE,1); 155 | //write_num(screen1, 10,11, cursorY, B_RED, F_WHITE,1); 156 | //write_num(screen1, 10,12, old_cursorX, B_GREEN, F_WHITE,1); 157 | //write_num(screen1, 10,12, old_cursorY, B_GREEN, F_WHITE,1); 158 | //write_num(screen1, 10,14, posBufX, B_RED, F_WHITE,1); 159 | //write_num(screen1, 10,15, posBufY, B_RED, F_WHITE,1); 160 | //write_num(screen1, 10,16, findEndline(tempLine), BH_BLUE, F_WHITE,1); 161 | //write_num(screen1, 10,17, _length(&edBuf1), B_RED, F_WHITE,1); 162 | //for (int i=0; i vdisplayArea ) { 195 | write_ch(screen1,new_columns-1, oldPositionY, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,1); 196 | positionY = posBufY; 197 | scrollRatio = _length(&edBuf1) / vdisplayArea; 198 | scrollIndicator = positionY / scrollRatio; 199 | percentage = (scrollIndicator * 100) / vdisplayArea; 200 | scrollBar = ((vdisplayArea-3) * percentage)/100; 201 | if (positionY == 1) percentage = 0; 202 | if (percentage > 100) percentage = 100; 203 | if (scrollBar+2>=new_rows-5) scrollBar = new_rows - 7; 204 | write_ch(screen1,new_columns-1, 4+scrollBar, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,1); 205 | oldPositionY = 4+scrollBar; 206 | pep = percentage; 207 | } 208 | if (posBufX>0){ 209 | positionX = posBufX; 210 | write_ch(screen1, oldPositionX,new_rows-1, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,1); 211 | oldPositionX = 2+hscrollBar; 212 | hscrollRatio = MAX_LINE_SIZE / hdisplayArea; 213 | hscrollIndicator = positionX / hscrollRatio; 214 | hpercentage = (hscrollIndicator * 100) / hdisplayArea; 215 | hscrollBar = (((hdisplayArea) * hpercentage)/100); 216 | if (hscrollBar+2>=new_columns-3) hscrollBar = new_columns-5; 217 | write_ch(screen1, 2+hscrollBar,new_rows-1, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,1); 218 | oldPositionX = 2+hscrollBar; 219 | } 220 | strcpy(info, "\0"); 221 | sprintf(info, "|LINES: %d| L: %ld C: %ld [%d%c] ", _length(&edBuf1), posBufY, posBufX,pep,'%'); 222 | update_str(new_columns - 40, new_rows, info, STATUSBAR, STATUSMSG); 223 | } 224 | 225 | 226 | int main(int argc, char *argv[]) { 227 | 228 | char ch=0; 229 | char old_ch=0; 230 | int esc_key = 0; 231 | int keypressed = 0; 232 | 233 | //Init Terminal 234 | init_term(); 235 | initCEDIT(); 236 | draw_screen(); 237 | resetch(); 238 | strcpy(fileName, "\0"); 239 | //tempLine.linea[0].ch = END_LINE_CHAR; 240 | //tempLine.linea[posBufX].ch = END_LINE_CHAR; 241 | //tempLine.linea[posBufX].specialChar = 0; 242 | //tempLine.linea[posBufX].attrib = EDIT_FORECOLOR; 243 | if(argc > 1) { 244 | //Does the file exist? Open or create? 245 | strcpy(fileName, argv[1]); 246 | filetoBuffer(fileName); 247 | flush_editarea(0); 248 | buffertoScreen(0); 249 | dump_screen(screen1); 250 | fileModified= FILE_UNMODIFIED; 251 | } 252 | do{ 253 | //end flag from any part of the program 254 | if (programStatus == ENDSIGNAL) break; 255 | //Time animation & resize window 256 | if (timerC(&timer3) == TRUE){ 257 | displayMessage(tempMessage, (new_columns/2)-strlen(tempMessage)/2, 1, FH_WHITE, B_RED, 5); 258 | } 259 | if (timerC(&timer2) == TRUE){ 260 | _animation(); 261 | //Refresh screen size buffers if terminal dimension changes 262 | if (new_rows != old_rows || new_columns != old_columns) 263 | { 264 | _resizeScreen(); 265 | } 266 | } 267 | //Cursor Animation 268 | if (timerC(&cursor_timer1) == TRUE){ 269 | //Animation 270 | cursor_tick(); 271 | //if (keypressed == FALSE) { esc_key = 0;} 272 | } 273 | //PROCESS INPUT 274 | keypressed = kbhit(1); 275 | if (keypressed == TRUE) { 276 | keypressed = FALSE; 277 | //try to catch and avoid printing unwanted chars with cursor keys 278 | old_ch = ch; 279 | ch=readch(); 280 | if (old_ch==ESC_KEY) {unwantedChars = 1; esc_key = 1;} 281 | if (ch==ESC_KEY) {unwantedChars = 1; esc_key = 1;} 282 | if (unwantedChars>0) esc_key = 1; 283 | 284 | //Keys with a escape sequenece 285 | if (ch == ESC_KEY) {//buffertoScreen(0, 0,FALSE); 286 | esc_key = special_keys(); 287 | cursor_tick(); 288 | ch = 0;} 289 | else { 290 | //Capture control keys 291 | if ((ch>0 && ch< 0x0F) && (ch!=K_ENTER && ch != K_TAB)){buffertoScreen(FALSE); esc_key= control_keys(ch); ch=0;} 292 | else 293 | //Process raw edit input from keyboard in editor.c 294 | { 295 | //try to avoid printing unwanted chars with cursor keys 296 | if (ch != 0 && esc_key==0 && unwantedChars == 0&& posBufX 0) { 330 | strcpy(fileName, tempfileName); 331 | filetoBuffer(fileName); 332 | flush_editarea(0); 333 | buffertoScreen(0); 334 | dump_screen(screen1); 335 | }//buffertoScreen(0, 0, 0); 336 | } 337 | 338 | if (ch == K_CTRL_N){ 339 | if (openFileDialog(fileName,fullPath) == 1){ 340 | filetoBuffer(fileName); 341 | flush_editarea(0); 342 | buffertoScreen(0); 343 | } 344 | dump_screen(screen1); 345 | 346 | 347 | } 348 | 349 | 350 | 351 | return returnValue; 352 | } 353 | 354 | //ESCAPE-RELATED KEYS 355 | int special_keys() { 356 | /* MANAGE SPECIAL KEYS */ 357 | /* 358 | New implementation: Trail of chars found in keyboard.c 359 | If K_ESCAPE is captured read a trail up to 5 characters from the console. 360 | This is to control the fact that some keys may change 361 | according to the terminal and expand the editor's possibilities. 362 | Eg: F2 can be either 27 79 81 or 27 91 91 82. 363 | */ 364 | //cursorY : position on screen 365 | //posBufY : position in buffer 366 | 367 | int esc_key = 0; 368 | char chartrail[5]; 369 | char returnMenuChar=0; 370 | int menuCounter = 0; 371 | int countCh = 0; 372 | int ok = -1; 373 | char tempfileName[MAXFILENAME]; 374 | old_cursorX = cursorX; 375 | old_cursorY = cursorY; 376 | oldposBufX = posBufX; 377 | oldposBufY = posBufY; 378 | 379 | 380 | strcpy(chartrail, "\0"); 381 | read_keytrail(chartrail); //Read trail after ESC key 382 | //only ESC key detected, finish program 383 | if (chartrail[0] == ESC_KEY && chartrail[1]==0) { 384 | 385 | buffertoScreen(0); 386 | if (fileModified == FILE_MODIFIED) { 387 | ok=yesnoWindow(WMODIFIED_MSG, "Alert Window"); 388 | switch (ok){ 389 | case 0: //save file and exit 390 | strcpy(chartrail, K_ALT_S); 391 | break; 392 | case 1: //don't save and exit 393 | return ENDSIGNAL; 394 | break; 395 | 396 | case 2: //cancel keep running c-edit 397 | buffertoScreen(0); 398 | break; 399 | } 400 | } else 401 | //regular escape with no modifications 402 | return ENDSIGNAL; 403 | } 404 | 405 | //Check key trails for special keys starting with ESC. 406 | //FUNCTION KEYS : F1 - F4 407 | if(strcmp(chartrail, K_F2_TRAIL) == 0 || 408 | strcmp(chartrail, K_F2_TRAIL2) == 0) { 409 | handlemenus(&returnMenuChar, &menuCounter,TRUE); 410 | } else if(strcmp(chartrail, K_F3_TRAIL) == 0 || 411 | strcmp(chartrail, K_F3_TRAIL2) == 0) { 412 | } else if(strcmp(chartrail, K_F1_TRAIL) == 0 || 413 | strcmp(chartrail, K_F1_TRAIL2) == 0) { 414 | flush_editarea(0); 415 | buffertoScreen(0); 416 | displayHelp(); 417 | } else if(strcmp(chartrail, K_F4_TRAIL) == 0 || 418 | strcmp(chartrail, K_F4_TRAIL2) == 0) { 419 | 420 | // ARROW KEYS 421 | } else if(strcmp(chartrail, K_LEFT_TRAIL) == 0) { 422 | //Left-arrow key 423 | unwantedChars++; 424 | if(cursorX > 1){ 425 | cursorX = cursorX - 1; 426 | //editScroll.bufferX--; 427 | } 428 | if (posBufX>0) posBufX--; 429 | //adjust shiftH when going back to account for the fact that cursorX=1 is not enough 430 | if (cursorX == new_columns - 4) shiftH++; 431 | if (cursorX == 1 && shiftH>0) {shiftH--;buffertoScreen(1);} 432 | } else if(strcmp(chartrail, K_RIGHT_TRAIL) == 0) { 433 | //Right-arrow key 434 | unwantedChars++; 435 | if(cursorX < new_columns - 3){ 436 | cursorX = cursorX + 1; 437 | //shiftH = 0; 438 | } else{ 439 | if (posBufX 2) { 448 | cursorY = cursorY - 1; 449 | 450 | }else{ 451 | //scrolling up 452 | if (currentLine>0) { 453 | currentLine--; 454 | buffertoScreen(1); 455 | } 456 | } 457 | if (posBufY > 0) posBufY--; 458 | 459 | } else if(strcmp(chartrail, K_DOWN_TRAIL) == 0) { 460 | //Down-arrow key 461 | //Check if there are more lines to go to 462 | unwantedChars++; 463 | if (posBufY<_length(&edBuf1)-1){ 464 | if(cursorY < new_rows - 3) { 465 | //stay put if we are are the end of the viewing area 466 | cursorY = cursorY + 1; 467 | } 468 | else{ 469 | //scrolling down 470 | if (_length(&edBuf1) > vdisplayArea ) { 471 | currentLine++; 472 | buffertoScreen(1); 473 | } 474 | } 475 | posBufY++; 476 | } 477 | } else if(strcmp(chartrail, K_PAGEDOWN_TRAIL) == 0) { 478 | //Page Down key 479 | vdisplayLimit = _length(&edBuf1) - vdisplayArea; 480 | if (_length(&edBuf1) > vdisplayArea ) { 481 | if (currentLine + vdisplayArea <= vdisplayLimit ) 482 | currentLine = currentLine + vdisplayArea; 483 | else 484 | currentLine = vdisplayLimit; // stop at the limit of our scroll 485 | posBufY = currentLine; 486 | cursorY = START_CURSOR_Y; 487 | buffertoScreen(1); 488 | } 489 | } else if(strcmp(chartrail, K_PAGEUP_TRAIL) == 0) { 490 | //Page Down key 491 | if (_length(&edBuf1) > vdisplayArea ) { 492 | if (currentLine >= vdisplayArea) 493 | currentLine = currentLine - vdisplayArea; 494 | else 495 | currentLine = 0; // stop at the top 496 | posBufY = currentLine; 497 | cursorY = START_CURSOR_Y; 498 | buffertoScreen(1); 499 | } 500 | }else if(strcmp(chartrail, K_HOME_TRAIL) == 0 || strcmp(chartrail, K_HOME_TRAIL2) == 0 ) { 501 | if (_length(&edBuf1) > vdisplayArea ) { 502 | currentLine=0; 503 | cursorY = START_CURSOR_Y; 504 | posBufY=0; 505 | buffertoScreen(1); 506 | } 507 | }else if(strcmp(chartrail, K_END_TRAIL) == 0 || strcmp(chartrail, K_END_TRAIL2) == 0 ) { 508 | if (_length(&edBuf1) > vdisplayArea ) { 509 | currentLine=_length(&edBuf1)-vdisplayArea; 510 | cursorY = new_rows-3; 511 | posBufY=_length(&edBuf1)-1; 512 | buffertoScreen(1); 513 | } 514 | } else if(strcmp(chartrail, K_DELETE) == 0) { 515 | deleteKeyPressed = 1; 516 | editor_section(0); 517 | //delete button; 518 | } else if(strcmp(chartrail, K_ALT_F) == 0) { 519 | returnMenuChar=FILE_MENU; 520 | menuCounter=FILE_MENU; 521 | handlemenus(&returnMenuChar, &menuCounter,FALSE); 522 | } else if(strcmp(chartrail, K_ALT_P) == 0) { 523 | returnMenuChar=OPT_MENU; 524 | menuCounter=OPT_MENU; 525 | handlemenus(&returnMenuChar, &menuCounter,FALSE); 526 | } else if(strcmp(chartrail, K_ALT_H) == 0) { 527 | returnMenuChar=HELP_MENU; 528 | menuCounter=HELP_MENU; 529 | handlemenus(&returnMenuChar, &menuCounter,FALSE); 530 | } else if(strcmp(chartrail, K_ALT_O) == 0) { 531 | //openFileHandler(); //Open file Dialog 532 | buffertoScreen(0); 533 | dump_screen(screen1); 534 | if (openFileDialog(fileName,fullPath) == 1){ 535 | //is it a binary file? 536 | filetoBuffer(fileName); 537 | flush_editarea(0); 538 | buffertoScreen(0); 539 | } 540 | dump_screen(screen1); 541 | } else if(strcmp(chartrail, K_ALT_N) == 0) { 542 | //newDialog(currentFile); // New file 543 | //refresh_screen(-1); 544 | resetch(); 545 | } else if(strcmp(chartrail, K_ALT_A) == 0) { 546 | //saveasDialog(currentFile); //Save as.. file 547 | //refresh_screen(-1); 548 | } else if(strcmp(chartrail, K_ALT_S) == 0) { 549 | //Save file 550 | flush_editarea(0); 551 | buffertoScreen(0); 552 | strcpy(tempMessage, "[File saved!]\0"); 553 | if (strcmp(fileName, "UNTITLED") == 0) { 554 | countCh=inputWindow("File:", tempfileName, "Save file as...",28,2,48); 555 | if (countCh>0) { 556 | strcpy(fileName, tempfileName); 557 | buffertoFile(fileName); 558 | flush_editarea(0); 559 | buffertoScreen(0); 560 | dump_screen(screen1); 561 | timer3.ticks=0; 562 | } 563 | } else{ 564 | buffertoFile(fileName); 565 | flush_editarea(0); 566 | buffertoScreen(0); 567 | dump_screen(screen1); 568 | timer3.ticks=0; 569 | } 570 | //a bit convoluted but it works / exit if user selcts yes after saving 571 | if (ok==0){printf("File saved!. Exiting...\n"); return ENDSIGNAL; } 572 | } else if(strcmp(chartrail, K_ALT_W) == 0) { 573 | //if(strcmp(currentFile, UNKNOWN) == 0) 574 | //saveasDialog(currentFile); //Write to file 575 | //else { 576 | //saveDialog(currentFile); 577 | //} 578 | //refresh_screen(-1); 579 | } else if(strcmp(chartrail, K_ALT_X) == 0) { 580 | /* 581 | if(fileModified == 1) 582 | exitp = confirmation(); //Shall we exit? Global variable! 583 | else 584 | exitp = EXIT_FLAG; 585 | } } 586 | */ 587 | } 588 | esc_key = 1; 589 | return esc_key; 590 | 591 | } 592 | 593 | /* 594 | void linetoScreen(long whereY, VLINES tempLine, BOOL clean){ 595 | //dump temporary Line to screen buffer 596 | int i,j=0; 597 | for (i=0; i16) 654 | if (i<=strlen(auth)) printf("%c", auth[i-1]); 655 | printf("\n"); 656 | i++; 657 | } 658 | } while (timer2.ticks <30); 659 | //log 660 | // _printlist(&edBuf1); 661 | // printf("%ld:%ld\n", posBufX, posBufY); 662 | // printf("\n%ld\n",sizeof(&edBuf1)); 663 | 664 | if (screen1 != NULL) deleteList(&screen1); 665 | if (screen2 != NULL) deleteList(&screen2); 666 | if (listBox1 != NULL) removeList(&listBox1); 667 | 668 | _deletetheList(&edBuf1); //free edit Buffer 669 | resetAnsi(0); 670 | showcursor(); 671 | resetAnsi(0); 672 | } 673 | 674 | void _resizeScreen(){ 675 | //redraw everything when screen size changes 676 | get_terminal_dimensions(&new_rows, &new_columns); 677 | if (screen1 != NULL) deleteList(&screen1); 678 | if (screen2 != NULL) deleteList(&screen2); 679 | create_screen(&screen1); 680 | create_screen(&screen1); 681 | draw_screen(); 682 | flush_editarea(0); 683 | hdisplayArea = new_columns - 2; 684 | vdisplayArea = new_rows - 4; 685 | //if screen resizes file pointers are rewound to the beginning 686 | currentLine = 0; 687 | posBufX = 0; 688 | posBufY = 0; 689 | shiftH = 0; 690 | buffertoScreen(0); 691 | dump_screen(screen1); 692 | cursorX = START_CURSOR_X; 693 | cursorY = START_CURSOR_Y; 694 | } 695 | 696 | int displayMessage(char *temporaryMessage, int x, int y, int fColor, int bColor, int timeDuration){ 697 | //display a temporary nessage controlled by Timer3 698 | if (timer3.ticks == -1) { 699 | write_str(screen1, x,y, temporaryMessage, B_WHITE, F_WHITE,1); 700 | return 0; 701 | } 702 | if (timer3.ticks >= timeDuration) { 703 | stop_timer(&timer3); 704 | write_str(screen1, x,y, temporaryMessage, B_WHITE, F_WHITE,1); 705 | return 0; 706 | } 707 | write_str(screen1, x,y, temporaryMessage, bColor, fColor,1); 708 | return 1; 709 | } 710 | 711 | 712 | -------------------------------------------------------------------------------- /src/menu.c: -------------------------------------------------------------------------------- 1 | /* Module to display Menus on C·edit 2 | * for a Text User Interface 3 | * TextBox 4 | * Window 5 | * Last modified: 6/4/2024 6 | * @author:velorek 7 | */ 8 | #include 9 | #include "rterm.h" 10 | #include "scbuf.h" 11 | #include "ui.h" 12 | #include "menu.h" 13 | #include "tm.h" 14 | #include "keyb.h" 15 | #include "global.h" 16 | #include "editor.h" 17 | #include "opfile.h" 18 | #include "fileb.h" 19 | /*--------------------------------------------*/ 20 | /* Load current menu into circular linked list*/ 21 | /*--------------------------------------------*/ 22 | 23 | void loadmenus(int choice) { 24 | 25 | if(choice == HOR_MENU) { 26 | if (listBox1 != NULL) removeList(&listBox1); 27 | listBox1 = addatend(listBox1, newitem("File", 0, 1,-1,-1)); 28 | listBox1 = addatend(listBox1, newitem("Options", 7, 1,-1,-1)); 29 | listBox1 = addatend(listBox1, newitem("Help", 16, 1,-1,-1)); 30 | } 31 | 32 | 33 | if(choice == FILE_MENU) { 34 | if (listBox1 != NULL) removeList(&listBox1); 35 | listBox1 = addatend(listBox1, newitem("New", -1, -1,-1,-1)); 36 | listBox1 = addatend(listBox1, newitem("Open", -1, -1,-1,-1)); 37 | listBox1 = addatend(listBox1, newitem("Quick load", -1, -1,-1,-1)); 38 | listBox1 = addatend(listBox1, newitem("Save", -1, -1,-1,-1)); 39 | listBox1 = addatend(listBox1, newitem("Save as...", -1, -1,-1,-1)); 40 | listBox1 = addatend(listBox1, newitem("Exit", -1, -1,-1,-1)); 41 | } 42 | if(choice == OPT_MENU) { 43 | if (listBox1 != NULL) removeList(&listBox1); 44 | listBox1 = addatend(listBox1, newitem("File Info", -1, -1,-1,-1)); 45 | listBox1 = addatend(listBox1, newitem("Find...", -1, -1,-1,-1)); 46 | listBox1 = addatend(listBox1, newitem("Colors", -1, -1,-1,-1)); 47 | } 48 | if(choice == HELP_MENU) { 49 | if (listBox1 != NULL) removeList(&listBox1); 50 | listBox1 = addatend(listBox1, newitem("Help...", -1, -1,-1,-1)); 51 | listBox1 = addatend(listBox1, newitem("About", -1, -1,-1,-1)); 52 | } 53 | /* 54 | if(choice == YESNO_MENU) { 55 | add_item(mylist, "[YES]", (columns / 2) - 11, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1); 56 | add_item(mylist, "[NO]", (columns / 2) - 3, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1); 57 | add_item(mylist, "[CANCEL]", (columns / 2) + 4, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1); 58 | } 59 | if(choice == OK_MENU) { 60 | add_item(mylist, "[OK]", (columns / 2) - 1, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1); 61 | } 62 | if(choice == OK_MENU2) { 63 | add_item(mylist, "[OK]", (columns / 2) - 1, (rows / 2) + 3, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1); 64 | } 65 | if(choice == COLORS_MENU) { 66 | add_item(mylist, "C-Edit Theme", (columns / 2) - 6, (rows / 2) - 2, 67 | MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1); 68 | add_item(mylist, "Classic Theme", (columns / 2) - 6, (rows / 2) -1, 69 | MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1); 70 | add_item(mylist, "Dark Theme", (columns / 2) - 6, (rows / 2), 71 | MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1); 72 | } 73 | */ 74 | } 75 | 76 | /*--------------- 77 | Menu loop 78 | It depends on two values passed by reference stored in the function from where this routine is called: 79 | -returnMenuChar 80 | -menuCounter 81 | It does some tricky modulo operation to cycle back 82 | */ 83 | void handlemenus(char *returnMenuChar, int *menuCounter, BOOL horizontalMenu) 84 | { 85 | 86 | setselectorLimit(15); 87 | copy_screen(screen2,screen1); 88 | if (horizontalMenu) *returnMenuChar= horizontal_menu(); 89 | do{ 90 | switch (*returnMenuChar) { 91 | case 0: *menuCounter=FILE_MENU; *returnMenuChar=filemenu(); if (*returnMenuChar != DONT_UPDATE) xor_update(screen2,screen1); break; 92 | case 1: *menuCounter=OPT_MENU; *returnMenuChar=optionsmenu(); xor_update(screen2,screen1); break; 93 | case 2: *menuCounter=HELP_MENU; *returnMenuChar=helpmenu(); xor_update(screen2,screen1); break; 94 | default: 95 | break; 96 | } 97 | //convert -2 from right cursor to 1 to advance 98 | if (*returnMenuChar == -2 ) *returnMenuChar = 1; 99 | *menuCounter=*menuCounter + *returnMenuChar; 100 | if (*returnMenuChar == K_ENTER) break; 101 | if (*returnMenuChar == DONT_UPDATE) break; 102 | if (*returnMenuChar != ESC_KEY ) { 103 | copy_screen(screen1,screen2); 104 | //euclidian modulo, we circle back through the different switch cases 105 | *returnMenuChar = ((*menuCounter % 3) + 3) % 3; 106 | } 107 | 108 | } while (*returnMenuChar != ESC_KEY); 109 | //xor_update(screen2,screen1); 110 | if (*returnMenuChar != DONT_UPDATE){ 111 | copy_screen(screen1,screen2); 112 | dump_screen(screen1); 113 | } 114 | } 115 | //Entry menu- horizontal 116 | char horizontal_menu() { 117 | char ch=0; 118 | 119 | dump_screen(screen1); 120 | //Save current screen to screen2 121 | loadmenus(HOR_MENU); 122 | //load menus from ui.c onto lisBox in (global.c) 123 | //dump_screen(screen1); 124 | ch = listBox(listBox1, 0, 1 , &scrollData, MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1, 3, HORIZONTAL,0,1); 125 | //delete listbox 126 | if(ch == ESC_KEY) scrollData.itemIndex = ch;; //to avoid warning 127 | removeList(&listBox1); 128 | //return option passed in scrollData (global.c) 129 | return scrollData.itemIndex; 130 | } 131 | /*-------------------------*/ 132 | /* Display File menu */ 133 | /*-------------------------*/ 134 | 135 | char filemenu() { 136 | char ch=0; 137 | int countCh = 0; 138 | char tempfileName[MAXFILENAME]; 139 | int ok2 = -1; 140 | int retvalue = 0; 141 | write_str(screen1,0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1); 142 | write_str(screen1,0, 1, "File", MENU_SELECTOR, MENU_FOREGROUND1,1); 143 | loadmenus(FILE_MENU); 144 | draw_window(screen1,0, 2, 13, 9, MENU_PANEL, MENU_FOREGROUND0,0, 1,0,1,1); 145 | ch = listBox(listBox1, 3, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1, -1, VERTICALWITHBREAK,0,1); 146 | // copy_screen(screen1,screen2); 147 | // dump_screen(screen1); 148 | 149 | //return if right and left arrow keys are pressed 150 | if (ch == K_RIGHTMENU || ch == K_LEFTMENU) return ch; 151 | 152 | if(scrollData.itemIndex == OPTION_1) { 153 | flush_editarea(0); 154 | buffertoScreen(0); 155 | countCh=inputWindow("File:", tempfileName, "[+] New file",26,2,44); 156 | if (countCh>0) { 157 | strcpy(fileName, tempfileName); 158 | filetoBuffer(fileName); 159 | flush_editarea(0); 160 | buffertoScreen(0); 161 | dump_screen(screen1); 162 | }//buffertoScreen(0, 0, 0); 163 | ch=0; 164 | return DONT_UPDATE; 165 | } 166 | 167 | if(scrollData.itemIndex == OPTION_2) { 168 | //openFile Dialog in opfile.c 169 | flush_editarea(0); 170 | buffertoScreen(0); 171 | if (openFileDialog(fileName,fullPath) == 1){ 172 | filetoBuffer(fileName); 173 | flush_editarea(0); 174 | buffertoScreen(0); 175 | } 176 | 177 | dump_screen(screen1); 178 | return DONT_UPDATE; 179 | } 180 | if(scrollData.itemIndex == OPTION_3) { 181 | //External Module - Open file dialog. 182 | //openFileHandler(); 183 | 184 | flush_editarea(0); 185 | buffertoScreen(0); 186 | countCh=inputWindow("File:", tempfileName, "Quick load...",26,2,44); 187 | if (countCh>0) { 188 | //check if it's a binary file 189 | if (openandcheckFile(tempfileName) == 1){ 190 | ok2 = yesnoWindow(WCHECKFILE_MSG, "Alert window"); 191 | switch (ok2){ 192 | case 0: // open binary file anyway 193 | retvalue=1; 194 | break; 195 | case 1: //don't open binary file 196 | strcpy (fileName,"\0"); 197 | strcpy (fullPath,"\0"); 198 | retvalue=0; 199 | break; 200 | case 2: //cancel is the same as no here 201 | strcpy (fileName,"\0"); 202 | strcpy (fullPath,"\0"); 203 | retvalue=0; 204 | break; 205 | } 206 | }else{ 207 | retvalue = 1; 208 | } 209 | if (retvalue==1){ 210 | strcpy(fileName, tempfileName); 211 | filetoBuffer(fileName); 212 | flush_editarea(0); 213 | buffertoScreen(0); 214 | dump_screen(screen1); 215 | } 216 | }//buffertoScreen(0, 0, 0); 217 | return DONT_UPDATE; 218 | 219 | } 220 | if(scrollData.itemIndex == OPTION_4) { 221 | //Save file 222 | flush_editarea(0); 223 | buffertoScreen(0); 224 | 225 | if (strcmp(fileName, "UNTITLED") == 0) { 226 | countCh=inputWindow("File:", tempfileName, "Save file as...",26,2,44); 227 | if (countCh>0) { 228 | 229 | strcpy(fileName, tempfileName); 230 | buffertoFile(fileName); 231 | flush_editarea(0); 232 | buffertoScreen(0); 233 | dump_screen(screen1); 234 | } 235 | } else{ 236 | buffertoFile(fileName); 237 | flush_editarea(0); 238 | buffertoScreen(0); 239 | dump_screen(screen1); 240 | } 241 | 242 | 243 | return DONT_UPDATE; 244 | } 245 | if(scrollData.itemIndex == OPTION_5) { 246 | //Save as option 247 | flush_editarea(0); 248 | buffertoScreen(0); 249 | 250 | countCh=inputWindow("File:", fileName, "Save file as...",26,2,44); 251 | if (countCh>0) { 252 | buffertoFile(fileName); 253 | flush_editarea(0); 254 | buffertoScreen(0); 255 | dump_screen(screen1); 256 | } 257 | return DONT_UPDATE; 258 | } 259 | 260 | if(scrollData.itemIndex == OPTION_6) { 261 | //Exit option 262 | //if(fileModified == 1) 263 | //exitp = confirmation(); //Shall we exit? Global variable! 264 | //else 265 | programStatus = ENDSIGNAL; 266 | } 267 | //restore previous screen 268 | //dump_screen(screen1); 269 | 270 | return ch; 271 | } 272 | 273 | /*--------------------------*/ 274 | /* Display Options menu */ 275 | /*--------------------------*/ 276 | 277 | char optionsmenu() { 278 | //int setColor; 279 | char ch=0; 280 | 281 | write_str(screen1,6, 1, "Options", MENU_SELECTOR, MENU_FOREGROUND1,1); 282 | write_str(screen1, 0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1); 283 | loadmenus(OPT_MENU); 284 | draw_window(screen1,6, 2, 19, 6, MENU_PANEL, MENU_FOREGROUND0,0, 1,0,1,1); 285 | ch = listBox(listBox1, 9, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1, -1, VERTICALWITHBREAK,0,1); 286 | if(scrollData.itemIndex == OPTION_1) { 287 | //File Info 288 | //fileInfoDialog(); 289 | } 290 | if(scrollData.itemIndex == OPTION_3) { 291 | //Set Colors 292 | /* setColor = colorsWindow(mylist,COLORSWTITLE); 293 | setColorScheme(setColor); 294 | checkConfigFile(setColor); //save new configuration in config file 295 | *///refresh_screen(1); 296 | } 297 | return ch; 298 | 299 | } 300 | 301 | /*--------------------------*/ 302 | /* Display Help menu */ 303 | /*--------------------------*/ 304 | 305 | char helpmenu() { 306 | char ch= 0; 307 | 308 | write_str(screen1,15, 1, "Help", MENU_SELECTOR, MENU_FOREGROUND1,1); 309 | write_str(screen1, 0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1); 310 | loadmenus(HELP_MENU); 311 | draw_window(screen1,15, 2, 25, 5, MENU_PANEL, MENU_FOREGROUND0, 0,1,0,1,1); 312 | ch = listBox(listBox1, 18, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1, -1, VERTICALWITHBREAK,0,1); 313 | if(scrollData.itemIndex == OPTION_1 && ch>0) { 314 | //Help dialog 315 | //help_info(); 316 | flush_editarea(0); 317 | buffertoScreen(0); 318 | displayHelp(); 319 | } 320 | if(scrollData.itemIndex == OPTION_2 && ch>0) { 321 | //About info 322 | flush_editarea(0); 323 | buffertoScreen(0); 324 | 325 | displayAbout(); 326 | } 327 | return ch; 328 | } 329 | 330 | //ABOUT 331 | 332 | int displayAbout(void) 333 | { 334 | char ch = 0; 335 | int i = 0; 336 | int colAnimation = F_BLACK; 337 | int keypressed = 0; 338 | int colCounter = 0; 339 | copy_screen(screen2, screen1); 340 | 341 | window(screen1, (new_columns / 2) - 18, (new_rows / 2) - 6, 342 | (new_columns / 2) + 17, (new_rows) / 2 + 3, B_WHITE, F_BLACK, 343 | B_BLACK, 1, 1, 1); 344 | 345 | for (i = 0; i < 6; i++) { 346 | write_str(screen1, (new_columns / 2) - 15, 347 | (new_rows / 2) - 5 + i, aboutMSG[i], B_WHITE, 348 | F_BLACK, 0); 349 | } 350 | 351 | write_str(screen1, (new_columns / 2) - 11, (new_rows / 2) - 7, 352 | "[+] ABOUT INFORMATION", B_BLACK, FH_WHITE, 1); 353 | 354 | // write_str(screen1, (new_columns / 2) - 25, (new_rows / 2) + 2, 355 | //aboutMSG[3], B_YELLOW, F_BLACK, 0); 356 | write_str(screen1, (new_columns / 2) - 1, (new_rows / 2) + 2, "[OK]", 357 | B_RED, FH_WHITE, 1); 358 | 359 | dump_screen(screen1); 360 | 361 | if (kbhit(100) == 1) 362 | ch = readch(); 363 | ch = 0; 364 | i = 0; 365 | colCounter = 0; 366 | //pulsating animation 367 | do { 368 | keypressed = kbhit(30); 369 | if (timerC(&timer2) == TRUE) { 370 | //About animation 371 | write_str(screen1, (new_columns / 2) - 15, 372 | (new_rows / 2) - 5 + i, aboutMSG[i], B_WHITE, 373 | colAnimation, 1); 374 | i++; 375 | if (i == 6) { 376 | i = 0; 377 | switch (colCounter){ 378 | case 1: 379 | colAnimation = FH_BLACK; 380 | break; 381 | case 2: 382 | colAnimation = FH_BLACK; 383 | break; 384 | case 3: 385 | colAnimation = FH_BLACK; 386 | break; 387 | case 4: 388 | colAnimation = FH_BLACK; 389 | break; 390 | case 5: 391 | colAnimation = FH_BLACK; 392 | break; 393 | case 6: 394 | colAnimation = FH_WHITE; 395 | break; 396 | case 7: 397 | colAnimation = FH_WHITE; 398 | break; 399 | case 8: 400 | colAnimation = FH_WHITE; 401 | break; 402 | case 9: 403 | colAnimation = F_BLACK; 404 | break; 405 | case 10: 406 | colAnimation = F_BLACK; 407 | break; 408 | 409 | 410 | } 411 | colCounter++; 412 | if (colCounter ==11) colCounter = 0; 413 | } 414 | //if terminal resizes 415 | if (_animation() == -1) 416 | break; 417 | } 418 | //Process keys 419 | if (keypressed == 1) { 420 | ch = readch(); 421 | keypressed = 0; 422 | 423 | //Read special keys 424 | if (ch == K_ESCAPE) { 425 | ch = readch(); 426 | if (ch == ESC_KEY) 427 | break; 428 | } 429 | 430 | } 431 | } while (ch != K_ENTER); 432 | resetch(); 433 | copy_screen(screen1, screen2); 434 | if (listBox1 != NULL) 435 | removeList(&listBox1); 436 | dump_screen(screen1); 437 | return ch; 438 | } 439 | void addItemsHelp(LISTCHOICE **listBox1, char textarray[][MAXLINE], int rows) 440 | { 441 | int h=0; 442 | //Load items into the list. 443 | //if (*listBox1 != NULL) removeList(listBox1); 444 | for (h = 0; h < rows-1; h++) { 445 | //*ch = textarray[h]; 446 | *listBox1 = addatend(*listBox1, newitem(textarray[h],-1,-1,-1,-1)); 447 | } 448 | *listBox1 = addatend(*listBox1, newitem(textarray[rows-1],-1,-1,B_WHITE,FH_BLUE)); 449 | } 450 | int displayHelp(void) 451 | { 452 | char ch = 0; 453 | resetScrollData(&scrollData); 454 | if (listBox1 != NULL) 455 | removeList(&listBox1); 456 | 457 | setselectorLimit(26*2-1); 458 | //scrollData.selectorLimit = (26 * 2) - 1; //No. of chars per item display 459 | //scrollData.selectorLimit = 100; //No. of chars per item display 460 | //create_screen(&screen2); 461 | copy_screen(screen2, screen1); 462 | window(screen1, (new_columns / 2) - 26, (new_rows / 2) - 8, 463 | (new_columns / 2) + 26, (new_rows) / 2 + 8, B_WHITE, F_BLACK, 464 | B_BLACK, 1, 1, 1); 465 | write_str(screen1, (new_columns / 2) - 12, (new_rows / 2) - 9, 466 | "[+] MAIN HELP INFORMATION", B_BLACK, FH_WHITE, 1); 467 | 468 | write_str(screen1, (new_columns / 2) - 1, (new_rows / 2) + 7, "[OK]", 469 | B_RED, F_WHITE, 1); 470 | dump_screen(screen1); 471 | addItemsHelp(&listBox1, help, HELPLINES); 472 | if (listBox1 != NULL) 473 | ch = listBox(listBox1, (new_columns / 2) - 24, 474 | (new_rows / 2) - 7, &scrollData, B_WHITE, F_BLACK, 475 | B_WHITE, FH_WHITE, 14, VERTICAL,1,LOCKED); 476 | copy_screen(screen1, screen2); 477 | // if (screen2 != NULL) 478 | // deleteList(&screen2); 479 | if (listBox1 != NULL) 480 | removeList(&listBox1); 481 | dump_screen(screen1); 482 | return ch; 483 | } 484 | 485 | -------------------------------------------------------------------------------- /src/menu.h: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | - HEADER - 4 | Module with all menus on C·EDIT 5 | @author : Velorek 6 | @version : 1.0 7 | Last modified: 06/04/2024 8 | ======================================================================== 9 | */ 10 | 11 | #ifndef _MENU_H_ 12 | #define _MENU_H_ 13 | 14 | #include "scbuf.h" 15 | #include 16 | 17 | void loadmenus(int choice); 18 | char horizontal_menu(); 19 | char filemenu(); 20 | char optionsmenu(); 21 | char helpmenu(); 22 | void credits(); 23 | void handlemenus(char *returnMenuChar, int *menuCounter, BOOL horizontalMenu); 24 | int displayAbout(); 25 | int displayHelp(void); 26 | 27 | #endif 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/opfile.c: -------------------------------------------------------------------------------- 1 | /*====================================================================*/ 2 | /* OPEN FILE MODULE 3 | +ListFiles with double linked list and selection menu in C. 4 | +Scroll function added. 5 | +Integrated with C-EDIT 6 | A window is drawn to the buffer and all of the scroll animations 7 | are drawn to the terminal on raw mode to have a better scrolling 8 | animation. Once the file is selected, the window is closed and the 9 | previous screen is painted to the terminal again. 10 | Last modified : 11/1/2019 - Switch to readch() instead of getch() 11 | 06/04/2019 - Corrected all memory leaks 12 | 14/04/2019 - Rename headers 13 | 22/04/2020 - Added Set File to Open 14 | 23/04/2023 - Merged with Lynx and vastly simplified 15 | Coded by Velorek. 16 | Target OS: Linux. */ 17 | /*====================================================================*/ 18 | 19 | /*====================================================================*/ 20 | /* COMPILER DIRECTIVES AND INCLUDES */ 21 | /*====================================================================*/ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "rterm.h" 27 | #include "scbuf.h" 28 | #include "listbox.h" 29 | #include "tm.h" 30 | #include "keyb.h" 31 | #include "global.h" 32 | #include "opfile.h" 33 | #include "ui.h" 34 | #include "fileb.h" 35 | /*====================================================================*/ 36 | /* GLOBAL VARIABLES */ 37 | /*====================================================================*/ 38 | 39 | int window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0; 40 | int ndirs=0, nfiles=0; 41 | 42 | /*====================================================================*/ 43 | /* CODE */ 44 | /*====================================================================*/ 45 | 46 | int listFiles(LISTCHOICE ** listBox1, char *directory) { 47 | DIR *d; 48 | struct dirent *dir; 49 | int i; 50 | char temp[MAX_ITEM_LENGTH]; 51 | int lenDir; //length of directory 52 | ndirs=0; 53 | nfiles=0; 54 | if (*listBox1 != NULL) removeList(listBox1); 55 | *listBox1 = addatend(*listBox1, newitem("[..]",-1,-1,FH_BLUE,B_WHITE)); // ".." 56 | 57 | //Start at current directory 58 | d = opendir(directory); 59 | //Find directories and add them to list first 60 | if(d) { 61 | while((dir = readdir(d)) != NULL) { 62 | if(dir->d_type == DT_DIR) { 63 | 64 | lenDir = strlen(dir->d_name); 65 | 66 | //Check length of directory 67 | //Directories are displayed between brackets [directory] 68 | if(lenDir > MAX_ITEM_LENGTH - 2) { 69 | //Directory name is long. CROP 70 | memset(&temp, '\0',sizeof(temp)); //Clear memory for temporary line 71 | strcpy(temp,"\0"); 72 | strcpy(temp, "["); 73 | for(i = 1; i < MAX_ITEM_LENGTH - 1; i++) { 74 | temp[i] = dir->d_name[i - 1]; 75 | } 76 | temp[MAX_ITEM_LENGTH - 1] = ']'; 77 | } else { 78 | //Directory's name is shorter than display 79 | //Add spaces to item string. 80 | memset(&temp, '\0',sizeof(temp)); //Clear memory for temporary line 81 | strcpy(temp,"\0"); 82 | strcpy(temp, "["); 83 | for(i = 1; i < lenDir + 1; i++) { 84 | temp[i] = dir->d_name[i - 1]; 85 | } 86 | temp[lenDir + 1] = ']'; 87 | } 88 | //Add all directories except CURRENTDIR and CHANGEDIR 89 | if(strcmp(dir->d_name, ".") != 0 90 | && strcmp(dir->d_name, "..") != 0) 91 | { ndirs++; 92 | *listBox1 = 93 | addatend(*listBox1, newitem(temp, -1,-1,FH_BLUE,B_WHITE));} 94 | } 95 | } 96 | } 97 | closedir(d); 98 | 99 | //Find files and add them to list after directories 100 | d = opendir(directory); 101 | if(d) { 102 | while((dir = readdir(d)) != NULL) { 103 | if(dir->d_type == DT_REG) { 104 | //only list valid fiels 105 | if(strlen(dir->d_name) > MAX_ITEM_LENGTH) { 106 | for(i = 0; i < MAX_ITEM_LENGTH; i++) { 107 | temp[i] = dir->d_name[i]; 108 | } 109 | } else { 110 | memset(&temp, '\0',sizeof(temp)); //Clear memory for temporary line 111 | strcpy(temp,"\0"); 112 | strcpy(temp, dir->d_name); 113 | } 114 | nfiles++; 115 | *listBox1 = 116 | addatend(*listBox1, newitem(temp, -1,-1,-1,-1)); 117 | } 118 | } 119 | closedir(d); 120 | } 121 | 122 | return 0; 123 | } 124 | 125 | void addItems(LISTCHOICE **listBox1) 126 | { 127 | int h=0; 128 | //Load items into the list. 129 | //if (listBox1 != NULL) removeList(listBox1); 130 | for (h = 0; h <10; h++) { 131 | //*ch = textarray[h]; 132 | *listBox1 = addatend(*listBox1, newitem("Test",-1,-1,-1,-1)); 133 | } 134 | } 135 | 136 | int openFileDialog(char fileName[MAXFILENAME], char fullPath[MAXFILENAME]){ 137 | char ch=0; 138 | char path[MAXFILENAME]; 139 | char bit[MAXFILENAME]; 140 | char ndirstr[100]; 141 | size_t i=0; 142 | int ok2 =0; 143 | int retvalue=0; 144 | char nfilestr[100]; 145 | char currentPath[4] = "./\0"; 146 | retvalue =0; 147 | setselectorLimit(23); 148 | window_y1 = (new_rows / 2) - 10; 149 | window_y2 = (new_rows / 2) + 10; 150 | window_x1 = (new_columns / 2) - 13; 151 | window_x2 = (new_columns / 2) + 13; 152 | copy_screen(screen2,screen1); 153 | old_rows = new_rows; 154 | old_columns = new_columns; 155 | do{ 156 | draw_window(screen1,window_x1, window_y1, window_x2, window_y2,B_WHITE,F_BLACK,B_BLACK,1,1,1,0); 157 | draw_window(screen1,window_x1, window_y2-3, window_x2, window_y2,B_CYAN,F_WHITE,B_BLACK,1,0,0,0); 158 | dump_screen(screen1); 159 | listFiles(&listBox1,currentPath); 160 | sprintf(ndirstr, "[%d] Directories", ndirs); 161 | sprintf(nfilestr, "[%d] Files", nfiles); 162 | write_str(screen1,window_x1+2,window_y2-2,ndirstr,B_CYAN,FH_WHITE,1); 163 | write_str(screen1,window_x1+2,window_y2-1,nfilestr,B_CYAN,F_WHITE,1); 164 | write_str(screen1,window_x1+1,window_y2-4, " PRESS [ESC] TO EXIT ",B_BLACK,FH_WHITE,1); 165 | write_str(screen1,window_x1+2,window_y1,"Select file...",B_BLACK,FH_WHITE,1); 166 | ch = listBox(listBox1, window_x1+3,window_y1+1, &scrollData, B_WHITE, F_BLACK,B_RED, FH_WHITE, 15, VERTICAL,1,LOCKED); 167 | if (_animation() == -1) {ch=K_ESCAPE; break;} 168 | if (ch == 0x27) {break;} 169 | if (ch == K_ENTER){ 170 | 171 | if (scrollData.item[0] == '[') { 172 | //directory 173 | memset(&path, '\0',sizeof(path)); //Clear memory for temporary line 174 | memset(&bit, '\0',sizeof(bit)); //Clear memory for temporary line 175 | strcpy(bit,"\0"); 176 | strcpy(path,"\0"); 177 | for (i=1; i 19 | #include 20 | #include 21 | #include 22 | #include "rterm.h" 23 | #include "scbuf.h" 24 | #include "listbox.h" 25 | #include "tm.h" 26 | #include "keyb.h" 27 | #include "global.h" 28 | 29 | /*====================================================================*/ 30 | /* CONSTANTS */ 31 | /*====================================================================*/ 32 | #define MAX_ITEM_LENGTH 15 33 | 34 | 35 | /*====================================================================*/ 36 | /* CONSTANT VALUES */ 37 | /*====================================================================*/ 38 | 39 | /*====================================================================*/ 40 | /* FUNCTION PROTOTYPES */ 41 | /*====================================================================*/ 42 | 43 | int listFiles(LISTCHOICE ** listBox1, char *directory); 44 | void addItems(LISTCHOICE **listBox1); 45 | int openFileDialog(char fileName[MAXFILENAME], char fullPath[MAXFILENAME]); 46 | 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/rterm.c: -------------------------------------------------------------------------------- 1 | /* 2 | ====================================================================== 3 | Module to control some display routines that implement ANSI functions. 4 | on LINUX Terminals 5 | 6 | @author : Velorek (routines extracted from the internet) 7 | @version : 1.0 8 | 9 | LAST MODIFIED : 18/01/2023 Kbhit with poll control added 10 | ====================================================================== 11 | */ 12 | 13 | /*====================================================================*/ 14 | /* COMPILER DIRECTIVES AND INCLUDES */ 15 | /*====================================================================*/ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "rterm.h" 26 | #include "keyb.h" 27 | /*====================================================================*/ 28 | /* GLOBAL VARIABLES */ 29 | /*====================================================================*/ 30 | 31 | struct winsize max; 32 | static struct termios term, failsafe; 33 | static int peek_character = -1; 34 | 35 | /*====================================================================*/ 36 | /* FUNCTIONS - CODE */ 37 | /*====================================================================*/ 38 | 39 | /*-------------------------------------*/ 40 | /* Initialize new terminal i/o settings*/ 41 | /*-------------------------------------*/ 42 | void pushTerm() { 43 | //Save terminal settings in failsafe to be retrived at the end 44 | tcgetattr(0, &failsafe); 45 | } 46 | 47 | /*---------------------------*/ 48 | /* Reset terminal to failsafe*/ 49 | /*---------------------------*/ 50 | int resetTerm() { 51 | //tcsetattr(0, TCSANOW, &failsafe); 52 | /* flush and reset */ 53 | if (tcsetattr(0,TCSAFLUSH,&failsafe) < 0) return -1; 54 | return 0; 55 | } 56 | 57 | 58 | /*--------------------------------------.*/ 59 | /* Detect whether a key has been pressed.*/ 60 | /*---------------------------------------*/ 61 | 62 | int kbhit(int timeout_ms) 63 | { 64 | struct pollfd fds = {STDIN_FILENO, POLLIN, 0}; 65 | fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); 66 | int ret = poll(&fds, 1, timeout_ms); 67 | fcntl(STDIN_FILENO, F_SETFL, 0); 68 | if (ret > 0) { 69 | return 1; 70 | } else if (ret == 0) { 71 | return 0; // timeout occurred 72 | } else { 73 | return -1; // error occurred 74 | } 75 | } 76 | 77 | /*----------------------*/ 78 | /*Read char with control*/ 79 | /*----------------------*/ 80 | char readch() { 81 | char ch; 82 | if(peek_character != -1) { 83 | ch = peek_character; 84 | peek_character = -1; 85 | return ch; 86 | } 87 | read(0, &ch, 1); 88 | return ch; 89 | } 90 | 91 | void resetch() { 92 | //Clear ch 93 | term.c_cc[VMIN] = 0; 94 | tcsetattr(0, TCSANOW, &term); 95 | peek_character = 0; 96 | } 97 | 98 | /*----------------------------------*/ 99 | /* Move cursor to specified position*/ 100 | /*----------------------------------*/ 101 | void gotoxy(int x, int y) { 102 | printf("%c[%d;%df", 0x1B, y, x); 103 | } 104 | 105 | /*---------------------*/ 106 | /* Change colour output*/ 107 | /*---------------------*/ 108 | void outputcolor(int foreground, int background) { 109 | printf("%c[%d;%dm", 0x1b, foreground, background); 110 | } 111 | 112 | /*-----------------------------------------------------*/ 113 | /* Change the whole color of the screen by applying CLS*/ 114 | /*-----------------------------------------------------*/ 115 | void screencol(int x) { 116 | gotoxy(0, 0); 117 | outputcolor(0, x); 118 | printf("%c[2J", 0x1b); 119 | outputcolor(0, 0); 120 | } 121 | 122 | /*-----------------------*/ 123 | /* Reset ANSI ATTRIBUTES */ 124 | /*-----------------------*/ 125 | void resetAnsi(int x) { 126 | switch (x) { 127 | case 0: //reset all colors and attributes 128 | printf("%c[0m", 0x1b); 129 | break; 130 | case 1: //reset only attributes 131 | printf("%c[20m", 0x1b); 132 | break; 133 | case 2: //reset foreg. colors and not attrib. 134 | printf("%c[39m", 0x1b); 135 | break; 136 | case 3: //reset back. colors and not attrib. 137 | printf("%c[49m", 0x1b); 138 | break; 139 | default: 140 | break; 141 | } 142 | } 143 | 144 | /*------------------------*/ 145 | /* Get terminal dimensions*/ 146 | /*------------------------*/ 147 | int get_terminal_dimensions(int *rows, int *columns) { 148 | ioctl(0, TIOCGWINSZ, &max); 149 | *columns = max.ws_col; 150 | *rows = max.ws_row; 151 | return 0; 152 | } 153 | 154 | /*--------------------------*/ 155 | /* Ansi function hide cursor*/ 156 | /*--------------------------*/ 157 | void hidecursor() { 158 | printf("\e[?25l"); 159 | } 160 | 161 | /*--------------------------*/ 162 | /* Ansi function show cursor*/ 163 | /*--------------------------*/ 164 | void showcursor() { 165 | printf("\e[?25h"); 166 | } 167 | /*----------------------------------*/ 168 | /* Get cursor position */ 169 | /*----------------------------------*/ 170 | 171 | int get_pos(int *y, int *x) { 172 | 173 | char buf[30]={0}; 174 | int ret, i, pow; 175 | char ch; 176 | 177 | *y = 0; *x = 0; 178 | 179 | struct termios term, restore; 180 | 181 | tcgetattr(0, &term); 182 | tcgetattr(0, &restore); 183 | term.c_lflag &= ~(ICANON|ECHO); 184 | tcsetattr(0, TCSANOW, &term); 185 | 186 | write(1, "\033[6n", 4); 187 | 188 | for( i = 0, ch = 0; ch != 'R'; i++ ) 189 | { 190 | ret = read(0, &ch, 1); 191 | if ( !ret ) { 192 | tcsetattr(0, TCSANOW, &restore); 193 | //fprintf(stderr, "getpos: error reading response!\n"); 194 | return 1; 195 | } 196 | buf[i] = ch; 197 | //printf("buf[%d]: \t%c \t%d\n", i, ch, ch); 198 | } 199 | 200 | if (i < 2) { 201 | tcsetattr(0, TCSANOW, &restore); 202 | //printf("i < 2\n"); 203 | return(1); 204 | } 205 | 206 | for( i -= 2, pow = 1; buf[i] != ';'; i--, pow *= 10) 207 | *x = *x + ( buf[i] - '0' ) * pow; 208 | 209 | for( i-- , pow = 1; buf[i] != '['; i--, pow *= 10) 210 | *y = *y + ( buf[i] - '0' ) * pow; 211 | 212 | tcsetattr(0, TCSANOW, &restore); 213 | return 0; 214 | } 215 | /*--------------------------*/ 216 | /* Set up terminal */ 217 | /*--------------------------*/ 218 | 219 | //For code simplification purposes 220 | void init_term(void) 221 | 222 | { 223 | //switch to alternate screen buffer 224 | printf("\033[?1049h"); 225 | hidecursor(); 226 | pushTerm(); 227 | resetch(); 228 | //Setup unicode 229 | setlocale(LC_ALL, ""); 230 | } 231 | 232 | void close_term(void) 233 | { 234 | showcursor(); 235 | resetTerm(); 236 | resetAnsi(0); 237 | //restore previous screen 238 | printf("\033[?1049l"); 239 | //cls 240 | gotoxy(0,0); 241 | printf("%c[2J\r", 0x1b); 242 | 243 | } 244 | /* 245 | void init_term(){ 246 | hidecursor(); 247 | pushTerm(); 248 | resetch(); 249 | //Setup unicode 250 | setlocale(LC_ALL, ""); 251 | } 252 | 253 | 254 | void close_term(){ 255 | showcursor(); 256 | resetTerm(); 257 | outputcolor(F_WHITE, B_BLACK); 258 | screencol(B_BLACK); 259 | resetAnsi(0); 260 | printf("\n"); 261 | } 262 | */ 263 | 264 | -------------------------------------------------------------------------------- /src/rterm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | - HEADER - 4 | Module to control some display routines that implement ANSI functions. 5 | @author : Velorek 6 | @version : 1.0 7 | Last modified: 15/09/2021 + Linux Term 8 | ======================================================================== 9 | */ 10 | 11 | #ifndef _RTERM_H_ 12 | #define _RTERM_H_ 13 | 14 | /*====================================================================*/ 15 | /* COMPILER DIRECTIVES AND INCLUDES */ 16 | /*====================================================================*/ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | /*====================================================================*/ 25 | /* COLOR CONSTANTS */ 26 | /*====================================================================*/ 27 | 28 | // Background colors low intensity 29 | #define B_BLACK 40 30 | #define B_RED 41 31 | #define B_GREEN 42 32 | #define B_YELLOW 43 33 | #define B_BLUE 44 34 | #define B_MAGENTA 45 35 | #define B_CYAN 46 36 | #define B_WHITE 47 37 | 38 | // Foreground colors low intensity 39 | #define F_BLACK 30 40 | #define F_RED 31 41 | #define F_GREEN 32 42 | #define F_YELLOW 33 43 | #define F_BLUE 34 44 | #define F_MAGENTA 35 45 | #define F_CYAN 36 46 | #define F_WHITE 37 47 | //#define F_WHITE 37 48 | #define F_GREY 90 49 | 50 | // Background colors high intensity 51 | #define BH_BLACK 100 52 | #define BH_RED 101 53 | #define BH_GREEN 102 54 | #define BH_YELLOW 103 55 | #define BH_BLUE 104 56 | #define BH_MAGENTA 105 57 | #define BH_CYAN 106 58 | #define BH_WHITE 107 59 | 60 | // Foreground colors high intensity 61 | #define FH_BLACK 90 62 | #define FH_RED 91 63 | #define FH_GREEN 92 64 | #define FH_YELLOW 93 65 | #define FH_BLUE 94 66 | #define FH_MAGENTA 95 67 | #define FH_CYAN 96 68 | #define FH_WHITE 97 69 | 70 | #define TRUE 1 71 | #define FALSE 0 72 | 73 | //Keys used. 74 | #define K_ENTER 13 75 | #define K_ENTER2 10 76 | #define K_ESCAPE 27 77 | #define K_UP_TRAIL "\e[A\0\0" 78 | #define K_DOWN_TRAIL "\e[B\0\0" 79 | #define K_RIGHT_TRAIL "\e[C\0\0" 80 | #define K_LEFT_TRAIL "\e[D\0\0" 81 | 82 | 83 | //#define K_UP_ARROW 'A' // K_ESCAPE + 'A' -> UP_ARROW 84 | //#define K_DOWN_ARROW 'B' // K_ESCAPE + 'B' -> DOWN_ARROW 85 | typedef int BOOL; 86 | 87 | /*====================================================================*/ 88 | /* FUNCTION PROTOTYPES */ 89 | /*====================================================================*/ 90 | 91 | void pushTerm(); 92 | int resetTerm(); 93 | int kbhit(int timeout_ms); 94 | 95 | char readch(); 96 | char getch(); 97 | void resetch(); 98 | //char getch(void); 99 | void gotoxy(int x, int y); 100 | void outputcolor(int foreground, int background); 101 | void screencol(int x); 102 | void resetAnsi(int x); 103 | int get_terminal_dimensions(int *rows, int *columns); 104 | int get_pos(int *y, int *x); 105 | void showcursor(); 106 | void hidecursor(); 107 | void init_term(); 108 | void close_term(); 109 | #endif 110 | -------------------------------------------------------------------------------- /src/scbuf.c: -------------------------------------------------------------------------------- 1 | /* Module to create a screen buffer 2 | * to act as an intermediate step between screen output and 3 | * the display so as to create a Text User Interface. 4 | * @author:velorek 5 | * Last modified: 1/02/2019 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include "rterm.h" 11 | #include "scbuf.h" 12 | 13 | #define ROWS_FAILSAFE 25 14 | #define COLUMNS_FAILSAFE 80 15 | #define FILL_CHAR 32 16 | 17 | int sc_rows=0, sc_columns=0; 18 | int buffersize=0; 19 | 20 | 21 | /* SINGLE LINKED LIST ROUTINES */ 22 | // create new list element of type SCREENCELL from the supplied text string 23 | SCREENCELL *newelement(SCREENCELL temp) 24 | { 25 | SCREENCELL *newp; 26 | newp = (SCREENCELL *) malloc (sizeof(SCREENCELL)); 27 | newp->index = temp.index; 28 | newp->backColor = temp.backColor; 29 | newp->foreColor = temp.foreColor; 30 | newp->toUpdate = 0; 31 | newp->ch = temp.ch; 32 | newp->next = NULL; 33 | return newp; 34 | } 35 | 36 | 37 | void deleteList(SCREENCELL **head) 38 | { 39 | /* deref head_ref to get the real head */ 40 | SCREENCELL *current = *head; 41 | SCREENCELL *next = NULL; 42 | while (current != NULL) 43 | { 44 | next = current->next; 45 | free(current); 46 | current = next; 47 | } 48 | 49 | free(current); 50 | free(next); 51 | current = NULL; 52 | next = NULL; 53 | *head = NULL; 54 | } 55 | 56 | /* addfront: add new SCREENCELL to front of list */ 57 | /* example usage: start = (addfront(start, newelement("burgers")); */ 58 | 59 | SCREENCELL *addfront(SCREENCELL *head, SCREENCELL *newp) 60 | { 61 | newp -> next = head; 62 | return newp; 63 | } 64 | 65 | /* addend: add new SCREENCELL to the end of a list */ 66 | /* usage example: start = (addend(start, newelement("wine")); */ 67 | 68 | SCREENCELL *addend (SCREENCELL *head, SCREENCELL *newp) 69 | { 70 | SCREENCELL *p2; 71 | if (head == NULL) 72 | return newp; 73 | // now find the end of list 74 | for (p2 = head; p2 -> next != NULL; p2 = p2 -> next) 75 | ; 76 | p2 -> next = newp; 77 | return head; 78 | } 79 | 80 | 81 | int length(SCREENCELL **head) 82 | // this routine uses pointer-to-pointer techniques :-) 83 | { 84 | 85 | int count=0; 86 | SCREENCELL **tracer = head; 87 | while ((*tracer) != NULL) { 88 | count = count +1; 89 | tracer = &(*tracer)->next; 90 | } 91 | return count; 92 | } 93 | 94 | void reindex(SCREENCELL **head) 95 | { 96 | int count=0; 97 | SCREENCELL *p=NULL; 98 | SCREENCELL **tracer = head; 99 | while ((*tracer) != NULL) { 100 | p = *tracer; 101 | p->index=count; 102 | count = count +1; 103 | tracer = &(*tracer)->next; 104 | } 105 | } 106 | 107 | /* SCREEN BUFFER ROUTINES */ 108 | 109 | int create_screen(SCREENCELL **newScreen){ 110 | /* 111 | Get terminal dimensions and create a dynamic list with the size of the screen. 112 | if it is not possible to determine screen dimensions default is set to 80x25. 113 | Insertion happens at the end of the list. */ 114 | int i=0; 115 | SCREENCELL temp; 116 | SCREENCELL **aux = newScreen; 117 | 118 | //We attempt to get terminal dimensions. If not 119 | //successful failsafe values (80x25) apply. 120 | get_terminal_dimensions(&sc_rows, &sc_columns); 121 | if(sc_rows == 0) 122 | sc_rows = ROWS_FAILSAFE; 123 | if(sc_columns == 0) 124 | sc_columns = COLUMNS_FAILSAFE; 125 | buffersize = sc_rows * sc_columns; 126 | 127 | // Assign dummy data to Screen buffer 128 | if(*aux == NULL) { 129 | //All cells have the same init data 130 | temp.ch = FILL_CHAR; 131 | temp.backColor = B_BLACK; 132 | temp.foreColor = F_WHITE; 133 | for(i = 0; i < buffersize; i++) { 134 | //Except for their index 135 | temp.index = buffersize - 1 - i; 136 | *aux = addfront(*aux, newelement(temp)); 137 | } 138 | return 1; 139 | } else{ 140 | //Pointer is not void 141 | return 0; 142 | } 143 | } 144 | void copy_screen(SCREENCELL *destination,SCREENCELL *source){ 145 | int i=0; 146 | SCREENCELL *aux1=destination; 147 | SCREENCELL *aux2=source; 148 | //We attempt to get terminal dimensions. If not 149 | //successful failsafe values (80x25) apply. 150 | if((aux1 != NULL && aux2 != NULL) && (length(&aux1) == length(&aux2)) ) { 151 | for(i = 0; i < buffersize; i++) { 152 | aux1->backColor = aux2->backColor; 153 | aux1->foreColor = aux2->foreColor; 154 | aux1->ch = aux2->ch; 155 | aux1 = aux1->next; 156 | aux2 = aux2->next; 157 | } 158 | } 159 | } 160 | 161 | 162 | /*------------------------------------------*/ 163 | /* Update single char to screen for display */ 164 | /*------------------------------------------*/ 165 | void update_ch(int x, int y, wchar_t ch, char backcolor, char forecolor) { 166 | //Write Unicode char to screen raw 167 | resetAnsi(0); 168 | gotoxy(x+1, y+1); 169 | outputcolor(forecolor, backcolor); 170 | printf("%lc", ch); //unicode 171 | } 172 | 173 | void write_ch(SCREENCELL *newScreen, int x, int y, wchar_t ch, char backcolor, char forecolor,BOOL raw) { 174 | /* Update cell on screenbuffer. It will be shown on screen when it is updated by calling update_screen */ 175 | int i, pos; 176 | 177 | SCREENCELL *aux = newScreen; 178 | resetAnsi(0); 179 | if (aux != NULL && buffersize <= length(&aux)){ 180 | 181 | pos = (y - 1) * sc_columns + x; //This is the formula to calculate the position index in the screen buffer 182 | if(pos < buffersize) { 183 | // If it is within buffer limits, otherwise do nothing. 184 | for(i = 0; i <= pos; i++) { 185 | //Run through the buffer until reaching desired position 186 | if (aux->index == pos) 187 | break; 188 | aux = aux->next; 189 | } 190 | //Update cell info at position selected. 191 | //Manage special charaters as well. 192 | aux->ch = ch; 193 | aux->backColor = backcolor; 194 | aux->foreColor = forecolor; 195 | aux->toUpdate = 1; 196 | 197 | if(raw==TRUE) { 198 | gotoxy(x+1, y); 199 | outputcolor(forecolor, backcolor); 200 | if (ch>31) printf("%lc", ch); //unicode 201 | } 202 | } 203 | } 204 | } 205 | 206 | SCREENCELL read_cell(SCREENCELL *newScreen, int x, int y) { 207 | /* read specific character with attributes from buffer */ 208 | int i=0, pos=0; 209 | SCREENCELL *aux=newScreen; 210 | SCREENCELL ret ={}; 211 | if (aux != NULL && buffersize <= length(&aux)){ 212 | pos = (y - 1) * sc_columns + x; //this is the formula to calculate the position index in the screen buffer 213 | if(pos < buffersize) { 214 | for(i = 0; i <= pos; i++) { 215 | //run through the buffer until reaching desired position 216 | if(aux->index == pos) 217 | break; 218 | aux = aux->next; 219 | } 220 | ret.index = aux->index; 221 | ret.ch = aux->ch; 222 | //for some unknown reason these values have to be inverted 223 | ret.backColor = aux->foreColor; 224 | ret.foreColor = aux->backColor; 225 | ret.next = NULL; 226 | } 227 | } 228 | return ret; 229 | } 230 | 231 | 232 | wchar_t read_char(SCREENCELL *newScreen, int x, int y) { 233 | /* read specific character from buffer */ 234 | int i=0, pos=0; 235 | wchar_t ch = FILL_CHAR; 236 | SCREENCELL *aux=newScreen; 237 | if (aux != NULL && buffersize <= length(&aux)){ 238 | pos = (y - 1) * sc_columns + x; //this is the formula to calculate the position index in the screen buffer 239 | if(pos < buffersize) { 240 | for(i = 0; i <= pos; i++) { 241 | //run through the buffer until reaching desired position 242 | if(aux->index == pos) 243 | break; 244 | aux = aux->next; 245 | } 246 | ch = aux->ch; 247 | } 248 | } 249 | return ch; 250 | } 251 | 252 | /*------------------------------------------*/ 253 | /* Writes a string of characters to buffer. */ 254 | /*------------------------------------------*/ 255 | 256 | void write_str(SCREENCELL *newScreen, int x, int y, char *str, char backcolor, char forecolor, BOOL raw) { 257 | //Writes a string of characters to buffer. 258 | char *astr=NULL; 259 | size_t i=0; 260 | int wherex=0; 261 | SCREENCELL *aux = newScreen; 262 | 263 | if (aux!=NULL){ 264 | wherex = x; 265 | astr = str; 266 | for(i = 0; i <= strlen(str) - 1; i++) { 267 | write_ch(aux, wherex, y, astr[i], backcolor, forecolor,raw); 268 | wherex = wherex + 1; 269 | } 270 | } 271 | } 272 | 273 | /*------------------------------------------*/ 274 | /* Writes a string of characters to screen. */ 275 | /*------------------------------------------*/ 276 | 277 | void update_str(int x, int y, char *str, char backcolor, char forecolor) { 278 | //Writes a string of characters to buffer. 279 | char *astr=NULL; 280 | size_t i=0; 281 | int wherex=0; 282 | 283 | resetAnsi(0); 284 | wherex = x; 285 | astr = str; 286 | for(i = 0; i <= strlen(str) - 1; i++) { 287 | update_ch(wherex, y, astr[i], backcolor, forecolor); 288 | wherex = wherex + 1; 289 | } 290 | } 291 | 292 | /*-----------------------------------------------*/ 293 | /* Writes an integer value as a string on screen */ 294 | /*-----------------------------------------------*/ 295 | 296 | int write_num(SCREENCELL *newScreen, int x, int y, int num, char backcolor, 297 | char forecolor, BOOL raw) { 298 | //the length of the string must be passed on the function 299 | char astr[30]; 300 | char len=0; 301 | SCREENCELL *aux = newScreen; 302 | 303 | if (aux!=NULL){ 304 | sprintf(astr, "%d", num); 305 | write_str(newScreen, x, y, astr, backcolor, forecolor,raw); 306 | len = strlen(astr); 307 | } 308 | return len; 309 | } 310 | 311 | void screen_color(SCREENCELL *newScreen, char bcolor, char fcolor, wchar_t ch) { 312 | /* Changes the color of all the cells to create the effect of changing color in the background */ 313 | int i=0; 314 | SCREENCELL *aux=newScreen; 315 | resetAnsi(0); 316 | //screen should be updated twice to get round the last row glitch 317 | if (aux != NULL && buffersize <= length(&aux)){ 318 | for(i = 0; i < buffersize; i++) { 319 | aux->backColor = bcolor; 320 | aux->foreColor = fcolor; 321 | aux->ch = ch; 322 | aux->toUpdate = 1; 323 | aux = aux->next; 324 | } 325 | } 326 | } 327 | 328 | /*------------------------------------*/ 329 | /* Dumps buffer to screen for display */ 330 | /*------------------------------------*/ 331 | 332 | 333 | void dump_screen(SCREENCELL *newScreen) { 334 | /* UPDATES ALL SCREEN CELLS TO DISPLAY */ 335 | int i=0; 336 | int wherex=0, wherey=0; 337 | SCREENCELL *aux=newScreen; 338 | if (aux!=NULL && buffersize <= length(&aux)){ 339 | for(i = 0; i < buffersize; i++) { 340 | update_ch(wherex,wherey,aux->ch,aux->backColor,aux->foreColor); 341 | wherex = wherex + 1; //line counter 342 | if(wherex == sc_columns) { 343 | //new line 344 | wherex = 0; 345 | wherey = wherey + 1; 346 | } 347 | aux = aux->next; 348 | } 349 | } 350 | } 351 | 352 | void update_screen(SCREENCELL *newScreen) { 353 | /* UPDATES ALL SCREEN CELLS TO DISPLAY */ 354 | int i=0; 355 | int wherex=0, wherey=0; 356 | SCREENCELL *aux=newScreen; 357 | if (aux!=NULL && buffersize <= length(&aux)){ 358 | for(i = 0; i < buffersize; i++) { 359 | if (aux->toUpdate ==1) {aux->toUpdate = 0; update_ch(wherex,wherey,aux->ch,aux->backColor,aux->foreColor);} 360 | wherex = wherex + 1; //line counter 361 | if(wherex == sc_columns) { 362 | //new line 363 | wherex = 0; 364 | wherey = wherey + 1; 365 | } 366 | aux = aux->next; 367 | } 368 | } 369 | } 370 | 371 | 372 | void xor_update(SCREENCELL *screen1, SCREENCELL *screen2) { 373 | /* UPDATE only the cells that are different */ 374 | int i=0; 375 | int wherex=0, wherey=0; 376 | SCREENCELL *aux1=screen1; 377 | SCREENCELL *aux2=screen2; 378 | if ((aux1!=NULL && aux2!=NULL) && (length(&aux1) == length(&aux2))){ 379 | for(i = 0; i < buffersize; i++) { 380 | if (aux1->ch != aux2->ch || aux1-> backColor != aux2 -> backColor || aux1-> foreColor != aux2 -> foreColor){ 381 | update_ch(wherex,wherey,aux1->ch,aux1->backColor,aux1->foreColor); 382 | } 383 | wherex = wherex + 1; //line counter 384 | if(wherex == sc_columns) { 385 | //new line 386 | wherex = 0; 387 | wherey = wherey + 1; 388 | } 389 | aux1 = aux1->next; 390 | aux2 = aux2->next; 391 | } 392 | } 393 | } 394 | 395 | 396 | void xor_copy(SCREENCELL *screen1, SCREENCELL *screen2) 397 | { 398 | /* UPDATES ALL SCREEN CELLS TO DISPLAY */ 399 | int i = 0; 400 | int wherex = 0, wherey = 0; 401 | SCREENCELL *aux1 = screen1; 402 | SCREENCELL *aux2 = screen2; 403 | if ((aux1 != NULL && aux2 != NULL) && (length(&aux1) == length(&aux2))) { 404 | for (i = 0; i < buffersize; i++) { 405 | 406 | if (aux1->ch != aux2->ch 407 | || aux1->backColor != aux2->backColor 408 | || aux1->foreColor != aux2->foreColor) { 409 | aux1->ch = aux2->ch; 410 | aux1->backColor = aux2->backColor; 411 | aux1->foreColor = aux2->foreColor; 412 | wherex = wherex + 1; //line counter 413 | 414 | if (wherex == sc_columns) { 415 | //new line 416 | wherex = 0; 417 | wherey = wherey + 1; 418 | } 419 | 420 | aux1 = aux1->next; 421 | aux2 = aux2->next; 422 | } 423 | } 424 | } 425 | } 426 | /*------------------------------------------*/ 427 | /* Draw window area with or without border. */ 428 | /*------------------------------------------*/ 429 | 430 | void draw_window(SCREENCELL *newScreen, int x1, int y1, int x2, int y2, int backcolor, int bordercolor, int titlecolor, BOOL border, BOOL title, BOOL shadow, BOOL raw) { 431 | /* 432 | Draw a box on screen 433 | */ 434 | SCREENCELL *aux = newScreen; 435 | int i, j; 436 | wchar_t ch=FILL_CHAR; 437 | i = x1; 438 | j = y1; 439 | //shadow 440 | resetAnsi(0); 441 | if (shadow == TRUE){ 442 | for(j = y1 + 1; j <= y2 + 1; j++) 443 | for(i = x1 + 1; i <= x2 + 1; i++) 444 | { 445 | ch=read_char(aux, i,j); //dynamic shadow 446 | if ((ch=='\0') || (ch == UNICODEBAR1) || (ch<0)) ch=FILL_CHAR; 447 | //ch=FILL_CHAR; 448 | //if (ch<0) ch = (tempLine.linea[i].specialChar << 8) | tempLine.linea[i].ch; 449 | write_ch(aux, i, j, ch, B_BLACK, F_WHITE,raw); 450 | } 451 | } 452 | //window 453 | for(j = y1; j <= y2; j++) 454 | for(i = x1; i <= x2; i++) 455 | write_ch(aux, i, j, FILL_CHAR, backcolor, bordercolor,raw); 456 | 457 | //borders 458 | if(border == TRUE) { 459 | for(i = x1; i <= x2; i++) { 460 | //upper and lower borders 461 | write_ch(aux, i, y1, HOR_LINE, backcolor, bordercolor,raw); //horizontal line box-like char 462 | write_ch(aux, i, y2, HOR_LINE, backcolor, bordercolor,raw); 463 | } 464 | for(j = y1; j <= y2; j++) { 465 | //left and right borders 466 | write_ch(aux, x1, j, VER_LINE, backcolor, bordercolor,raw); //vertical line box-like char 467 | write_ch(aux, x2, j, VER_LINE, backcolor, bordercolor,raw); 468 | } 469 | write_ch(aux, x1, y1, UPPER_LEFT_CORNER, backcolor, bordercolor,raw); //upper-left corner box-like char 470 | write_ch(aux, x1, y2, LOWER_LEFT_CORNER, backcolor, bordercolor,raw); //lower-left corner box-like char 471 | write_ch(aux, x2, y1, UPPER_RIGHT_CORNER, backcolor, bordercolor,raw); //upper-right corner box-like char 472 | write_ch(aux, x2, y2, LOWER_RIGHT_CORNER, backcolor, bordercolor,raw); //lower-right corner box-like char 473 | } 474 | 475 | if (title == TRUE) { 476 | for(i = x1+1; i <= x2-1; i++) 477 | write_ch(aux, i, y1, ' ', titlecolor, titlecolor,raw); 478 | } 479 | } 480 | 481 | 482 | -------------------------------------------------------------------------------- /src/scbuf.h: -------------------------------------------------------------------------------- 1 | #ifndef _SCBUF_H_ 2 | #define _SCBUF_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "rterm.h" 11 | 12 | #define HOR_LINE 9472 13 | #define VER_LINE 9474 14 | #define UPPER_LEFT_CORNER 9484 15 | #define LOWER_LEFT_CORNER 9492 16 | #define UPPER_RIGHT_CORNER 9488 17 | #define LOWER_RIGHT_CORNER 9496 18 | #define UNICODEBAR1 0x2592 19 | 20 | typedef struct _screencell 21 | { 22 | int index; 23 | char backColor; 24 | char foreColor; 25 | unsigned char toUpdate; 26 | //int char attrib; 27 | wchar_t ch; 28 | struct _screencell *next; 29 | } SCREENCELL; 30 | 31 | 32 | /* Adapted from Kernighan and Pike's "The Practice of Programming" pp.46 et 33 | seq. (Addison-Wesley 1999) - computerPhile */ 34 | 35 | // create new list element of type SCREENCELL from the supplied text string 36 | SCREENCELL *newelement(SCREENCELL temp); 37 | SCREENCELL *addfront(SCREENCELL *head, SCREENCELL *newp); 38 | SCREENCELL *addend (SCREENCELL *head, SCREENCELL *newp); 39 | void deleteList(SCREENCELL **head); 40 | int length(SCREENCELL **head); 41 | void reindex(SCREENCELL **head); 42 | //SCREEN BUFFER ROUTINES 43 | int create_screen(SCREENCELL **newScreen); 44 | void update_ch(int x, int y, wchar_t ch, char backcolor, char forecolor); 45 | void update_screen(SCREENCELL *newScreen); 46 | void dump_screen(SCREENCELL *newScreen); 47 | void write_ch(SCREENCELL *newScreen, int x, int y, wchar_t ch, char backcolor, char forecolor, BOOL raw); 48 | wchar_t read_char(SCREENCELL *newScreen, int x, int y); 49 | SCREENCELL read_cell(SCREENCELL *newScreen, int x, int y); 50 | void write_str(SCREENCELL *newScreen, int x, int y, char *str, char backcolor, char forecolor, BOOL raw); 51 | void update_str(int x, int y, char *str, char backcolor, char forecolor); 52 | int write_num(SCREENCELL *newScreen, int x, int y, int num, char backcolor, 53 | char forecolor, BOOL raw); 54 | void screen_color(SCREENCELL *newScreen, char bcolor, char fcolor, wchar_t ch); 55 | void copy_screen(SCREENCELL *destination,SCREENCELL *source); 56 | void xor_update(SCREENCELL *screen1, SCREENCELL *screen2); 57 | void xor_copy(SCREENCELL *screen1, SCREENCELL *screen2); 58 | void draw_window(SCREENCELL *newScreen, int x1, int y1, int x2, int y2, int backcolor, int bordercolor, int titlecolor, BOOL border, BOOL title, BOOL shadow, BOOL raw); 59 | #endif 60 | -------------------------------------------------------------------------------- /src/t.txt: -------------------------------------------------------------------------------- 1 | Hello 2 | 3 | 4 | there 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/tm.c: -------------------------------------------------------------------------------- 1 | /* Module to create a milisecond timer 2 | * @author: velorek 3 | * Last modified: 10/08/2020 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "tm.h" 10 | 11 | #include 12 | #include 13 | 14 | long long epoch_ms(void) 15 | { 16 | struct timeval tv; 17 | gettimeofday(&tv, NULL); 18 | return tv.tv_sec * 1000LL + (tv.tv_usec + 500) / 1000; 19 | } 20 | int timerC(NTIMER *mytimer1){ 21 | long long difference = 0; 22 | long long res; 23 | if (mytimer1->ticks == -1) return 0; 24 | if (mytimer1->ticks == 0){ 25 | // First tick, set up values 26 | mytimer1->oldtime = epoch_ms(); 27 | mytimer1->ticks = 1; 28 | return 1; 29 | } else { 30 | // Subsequent ticks 31 | long long now = epoch_ms(); 32 | difference = now - mytimer1->oldtime; 33 | res = difference; 34 | if (res < mytimer1->ms) { 35 | return 0; 36 | } else { 37 | mytimer1->oldtime = now; 38 | mytimer1->ticks = mytimer1->ticks + 1; 39 | return 1; 40 | } 41 | } 42 | } 43 | 44 | void init_timer(NTIMER *mytimer1, int ms){ 45 | // Init routine 46 | mytimer1->ticks = 0; 47 | mytimer1->ms = ms; 48 | } 49 | 50 | void stop_timer(NTIMER *mytimer1){ 51 | // Stop routine 52 | mytimer1->ticks = -1; 53 | } 54 | 55 | void resume_timer(NTIMER *mytimer1){ 56 | // Resume routine 57 | mytimer1->ticks = 0; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/tm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | - HEADER - 4 | Module to implement a millisecond TIMER in C. 5 | @author : Velorek 6 | @version : 1.0 7 | Last modified: 15/09/2021 + New technique + init timer 8 | ======================================================================== 9 | */ 10 | 11 | #ifndef _TM_H_ 12 | #define _TM_H_ 13 | 14 | /*====================================================================*/ 15 | /* COMPILER DIRECTIVES AND INCLUDES */ 16 | /*====================================================================*/ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | /*====================================================================*/ 23 | /* FUNCTION PROTOTYPES */ 24 | /*====================================================================*/ 25 | typedef struct nTimer{ 26 | int ms; //milliseconds 27 | long oldtime; //to calculate increment in time 28 | long ticks; //how many ticks have been made 29 | } NTIMER; 30 | 31 | /* Miliseconds timer */ 32 | int timerC(NTIMER *mytimer1); 33 | void init_timer(NTIMER *mytimer, int ms); 34 | void stop_timer(NTIMER *mytimer); 35 | void resume_timer(NTIMER *mytimer); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/ui.c: -------------------------------------------------------------------------------- 1 | /* Module to create different widgets/gadgets 2 | * for a Text User Interface 3 | * TextBox 4 | * Window 5 | * Last modified: 15/04/2023 6 | * @author:velorek 7 | */ 8 | #include 9 | #include "rterm.h" 10 | #include "scbuf.h" 11 | #include "ui.h" 12 | #include "tm.h" 13 | #include "keyb.h" 14 | #include "global.h" 15 | /*----------------------------*/ 16 | /* User Interface - Text Box. */ 17 | /*----------------------------*/ 18 | int textbox(SCREENCELL *newScreen,int wherex, int wherey, int displayLength, 19 | char *label, char text[MAX_TEXT], int backcolor, 20 | int labelcolor, int textcolor, BOOL raw, BOOL locked) { 21 | int charCount = 0; 22 | int exitFlag = 0; 23 | int cursorON = 1; 24 | int i; 25 | int limitCursor = 0; 26 | int positionx = 0; 27 | int posCursor = 0; 28 | int keypressed = 0; 29 | char chartrail[5]; 30 | // char accentchar[2]; 31 | char displayChar; 32 | char ch; 33 | NTIMER cursorTime; 34 | SCREENCELL *aux = newScreen; 35 | resetAnsi(0); 36 | init_timer(&cursorTime,150); 37 | positionx = wherex + strlen(label); 38 | limitCursor = wherex+strlen(label)+displayLength+1; 39 | write_str(aux,wherex, wherey, label, backcolor, labelcolor,raw); 40 | write_ch(aux,positionx, wherey, '[', backcolor, textcolor,raw); 41 | for(i = positionx + 1; i <= positionx + displayLength; i++) { 42 | write_ch(aux,i, wherey, '.', backcolor, textcolor,raw); 43 | } 44 | write_ch(aux,positionx + displayLength + 1, wherey, ']', backcolor, 45 | textcolor,raw); 46 | if (raw != TRUE) dump_screen(aux); 47 | //Reset keyboard 48 | if(kbhit(1) == 1) ch = readch(); 49 | ch = 0; 50 | 51 | do { 52 | if (locked == 0) break; 53 | keypressed = kbhit(1); 54 | if (timerC(&timer2) == TRUE) _animation(); 55 | //Cursor Animation 56 | if (keypressed == 0){ 57 | 58 | if (timerC(&cursorTime) == TRUE){ 59 | switch (cursorON) { 60 | case 1: 61 | posCursor = positionx + 1; 62 | displayChar = '.'; 63 | if (posCursor == limitCursor) { 64 | posCursor = posCursor - 1; 65 | displayChar = ch; 66 | } 67 | write_ch(aux,posCursor, wherey, displayChar, backcolor, textcolor,raw); 68 | //update_screen(aux); 69 | if (raw != TRUE) dump_screen(aux); 70 | cursorON = 0; 71 | break; 72 | case 0: 73 | posCursor = positionx + 1; 74 | if (posCursor == limitCursor) posCursor = posCursor - 1; 75 | write_ch(aux,posCursor, wherey, '|', backcolor, textcolor,raw); 76 | //update_screen(aux); 77 | if (raw != TRUE) dump_screen(aux); 78 | cursorON = 1; 79 | break; 80 | } 81 | } 82 | } 83 | //Process keys 84 | if(keypressed == 1) { 85 | ch = readch(); 86 | keypressed = 0; 87 | //Read special keys 88 | if (ch==K_ESCAPE) { 89 | read_keytrail(chartrail); 90 | } 91 | //Read accents 92 | //if (ch==SPECIAL_CHARSET_1) read_accentchar(&ch, accentchar); 93 | //if (ch==SPECIAL_CHARSET_2) read_accentchar(&ch, accentchar); 94 | 95 | if(charCount < displayLength) { 96 | if(ch > 31 && ch < 127) { 97 | write_ch(aux,positionx + 1, wherey, ch, backcolor, textcolor,raw); 98 | text[charCount] = ch; 99 | positionx++; 100 | charCount++; 101 | //update_screen(aux); 102 | if (raw != TRUE) dump_screen(aux); 103 | } 104 | } 105 | } 106 | if (ch==K_CTRL_C){ 107 | return ENDSIGNAL; 108 | } 109 | if (ch==K_BACKSPACE){ 110 | if (positionx>0 && charCount>0){ 111 | ch=0; 112 | positionx--; 113 | charCount--; 114 | text[charCount] = '\0'; 115 | write_ch(aux,positionx + 1, wherey, '.', backcolor, textcolor,raw); 116 | if (positionx < limitCursor-2) write_ch(aux,positionx + 2, wherey, '.', backcolor, textcolor,raw); 117 | //update_screen(aux); 118 | if (raw != TRUE) dump_screen(aux); 119 | //resetch(); 120 | } 121 | } 122 | if(ch == K_ENTER || ch == K_TAB || ch == K_ESCAPE) 123 | exitFlag = 1; 124 | 125 | //ENTER OR TAB FINISH LOOP 126 | } while(exitFlag != 1); 127 | text[charCount] = '\0'; 128 | //Clear field 129 | positionx = wherex + strlen(label); 130 | for(i = positionx + 1; i <= positionx + displayLength; i++) { 131 | write_ch(aux,i, wherey, '.', backcolor, textcolor,raw); 132 | } 133 | write_ch(aux,positionx + displayLength + 1, wherey, ']', backcolor, 134 | textcolor,raw); 135 | 136 | //resetch(); 137 | if (ch == K_ESCAPE) charCount = 0; 138 | return charCount; 139 | } 140 | 141 | 142 | void window(SCREENCELL *screen1, int x1, int y1, int x2, int y2, int backcolor, 143 | int bordercolor, int titlecolor, int border, int title, int shadow) { 144 | /* 145 | Chars for drawing box-like characters will be passed as negative values. 146 | When the update_screen routine is called, it will check for negative 147 | values and map these chars to Unicode characters. 148 | */ 149 | int i, j; 150 | //char ch=0x20; 151 | wchar_t ch=0x20; 152 | i = x1; 153 | j = y1; 154 | 155 | resetAnsi(0); 156 | //shadow 157 | if (shadow==1){ 158 | for(j = y1 + 1; j <= y2 + 1; j++) 159 | for(i = x1 + 1; i <= x2 + 1; i++) 160 | { 161 | ch=read_char(screen1, i,j); //dynamic shadow 162 | if ((ch=='\0') || (ch==UNICODEBAR1)) ch=0x20; 163 | write_ch(screen1, i, j, ch, B_BLACK, F_WHITE,0); 164 | } 165 | } 166 | //window 167 | for(j = y1; j <= y2; j++) 168 | for(i = x1; i <= x2; i++) 169 | write_ch(screen1, i, j, ' ', backcolor, bordercolor,0); 170 | //borders 171 | if(border == 1) { 172 | //with borders. ANSI-ASCII 106-121 173 | for(i = x1; i <= x2; i++) { 174 | //upper and lower borders 175 | write_ch(screen1, i, y1, HOR_LINE, backcolor, bordercolor,0); //horizontal line box-like char 176 | write_ch(screen1, i, y2, HOR_LINE, backcolor, bordercolor,0); 177 | } 178 | for(j = y1; j <= y2; j++) { 179 | //left and right borders 180 | write_ch(screen1,x1, j, VER_LINE, backcolor, bordercolor,0); //vertical line box-like char 181 | write_ch(screen1,x2, j, VER_LINE, backcolor, bordercolor,0); 182 | } 183 | write_ch(screen1, x1, y1, UPPER_LEFT_CORNER, backcolor, bordercolor,0); //upper-left corner box-like char 184 | write_ch(screen1, x1, y2, LOWER_LEFT_CORNER, backcolor, bordercolor,0); //lower-left corner box-like char 185 | write_ch(screen1, x2, y1, UPPER_RIGHT_CORNER, backcolor, bordercolor,0); //upper-right corner box-like char 186 | write_ch(screen1, x2, y2, LOWER_RIGHT_CORNER, backcolor, bordercolor,0); //lower-right corner box-like char 187 | } 188 | if (title == 1) { 189 | for(i = x1; i <= x2; i++) 190 | write_ch(screen1, i, y1-1, ' ', titlecolor, titlecolor,0); 191 | } 192 | // dump_screen(screen1); 193 | } 194 | 195 | int inputWindow(char *label, char *tempFile, char *windowTitle, int offsetX, int offsetY, int length) { 196 | int window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0; 197 | int count = 0; 198 | resetAnsi(0); 199 | copy_screen(screen2,screen1); 200 | window_y1 = (new_rows / 2) - offsetY; 201 | window_y2 = (new_rows / 2); 202 | window_x1 = (new_columns / 2) - offsetX; 203 | window_x2 = (new_columns / 2) + offsetX; 204 | 205 | window(screen1,window_x1, window_y1, window_x2, window_y2, MENU_PANEL, MENU_FOREGROUND0, 206 | WINDOW_TITLEB,1,1,1); 207 | write_str(screen1, (window_x2-window_x1) /2 + window_x1 - (strlen(windowTitle)/2) , window_y1-1, windowTitle, WINDOW_TITLEB, WINDOW_TITLEF,0); 208 | dump_screen(screen1); 209 | count = 210 | textbox(screen1, window_x1 + 1, window_y1 + 1, length, label, tempFile, MENU_PANEL, 211 | MENU_FOREGROUND0, MENU_FOREGROUND0,1,1); 212 | copy_screen(screen1,screen2); 213 | dump_screen(screen1); 214 | return count; 215 | } 216 | 217 | int yesnoWindow(char *message, char *windowTitle) { 218 | 219 | int window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0; 220 | char ch = 0; 221 | int ok = 0; 222 | size_t i=0; 223 | int j = 0; 224 | int ix = 0; 225 | char tempChar=0; 226 | resetAnsi(0); 227 | copy_screen(screen2,screen1); 228 | 229 | window_y1 = (new_rows / 2) - 4; 230 | window_y2 = (new_rows / 2) + 4; 231 | window_x1 = (new_columns / 2) - 16; 232 | window_x2 = (new_columns / 2) + 16; 233 | window(screen1,window_x1, window_y1, window_x2, window_y2, MENU_PANEL, MENU_FOREGROUND0, WINDOW_TITLEB,1,0,1); 234 | dump_screen(screen1); 235 | write_str(screen1, (window_x2-window_x1) /2 + window_x1 - (strlen(windowTitle)/2) , window_y1, windowTitle, WINDOW_TITLEB, WINDOW_TITLEF,1); 236 | //'|' is used as line separator 237 | 238 | for(i = 0; i < strlen(message); i++) { 239 | tempChar = message[i]; 240 | if (tempChar != '|'){ 241 | write_ch(screen1,window_x1 + 1 + ix, window_y1 + 1 + j, tempChar, MENU_PANEL,MENU_FOREGROUND0,1); 242 | ix++; 243 | }else { 244 | j++; 245 | ix = 0; 246 | } 247 | } 248 | printf("\n"); 249 | if (listBox1 != NULL) removeList(&listBox1); 250 | listBox1 = addatend(listBox1, newitem("[ YES ]",window_x1+3,window_y2-1,-1,-1)); 251 | listBox1 = addatend(listBox1, newitem("[ NO ]",window_x1+13,window_y2-1,-1,-1)); 252 | listBox1 = addatend(listBox1, newitem("[CANCEL]",window_x1+23,window_y2-1,-1,-1)); 253 | 254 | setselectorLimit(8); 255 | ch = listBox(listBox1, window_x1+2,window_y2, &scrollData, MENU_PANEL, MENU_FOREGROUND0,MENU_SELECTOR, MENU_FOREGROUND1, 3, HORIZONTAL,1,LOCKED); 256 | ok = scrollData.itemIndex; 257 | if (listBox1 != NULL) removeList(&listBox1); 258 | ch++; 259 | copy_screen(screen1,screen2); 260 | dump_screen(screen1); 261 | resetScrollData(&scrollData); 262 | return ok; 263 | } 264 | -------------------------------------------------------------------------------- /src/ui.h: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================== 3 | - HEADER - 4 | Module with different UI gadgets for LYNX. 5 | @author : Velorek 6 | @version : 1.0 7 | Last modified: 06/02/2022 8 | ======================================================================== 9 | */ 10 | 11 | #ifndef _UI_H_ 12 | #define _UI_H_ 13 | #define MAX_TEXT 255 14 | 15 | #include "scbuf.h" 16 | #include 17 | 18 | int textbox(SCREENCELL *newScreen,int wherex, int wherey, int displayLength, 19 | char *label, char text[MAX_TEXT], int backcolor, 20 | int labelcolor, int textcolor, BOOL raw, BOOL locked); 21 | 22 | void window(SCREENCELL *screen1, int x1, int y1, int x2, int y2, int backcolor, 23 | int bordercolor, int titlecolor, int border, int title, int shadow); 24 | 25 | int inputWindow(char *label, char *tempFile, char *windowTitle, int offsetX, int offsetY, int length); 26 | int yesnoWindow(char *message, char *windowTitle); 27 | #endif 28 | 29 | 30 | --------------------------------------------------------------------------------