Repository: velorek1/c-edit
Branch: master
Commit: 253369833412
Files: 32
Total size: 163.4 KB
Directory structure:
gitextract_9g946023/
├── LICENSE
├── README.md
├── TODO
├── TODO.md
└── 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
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Velorek1
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
C-EDIT Project in C language (NO NCURSES)
=========================================
C-EDIT for linux - ALPHA - A linux text editor in the style of the MSDOS EDIT - WITHOUT USING NCURSES
Works well with Termux! :)
* WARNING: DO NOT EDIT YOUR PRECIOUS FILES WITH THIS EDITOR!!
Contact me at: velorek1@gmail.com
**NEW: AUGUST 2025**
- Fixed flickering issues in status bar
- Added pageup/down home/end keys
History:
- 2024 -> Dynamyc buffer added (vector of lineS)
- 2023 -> Previous demo version kept in https://github.com/velorek1/C-editold
- 2022 -> I have rewritten the screenbuffer and fixed polling issues (lynx: https://github.com/velorek1/lynx).
Ideally, a keyboard library abstraction would be nice to expand the editor's possibilities.**
- 2018 -> Start of the project; basic demo concepts developed (https://oldstuff286.blogspot.com/2018/03/c-edit-in-progress.html)
TO INSTALL:
* Download or clone repository.
* Type "cd src", "make" and "./cedit" to execute.
So far I have implemented:
* A very simple Double Screen Buffer with a simple linked list in memory for greater display control.
* Rudimentary Text User Interface with Windows, Textbox, Keyboard handling, Color schemes, etc.
* Automatic display resizing.
* Open file dialog with a Listbox and SCROLL capabilities to navigate and find the file to open.
* Rudimentary Edit buffer with vertical and horizontal scroll (vector of lines).
* A millisecond timer for animations.
* Timers and kbhit with no polling for optimate CPU usage.
* Greater modularity than Demo version
* Rudimentary syntax highlighting
Files in /src/:
===============
* rterm.c -> code for the library that handles output with Ansi Functions and kbhit() in linux console (with its header file)
* listbox.c -> code for the circular linked list responsible for handling menus
* scbuf.c -> code for controlling display with a double screen buffer (with its header file)
* keyb.c -> module to control keyboard input.
* opfile.c -> module that list files with scroll capabilities to select the file to open.
* ui.c -> module with user interface widgets: alert windows, confirmation windows, textbox, etc.
* fileb.c -> module for single file operations.
* tm.c -> module for a millisecond timer for animations (C11)
* main.c -> Editor in C in the style of MSDOS EDIT (In progress).
* global.c -> Global variables and main animation
* menu.c -> Drop-down menu
* editor.c -> Code for the editor section
* edbuf.c -> Buffer - vector of lines
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)
TO-DO:
* Clean code
* Complete menus / dialogs
* READ MODE
* FULL UTF 8! - SUPPORT change from char to win_t/wchar in editor buffer
* Copy/Paste/Cut routines / Highlight text
* Create Keyboard abstraction to make it more portable (bottom-up fashion!)
* Address glitches/bugs


================================================
FILE: TODO
================================================
* Top Priority:
Check https://github.com/velorek1/ceditbuf/ for latest development implementations (2024(
- Code a more backward compatible timer : tm.c (done!)
- Create Keyboard abstraction to make it more portable (bottom-up fashion!)
- Rewrite screen buffer (in progress).
- Rewrite and merge listbox with openfiledialog and menus.
- Turn fw into a library to display long text with scroll.
- Change editBuffer from static array to dynamic structure (in progress)
- Expand behaviour of ENTER and BACKSPACE and REAL TAB SUPPORT! (in progress)
- Add horizontal scroll (in progress)
* Less Priority:
- Highlight text and copy/paste function
- Find text
- Full UTF8 support?
================================================
FILE: TODO.md
================================================
* Top Priority: (2025)
- Complete menus / dialogs
- READ MODE
- FULL UTF 8 - SUPPORT change char to win_t/wchar in editor buffer
- Copy/Paste/Cut routines / Highlight text
- Create Keyboard abstraction to make it more portable (bottom-up fashion!)
- Address glitches/bugs
================================================
FILE: src/Makefile
================================================
.POSIX:
TARGET = cedit
CC = cc
CFLAGS = -Wall -Wextra -fsigned-char
LDFLAGS =
LDLIBS =
# The list of object files.
OBJS = main.o rterm.o listbox.o scbuf.o
OBJS += ui.o fileb.o global.o menu.o editor.o
OBJS += keyb.o tm.o edbuf.o opfile.o
# the list of files to clean
TOCLEAN = cedit $(OBJS)
RM ?= rm -f
all: $(TARGET)
clean:
$(RM) $(TOCLEAN)
cedit: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
# INCLUDE DEPENDENCIES to compile depending on which
# source has been touched.
main.o: main.c rterm.h listbox.h scbuf.h keyb.h ui.h fileb.h tm.h
fileb.o: fileb.c fileb.h
keyb.o: keyb.c rterm.h keyb.h
listbox.o: listbox.c scbuf.h keyb.h
editor.o: scbuf.h keyb.h rterm.h
rterm.o: rterm.c
menu.o: listbox.c scbuf.h ui.h keyb.h rterm.h
tm.o: tm.c tm.h
global.o: global.c global.h
scbuf.o: scbuf.c rterm.h keyb.h scbuf.h
ui.o: ui.c scbuf.h rterm.h keyb.h
opfile.o: opfile.c scbuf.h rterm.h listbox.h keyb.h tm.h global.h ui.h
================================================
FILE: src/TODO.md
================================================
# ceditbuf
C-edit with dynamic buffer (in development)
================================================
FILE: src/edbuf.c
================================================
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "edbuf.h"
// create new list element of type VLINES from the supplied text string
VLINES *_newline(VLINES temp)
{
VLINES *newp;
newp = (VLINES *) malloc (sizeof(VLINES));
newp->index = temp.index;
memcpy(newp->linea,temp.linea,sizeof(temp.linea)+1);
newp->next = NULL;
return newp;
}
// Delete first element on list whose item field matches the given text
// NOTE!! delete requests for elements not in the list are silently ignored :-)
void _RemoveThing(VLINES **head, int index)
{
BOOL present = FALSE;
VLINES *old;
VLINES **tracer = head;
if ((*tracer)->index==index) present=TRUE;
while((*tracer) && !(present)){
if ((*tracer)->index==index) present=TRUE;
tracer = &(*tracer)->next;
}
if(present)
{
old = *tracer;
*tracer = (*tracer)->next;
free(old); // free up remainder of list element
}
}
void _hardupdateLINE(VLINES **head, int index, VLINES temp)
{
int i=0;
BOOL present = FALSE;
VLINES **tracer = head;
if ((*tracer)->index==index) present=TRUE;
while((*tracer) && !(present)){
if ((*tracer)->index==index) {present=TRUE; break;}
tracer = &(*tracer)->next;
}
if(present)
{
for (i=0; i<MAX_LINE_SIZE; i++)
{
(*tracer)->linea[i].ch = temp.linea[i].ch;
(*tracer)->linea[i].attrib = temp.linea[i].attrib;
(*tracer)->linea[i].specialChar = temp.linea[i].specialChar;
}
}
}
void _deletetheList(VLINES **head)
{
/* deref head_ref to get the real head */
VLINES *current = *head;
VLINES *next = NULL;
VLINES **tracer=head;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
/* deref head_ref to affect the real head back
in the caller. */
*tracer = NULL;
}
// updatelement: remove from list the first instance of an element
VLINES *_update(VLINES *head, int index, VLINES temp)
{
VLINES *p;
for (p = head; p != NULL; p = p -> next) {
if (p -> index == index) {
break;
}
}
p-> index = temp.index;
return head;
}
// getObject
VLINES *_getObject(VLINES *head, int index)
{
VLINES *p;
for (p = head; p != NULL; p = p -> next) {
if (p -> index == index) {
break;
}
}
//p-> index = temp.index;
return p;
}
// deleteline: remove from list the first instance of an element
// containing a given text string
// NOTE!! delete requests for elements not in the list are silently ignored
VLINES *_deleteline(VLINES *head, int index)
{
VLINES *p, *prev;
prev = NULL;
for (p = head; p != NULL; p = p -> next) {
if (p -> index == index) {
if(prev == NULL)
head = p-> next;
else
prev -> next = p -> next;
free(p); // remove rest of VLINES
return head;
}
prev = p;
}
return NULL;
}
/* addfront: add new VLINES to front of list */
/* example usage: start = (addfront(start, newelement("burgers")); */
VLINES *_addfront(VLINES *head, VLINES *newp)
{
newp -> next = head;
return newp;
}
/* addend: add new VLINES to the end of a list */
/* usage example: start = (addend(start, newelement("wine")); */
VLINES *_addatend (VLINES *head, VLINES *newp)
{
VLINES *p2;
if (head == NULL)
return newp;
// now find the end of list
for (p2 = head; p2 -> next != NULL; p2 = p2 -> next)
;
p2 -> next = newp;
return head;
}
void _printlist(VLINES **head)
// this routine uses pointer-to-pointer techniques :-)
{
VLINES **tracer = head;
int index=0, i = 0;
while ((*tracer) != NULL) {
index = (*tracer)->index;
printf("LINE %d | ", index);
for (i=0; i < MAX_LINE_SIZE; i++)
printf("%c",(*tracer)->linea[i].ch);
printf("\n");
tracer = &(*tracer)->next;
}
}
int _length(VLINES **head)
// this routine uses pointer-to-pointer techniques :-)
{
int count=0;
VLINES **tracer = head;
if (*head == NULL) return -1;
while ((*tracer) != NULL) {
count = count +1;
tracer = &(*tracer)->next;
}
return count;
}
void _reindex(VLINES **head)
{
int count=0;
VLINES *p=NULL;
VLINES **tracer = head;
while ((*tracer) != NULL) {
p = *tracer;
p->index=count;
count = count +1;
tracer = &(*tracer)->next;
}
}
void _deleteObject(VLINES **head,int index, BOOL sort){
VLINES *p=*head;
if (index == 0 || _length(head) <=1 || p->index == index )
_RemoveThing(head,index);
else
_deleteline(*head,index);
if (sort == TRUE) _reindex(head);
}
int _dumpLine(VLINES *head, long index, VLINES *line){
//Dumps contents of desired line from buffer into temporary line
int i=-1; char ch=0; char attrib = 0; char specialChar = 0;
VLINES *aux = NULL; //auxiliary pointer
aux = _getObject(head, index);
memset(line, '\0',sizeof(&line)); //Clear memory for temporary line
//Does the line exist?
if (aux != NULL) {
for (i=0; i<MAX_LINE_SIZE; i++)
{
ch = aux->linea[i].ch;
attrib = aux->linea[i].attrib;
specialChar = aux->linea[i].specialChar;
line->linea[i].ch = ch;
line->linea[i].attrib = attrib;
line->linea[i].specialChar = specialChar;
}
i = aux->index;
}
return i;
}
int _updateLine(VLINES *head, long index, VLINES *line){
//Copies contents of desired line from temporary line to buffer
int i=0; char ch=0; char specialChar = 0;
char attrib = 0;
VLINES *aux = NULL; //auxiliary pointer
aux = _getObject(head, index);
//Does the line exist?
if (aux != NULL) {
for (i=0; i<MAX_LINE_SIZE-1; i++)
{
ch = line->linea[i].ch;
specialChar = line->linea[i].specialChar;
attrib = line->linea[i].attrib;
aux->linea[i].ch = ch;
aux->linea[i].specialChar = specialChar;
aux->linea[i].attrib = attrib;
}
i = aux->index;
}
return i;
}
CHARBUF _getSingleChar(VLINES *head, long X, long Y ){
//Dumps contents of desired line from buffer into temporary line
char ch=0; char attrib = 0; char specialChar = 0;
CHARBUF retvalues;
VLINES *aux = NULL; //auxiliary pointer
aux = _getObject(head, Y);
//Does the line exist?
if (aux != NULL) {
ch = aux->linea[X].ch;
specialChar = aux->linea[X].specialChar;
attrib = aux->linea[X].attrib;
} else
{
ch = '\0';
specialChar = '\0';
attrib = '\0';
}
retvalues.ch = ch;
retvalues.attrib = attrib;
retvalues.specialChar = specialChar;
return retvalues;
}
int findEndline(VLINES line) {
char ch = 0;
int i=0;
int result = 0;
do {
ch = line.linea[i].ch;
//write_ch(i,1,ch,F_RED,B_WHITE);
if(ch == 0x00 || ch == 0x10 || ch == 0x0A) //ch = 00
break;
i++;
} while(i < MAX_LINE_SIZE);
result = i;
ch = 0;
return result;
}
BOOL isLineTerminated(VLINES line) {
BOOL flag=FALSE;
char ch=0;
int i = 0;
for (i=0; i< MAX_LINE_SIZE; i++){
ch = line.linea[i].ch;
if(ch == 0x10 || ch == 0x0A)
flag = TRUE;
}
return flag;
}
================================================
FILE: src/edbuf.h
================================================
#ifndef _EDBUF_H_
#define _EDBUF_H_
#include <stdio.h>
#include <stdlib.h>
#define MAX_LINE_SIZE 512
#define TRUE 1
#define FALSE 0
typedef int BOOL;
typedef struct _charbuf
{
char ch;
char specialChar;
char attrib;
}CHARBUF;
typedef struct _vlines
{
int index;
CHARBUF linea[MAX_LINE_SIZE];
struct _vlines *next;
} VLINES;
/* Adapted from Kernighan and Pike's "The Practice of Programming" pp.46 et
seq. (Addison-Wesley 1999) */
// create new list element of type VLINES from the supplied text string
VLINES *_newline(VLINES temp);
VLINES *_addfront(VLINES *head, VLINES *newp);
VLINES *_addatend (VLINES *head, VLINES *newp);
VLINES *_addmiddle (VLINES *head, VLINES *newp);
VLINES *_update(VLINES *head, int index, VLINES temp);
VLINES *_getObject(VLINES *head, int index);
void _hardupdateLINE(VLINES **head, int index, VLINES temp);
void _RemoveThing(VLINES **head, int index);
void _deletetheList(VLINES **head);
VLINES *_deleteline(VLINES *head, int index);
void _deleteObject(VLINES **head,int index, BOOL sort);
int _length(VLINES **head);
void _printlist(VLINES **head);
void _reindex(VLINES **head);
int _dumpLine(VLINES *head, long index, VLINES *line);
int _updateLine(VLINES *head, long index, VLINES *line);
CHARBUF _getSingleChar(VLINES *head, long X, long Y );
int findEndline(VLINES line);
BOOL isLineTerminated(VLINES line);
#endif
================================================
FILE: src/editor.c
================================================
/* Main editor section C·edit
* for a Text User Interface
* Last modified: 6/04/2024
* @author:velorek
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <wchar.h>
#include "rterm.h"
#include "scbuf.h"
#include "ui.h"
#include "tm.h"
#include "keyb.h"
#include "global.h"
#include "editor.h"
#include "fileb.h"
#include "edbuf.h"
int oldEndLine= 0;
wchar_t convertChar(char c1, char c2) {
// Combine the bytes into a single string
char temp[3];
temp[0] = c1;
temp[1] = c2;
temp[2] = '\0';
wchar_t wchar;
mbstowcs(&wchar, temp, 1);
return wchar;
}
void linetoScreenRAW(long whereY, VLINES tempLine){
//dump temporary Line to screen buffer - RAW MODE
int i=0;
int attrib = EDIT_FORECOLOR;
int tempEndLine = findEndline(tempLine);
//if (tempEndLine <0) return;
for (i=0; i<tempEndLine; i++){
attrib = tempLine.linea[i+shiftH].attrib;
//don't print beyond display!
if (i+START_CURSOR_X < new_columns-1){
if(tempLine.linea[i+shiftH].specialChar!= 0) {
//Special char ? print the two values to screen buffer.
gotoxy(i+START_CURSOR_X+1, whereY+1);
outputcolor(attrib, EDITAREACOL);
printf("%c%c", tempLine.linea[i+shiftH].specialChar,tempLine.linea[i+shiftH].ch);
} else {
gotoxy(i+START_CURSOR_X+1, whereY+1);
outputcolor(attrib, EDITAREACOL);
printf("%c", tempLine.linea[i+shiftH].ch);
}
}
}
}
void linetoScreen(long whereY, VLINES tempLine){
//dump temporary Line to screen buffer - RAW MODE
int i=0;
int attrib = EDIT_FORECOLOR;
wchar_t temp='0';
int tempEndLine = findEndline(tempLine);
for (i=0; i<tempEndLine; i++){
attrib = tempLine.linea[i+shiftH].attrib;
//don't print beyond display!
if (i+START_CURSOR_X < new_columns-1){
if(tempLine.linea[i].specialChar != 0) {
//Special char ? print the two values to screen buffer.
//write_ch(screen1,i+START_CURSOR_X, whereY+1,temp,attrib,EDITAREACOL,0);
temp = convertChar(tempLine.linea[i+shiftH].specialChar, tempLine.linea[i+shiftH].ch); // Second char
//if (temp<1 ) {temp = FILL_CHAR; attrib =F_BLUE;}
if ((temp<1 || temp =='\0' || temp==END_LINE_CHAR)) {temp = FILL_CHAR; attrib =F_BLUE;}
write_ch(screen1,i+START_CURSOR_X, whereY+1,temp,attrib,EDITAREACOL,0);
//rintf("%c%c", tempLine.linea[i].specialChar,tempLine.linea[i].ch);
} else {
//write_ch(screen1,i+START_CURSOR_X, whereY+1,tempLine.linea[i].ch,attrib,EDITAREACOL,0);
temp = tempLine.linea[i+shiftH].ch;
//if (temp<1 ) temp = FILL_CHAR;
if ((temp<1 || temp =='\0' || temp==END_LINE_CHAR)) {temp = FILL_CHAR; attrib =F_BLUE;}
write_ch(screen1,i+START_CURSOR_X, whereY+1,temp,attrib,EDITAREACOL,0);
//printf("%c", tempLine.linea[i].ch);
}
}
}
}
void cleanScreenLine(long whereY)
{
int i=0;
for (i=0; i<new_columns-2; i++){
gotoxy(i+START_CURSOR_X+1, whereY+1);
outputcolor(EDIT_FORECOLOR, EDITAREACOL);
printf("%c", FILL_CHAR);
}
resetAnsi(0);
}
void cleanSection(long whereY, long start, int amount)
{
int i=0;
for (i=start; i<start+amount; i++){
if (i<new_columns-2){
gotoxy(i+START_CURSOR_X+1, whereY+1);
outputcolor(EDIT_FORECOLOR, EDITAREACOL);
printf("%c", FILL_CHAR);
}
}
resetAnsi(0);
}
void buffertoScreen(BOOL raw){
long j=0;
if (raw == 0) flush_editarea(0);
for (j=0; j<vdisplayArea; j++){
_dumpLine(edBuf1, j+currentLine , &tempLine);
if (raw==TRUE){
cleanScreenLine(j+START_CURSOR_Y);
linetoScreenRAW(j+START_CURSOR_Y, tempLine);
}else{
//cleanScreenLine(j+START_CURSOR_Y);
linetoScreen(j+START_CURSOR_Y, tempLine);
}
}
//restore tempLine to active line
memset(&tempLine, '\0',sizeof(tempLine));
_dumpLine(edBuf1, currentLine, &tempLine);
resetAnsi(0);
}
void buffertoFile(char *fileName){
long j=0,i=0;
wchar_t tempLongChar = 0;
openFile(&filePointer, fileName, "w");
if (filePointer != NULL){
for (j=0; j<_length(&edBuf1); j++){
//tempLine = {0};
_dumpLine(edBuf1, j, &tempLine);
for (i=0; i<findEndline(tempLine); i++){
if(tempLine.linea[i].specialChar != 0) {
tempLongChar = convertChar(tempLine.linea[i].specialChar, tempLine.linea[i].ch); // Special character
fprintf(filePointer, "%lc", tempLongChar);
}else{
//regular ASCII char
fprintf(filePointer, "%c", tempLine.linea[i].ch);
}
}
fprintf(filePointer,"%c" , END_LINE_CHAR);
}
closeFile(filePointer);
fileModified = FILE_UNMODIFIED;
}
};
int editor_section(char ch){
char accentchar[2];
int insertMode=0;
VLINES *aux = NULL;
VLINES splitLine = {0};
int i,j=0;
int attrib=EDIT_FORECOLOR;
char newch=0;
int endLine=0;
if (fileModified==FILE_UNMODIFIED) fileModified= FILE_MODIFIED;
//Check whether we are on Readmode
// if (fileModified != FILE_READMODE) {
//if ((ch > 31 && ch < 127) || ch < 0) {
// A KEY IS PRESSED AND ADDED TO EDIT BUFFER
// FIRST check for negative chars and special characters
newch=ch;
accentchar[0] = 0;
accentchar[1] = newch;
//Check whether we are on Readmode
// if (fileModified != FILE_READMODE) {
//Process normal printable chars first
if (ch == 27) return 0;
if ((ch > 31 && ch < 127) || ch < 0) {
if (ch < 0) {
read_accent(&newch, accentchar);
newch = accentchar[1];
}
//if ((posBufX != endLine) && (shiftH>0)) return 0;
//check if we are at the limit of our display to print chars
if (cursorX < new_columns-2) cursorX++;
if (posBufX < MAX_LINE_SIZE && cursorX == new_columns-2) {shiftH++;}
//write_num(screen1,20,2,currentLine,B_CYAN,F_WHITE,1);
//SYNTAX HIGHLIGHTING DEMO
//Highlight numbers in GREEN
if ((accentchar[1] >= 48) && (accentchar[1] <=57)) attrib = FH_GREEN;
//Highlight special characters in CYAN
if ((accentchar[1] >= 33) && (accentchar[1] <=47)) attrib = FH_CYAN;
aux = _getObject(edBuf1, posBufY);
if ((accentchar[1] >= 58) && (accentchar[1] <=64)) attrib = FH_CYAN;
aux = _getObject(edBuf1, posBufY);
if ((accentchar[1] >= 91) && (accentchar[1] <=96)) attrib = FH_CYAN;
aux = _getObject(edBuf1, posBufY);
if ((accentchar[1] >= 123) && (accentchar[1] <=126)) attrib = FH_CYAN;
aux = _getObject(edBuf1, posBufY);
//FIRST TIME -> CREATE LINES IN BUFFER
if (aux == NULL) {
//FIRST CHAR - if not we create a new line in buffer
tempLine.index = posBufY;
//Add spaces if cursor is not at (0,0)
if (posBufX != 0) {
for (i=0; i<posBufX; i++) {
tempLine.linea[i].ch = FILL_CHAR;
tempLine.linea[i].specialChar = 0;
tempLine.linea[i].attrib = EDIT_FORECOLOR;
}
}
tempLine.linea[posBufX].ch = accentchar[1];
tempLine.linea[posBufX].specialChar = accentchar[0];
tempLine.linea[posBufX].attrib = attrib;
//add end_line_char to line
posBufX = posBufX + 1;
tempLine.linea[posBufX].ch = END_LINE_CHAR;
tempLine.linea[posBufX].specialChar = 0;
tempLine.linea[posBufX].attrib = attrib;
edBuf1 = _addatend(edBuf1, _newline(tempLine));
linetoScreenRAW(cursorY,tempLine);
} else
//LINE ALREADY EXISTS
{
//Locate the end of the line
endLine = findEndline(tempLine);
//Insert characters in the middle of other characters
if (endLine > posBufX) {
tempLine.index = posBufY; //with every line index is incremented
if (insertMode == FALSE){
for (i=endLine; i>=posBufX; i--){
tempLine.linea[i+1].ch = tempLine.linea[i].ch;
tempLine.linea[i+1].specialChar = tempLine.linea[i].specialChar;
tempLine.linea[i+1].attrib = tempLine.linea[i].attrib;
}
}
tempLine.linea[posBufX].ch = accentchar[1];
tempLine.linea[posBufX].specialChar = accentchar[0];
tempLine.linea[posBufX].attrib = attrib;
posBufX = posBufX + 1;
_updateLine(edBuf1, posBufY, &tempLine);
linetoScreenRAW(cursorY,tempLine);
}
else {
// POSBUFX >= ENDLINE: Cursor is at the end or further away from latest text
//ADD SPACES IF CURSOR IS NOT AT THE END OF THE LINE AND LINE ALREADY EXISTS
if(posBufX > endLine) {
for(i = endLine; i < posBufX; i++) {
tempLine.linea[i].ch = FILL_CHAR;
tempLine.linea[i].specialChar = 0;
tempLine.linea[i].attrib = EDIT_FORECOLOR;
}
}
tempLine.linea[posBufX].ch = accentchar[1];
tempLine.linea[posBufX].specialChar = accentchar[0];
tempLine.linea[posBufX].attrib = attrib;
posBufX = posBufX + 1;
tempLine.linea[posBufX].ch = END_LINE_CHAR;
tempLine.linea[posBufX].specialChar = 0;
tempLine.linea[posBufX].attrib = attrib;
_updateLine(edBuf1, posBufY, &tempLine);
linetoScreenRAW(cursorY,tempLine);
//the cursor returns to its place when scrolling horizontally
if (posBufX < MAX_LINE_SIZE && cursorX == new_columns-2) {cursorX--;}
}
}
if (shiftH>0){
buffertoScreen(1);
}
}
//record previous values
old_cursorX = cursorX;
old_cursorY = cursorY;
oldposBufX = posBufX;
oldposBufY = posBufY;
oldEndLine = endLine;
//HANDLE ENTER KEY
if (ch == K_ENTER) {
// ENTER key
update_ch(cursorX, cursorY, ' ', EDITAREACOL, EDITAREACOL);
// Move cursor down if not at the bottom of the screen
if (cursorY < new_rows - 3) {
cursorY++;
}
cursorX = START_CURSOR_X;
// If the buffer pointer is at the end, create a new empty line
if (_length(&edBuf1) <= posBufY) {
// Create a new line without characters in the current line in the edit buffer
memset(&tempLine, '\0', sizeof(tempLine));
tempLine.index = _length(&edBuf1);
tempLine.linea[0].ch = END_LINE_CHAR;
tempLine.linea[0].specialChar = 0;
tempLine.linea[0].attrib = 0;
edBuf1 = _addatend(edBuf1, _newline(tempLine));
} else {
// SPLIT LINE INTO TWO
_dumpLine(edBuf1, posBufY, &tempLine);
endLine = findEndline(tempLine);
// Create a new line to insert the split content
memset(&splitLine, '\0', sizeof(splitLine));
memset(&tempLine, '\0', sizeof(tempLine));
tempLine.index = _length(&edBuf1);
edBuf1 = _addatend(edBuf1, _newline(tempLine));
// Move lines below the current line down by one
for (j = _length(&edBuf1) - 1; j > posBufY; j--) {
_dumpLine(edBuf1, j, &tempLine);
_updateLine(edBuf1, j + 1, &tempLine);
if (j + START_CURSOR_Y < new_rows - 3) {
cleanSection(j + START_CURSOR_Y, 0, findEndline(tempLine));
}
}
// Split the current line at the cursor position
_dumpLine(edBuf1, posBufY, &tempLine);
memset(&splitLine, '\0', sizeof(splitLine));
// Copy characters before the cursor to the current line
for (i = 0; i < posBufX; i++) {
splitLine.linea[i].ch = tempLine.linea[i].ch;
splitLine.linea[i].specialChar = tempLine.linea[i].specialChar;
splitLine.linea[i].attrib = tempLine.linea[i].attrib;
}
if (isLineTerminated(splitLine) == FALSE) {
splitLine.linea[i].ch = END_LINE_CHAR;
}
_updateLine(edBuf1, posBufY, &splitLine);
// Move characters after the cursor to the next line
memset(&splitLine, '\0', sizeof(splitLine));
j = 0;
for (i = posBufX; i < endLine; i++) {
splitLine.linea[j].ch = tempLine.linea[i].ch;
splitLine.linea[j].specialChar = tempLine.linea[i].specialChar;
splitLine.linea[j].attrib = tempLine.linea[i].attrib;
j++;
}
if (isLineTerminated(splitLine) == FALSE) {
splitLine.linea[j].ch = END_LINE_CHAR;
}
// Update the new line with the split content
_updateLine(edBuf1, posBufY + 1, &splitLine);
// Clean the screen for the current line and refresh the buffer
cleanSection(cursorY - 1, 0, findEndline(tempLine));
buffertoScreen(TRUE);
}
// Scroll if needed when cursor is at the bottom of the screen
if (_length(&edBuf1) > vdisplayArea && cursorY == new_rows - 3) {
buffertoScreen(1);
currentLine++;
}
// Move buffer pointer positions
posBufY++;
posBufX = 0;
}
if(ch == K_BACKSPACE) {
// BACKSPACE key
update_ch(cursorX, cursorY, ' ', EDITAREACOL, EDITAREACOL);
if (posBufX == findEndline(tempLine)) {
// Cursor is at the end of the line
tempLine.linea[posBufX-1].ch = 0;
tempLine.linea[posBufX-1].specialChar = 0;
tempLine.linea[posBufX-1].attrib = 0;
} else {
// Shift characters to the left if we are not at the end of the line
if (posBufX != 0) {
for(i = posBufX - 1; i < findEndline(tempLine) - 1; i++) {
tempLine.linea[i].ch = tempLine.linea[i + 1].ch;
tempLine.linea[i].specialChar = tempLine.linea[i + 1].specialChar;
tempLine.linea[i].attrib = tempLine.linea[i + 1].attrib;
}
// Clear the last character in the line
tempLine.linea[i].ch = 0;
tempLine.linea[i].specialChar = 0;
tempLine.linea[i].attrib = 0;
}
}
// Remove line if we continue pressing backspace at the beginning of a line
if(cursorX == START_CURSOR_X && cursorY > START_CURSOR_Y) {
if (posBufY > 0) {
memset(&tempLine, '\0', sizeof(tempLine));
memset(&splitLine, '\0', sizeof(splitLine));
_dumpLine(edBuf1, posBufY - 1, &tempLine);
if (findEndline(tempLine) < 1) {
// Previous line is empty, remove it
for (j = posBufY - 1; j < _length(&edBuf1) - 1; j++) {
_dumpLine(edBuf1, j + 1, &tempLine);
_hardupdateLINE(&edBuf1, j, tempLine);
}
_deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE);
} else {
// Merge two lines
endLine = findEndline(tempLine);
_dumpLine(edBuf1, posBufY, &splitLine);
for (i = 0; i < findEndline(splitLine); i++) {
tempLine.linea[endLine + i].ch = splitLine.linea[i].ch;
tempLine.linea[endLine + i].attrib = splitLine.linea[i].attrib;
tempLine.linea[endLine + i].specialChar = splitLine.linea[i].specialChar;
}
tempLine.linea[endLine + i].ch = END_LINE_CHAR;
_hardupdateLINE(&edBuf1, posBufY - 1, tempLine);
// Update subsequent lines
for (j = posBufY; j < _length(&edBuf1) - 1; j++) {
_dumpLine(edBuf1, j + 1, &tempLine);
_hardupdateLINE(&edBuf1, j, tempLine);
}
_deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE);
}
posBufY--;
cursorY--;
if (cursorY == new_rows - 3 && currentLine > 0) currentLine--;
buffertoScreen(1);
_dumpLine(edBuf1, posBufY, &tempLine);
// Adjust cursor position after merging lines
if (findEndline(splitLine) != 0 && findEndline(splitLine) != findEndline(tempLine)) {
posBufX = findEndline(tempLine) + 1;
cursorX = posBufX + START_CURSOR_X;
} else {
if (endLine != findEndline(tempLine)) {
cursorX = START_CURSOR_X;
posBufX = cursorX - 1;
} else {
posBufX = findEndline(tempLine) + 1;
cursorX = posBufX + START_CURSOR_X;
}
}
}
}
// Normal backspace within a line
if(cursorX > START_CURSOR_X) {
cursorX--;
posBufX--;
_updateLine(edBuf1, posBufY, &tempLine);
}
// Clean up and refresh the line on screen
cleanSection(cursorY, findEndline(tempLine), 2);
linetoScreenRAW(cursorY, tempLine);
}
if (deleteKeyPressed == 1) {
deleteKeyPressed = 0;
// DEL key
if (posBufX == findEndline(tempLine)) {
// Cursor is at the end of the line
if (posBufY < _length(&edBuf1) - 1) {
// If there is a next line, merge it with the current line
_dumpLine(edBuf1, posBufY + 1, &splitLine);
endLine = findEndline(tempLine);
// Copy the characters from the next line to the end of the current line
for (i = 0; i < findEndline(splitLine); i++) {
tempLine.linea[endLine + i].ch = splitLine.linea[i].ch;
tempLine.linea[endLine + i].attrib = splitLine.linea[i].attrib;
tempLine.linea[endLine + i].specialChar = splitLine.linea[i].specialChar;
}
tempLine.linea[endLine + i].ch = END_LINE_CHAR;
// Update the buffer with the modified line
_hardupdateLINE(&edBuf1, posBufY, tempLine);
// Remove the next line from the buffer
for (j = posBufY + 1; j < _length(&edBuf1); j++) {
_dumpLine(edBuf1, j + 1, &tempLine);
_hardupdateLINE(&edBuf1, j, tempLine);
}
_deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE);
// Update the screen
buffertoScreen(1);
}
} else {
// Cursor is in the middle of the line, so delete the character at the cursor position
for (i = posBufX; i < findEndline(tempLine); i++) {
tempLine.linea[i].ch = tempLine.linea[i + 1].ch;
tempLine.linea[i].specialChar = tempLine.linea[i + 1].specialChar;
tempLine.linea[i].attrib = tempLine.linea[i + 1].attrib;
}
tempLine.linea[i].ch = 0; // Nullify the last character
// Update the buffer with the modified line
_updateLine(edBuf1, posBufY, &tempLine);
// Update the screen
cleanSection(cursorY, findEndline(tempLine), 2);
linetoScreenRAW(cursorY, tempLine);
}
}
if(ch == K_TAB) {
//TAB key sends spaces for convenience
for (i=posBufX; i<posBufX+TAB_SPACES; i++)
{
tempLine.linea[i].ch = FILL_CHAR;
tempLine.linea[i].specialChar = 0;
tempLine.linea[i].attrib = EDIT_FORECOLOR;
}
posBufX=posBufX + TAB_SPACES;
if (cursorX < new_columns-8) {
for (i=0; i<TAB_SPACES; i++) update_ch(cursorX+i, cursorY, ' ', EDITAREACOL, EDITAREACOL);
cursorX = cursorX + TAB_SPACES;
}
_updateLine(edBuf1, posBufY, &tempLine);
}
return 0;
}
/*------------------------------*/
/* Open file and dump to buffer */
/*------------------------------*/
int filetoBuffer(char *fileName) { //EDBUF*
long inlineChar = 0, lineCounter = 0;
//wchar_t tempLongChar = 0;
char ch;
int attrib = EDIT_FORECOLOR;
fileModified = FILE_UNMODIFIED;
openFile(&filePointer, fileName, "r");
memset(&tempLine, '\0',sizeof(tempLine));
tempLine.index = 0;
if (edBuf1 != NULL) _deletetheList(&edBuf1);
edBuf1 = _addatend(edBuf1, _newline(tempLine));
//Check if pointer is valid
if(filePointer != NULL) {
rewind(filePointer); //Make sure we are at the beginning
ch = getc(filePointer); //Peek ahead in the file
while(!feof(filePointer)) {
if(ch != '\0') {
//Temporary restrictions until scroll is implemented.
//if(lineCounter == rows - 4)
// break;
if(ch == SPECIAL_CHARS_SET1 || ch == SPECIAL_CHARS_SET2) {
tempLine.linea[inlineChar].specialChar = ch;
//Read accents
ch = getc(filePointer);
tempLine.linea[inlineChar].ch = ch;
} else {
if(ch > 0)
tempLine.linea[inlineChar].ch = ch;
}
//SYNTAX HIGHLIGHTING DEMO
//Highlight numbers in GREEN
attrib = EDIT_FORECOLOR;
if ((ch >= 48) && (ch <=57)) attrib = FH_GREEN;
//Highlight special characters in CYAN
if ((ch >= 33) && (ch <=47)) attrib = FH_CYAN;
if ((ch >= 58) && (ch <=64)) attrib = FH_CYAN;
if ((ch >= 91) && (ch <=96)) attrib = FH_CYAN;
if ((ch >= 123) && (ch <=126)) attrib = FH_CYAN;
tempLine.linea[inlineChar].attrib = attrib;
//TABs are converted into spaces
/* if(ch == K_TAB) {
for (tabcount=0;tabcount<TAB_DISTANCE;tabcount++){
ch = FILL_CHAR;
writetoBuffer(editBuffer, inlineChar, lineCounter, ch);
inlineChar++;
}*/
inlineChar++; //NEXT CHARACTER
if(ch == END_LINE_CHAR) {
inlineChar = 0;
ch = 0;
_updateLine(edBuf1, lineCounter, &tempLine);
lineCounter++;
memset(&tempLine, '\0',sizeof(tempLine));
tempLine.index = _length(&edBuf1);
edBuf1 = _addatend(edBuf1, _newline(tempLine));
}
if (lineCounter == MAX_LINES) {
//open as readMode
fileModified = FILE_READMODE;
break;
}
//If file is bigger than buffer
//break loop at last allowed line.
}
ch = getc(filePointer);
}
}
closeFile(filePointer);
return 1;
}
void flush_editarea(int force_update) {
int i;
//Paint blue edit area
//draw_screen();
screen_color(screen1, EDITAREACOL, EDITAREACOL, FILL_CHAR);
//Draw upper and lower bars
for(i = 0; i < old_columns; i++) {
write_ch(screen1, i, 1, FILL_CHAR, MENU_PANEL, MENU_PANEL,0);
}
for(i = 0; i < old_columns; i++) {
write_ch(screen1, i, old_rows, FILL_CHAR, STATUSBAR, STATUSMSG,1);
}
// Text messages
write_str(screen1, 0, 1, "File Options Help", MENU_PANEL, MENU_FOREGROUND0,0);
write_str(screen1, 0, 1, "F", MENU_PANEL, F_RED,0);
write_str(screen1, 7, 1, "p", MENU_PANEL, F_RED,0);
write_str(screen1, 15, 1, "H", MENU_PANEL, F_RED,0);
write_str(screen1, 0, old_rows, STATUS_BAR_MSG1, STATUSBAR, STATUSMSG,0);
/* Frames */
//window appearance and scroll bar
for(i = 2; i < old_rows; i++) {
write_ch(screen1,old_columns-1, i, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,0); //Scroll bar
write_ch(screen1,0, i, VER_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //upper vertical line box-like char
}
for(i = 0; i < old_columns; i++) {
write_ch(screen1,i, 2, HOR_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //horizontal line box-like char
write_ch(screen1,i, old_rows - 1, ' ', EDITWINDOW_BACK, EDITWINDOW_FORE,0);
}
write_ch(screen1,0, 2, UPPER_LEFT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //upper-left box-like char
//horizontal scroll bar
for(i = 0; i < old_columns; i++) {
write_ch(screen1,i, old_rows - 1, FILL_CHAR, SCROLLBAR_BACK, SCROLLBAR_FORE,0);
}
//Window-appearance
write_ch(screen1,old_columns-1, 2, UPPER_RIGHT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //right window corner
write_ch(screen1,old_columns-1, old_rows - 1, LOWER_RIGHT_CORNER, EDITWINDOW_BACK,
EDITWINDOW_FORE,0);
write_ch(screen1, 0, old_rows - 1, LOWER_LEFT_CORNER, EDITWINDOW_BACK,
EDITWINDOW_FORE,0);
//Scroll symbols
write_ch(screen1,old_columns-1, 3, '^', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
write_ch(screen1, old_columns-1, old_rows - 2, 'v', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
write_ch(screen1, old_columns-1, 4, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);
write_ch(screen1, 2, old_rows - 1, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);
write_ch(screen1, 1, old_rows - 1, '<', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
write_ch(screen1, old_columns - 2, old_rows - 1, '>', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
if (strlen(fileName) == 0) strcpy(fileName,"UNTITLED");
write_str(screen1,(new_columns / 2) - (strlen(fileName) / 2), 2, fileName,
MENU_PANEL, MENU_FOREGROUND0,0);
if (force_update) dump_screen(screen1);
}
================================================
FILE: src/editor.h
================================================
/*
========================================================================
- HEADER -
Module with main editor in C·edit
@author : Velorek
@version : 1.0
Last modified: 06/04/2024
========================================================================
*/
#ifndef _EDITOR_H_
#define _EDITOR_H_
#include "scbuf.h"
#include "global.h"
#include "edbuf.h"
#include <stdio.h>
int process_input(char ch);
int special_keys();
int control_keys(char ch);
void linetoScreen(long whereY, VLINES tempLine);
void linetoScreenRAW(long whereY, VLINES tempLine);
void cleanScreenLine(long whereY);
void cleanSection(long whereY, long start, int amount);
void buffertoScreen(BOOL raw);
int editor_section(char ch);
wchar_t convertChar(char c1, char c2);
//int filetoBuffer(FILE * filePtr);
void buffertoFile(char *fileName);
int filetoBuffer(char *fileName);
void flush_editarea(int force_update);
#endif
================================================
FILE: src/fileb.c
================================================
/*
======================================================================
Module to describe basic file operations.
@author : Velorek
@version : 1.0
LAST MODIFIED : 14/04/2019 - Rename headers
======================================================================
*/
/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <stdio.h>
#include "global.h"
#include "fileb.h"
/*====================================================================*/
/* FUNCTIONS - CODE */
/*====================================================================*/
/*----------------------*/
/* Check if file exists */
/*----------------------*/
int file_exists(char *fileName) {
int ok=0;
if(access(fileName, F_OK) != -1) {
ok = 1; //File exists
} else {
ok = 0;
}
return ok;
}
/*---------------*/
/* Get file size */
/*---------------*/
long getfileSize(FILE * filePtr) {
long sz=0;
if(filePtr != NULL) {
fseek(filePtr, 0L, SEEK_END);
sz = ftell(filePtr);
rewind(filePtr);
}
return sz;
}
/*---------------------*/
/* Count lines in File */
/*---------------------*/
long countLinesFile(FILE * filePtr) {
char ch=0;
long counterA = 0;
if(filePtr != NULL) {
rewind(filePtr); //Make sure we are at the beginning
ch = getc(filePtr); //Peek ahead in the file
while(!feof(filePtr)) {
if(ch == END_LINE_CHAR) {
counterA++;
}
ch = getc(filePtr);
}
}
return counterA;
}
/*-----------------*/
/* Check file type */
/*-----------------*/
long checkFile(FILE * filePtr) {
char ch=0;
long counterA = 0;
if(filePtr != NULL) {
rewind(filePtr); //Make sure we are at the beginning
ch = getc(filePtr); //Peek ahead in the file
while(!feof(filePtr)) {
if(ch < 9) {
//discard accents
if(ch > -60)
counterA++;
}
ch = getc(filePtr);
}
}
return counterA;
}
//check whether the file is a text file
int openandcheckFile(char *fileName) {
unsigned char ch=0;
long counterA = 0;
FILE *fp;
openFile(&fp, fileName, "r");
if(fp != NULL) {
rewind(fp); //Make sure we are at the beginning
ch = getc(fp); //Peek ahead in the file
while(!feof(fp)) {
if (ch == 0x00) {closeFile(fp); fp = NULL; return 1;}
if(ch < 9) {
//discard accents
if(ch > 196)
counterA++;
}
ch = getc(fp);
}
}
//If there are more strange characters than half the size of the file probably a binary file
if (counterA > (getfileSize(fp)/2)) {
if (fp != NULL) closeFile(fp);
fp = NULL;
return 1;
}
if (fp != NULL) closeFile(fp);
fp = NULL;
return 0;
}
/*-----------*/
/* Open file */
/*-----------*/
int openFile(FILE ** filePtr, char fileName[], char *mode)
/*
Open file.
@return ok = 1 ? 0 Success!
*/
{
int ok = 0;
*filePtr = fopen(fileName, mode);
if(*filePtr != NULL) {
//File opened correctly.
ok = 1;
} else {
//Error
ok = 0;
}
return ok;
}
/*------------*/
/* Close file */
/*------------*/
int closeFile(FILE * filePtr) {
/*
Close file
@return ok:
*/
int ok=0;
if(filePtr != NULL) {
ok = fclose(filePtr);
}
return ok;
}
================================================
FILE: src/fileb.h
================================================
/*
========================================================================
- HEADER -
Module to handle basic file operations
@author : Velorek
@version : 1.0
Last modified: 31/08/2025 Open and check file
========================================================================
*/
#ifndef _FILEB_H_
#define _FILEB_H_
/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <stdio.h>
#include "scbuf.h"
/*====================================================================*/
/* CONSTANTS */
/*====================================================================*/
#define CONFIGFILE "cedit.cfg"
/*====================================================================*/
/* FUNCTION PROTOTYPES */
/*====================================================================*/
int openFile(FILE ** filePtr, char fileName[], char *mode);
int closeFile(FILE * filePtr);
long getfileSize(FILE * filePtr);
long countLinesFile(FILE * filePtr);
long checkFile(FILE * filePtr);
int openandcheckFile(char *fileName);
int file_exists(char *fileName);
#endif
================================================
FILE: src/global.c
================================================
#include "global.h"
#include "rterm.h"
#include "time.h"
// GLOBALS : SCREEN1 : ANIMATED | SCREEN2 : BASE SCREEN
LISTCHOICE *listBox1 = NULL;
SCREENCELL *screen1=NULL;
SCREENCELL *screen2=NULL;
SCREENCELL *screen3=NULL;
NTIMER cursor_timer1;
NTIMER timer2;
NTIMER timer3;
//NTIMER timer4;
SCROLLDATA scrollData;
VLINES *edBuf1=NULL; //Buffer vector of lines(1022 chars)
VLINES tempLine;
//C-Edit Theme
int EDITAREACOL= B_BLUE;
int EDIT_FORECOLOR=FH_WHITE;
int STATUSBAR =B_BLACK;
int STATUSMSG =F_WHITE;
int MENU_PANEL =B_WHITE;
int MENU2_PANEL = B_BLACK;
int MENU_SELECTOR =B_RED;
int MENU_FOREGROUND0 =F_BLACK;
int MENU2_FOREGROUND0 = F_WHITE;
int MENU_FOREGROUND1= FH_WHITE;
int EDITWINDOW_BACK= B_BLUE;
int EDITWINDOW_FORE= F_WHITE;
int SCROLLBAR_BACK= B_WHITE;
int SCROLLBAR_FORE= FH_WHITE;
int SCROLLBAR_SEL= B_CYAN;
int SCROLLBAR_ARR= B_BLACK;
int WINDOW_TITLEB = B_BLACK;
int WINDOW_TITLEF = F_WHITE;
int new_rows = 0, new_columns = 0, old_rows = 0, old_columns = 0; // Terminal dimensions
int cursorX = START_CURSOR_X, cursorY = START_CURSOR_Y;
int old_cursorX = START_CURSOR_X, old_cursorY = START_CURSOR_Y;
long posBufX = 0, posBufY = 0;
long oldposBufX = 0, oldposBufY = 0;
long shiftH = 0;
int unwantedChars = 0; //try to avoid printing unwanted characgters from cursor chars counter
//TEXT BUFFER POINTERS
int hdisplayLimit=0; //horizontal scroll, last char position in line that allows scroll
int currentColumn=0; //horizontal scroll, pointer to current char position in line
long linesinFile=0; //vertical scroll
long vdisplayLimit=0; //vertical scroll, last line that allows scroll
int vdisplayArea = 0; //size in lines of the allowed displayed area // calculated when screen resizes
int hdisplayArea = 0; //size in lines of the allowed displayed area // calculated when screen resizes
long currentLine=0; //verticall scroll, pointer to current top line in scroll
int vscrollActive=0; //vertical scroll, vertical scroll is posible
//extern int hscrollActive; //horizontal scroll, horizontal scroll is posible
int programStatus = 0; //signal for overall program Status
char fileName[MAXFILENAME];
char fullPath[MAXFILENAME];
FILE *filePointer;
int fileModified=FILE_UNMODIFIED;
int deleteKeyPressed = 0;
char aboutMSG[7][MAXLINE] = {ABOUT_ASC_0,ABOUT_ASC_1,ABOUT_ASC_2,ABOUT_ASC_3,ABOUT_ASC_4,ABOUT_ASC_5};
char help[HELPLINES][MAXLINE] = { HELP0,
HELP1, HELP2, HELP3,
HELP4, HELP5, HELP6,
HELP7, HELP8, HELP9,
HELP10, HELP11, HELP12,
HELP13, HELP14, HELP15,
HELP16, HELP17, HELP18,
HELP19, HELP20
};
int initCEDIT(){
get_terminal_dimensions(&new_rows,&new_columns);
//Init timer
init_timer(&cursor_timer1,TIMER_SPEED);
init_timer(&timer2,TIMER_SPEED2);
init_timer(&timer3,TIMER_SPEED3);
//init_timer(&timer4,ABOUT_SPEED);
timer2.ticks=0;
timer3.ticks=-1;
//timer4.ticks=0;
cursor_timer1.ticks=0;
//Init Text buffer
VLINES tempLine = {0};
memset(&fileName, '\0',sizeof(fileName)); //Clear fileName
memset(&tempLine, '\0',sizeof(tempLine)); //Clear memory for temporary line
//Create one screen in memory
if (screen1 != NULL) deleteList(&screen1);
if (screen2 != NULL) deleteList(&screen2);
//Init 2 : Create 2 Screens for a double buffer approach
old_rows=new_rows;
old_columns=new_columns;
create_screen(&screen1);
create_screen(&screen2);
//how many lines are vertical display area consists of
vdisplayArea = new_rows - 4;
hdisplayArea = new_columns - 2;
shiftH=0;
return 0;
}
int _animation(){
/* Timer for animations - Display time and clean cursor */
time_t mytime = time(NULL);
char *time_str = ctime(&mytime);
char temp[4];
temp[0] = '[';
temp[1] = ANIMATION[timer2.ticks];
temp[2] = ']';
temp[3] = '\0';
get_terminal_dimensions(&new_rows,&new_columns);
resetAnsi(0);
time_str[strlen(time_str) - 1] = '\0';
//display system time
update_str(new_columns - strlen(time_str) - 1, 0, time_str, MENU_PANEL,
MENU_FOREGROUND0);
update_str(new_columns - strlen(time_str) - 5, 0, temp, MENU_PANEL,
MENU_FOREGROUND0);
printf("\n");
//update only the screen bits that change
if(timer2.ticks > 6)
timer2.ticks = 0;
//return a signal if screen size changes
if (new_rows != old_rows || new_columns != old_columns)
return -1;
else
return 0;
}
================================================
FILE: src/global.h
================================================
/*
* Global variables are intented to be placed here
* Last modified: 9/7/2022
* @author: velorek
*
*/
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
#include "scbuf.h"
#include "tm.h"
#include "edbuf.h"
#include "listbox.h"
#define TIMER_SPEED 100 //animation
#define TIMER_SPEED2 30 //cursor
#define TIMER_SPEED3 100 //temporary messages
//#define ABOUT_SPEED 300 //about animation
#define END_LINE_CHAR 0x0A
#define FILL_CHAR 0x20
#define ENDSIGNAL -1
#define ESC_KEY '\e'
#define ROWS_FAILSAFE 25
#define COLUMNS_FAILSAFE 80
#define TRUE 1
#define FALSE 0
#define CURSOR_CHAR '|'
typedef int BOOL;
//USER-DEFINED MESSAGES
extern SCREENCELL *screen1;
extern SCREENCELL *screen2;
extern NTIMER cursor_timer1;
extern NTIMER timer2;
extern NTIMER timer3;
//extern NTIMER timer4;
extern size_t animation;
extern int centerX;
//extern LISTCHOICE listBox1;
extern SCROLLDATA scrollData;
extern VLINES *edBuf1; //Buffer vector of lines(512 chars)
extern VLINES tempLine;
//COLOR SCHEME
extern int EDITAREACOL;
extern int EDIT_FORECOLOR;
extern int STATUSBAR;
extern int STATUSMSG;
extern int MENU_PANEL;
extern int MENU2_PANEL;
extern int MENU_SELECTOR;
extern int MENU_FOREGROUND0;
extern int MENU2_FOREGROUND0;
extern int MENU_FOREGROUND1;
extern int EDITWINDOW_BACK;
extern int EDITWINDOW_FORE;
extern int SCROLLBAR_BACK;
extern int SCROLLBAR_FORE;
extern int SCROLLBAR_SEL;
extern int SCROLLBAR_ARR;
extern int WINDOW_TITLEB; // to be accessible from opfile.c
extern int WINDOW_TITLEF;
//GOODBYE MSG - ASCII ART
#define cedit_ascii_1 " _____ ______ _ _ _ \n"
#define cedit_ascii_2 " / ____| | ____| | (_) | \n"
#define cedit_ascii_3 "| | ______| |__ __| |_| |_ \n"
#define cedit_ascii_4 "| | |______| __| / _` | | __|\n"
#define cedit_ascii_5 "| |____ | |___| (_| | | |_ \n"
#define cedit_ascii_6 " \\_____| |______\\__,_|_|\\__|\n"
#define TAB_SPACES 8
//ABOUT - ASCII ART
#define ABOUT_ASC_0 "______________________________"
#define ABOUT_ASC_1 " _ __ "
#define ABOUT_ASC_2 " / _|__ _|.___ "
#define ABOUT_ASC_3 " \\_ |__(_]| | v0.1 "
#define ABOUT_ASC_4 "______________________________"
#define ABOUT_ASC_5 " Coded by V3l0rek "
#define ANIMATION "||//--\\\\"
#define HELP0 "C-EDIT \0"
#define HELP1 "======= \0"
#define HELP2 "C-EDIT is a terminal TUI curses text editor. \0"
#define HELP3 "It offers both vertical and horizontal scroll \0"
#define HELP4 "for file buffer navigation. It also features a \0"
#define HELP5 "variety of animations and has a built-in open file \0"
#define HELP6 "dialog to easily locate the files in directories. \0"
#define HELP7 "___________________________________________________\0"
#define HELP8 "[F1] or [ALT + H] -> Display help \0"
#define HELP9 "[F2] or [CTRL + L] -> Activate menu \0"
#define HELP10 "[Arrow Keys] -> Navigate file buffer \0"
#define HELP11 "[CTRL + A] -> Quick Load | CTRL + N -> New file \0"
#define HELP12 "[ALT + O] -> Open file | \0"
#define HELP13 "[ALT + S] -> Save file \0"
#define HELP14 "[ESC] or [CTRL + C] or [ALT+X] -> Exit program \0"
#define HELP15 "[S] Hide/Show table | CTRL or ALT may be used. \0"
#define HELP16 "___________________________________________________\0"
#define HELP17 "This program was coded in C & Vim from 2018-2024. \0"
#define HELP18 "Some of the techniques used can be found in my \0"
#define HELP19 "personal blog : oldstuff286.blogspot.com \0"
#define HELP20 "Peace! - by v3l0r3k \0"
#define HELPLINES 21
//USER-DEFINED MESSAGES
#define UNKNOWN "UNTITLED"
#define WINDOWMSG "DISPLAY IS TOO SMALL. PLEASE, RESIZE WINDOW"
#define STATUS_BAR_MSG1 " [C-Edit] | F2,CTRL+L: MENU | F1: HELP"
#define STATUS_BAR_MSG2 " [C-Edit] Press ESC to exit menu. "
#define STATUS_BAR_MSG3 " ENTER: SELECT | <- -> ARROW KEYS "
#define WLEAVE_MSG "\n Are you sure\n you want to quit?"
#define WSAVE_MSG ":\nFile saved successfully!"
#define WSAVELABEL_MSG "[-] File:"
#define WINFO_NOPEN "Error:\nThere isn't any file open!"
#define WINFO_SIZE "-File size: "
#define WINFO_SIZE2 "\n-No. of lines: "
#define WINFO_SIZE3 "\n-File name: "
#define WCHECKFILE2_MSG " File does not exist! \n\n A new buffer will be created. \n"
#define WCHECKFILE_MSG " This file isn't a|text file. Program may crash.|Open anyway?"
#define WINFONOTYET_MSG "Not implemented yet!"
#define WCHECKLINES_MSG " File longer than 3000 \n lines. You'll view those \n lines as read Mode! "
#define WMODIFIED_MSG "File has been modified|Save current buffer?"
#define WFILEEXISTS_MSG " File exists. \n Overwrite?"
#define WFILEINREADMODE_MSG " File is on read mode. \n"
#define START_CURSOR_X 1
#define START_CURSOR_Y 2
//MENU CONSTANTS
#define HOR_MENU -1
#define FILE_MENU 0
#define OPT_MENU 1
#define HELP_MENU 2
#define YESNO_MENU 3
#define OK_MENU 4
#define MAX_FILENAME 255
#define MAX_LINES 100000
#define MAXLINE 255
//DROP-DOWN MENUS
#define OPTION_1 0
#define OPTION_2 1
#define OPTION_3 2
#define OPTION_4 3
#define OPTION_5 4
#define OPTION_6 5
#define OPTION_NIL -1 //Reset option
#define CONFIRMATION 1
#define K_LEFTMENU -1 //Left arrow key pressed while in menu
#define K_RIGHTMENU -2 //Right arrow key pressed while in menu
#define DONT_UPDATE -5
//MENU CONSTANTS
#define HOR_MENU -1
#define FILE_MENU 0
#define OPT_MENU 1
#define HELP_MENU 2
#define YESNO_MENU 3
#define OK_MENU 4
#define MAXFILENAME 100
#define OK_MENU2 5
#define COLORS_MENU 6
//FILE CONSTANTS
#define FILE_MODIFIED 1
#define FILE_UNMODIFIED 0
#define FILE_READMODE 2
extern char aboutMSG[7][MAXLINE];
extern char help[HELPLINES][MAXLINE];
extern int new_rows, new_columns, old_rows, old_columns; // Terminal dimensions
extern int cursorX, cursorY; //position on screen X:[0, columns -2] Y:[0, rows-3]
extern int old_cursorX, old_cursorY;
extern long posBufX, posBufY; //position in the edit buffer X:[0,1022] Y:[0,13000]
extern long oldposBufX, oldposBufY; //position in the edit buffer X:[0,1022] Y:[0,13000]
extern long shiftH; //for horizontal scroll
extern int unwantedChars;
int _animation();
int initCEDIT();
//TEXT BUFFER POINTERS
extern VLINES *edBuf1; //Buffer vector of lines(1022 chars)
extern VLINES tempLine;
extern FILE *filePointer;
extern int vdisplayArea; //size in lines of the allowed displayed area // calculated when screen resizes
extern int hdisplayArea; //size in lines of the allowed displayed area // calculated when screen resizes
extern int hdisplayLimit; //horizontal scroll, last char position in line that allows scroll
extern int currentColumn; //horizontal scroll, pointer to current char position in line
extern long linesinFile; //vertical scroll
extern long vdisplayLimit; //vertical scroll, last line that allows scroll
extern long currentLine; //verticall scroll, pointer to current top line in scroll
extern int vscrollActive; //vertical scroll, vertical scroll is posible
extern int programStatus; //signal for overall program status
extern char fileName[MAXFILENAME];
extern char fullPath[MAXFILENAME];
extern int fileModified;
extern int deleteKeyPressed;
//extern int hscrollActive; //horizontal scroll, horizontal scroll is posible
#endif
================================================
FILE: src/keyb.c
================================================
/*
======================================================================
Module to control keyboard input.
@author : Velorek
@version : 1.0
LAST MODIFIED : 14/04/2019 Rename headers
======================================================================
*/
/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <stdio.h>
#include "rterm.h"
#include "keyb.h"
/*====================================================================*/
/* FUNCTIONS - CODE */
/*====================================================================*/
/*----------------------------------*/
/* Read ESC-key char with its trail */
/*----------------------------------*/
int read_keytrail(char chartrail[5]){
/*
New implementation: Trail of chars found in keyboard.c
If K_ESCAPE is captured read a trail up to 5 characters from the console.
This is to control the fact that some keys may change
according to the terminal and expand the editor's possibilities.
Eg: F2 can be either 27 79 81 or 27 91 91 82.
*/
char ch;
int i;
chartrail[0] = K_ESCAPE;
for(i = 1; i < 5; i++) {
if(kbhit(1) == 1) {
ch=readch();
chartrail[i] = ch;
} else {
chartrail[i] = 0;
}
}
resetch();
return 1;
}
/*----------------------------------*/
/* Read Accents and Special Chars */
/*----------------------------------*/
int read_accent(char *ch, char accentchar[2])
{
/*
Input Ref: ch, accentchar
@return : 1 - SET 1 | 2 - SET 2 | 0 - NO ACCENT CHAR
*/
int result;
result = 0;
//Accents and special chars
accentchar[0] = 0;
accentchar[1] = *ch;
if(*ch == SPECIAL_CHARS_SET1) {
accentchar[0] = SPECIAL_CHARS_SET1; //Accents and special chars SET1
accentchar[1] = readch();
result = 1;
resetch();
}
if(*ch == SPECIAL_CHARS_SET2) {
accentchar[0] = SPECIAL_CHARS_SET2; //Accents and special chars SET2
accentchar[1] = readch();
result = 2;
resetch();
}
return result;
}
================================================
FILE: src/keyb.h
================================================
/*
========================================================================
- HEADER -
Module to handle keyboard input in Linux and create
a further layer of abstraction.
@author : Velorek
@version : 1.0
Last modified: 14/04/2019 Rename Headers
========================================================================
*/
#ifndef _KEYB_H_
#define _KEYB_H_
/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <stdio.h>
#include "rterm.h"
/*====================================================================*/
/* KEYS - CONSTANTS */
/*====================================================================*/
#define K_ENTER 13
#define K_CAPS 91
#define K_BACKSPACE 127
#define K_TAB 9
#define K_ESCAPE 27
#define K_F1_TRAIL "\eOP\0\0"
#define K_F1_TRAIL2 "\e[[A\0"
#define K_F2_TRAIL "\eOQ\0\0"
#define K_F2_TRAIL2 "\e[[B\0"
#define K_F3_TRAIL "\eOR\0\0"
#define K_F3_TRAIL2 "\e[[C\0"
#define K_F4_TRAIL "\eOS\0\0"
#define K_F4_TRAIL2 "\e[[D\0"
#define K_UP_TRAIL "\e[A\0\0"
#define K_DOWN_TRAIL "\e[B\0\0"
#define K_RIGHT_TRAIL "\e[C\0\0"
#define K_LEFT_TRAIL "\e[D\0\0"
#define K_PAGEDOWN_TRAIL "\e[6~"
#define K_PAGEUP_TRAIL "\e[5~"
#define K_HOME_TRAIL "\e[H"
#define K_END_TRAIL "\e[F"
#define K_HOME_TRAIL2 "\e[1~"
#define K_END_TRAIL2 "\e[4~"
#define K_DELETE "\e[3~"
#define K_CTRL_A 0x01
#define K_CTRL_B 0x02
#define K_CTRL_C 0x03
#define K_CTRL_D 0x04
#define K_CTRL_E 0x05
#define K_CTRL_J 0x0A
#define K_CTRL_L 0x0C
#define K_CTRL_H 0x08
#define K_CTRL_M 0x0D
#define K_CTRL_N 0x0E
#define K_CTRL_O 0x0F
#define K_CTRL_S 0x14
#define K_ALT_X "\ex"
#define K_ALT_L "\el"
#define K_ALT_S "\es"
#define K_ALT_W "\ew"
#define K_ALT_H "\eh"
#define K_ALT_N "\en"
#define K_ALT_O "\eo"
#define K_ALT_W "\ew"
#define K_ALT_A "\ea"
#define K_ALT_I "\ei"
#define K_ALT_C "\ec"
#define K_ALT_F "\ef"
#define K_ALT_P "\ep"
#define K_ALT_S "\es"
#define K_ALT_V "\ev"
#define K_ALT_D "\ed"
#define ESC3X "\e\e\e"
#define ESC2X "\e\e"
#define SPECIAL_CHARS_SET1 -61
#define SPECIAL_CHARS_SET2 -62
/*====================================================================*/
/* FUNCTION PROTOTYPES */
/*====================================================================*/
int read_keytrail(char chartrail[5]);
int read_accent(char *ch, char accentchar[2]);
#endif
================================================
FILE: src/listbox.c
================================================
/*====================================================================*/
/* +ListBox with double linked list and selection menu in C with
* horizontal scroll.
+Scroll function added.
Last modified : 01/04/2024 + Horizontal option implementation started
+ ESC_KEY added
+ X,Y option added for different options
- Pending: horizontal scroll
Coded by Velorek. Raw output
Target OS: Linux. */
/*====================================================================*/
/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rterm.h"
#include "listbox.h"
#include "keyb.h"
#include "tm.h"
#include "global.h"
/*====================================================================*/
/* CODE */
/*====================================================================*/
int double_escape=0;
int selectorLimit = 15; //by default selectoLimit is 15 when spaces are added
int newrows=0, newcolumns=0;
int listrows=0, listcolumns=0;
char KTRAIL0[5]={0};
char KTRAIL1[5]={0};
/* --------------------- */
/* Dynamic List routines */
/* --------------------- */
// create new list element of type LISTCHOICE from the supplied text string
LISTCHOICE *newitem(char *text,unsigned setX, unsigned setY,unsigned foreColor, unsigned backColor) {
LISTCHOICE *newp;
newp = (LISTCHOICE *) malloc(sizeof(LISTCHOICE));
newp->item = (char *)malloc(strlen(text) + 1);
strcpy(newp->item, text);
newp->next = NULL;
newp->back = NULL;
newp->setX = setX;
newp->setY = setY;
newp->foreColor = foreColor;
newp->backColor = backColor;
return newp;
}
// deleleteList: remove list from memory
void removeList(LISTCHOICE ** head) {
LISTCHOICE *aux = *head;
LISTCHOICE *next = NULL;
while(aux != NULL) {
next = aux->next;
free(aux->item);
free(aux); //remove item
aux = next;
}
*head = NULL;
}
/* addatend: add new LISTCHOICE to the end of a list */
/* usage example: listBox1 = (addatend(listBox1, newitem("Item")); */
LISTCHOICE *addatend(LISTCHOICE * head, LISTCHOICE * newp) {
LISTCHOICE *p2;
if(head == NULL) {
newp->index = 0;
newp->back = NULL;
return newp;
}
// now find the end of list
for(p2 = head; p2->next != NULL; p2 = p2->next) ;
p2->next = newp;
newp->back = p2;
newp->index = newp->back->index + 1;
return head;
}
/* ---------------- */
/* Listbox routines */
/* ---------------- */
void gotoIndex(LISTCHOICE ** aux, SCROLLDATA * scrollData,
unsigned indexAt)
//Go to a specific location on the list.
{
LISTCHOICE *aux2;
unsigned counter = 0;
*aux = listBox1;
aux2 = *aux;
while(counter != indexAt) {
aux2 = aux2->next;
counter++;
}
//Highlight current item
displayItem(aux2, scrollData, SELECT_ITEM);
//Update pointer
*aux = aux2;
}
void printlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned displayLimit) {
/*
Displays the items contained in the list with the properties specified
in scrollData.
*/
LISTCHOICE *aux;
unsigned wherey, counter = 0;
aux = head;
gotoIndex(&aux, scrollData, 0);
/* Save values */
//wherex = scrollData->wherex;
wherey = scrollData->wherey;
do {
displayItem(aux, scrollData, UNSELECT_ITEM);
aux = aux->next;
counter++;
scrollData->selector++; // wherey++
} while(counter != displayLimit);
scrollData->selector = wherey; //restore value
}
void loadlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned indexAt) {
/*
Displays the items contained in the list with the properties specified
in scrollData.
*/
LISTCHOICE *aux;
unsigned wherey, counter = 0;
aux = head;
gotoIndex(&aux, scrollData, indexAt);
/* Save values */
//wherex = scrollData->wherex;
wherey = scrollData->wherey;
do {
displayItem(aux, scrollData, UNSELECT_ITEM);
aux = aux->next;
counter++;
scrollData->selector++; // wherey++
} while(counter != scrollData->displayLimit);
scrollData->selector = wherey; //restore value
}
int query_length(LISTCHOICE ** head) {
//Return no. items in a list.
{
LISTCHOICE *aux;
unsigned itemCount = 0;
aux = *head;
while(aux->next != NULL) {
aux = aux->next;
itemCount++;
}
return itemCount;
}
}
void displayItem(LISTCHOICE * aux, SCROLLDATA * scrollData, int select)
//Select or unselect item animation
{
size_t i=0;
wchar_t newchar=0;
resetAnsi(0);
switch (select) {
case SELECT_ITEM:
if ((aux->setX == -1) || (aux->setY== -1 ))
gotoxy(scrollData->wherex, scrollData->selector);
else
gotoxy(aux-> setX, aux -> setY);
if ((aux->foreColor == -1) || (aux->backColor== -1 ))
outputcolor(scrollData->foreColor1, scrollData->backColor1);
else
outputcolor(aux->foreColor, aux->backColor);
//printf("%s\n", aux->item);
for (i=0;i<scrollData->selectorLimit;i++) {
if(i < strlen(aux->item)){
newchar=aux->item[i];
printf("%lc", newchar);
}
else
if (scrollData->addSpaces != 0) printf("%c", 0x20);
}
printf("\n");
break;
case UNSELECT_ITEM:
if ((aux->setX == -1) || (aux->setY== -1 ))
gotoxy(scrollData->wherex, scrollData->selector);
else
gotoxy(aux -> setX, aux -> setY);
outputcolor(scrollData->foreColor0, scrollData->backColor0);
//printf("%s\n", aux->item);
for (i=0;i<scrollData->selectorLimit;i++) {
if(i < strlen(aux->item)){
newchar = aux->item[i];
printf("%lc", newchar);
}
else
if (scrollData->addSpaces != 0) printf("%c", 0x20);
}
printf("\n");
break;
}
}
int move_selector(LISTCHOICE ** selector, SCROLLDATA * scrollData) {
/*
Creates animation by moving a selector highlighting next item and
unselecting previous item
*/
LISTCHOICE *aux;
unsigned scrollControl = 0, continueScroll = 0, circular =
CIRCULAR_INACTIVE;
//Auxiliary pointer points to selector.
aux = *selector;
//Circular list animation when not scrolling.
if(aux->index == scrollData->listLength - 1
&& scrollData->scrollActive == SCROLL_INACTIVE
&& scrollData->scrollDirection == DOWN_SCROLL) {
//After last item go back to the top.
displayItem(aux, scrollData, UNSELECT_ITEM);
scrollData->selector = scrollData->wherey;
gotoIndex(&aux, scrollData, 0);
*selector = aux;
circular = CIRCULAR_ACTIVE;
}
if(aux->index == 0 && scrollData->scrollActive == SCROLL_INACTIVE
&& scrollData->scrollDirection == UP_SCROLL) {
//Before first item go back to the bottom.
displayItem(aux, scrollData, UNSELECT_ITEM);
scrollData->selector = scrollData->wherey + scrollData->listLength - 1;
gotoIndex(&aux, scrollData, scrollData->listLength - 1);
*selector = aux;
circular = CIRCULAR_ACTIVE;
}
//Check if we do the circular list animation.
//If active, we skip the code one time.
if(circular == CIRCULAR_INACTIVE) {
//Check if we are within boundaries.
if((aux->next != NULL && scrollData->scrollDirection == DOWN_SCROLL)
|| (aux->back != NULL && scrollData->scrollDirection == UP_SCROLL)) {
//Unselect previous item
displayItem(aux, scrollData, UNSELECT_ITEM);
//Check whether we move UP or Down
switch (scrollData->scrollDirection) {
case UP_SCROLL:
//Calculate new top index if scroll is active
//otherwise it defaults to 0 (top)
if(scrollData->scrollActive == SCROLL_ACTIVE)
scrollControl = scrollData->currentListIndex;
else
scrollControl = 0;
//Move selector
if(aux->back->index >= scrollControl) {
scrollData->selector--; //whereY--
aux = aux->back; //Go to previous item
} else {
if(scrollData->scrollActive == SCROLL_ACTIVE)
continueScroll = 1;
else
continueScroll = 0;
}
break;
case DOWN_SCROLL:
//Calculate bottom index limit if scroll is ACTIVE
//Otherwise it defaults to scrollData->ListLength-1
if(scrollData->scrollActive == SCROLL_ACTIVE)
scrollControl =
scrollData->currentListIndex + (scrollData->displayLimit -
1);
else
scrollControl = scrollData->listLength - 1;
//Move selector
if(aux->next->index <= scrollControl) {
aux = aux->next; //Go to next item
scrollData->selector++; //whereY++;
} else {
if(scrollData->scrollActive == SCROLL_ACTIVE)
continueScroll = 1;
else
continueScroll = 0;
}
break;
}
/* //Metrics
gotoxy(6, 5);
printf("Length:%d|Index:%d|Memory addr:%p",
scrollData->listLength, aux->index, aux);
gotoxy(6, 6);
printf("Scroll Limit: %d|IsScActive?:%d|ContinueScroll: %d",
scrollControl, scrollData->scrollActive, continueScroll);
*/
//Highlight new item
displayItem(aux, scrollData, SELECT_ITEM);
// update_screen(screen1);
//Update selector pointer
*selector = aux;
}
}
//update_screen(screen1);
circular = CIRCULAR_INACTIVE;
return continueScroll;
}
char selectorMenu(LISTCHOICE * aux, SCROLLDATA * scrollData) {
char ch=0;
int keypressed=0;
int control = 0;
int continueScroll=0;
unsigned counter = 0;
char chartrail[5];
//Go to and select expected item at the beginning
gotoIndex(&aux, scrollData, scrollData->currentListIndex);
if(scrollData->scrollDirection == DOWN_SCROLL
&& scrollData->currentListIndex != 0) {
//If we are going down we'll select the last item
//to create a better scrolling transition (animation)
for(counter = 0; counter < scrollData->displayLimit; counter++) {
scrollData->scrollDirection = DOWN_SCROLL;
move_selector(&aux, scrollData);
}
} else {
//Do nothing if we are going up. Selector is always at the top item.
}
//It break the loop everytime the boundaries are reached.
//to reload a new list to show the scroll animation.
while(control != CONTINUE_SCROLL) {
if (timerC(&timer2) == TRUE){
//Animation in global.c
if (_animation() == -1) {scrollData->itemIndex = -1;double_escape = 1; break;}
}
//check listbox orientation and change keys
if (scrollData->orientation == VERTICAL || scrollData->orientation == VERTICALWITHBREAK){
strcpy(KTRAIL0, K_UP_TRAIL);
strcpy(KTRAIL1, K_DOWN_TRAIL);
}
else
{
strcpy(KTRAIL1, K_RIGHT_TRAIL);
strcpy(KTRAIL0, K_LEFT_TRAIL);
}
keypressed = kbhit(1);
if (keypressed == 1)
ch = readch();
else
ch = 0;
//if enter key pressed - break loop
if(ch == K_ENTER)
control = CONTINUE_SCROLL; //Break the loop
if (ch == 'x' || ch == K_BACKSPACE || ch == K_CTRL_C){
double_escape=1;
scrollData->itemIndex = -1;
break;
}
if (ch == K_ESCAPE) // escape key
{
strcpy(chartrail, "\0");
read_keytrail(chartrail);
//If mode VERTICALWITHBREAK is selected; selector menu is interrupted when left/right arrow keys are pressed
if ((scrollData->orientation == VERTICALWITHBREAK) && (strcmp(chartrail,K_LEFT_TRAIL))==0)
return K_LEFTMENU;
if ((scrollData->orientation == VERTICALWITHBREAK) && (strcmp(chartrail,K_RIGHT_TRAIL))==0)
return K_RIGHTMENU;
if (chartrail[0] == K_ESCAPE && chartrail[1] == 0) {
double_escape = 1;
scrollData->itemIndex = -1;
break;
}
if (strcmp(chartrail, K_ALT_X) == 0) {
break;
}
if (strcmp(chartrail, KTRAIL0) == 0) {
// escape key + A => arrow key up
//Move selector up
scrollData->scrollDirection = UP_SCROLL;
continueScroll =
move_selector(&aux, scrollData);
//Break the loop if we are scrolling
if (scrollData->scrollActive == SCROLL_ACTIVE
&& continueScroll == 1) {
control = CONTINUE_SCROLL;
//Update data
scrollData->currentListIndex =
scrollData->currentListIndex - 1;
scrollData->selector =
scrollData->wherey;
scrollData->item = aux->item;
scrollData->itemIndex = aux->index;
//Return value
ch = control;
}
}
// escape key + B => arrow key down
if (strcmp(chartrail, KTRAIL1) == 0) {
//Move selector down
scrollData->scrollDirection = DOWN_SCROLL;
continueScroll =
move_selector(&aux, scrollData);
//Break the loop if we are scrolling
if (scrollData->scrollActive == SCROLL_ACTIVE
&& continueScroll == 1) {
control = CONTINUE_SCROLL;
//Update data
scrollData->currentListIndex =
scrollData->currentListIndex + 1;
scrollData->selector =
scrollData->wherey;
scrollData->item = aux->item;
scrollData->itemIndex = aux->index;
scrollData->scrollDirection =
DOWN_SCROLL;
}
//Return value
ch = control;
}
}
}
if (ch == K_ENTER || ch == K_ENTER2) // enter key
{
//Pass data of last item selected
scrollData->item = aux->item;
scrollData->itemIndex = aux->index;
}
return ch;
}
//method to change how wide the selector is
void setselectorLimit(int num){
selectorLimit = num;
}
void resetScrollData(SCROLLDATA *scrollData)
{
scrollData->scrollActive = 0; //To know whether scroll is active or not.
scrollData->scrollLimit = 0; //Last index for scroll.
scrollData->listLength = 0; //Total no. of items in the list
scrollData->currentListIndex = 0; //Pointer to new sublist of items when scrolling.
scrollData->displayLimit = 0; //No. of elements to be displayed.
scrollData->selectorLimit = selectorLimit; //No. of chars per item display
scrollData->scrollDirection = 0; //To keep track of scrolling Direction.
scrollData->selector = 0; //Y++
scrollData->wherex = 0;
scrollData->wherey = 0;
scrollData->backColor0 = 0; //0 unselected; 1 selected
scrollData->foreColor0 = 0;
scrollData->backColor1 = 0;
scrollData->foreColor1 = 0;
scrollData->itemIndex = 0;
scrollData->addSpaces = 0;
scrollData->orientation = VERTICAL;
}
char listBox(LISTCHOICE * head,
unsigned whereX, unsigned whereY,
SCROLLDATA * scrollData, unsigned bColor0,
unsigned fColor0, unsigned bColor1, unsigned fColor1,
unsigned displayLimit,unsigned listorientation, unsigned addSpaces, unsigned locked) {
unsigned list_length = 0;
//unsigned currentIndex = 0;
int scrollLimit = 0;
unsigned currentListIndex = 0;
char ch=0;
LISTCHOICE *aux=NULL;
//Init values
double_escape=0;
resetScrollData(scrollData);
scrollData->orientation = listorientation;
// Query size of the list
list_length = query_length(&head) + 1;
//Save calculations for SCROLL and store DATA
scrollData->displayLimit = displayLimit;
scrollLimit = list_length - scrollData->displayLimit; //Careful with negative integers
if(scrollLimit < 0 || displayLimit > list_length)
scrollData->displayLimit = list_length; //Failsafe for overboard values
scrollData->scrollLimit = scrollLimit;
scrollData->listLength = list_length;
scrollData->wherex = whereX;
scrollData->wherey = whereY;
scrollData->selector = whereY;
scrollData->backColor0 = bColor0;
scrollData->backColor1 = bColor1;
scrollData->foreColor0 = fColor0;
scrollData->foreColor1 = fColor1;
scrollData->addSpaces = addSpaces;
get_terminal_dimensions(&listrows,&listcolumns);
//Check whether we have to activate scroll or not
//and if we are within bounds. [1,list_length)
ch=0;
aux = head;
printlist(aux, scrollData, scrollData->displayLimit);
if (locked == LOCKED) {
if(list_length > scrollData->displayLimit && scrollLimit > 0
&& displayLimit > 0) {
//Scroll is possible
scrollData->scrollActive = SCROLL_ACTIVE;
currentListIndex = 0; //We listBox1 the scroll at the top index.
scrollData->currentListIndex = currentListIndex;
//Scroll loop animation. Finish with ENTER.
loadlist(aux, scrollData, currentListIndex);
do {
currentListIndex = scrollData->currentListIndex;
loadlist(aux, scrollData, currentListIndex);
gotoIndex(&aux, scrollData, currentListIndex);
/* gotoxy(6, 4);
printf("Current List Index: %d:%d\n", scrollData->currentListIndex,
aux->index); */
ch = selectorMenu(aux, scrollData);
if (double_escape == 1) {
scrollData->itemIndex = -1;
locked = FALSE;
ch= K_ESCAPE;
break;
}
if (_animation() == -1) {
scrollData->itemIndex = -1;
double_escape = 1;
ch = K_ESCAPE;
locked = FALSE;
break;
}
} while(ch != K_ENTER);
} else {
//Scroll is not possible.
//Display all the elements and create selector
//
scrollData->scrollActive = SCROLL_INACTIVE;
scrollData->currentListIndex = 0;
scrollData->displayLimit = list_length; //Default to list_length
loadlist(head, scrollData, 0);
ch = selectorMenu(head, scrollData);
if (double_escape == 1) {
scrollData->itemIndex = -1;
locked = FALSE;
ch= K_ESCAPE;
//break;
}
}
}
return ch;
}
================================================
FILE: src/listbox.h
================================================
/*
========================================================================
- HEADER -
Module to implement a listBox integrated with LYNX.
@author : Velorek
@version : 1.0
Last modified: 26/12/2022
========================================================================
*/
#ifndef _LISTBOX_H_
#define _LISTBOX_H_
/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <stdio.h>
#include "scbuf.h"
/*====================================================================*/
/* CONSTANTS */
/*====================================================================*/
//Scroll Control values.
#define SCROLL_ACTIVE 1
#define SCROLL_INACTIVE 0
#define CONTINUE_SCROLL -1
#define DOWN_SCROLL 1
#define UP_SCROLL 0
#define SELECT_ITEM 1
#define UNSELECT_ITEM 0
#define CIRCULAR_ACTIVE 1
#define CIRCULAR_INACTIVE 0
#define LOCKED 1
#define NOT_LOCKED 0
#define VERTICAL 0
#define HORIZONTAL 1
#define VERTICALWITHBREAK 2
/*====================================================================*/
/* TYPEDEF STRUCTS DEFINITIONS */
/*====================================================================*/
typedef struct _listchoice {
unsigned index; // Item number
char *item; // Item string
int setX; //X,Y position
int setY; //-1 to ignore
int foreColor; //-1 to ignore
int backColor; //-1 to ignore
struct _listchoice *next; // Pointer to next item
struct _listchoice *back; // Pointer to previous item
} LISTCHOICE;
typedef struct _scrolldata {
unsigned scrollActive; //To know whether scroll is active or not.
unsigned scrollLimit; //Last index for scroll.
unsigned listLength; //Total no. of items in the list
unsigned currentListIndex; //Pointer to new sublist of items when scrolling.
unsigned displayLimit; //No. of elements to be displayed.
unsigned selectorLimit; //how many items of string item can be displayed
unsigned scrollDirection; //To keep track of scrolling Direction.
unsigned wherex;
unsigned wherey;
unsigned selector; //Y++
unsigned backColor0; //0 unselected; 1 selected
unsigned foreColor0;
unsigned backColor1;
unsigned foreColor1;
unsigned addSpaces; //whether to add spaces or not
unsigned orientation;
unsigned displayMetrics; //to show metrics on screen/reuse code for text viewing
char *item;
int itemIndex; //-1 means ESC was pressed
LISTCHOICE *head; //store head of the list
} SCROLLDATA;
/*====================================================================*/
/* GLOBAL VARIABLES */
/*====================================================================*/
extern LISTCHOICE *listBox1; //Head pointer.
/*====================================================================*/
/* PROTOTYPES OF FUNCTIONS */
/*====================================================================*/
//DYNAMIC LINKED LIST FUNCTIONS
void removeList(LISTCHOICE ** head);
LISTCHOICE *addatend(LISTCHOICE * head, LISTCHOICE * newp);
LISTCHOICE *newitem(char *text,unsigned setX, unsigned setY,unsigned foreColor, unsigned backColor);
//LISTBOX FUNCTIONS
//void addItems(LISTCHOICE ** listBox1);
char listBox(LISTCHOICE * selector, unsigned whereX, unsigned whereY,
SCROLLDATA * scrollData, unsigned bColor0,
unsigned fColor0, unsigned bColor1, unsigned fColor1,
unsigned displayLimit,unsigned listorientation, unsigned addSpaces, unsigned locked);
void loadlist(LISTCHOICE * head, SCROLLDATA * scrollData,
unsigned indexAt);
void printlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned displayLimit);
void gotoIndex(LISTCHOICE ** aux, SCROLLDATA * scrollData,
unsigned indexAt);
int query_length(LISTCHOICE ** head);
int move_selector(LISTCHOICE ** head, SCROLLDATA * scrollData);
char selectorMenu(LISTCHOICE * aux, SCROLLDATA * scrollData);
void displayItem(LISTCHOICE * aux, SCROLLDATA * scrollData, int select);
void resetScrollData(SCROLLDATA *scrollData);
void setselectorLimit(int num);
/*====================================================================*/
/* FUNCTION PROTOTYPES */
/*====================================================================*/
#endif
================================================
FILE: src/main.c
================================================
/* C-edit project
* Last updated - 29/8/2024
* New drop-down menu implementation
* Added more modularisation: editor.c menu.c
* Scrollbars added
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "listbox.h"
#include "scbuf.h"
#include "rterm.h"
#include "tm.h"
#include "global.h"
#include "keyb.h"
#include "edbuf.h"
#include "ui.h"
#include "menu.h"
#include "editor.h"
#include "opfile.h"
#include "fileb.h"
//Prototypes
void draw_screen();
void cursor_tick();
int special_keys();
int control_keys(char ch);
void _resizeScreen();
wchar_t currentChar = 0;
char tempMessage[150];
int displayMessage(char *temporaryMessage, int x, int y, int fColor, int bColor, int timeDuration);
void update_indicators();
int oldPositionY = 4;
int oldPositionX = 2;
void draw_screen(){
//BASE SCREEN IS STORED IN SCREEN 2
int i=0;
if (screen1 != NULL) deleteList(&screen1);
//if (screen2 != NULL) deleteList(&screen2);
//Init 2 : Create 2 Screens for a double buffer approach
old_rows=new_rows;
old_columns=new_columns;
create_screen(&screen1);
create_screen(&screen2);
//SCREEN 2
screen_color(screen1, EDITAREACOL, EDIT_FORECOLOR, FILL_CHAR);
//Failsafe just in case it can't find the terminal dimensions
if(old_rows == 0)
old_rows = ROWS_FAILSAFE;
if(old_columns == 0)
old_columns = COLUMNS_FAILSAFE;
//Draw upper and lower bars
for(i = 0; i < old_columns; i++) {
write_ch(screen1, i, 1, FILL_CHAR, MENU_PANEL, MENU_PANEL,0);
}
for(i = 0; i < old_columns; i++) {
write_ch(screen1, i, old_rows, FILL_CHAR, STATUSBAR, STATUSMSG,1);
}
// Text messages
write_str(screen1, 0, 1, "File Options Help", MENU_PANEL, MENU_FOREGROUND0,0);
write_str(screen1, 0, 1, "F", MENU_PANEL, F_RED,0);
write_str(screen1, 7, 1, "p", MENU_PANEL, F_RED,0);
write_str(screen1, 15, 1, "H", MENU_PANEL, F_RED,0);
write_str(screen1, 0, old_rows, STATUS_BAR_MSG1, STATUSBAR, STATUSMSG,0);
/* Frames */
//window appearance and scroll bar
for(i = 2; i < old_rows; i++) {
write_ch(screen1,old_columns-1, i, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,0); //Scroll bar
write_ch(screen1,0, i, VER_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //upper vertical line box-like char
}
for(i = 0; i < old_columns; i++) {
write_ch(screen1,i, 2, HOR_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //horizontal line box-like char
write_ch(screen1,i, old_rows - 1, ' ', EDITWINDOW_BACK, EDITWINDOW_FORE,0);
}
write_ch(screen1,0, 2, UPPER_LEFT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //upper-left box-like char
//horizontal scroll bar
for(i = 0; i < old_columns; i++) {
write_ch(screen1,i, old_rows - 1, FILL_CHAR, SCROLLBAR_BACK, SCROLLBAR_FORE,0);
}
//Window-appearance
write_ch(screen1,old_columns-1, 2, UPPER_RIGHT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0); //right window corner
write_ch(screen1,old_columns-1, old_rows - 1, LOWER_RIGHT_CORNER, EDITWINDOW_BACK,
EDITWINDOW_FORE,0);
write_ch(screen1, 0, old_rows - 1, LOWER_LEFT_CORNER, EDITWINDOW_BACK,
EDITWINDOW_FORE,0);
//Scroll symbols
write_ch(screen1,old_columns-1, 3, '^', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
write_ch(screen1, old_columns-1, old_rows - 2, 'v', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
write_ch(screen1, old_columns-1, 4, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);
write_ch(screen1, 2, old_rows - 1, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);
write_ch(screen1, 1, old_rows - 1, '<', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
write_ch(screen1, old_columns - 2, old_rows - 1, '>', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
if (strlen(fileName) == 0) strcpy(fileName, "UNTITLED");
write_str(screen1,(new_columns / 2) - (strlen(fileName) / 2), 2, fileName,
MENU_PANEL, MENU_FOREGROUND0,0);
dump_screen(screen1);
//Save screen for later
//copy_screen(screen2,screen1);
}
void cursor_tick(void){
//CURSOR ANIMATION
char drawChar=FILL_CHAR;
char drawChar0=FILL_CHAR;
int attrib = 0;
wchar_t code_point;
//GET CHAR BEING POINTED AT FROM EDIT BUFFER
if (edBuf1 != NULL)_dumpLine(edBuf1, posBufY, &tempLine);
drawChar = tempLine.linea[posBufX].ch;
drawChar0 = tempLine.linea[posBufX].specialChar;
attrib = tempLine.linea[posBufX].attrib;
//CHECK FOR SPECIAL CHARACTERS AND CONVERT THEM TO UNICODE TO PRINT
//IF CURSOR IS ON A CHAR HIGHLIGHT IT IN YELLOW
if (drawChar0 != 0 && drawChar != '\0') code_point = ((drawChar0 & 0x1F) << 6) | (drawChar & 0x3F);
else {
if (drawChar == 0 || drawChar == END_LINE_CHAR) drawChar = FILL_CHAR;
code_point = drawChar;
}
if (cursor_timer1.ticks % 2 == 0) update_ch(cursorX, cursorY, CURSOR_CHAR, B_BLUE, F_WHITE);
else update_ch(cursorX, cursorY, code_point, EDITAREACOL, FH_YELLOW);
//REST ANSI VALUES TO HAVE HIGH INTENSITY COLORS
resetAnsi(0);
//CLEAR LAST POSITION OF CURSOR WITH FILL_CHAR OR GO BACK TO PREVIOUS CHAR
if ((old_cursorX != cursorX) || (old_cursorY != cursorY)){
//old?
if (edBuf1 != NULL)_dumpLine(edBuf1, oldposBufY, &tempLine);
drawChar = tempLine.linea[oldposBufX].ch;
drawChar0 = tempLine.linea[oldposBufX].specialChar;
attrib = tempLine.linea[oldposBufX].attrib;
//always clear cursor cell (avoids false misprints)
update_ch(old_cursorX, old_cursorY, ' ', EDITAREACOL, EDIT_FORECOLOR);
//then try to update to its previous state
if (drawChar0 != 0 && drawChar != '\0') code_point = ((drawChar0 & 0x1F) << 6) | (drawChar & 0x3F);
else {
if (drawChar == 0 || drawChar == END_LINE_CHAR) drawChar = FILL_CHAR;
code_point = drawChar;
}
update_ch(old_cursorX, old_cursorY, code_point, EDITAREACOL, attrib);
}
if (old_cursorY != cursorY) {
//Point to line in buffer when Y position changes
if (edBuf1 != NULL) _dumpLine(edBuf1, posBufY, &tempLine);
}
//printf("\n");
//write_num(screen1, 10,10, cursorX, B_GREEN, F_WHITE,1);
//write_num(screen1, 10,11, cursorY, B_RED, F_WHITE,1);
//write_num(screen1, 10,12, old_cursorX, B_GREEN, F_WHITE,1);
//write_num(screen1, 10,12, old_cursorY, B_GREEN, F_WHITE,1);
//write_num(screen1, 10,14, posBufX, B_RED, F_WHITE,1);
//write_num(screen1, 10,15, posBufY, B_RED, F_WHITE,1);
//write_num(screen1, 10,16, findEndline(tempLine), BH_BLUE, F_WHITE,1);
//write_num(screen1, 10,17, _length(&edBuf1), B_RED, F_WHITE,1);
//for (int i=0; i<findEndline(tempLine);i++) write_ch(screen1, 10+i,16, code_point, B_RED, F_WHITE,1);
//dump_screen(screen1);
//Buffer pointer position
/*
update_str(new_columns - 24, new_rows, "| L: C: ", STATUSBAR, STATUSMSG);
write_num(screen1, new_columns - 10, new_rows, posBufX, STATUSBAR, STATUSMSG,1);
write_num(screen1, new_columns - 20, new_rows, posBufY+1, STATUSBAR, STATUSMSG,1);
update_str(new_columns - 39, new_rows, "| LINES: ", STATUSBAR, STATUSMSG);
write_num(screen1, new_columns - 31, new_rows, _length(&edBuf1), STATUSBAR, STATUSMSG,1);
*/
}
void update_indicators() {
/*
Update cursor position display on screen.
Values are float to save decimal points.
- Formulas:
scrollRatio = totalFileLines / displayLength;
currentPosition = bufferY / scrollRatio;
percentage = (currentPosition * 100) / displayLength;
To adjust to the bar dimensions:
scrollBar = ((displayLength-3) * percentage) / 100;
*/
char info[255];
int pep=0;
float scrollIndicator=1.0, positionY=0.0;
float hscrollIndicator=1.0, positionX=0.0;
float percentage=0.0, scrollBar=0.0, scrollRatio =0.0;
float hpercentage=0.0, hscrollBar=0.0, hscrollRatio =0.0;
pep = 100;
//Scroll indicator and percentage display
if (_length(&edBuf1) > vdisplayArea ) {
write_ch(screen1,new_columns-1, oldPositionY, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,1);
positionY = posBufY;
scrollRatio = _length(&edBuf1) / vdisplayArea;
scrollIndicator = positionY / scrollRatio;
percentage = (scrollIndicator * 100) / vdisplayArea;
scrollBar = ((vdisplayArea-3) * percentage)/100;
if (positionY == 1) percentage = 0;
if (percentage > 100) percentage = 100;
if (scrollBar+2>=new_rows-5) scrollBar = new_rows - 7;
write_ch(screen1,new_columns-1, 4+scrollBar, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,1);
oldPositionY = 4+scrollBar;
pep = percentage;
}
if (posBufX>0){
positionX = posBufX;
write_ch(screen1, oldPositionX,new_rows-1, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,1);
oldPositionX = 2+hscrollBar;
hscrollRatio = MAX_LINE_SIZE / hdisplayArea;
hscrollIndicator = positionX / hscrollRatio;
hpercentage = (hscrollIndicator * 100) / hdisplayArea;
hscrollBar = (((hdisplayArea) * hpercentage)/100);
if (hscrollBar+2>=new_columns-3) hscrollBar = new_columns-5;
write_ch(screen1, 2+hscrollBar,new_rows-1, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,1);
oldPositionX = 2+hscrollBar;
}
strcpy(info, "\0");
sprintf(info, "|LINES: %d| L: %ld C: %ld [%d%c] ", _length(&edBuf1), posBufY, posBufX,pep,'%');
update_str(new_columns - 40, new_rows, info, STATUSBAR, STATUSMSG);
}
int main(int argc, char *argv[]) {
char ch=0;
char old_ch=0;
int esc_key = 0;
int keypressed = 0;
//Init Terminal
init_term();
initCEDIT();
draw_screen();
resetch();
strcpy(fileName, "\0");
//tempLine.linea[0].ch = END_LINE_CHAR;
//tempLine.linea[posBufX].ch = END_LINE_CHAR;
//tempLine.linea[posBufX].specialChar = 0;
//tempLine.linea[posBufX].attrib = EDIT_FORECOLOR;
if(argc > 1) {
//Does the file exist? Open or create?
strcpy(fileName, argv[1]);
filetoBuffer(fileName);
flush_editarea(0);
buffertoScreen(0);
dump_screen(screen1);
fileModified= FILE_UNMODIFIED;
}
do{
//end flag from any part of the program
if (programStatus == ENDSIGNAL) break;
//Time animation & resize window
if (timerC(&timer3) == TRUE){
displayMessage(tempMessage, (new_columns/2)-strlen(tempMessage)/2, 1, FH_WHITE, B_RED, 5);
}
if (timerC(&timer2) == TRUE){
_animation();
//Refresh screen size buffers if terminal dimension changes
if (new_rows != old_rows || new_columns != old_columns)
{
_resizeScreen();
}
}
//Cursor Animation
if (timerC(&cursor_timer1) == TRUE){
//Animation
cursor_tick();
//if (keypressed == FALSE) { esc_key = 0;}
}
//PROCESS INPUT
keypressed = kbhit(1);
if (keypressed == TRUE) {
keypressed = FALSE;
//try to catch and avoid printing unwanted chars with cursor keys
old_ch = ch;
ch=readch();
if (old_ch==ESC_KEY) {unwantedChars = 1; esc_key = 1;}
if (ch==ESC_KEY) {unwantedChars = 1; esc_key = 1;}
if (unwantedChars>0) esc_key = 1;
//Keys with a escape sequenece
if (ch == ESC_KEY) {//buffertoScreen(0, 0,FALSE);
esc_key = special_keys();
cursor_tick();
ch = 0;}
else {
//Capture control keys
if ((ch>0 && ch< 0x0F) && (ch!=K_ENTER && ch != K_TAB)){buffertoScreen(FALSE); esc_key= control_keys(ch); ch=0;}
else
//Process raw edit input from keyboard in editor.c
{
//try to avoid printing unwanted chars with cursor keys
if (ch != 0 && esc_key==0 && unwantedChars == 0&& posBufX <MAX_LINE_SIZE) editor_section(ch);
}
}
update_indicators();
}else{
//if not keypressed reset values for unwanted characters
esc_key=0; unwantedChars = 0;
}//Check for ESC-related keys
} while (esc_key != ENDSIGNAL);
//restore terminal
credits();
return 0;
}
//CONTROL KEYS
int control_keys(char ch){
char returnMenuChar=0;
int menuCounter = 0;
int returnValue=0;
char countCh=0;
char tempfileName[MAXFILENAME];
if(ch == K_CTRL_L) {
//Akin to F2
handlemenus(&returnMenuChar, &menuCounter,TRUE);
}
if(ch == K_CTRL_C) {
returnValue = ENDSIGNAL;
}
if (ch == K_CTRL_A) {
flush_editarea(0);
buffertoScreen(0);
countCh=inputWindow("File:", tempfileName, "Quick load...",28,2,48);
if (countCh>0) {
strcpy(fileName, tempfileName);
filetoBuffer(fileName);
flush_editarea(0);
buffertoScreen(0);
dump_screen(screen1);
}//buffertoScreen(0, 0, 0);
}
if (ch == K_CTRL_N){
if (openFileDialog(fileName,fullPath) == 1){
filetoBuffer(fileName);
flush_editarea(0);
buffertoScreen(0);
}
dump_screen(screen1);
}
return returnValue;
}
//ESCAPE-RELATED KEYS
int special_keys() {
/* MANAGE SPECIAL KEYS */
/*
New implementation: Trail of chars found in keyboard.c
If K_ESCAPE is captured read a trail up to 5 characters from the console.
This is to control the fact that some keys may change
according to the terminal and expand the editor's possibilities.
Eg: F2 can be either 27 79 81 or 27 91 91 82.
*/
//cursorY : position on screen
//posBufY : position in buffer
int esc_key = 0;
char chartrail[5];
char returnMenuChar=0;
int menuCounter = 0;
int countCh = 0;
int ok = -1;
char tempfileName[MAXFILENAME];
old_cursorX = cursorX;
old_cursorY = cursorY;
oldposBufX = posBufX;
oldposBufY = posBufY;
strcpy(chartrail, "\0");
read_keytrail(chartrail); //Read trail after ESC key
//only ESC key detected, finish program
if (chartrail[0] == ESC_KEY && chartrail[1]==0) {
buffertoScreen(0);
if (fileModified == FILE_MODIFIED) {
ok=yesnoWindow(WMODIFIED_MSG, "Alert Window");
switch (ok){
case 0: //save file and exit
strcpy(chartrail, K_ALT_S);
break;
case 1: //don't save and exit
return ENDSIGNAL;
break;
case 2: //cancel keep running c-edit
buffertoScreen(0);
break;
}
} else
//regular escape with no modifications
return ENDSIGNAL;
}
//Check key trails for special keys starting with ESC.
//FUNCTION KEYS : F1 - F4
if(strcmp(chartrail, K_F2_TRAIL) == 0 ||
strcmp(chartrail, K_F2_TRAIL2) == 0) {
handlemenus(&returnMenuChar, &menuCounter,TRUE);
} else if(strcmp(chartrail, K_F3_TRAIL) == 0 ||
strcmp(chartrail, K_F3_TRAIL2) == 0) {
} else if(strcmp(chartrail, K_F1_TRAIL) == 0 ||
strcmp(chartrail, K_F1_TRAIL2) == 0) {
flush_editarea(0);
buffertoScreen(0);
displayHelp();
} else if(strcmp(chartrail, K_F4_TRAIL) == 0 ||
strcmp(chartrail, K_F4_TRAIL2) == 0) {
// ARROW KEYS
} else if(strcmp(chartrail, K_LEFT_TRAIL) == 0) {
//Left-arrow key
unwantedChars++;
if(cursorX > 1){
cursorX = cursorX - 1;
//editScroll.bufferX--;
}
if (posBufX>0) posBufX--;
//adjust shiftH when going back to account for the fact that cursorX=1 is not enough
if (cursorX == new_columns - 4) shiftH++;
if (cursorX == 1 && shiftH>0) {shiftH--;buffertoScreen(1);}
} else if(strcmp(chartrail, K_RIGHT_TRAIL) == 0) {
//Right-arrow key
unwantedChars++;
if(cursorX < new_columns - 3){
cursorX = cursorX + 1;
//shiftH = 0;
} else{
if (posBufX<MAX_LINE_SIZE) shiftH++;
buffertoScreen(1);
}
if (posBufX<MAX_LINE_SIZE) posBufX++;
} else if(strcmp(chartrail, K_UP_TRAIL) == 0) {
//Up-arrow key
unwantedChars++;
if(cursorY > 2) {
cursorY = cursorY - 1;
}else{
//scrolling up
if (currentLine>0) {
currentLine--;
buffertoScreen(1);
}
}
if (posBufY > 0) posBufY--;
} else if(strcmp(chartrail, K_DOWN_TRAIL) == 0) {
//Down-arrow key
//Check if there are more lines to go to
unwantedChars++;
if (posBufY<_length(&edBuf1)-1){
if(cursorY < new_rows - 3) {
//stay put if we are are the end of the viewing area
cursorY = cursorY + 1;
}
else{
//scrolling down
if (_length(&edBuf1) > vdisplayArea ) {
currentLine++;
buffertoScreen(1);
}
}
posBufY++;
}
} else if(strcmp(chartrail, K_PAGEDOWN_TRAIL) == 0) {
//Page Down key
vdisplayLimit = _length(&edBuf1) - vdisplayArea;
if (_length(&edBuf1) > vdisplayArea ) {
if (currentLine + vdisplayArea <= vdisplayLimit )
currentLine = currentLine + vdisplayArea;
else
currentLine = vdisplayLimit; // stop at the limit of our scroll
posBufY = currentLine;
cursorY = START_CURSOR_Y;
buffertoScreen(1);
}
} else if(strcmp(chartrail, K_PAGEUP_TRAIL) == 0) {
//Page Down key
if (_length(&edBuf1) > vdisplayArea ) {
if (currentLine >= vdisplayArea)
currentLine = currentLine - vdisplayArea;
else
currentLine = 0; // stop at the top
posBufY = currentLine;
cursorY = START_CURSOR_Y;
buffertoScreen(1);
}
}else if(strcmp(chartrail, K_HOME_TRAIL) == 0 || strcmp(chartrail, K_HOME_TRAIL2) == 0 ) {
if (_length(&edBuf1) > vdisplayArea ) {
currentLine=0;
cursorY = START_CURSOR_Y;
posBufY=0;
buffertoScreen(1);
}
}else if(strcmp(chartrail, K_END_TRAIL) == 0 || strcmp(chartrail, K_END_TRAIL2) == 0 ) {
if (_length(&edBuf1) > vdisplayArea ) {
currentLine=_length(&edBuf1)-vdisplayArea;
cursorY = new_rows-3;
posBufY=_length(&edBuf1)-1;
buffertoScreen(1);
}
} else if(strcmp(chartrail, K_DELETE) == 0) {
deleteKeyPressed = 1;
editor_section(0);
//delete button;
} else if(strcmp(chartrail, K_ALT_F) == 0) {
returnMenuChar=FILE_MENU;
menuCounter=FILE_MENU;
handlemenus(&returnMenuChar, &menuCounter,FALSE);
} else if(strcmp(chartrail, K_ALT_P) == 0) {
returnMenuChar=OPT_MENU;
menuCounter=OPT_MENU;
handlemenus(&returnMenuChar, &menuCounter,FALSE);
} else if(strcmp(chartrail, K_ALT_H) == 0) {
returnMenuChar=HELP_MENU;
menuCounter=HELP_MENU;
handlemenus(&returnMenuChar, &menuCounter,FALSE);
} else if(strcmp(chartrail, K_ALT_O) == 0) {
//openFileHandler(); //Open file Dialog
buffertoScreen(0);
dump_screen(screen1);
if (openFileDialog(fileName,fullPath) == 1){
//is it a binary file?
filetoBuffer(fileName);
flush_editarea(0);
buffertoScreen(0);
}
dump_screen(screen1);
} else if(strcmp(chartrail, K_ALT_N) == 0) {
//newDialog(currentFile); // New file
//refresh_screen(-1);
resetch();
} else if(strcmp(chartrail, K_ALT_A) == 0) {
//saveasDialog(currentFile); //Save as.. file
//refresh_screen(-1);
} else if(strcmp(chartrail, K_ALT_S) == 0) {
//Save file
flush_editarea(0);
buffertoScreen(0);
strcpy(tempMessage, "[File saved!]\0");
if (strcmp(fileName, "UNTITLED") == 0) {
countCh=inputWindow("File:", tempfileName, "Save file as...",28,2,48);
if (countCh>0) {
strcpy(fileName, tempfileName);
buffertoFile(fileName);
flush_editarea(0);
buffertoScreen(0);
dump_screen(screen1);
timer3.ticks=0;
}
} else{
buffertoFile(fileName);
flush_editarea(0);
buffertoScreen(0);
dump_screen(screen1);
timer3.ticks=0;
}
//a bit convoluted but it works / exit if user selcts yes after saving
if (ok==0){printf("File saved!. Exiting...\n"); return ENDSIGNAL; }
} else if(strcmp(chartrail, K_ALT_W) == 0) {
//if(strcmp(currentFile, UNKNOWN) == 0)
//saveasDialog(currentFile); //Write to file
//else {
//saveDialog(currentFile);
//}
//refresh_screen(-1);
} else if(strcmp(chartrail, K_ALT_X) == 0) {
/*
if(fileModified == 1)
exitp = confirmation(); //Shall we exit? Global variable!
else
exitp = EXIT_FLAG;
} }
*/
}
esc_key = 1;
return esc_key;
}
/*
void linetoScreen(long whereY, VLINES tempLine, BOOL clean){
//dump temporary Line to screen buffer
int i,j=0;
for (i=0; i<findEndline(tempLine); i++){
if(tempLine.linea[i].specialChar != 0) {
//Special char ? print the two values to screen buffer.
write_ch(i+START_CURSOR_X, whereY, tempLine.linea[i].specialChar, EDITAREACOL,
EDIT_FORECOLOR);
write_ch(i+START_CURSOR_X, whereY, tempLine.linea[i].ch, EDITAREACOL, EDIT_FORECOLOR);
} else {
write_ch(i+START_CURSOR_X, whereY, tempLine.linea[i].ch, EDITAREACOL,
EDIT_FORECOLOR);
}
if (clean == TRUE)
for (j=findEndline(tempLine); j<columns -2; j++)
write_ch(j+START_CURSOR_X, whereY, FILL_CHAR, EDITAREACOL, EDIT_FORECOLOR);
}
write_ch(findEndline(tempLine)+START_CURSOR_X, whereY, '|', B_GREEN,
F_WHITE);
}
*/
/*---------*/
/* Credits */
/*---------*/
void credits() {
//Frees memory and displays goodbye message
//Free selected path item/path from opfiledialog
size_t i; //to be compatible with strlen
char auth[27] ="Coded by v3l0r3k 2018-2025";
//int wherex=0,wherey=0;
close_term(); //restore terminal settings from failsafe
gotoxy(1,1);
printf(cedit_ascii_1);
gotoxy(1,2);
printf(cedit_ascii_2);
gotoxy(1,3);
printf(cedit_ascii_3);
gotoxy(1,4);
printf(cedit_ascii_4);
gotoxy(1,5);
printf(cedit_ascii_5);
gotoxy(1,6);
printf(cedit_ascii_6);
gotoxy(1,7);
outputcolor(0, 90);
printf("\n%s",auth);
outputcolor(0, 37);
timer2.ms=10;
timer2.ticks=0;
i=0;
outputcolor(0, 97);
do{
if (timerC(&timer2) == 1) {
gotoxy(i,8);
if (i==strlen(auth)) outputcolor(0,93);
if (i<10 || i>16)
if (i<=strlen(auth)) printf("%c", auth[i-1]);
printf("\n");
i++;
}
} while (timer2.ticks <30);
//log
// _printlist(&edBuf1);
// printf("%ld:%ld\n", posBufX, posBufY);
// printf("\n%ld\n",sizeof(&edBuf1));
if (screen1 != NULL) deleteList(&screen1);
if (screen2 != NULL) deleteList(&screen2);
if (listBox1 != NULL) removeList(&listBox1);
_deletetheList(&edBuf1); //free edit Buffer
resetAnsi(0);
showcursor();
resetAnsi(0);
}
void _resizeScreen(){
//redraw everything when screen size changes
get_terminal_dimensions(&new_rows, &new_columns);
if (screen1 != NULL) deleteList(&screen1);
if (screen2 != NULL) deleteList(&screen2);
create_screen(&screen1);
create_screen(&screen1);
draw_screen();
flush_editarea(0);
hdisplayArea = new_columns - 2;
vdisplayArea = new_rows - 4;
//if screen resizes file pointers are rewound to the beginning
currentLine = 0;
posBufX = 0;
posBufY = 0;
shiftH = 0;
buffertoScreen(0);
dump_screen(screen1);
cursorX = START_CURSOR_X;
cursorY = START_CURSOR_Y;
}
int displayMessage(char *temporaryMessage, int x, int y, int fColor, int bColor, int timeDuration){
//display a temporary nessage controlled by Timer3
if (timer3.ticks == -1) {
write_str(screen1, x,y, temporaryMessage, B_WHITE, F_WHITE,1);
return 0;
}
if (timer3.ticks >= timeDuration) {
stop_timer(&timer3);
write_str(screen1, x,y, temporaryMessage, B_WHITE, F_WHITE,1);
return 0;
}
write_str(screen1, x,y, temporaryMessage, bColor, fColor,1);
return 1;
}
================================================
FILE: src/menu.c
================================================
/* Module to display Menus on C·edit
* for a Text User Interface
* TextBox
* Window
* Last modified: 6/4/2024
* @author:velorek
*/
#include <stdio.h>
#include "rterm.h"
#include "scbuf.h"
#include "ui.h"
#include "menu.h"
#include "tm.h"
#include "keyb.h"
#include "global.h"
#include "editor.h"
#include "opfile.h"
#include "fileb.h"
/*--------------------------------------------*/
/* Load current menu into circular linked list*/
/*--------------------------------------------*/
void loadmenus(int choice) {
if(choice == HOR_MENU) {
if (listBox1 != NULL) removeList(&listBox1);
listBox1 = addatend(listBox1, newitem("File", 0, 1,-1,-1));
listBox1 = addatend(listBox1, newitem("Options", 7, 1,-1,-1));
listBox1 = addatend(listBox1, newitem("Help", 16, 1,-1,-1));
}
if(choice == FILE_MENU) {
if (listBox1 != NULL) removeList(&listBox1);
listBox1 = addatend(listBox1, newitem("New", -1, -1,-1,-1));
listBox1 = addatend(listBox1, newitem("Open", -1, -1,-1,-1));
listBox1 = addatend(listBox1, newitem("Quick load", -1, -1,-1,-1));
listBox1 = addatend(listBox1, newitem("Save", -1, -1,-1,-1));
listBox1 = addatend(listBox1, newitem("Save as...", -1, -1,-1,-1));
listBox1 = addatend(listBox1, newitem("Exit", -1, -1,-1,-1));
}
if(choice == OPT_MENU) {
if (listBox1 != NULL) removeList(&listBox1);
listBox1 = addatend(listBox1, newitem("File Info", -1, -1,-1,-1));
listBox1 = addatend(listBox1, newitem("Find...", -1, -1,-1,-1));
listBox1 = addatend(listBox1, newitem("Colors", -1, -1,-1,-1));
}
if(choice == HELP_MENU) {
if (listBox1 != NULL) removeList(&listBox1);
listBox1 = addatend(listBox1, newitem("Help...", -1, -1,-1,-1));
listBox1 = addatend(listBox1, newitem("About", -1, -1,-1,-1));
}
/*
if(choice == YESNO_MENU) {
add_item(mylist, "[YES]", (columns / 2) - 11, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
add_item(mylist, "[NO]", (columns / 2) - 3, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
add_item(mylist, "[CANCEL]", (columns / 2) + 4, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
}
if(choice == OK_MENU) {
add_item(mylist, "[OK]", (columns / 2) - 1, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
}
if(choice == OK_MENU2) {
add_item(mylist, "[OK]", (columns / 2) - 1, (rows / 2) + 3, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
}
if(choice == COLORS_MENU) {
add_item(mylist, "C-Edit Theme", (columns / 2) - 6, (rows / 2) - 2,
MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
add_item(mylist, "Classic Theme", (columns / 2) - 6, (rows / 2) -1,
MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
add_item(mylist, "Dark Theme", (columns / 2) - 6, (rows / 2),
MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
}
*/
}
/*---------------
Menu loop
It depends on two values passed by reference stored in the function from where this routine is called:
-returnMenuChar
-menuCounter
It does some tricky modulo operation to cycle back
*/
void handlemenus(char *returnMenuChar, int *menuCounter, BOOL horizontalMenu)
{
setselectorLimit(15);
copy_screen(screen2,screen1);
if (horizontalMenu) *returnMenuChar= horizontal_menu();
do{
switch (*returnMenuChar) {
case 0: *menuCounter=FILE_MENU; *returnMenuChar=filemenu(); if (*returnMenuChar != DONT_UPDATE) xor_update(screen2,screen1); break;
case 1: *menuCounter=OPT_MENU; *returnMenuChar=optionsmenu(); xor_update(screen2,screen1); break;
case 2: *menuCounter=HELP_MENU; *returnMenuChar=helpmenu(); xor_update(screen2,screen1); break;
default:
break;
}
//convert -2 from right cursor to 1 to advance
if (*returnMenuChar == -2 ) *returnMenuChar = 1;
*menuCounter=*menuCounter + *returnMenuChar;
if (*returnMenuChar == K_ENTER) break;
if (*returnMenuChar == DONT_UPDATE) break;
if (*returnMenuChar != ESC_KEY ) {
copy_screen(screen1,screen2);
//euclidian modulo, we circle back through the different switch cases
*returnMenuChar = ((*menuCounter % 3) + 3) % 3;
}
} while (*returnMenuChar != ESC_KEY);
//xor_update(screen2,screen1);
if (*returnMenuChar != DONT_UPDATE){
copy_screen(screen1,screen2);
dump_screen(screen1);
}
}
//Entry menu- horizontal
char horizontal_menu() {
char ch=0;
dump_screen(screen1);
//Save current screen to screen2
loadmenus(HOR_MENU);
//load menus from ui.c onto lisBox in (global.c)
//dump_screen(screen1);
ch = listBox(listBox1, 0, 1 , &scrollData, MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1, 3, HORIZONTAL,0,1);
//delete listbox
if(ch == ESC_KEY) scrollData.itemIndex = ch;; //to avoid warning
removeList(&listBox1);
//return option passed in scrollData (global.c)
return scrollData.itemIndex;
}
/*-------------------------*/
/* Display File menu */
/*-------------------------*/
char filemenu() {
char ch=0;
int countCh = 0;
char tempfileName[MAXFILENAME];
int ok2 = -1;
int retvalue = 0;
write_str(screen1,0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1);
write_str(screen1,0, 1, "File", MENU_SELECTOR, MENU_FOREGROUND1,1);
loadmenus(FILE_MENU);
draw_window(screen1,0, 2, 13, 9, MENU_PANEL, MENU_FOREGROUND0,0, 1,0,1,1);
ch = listBox(listBox1, 3, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1, -1, VERTICALWITHBREAK,0,1);
// copy_screen(screen1,screen2);
// dump_screen(screen1);
//return if right and left arrow keys are pressed
if (ch == K_RIGHTMENU || ch == K_LEFTMENU) return ch;
if(scrollData.itemIndex == OPTION_1) {
flush_editarea(0);
buffertoScreen(0);
countCh=inputWindow("File:", tempfileName, "[+] New file",26,2,44);
if (countCh>0) {
strcpy(fileName, tempfileName);
filetoBuffer(fileName);
flush_editarea(0);
buffertoScreen(0);
dump_screen(screen1);
}//buffertoScreen(0, 0, 0);
ch=0;
return DONT_UPDATE;
}
if(scrollData.itemIndex == OPTION_2) {
//openFile Dialog in opfile.c
flush_editarea(0);
buffertoScreen(0);
if (openFileDialog(fileName,fullPath) == 1){
filetoBuffer(fileName);
flush_editarea(0);
buffertoScreen(0);
}
dump_screen(screen1);
return DONT_UPDATE;
}
if(scrollData.itemIndex == OPTION_3) {
//External Module - Open file dialog.
//openFileHandler();
flush_editarea(0);
buffertoScreen(0);
countCh=inputWindow("File:", tempfileName, "Quick load...",26,2,44);
if (countCh>0) {
//check if it's a binary file
if (openandcheckFile(tempfileName) == 1){
ok2 = yesnoWindow(WCHECKFILE_MSG, "Alert window");
switch (ok2){
case 0: // open binary file anyway
retvalue=1;
break;
case 1: //don't open binary file
strcpy (fileName,"\0");
strcpy (fullPath,"\0");
retvalue=0;
break;
case 2: //cancel is the same as no here
strcpy (fileName,"\0");
strcpy (fullPath,"\0");
retvalue=0;
break;
}
}else{
retvalue = 1;
}
if (retvalue==1){
strcpy(fileName, tempfileName);
filetoBuffer(fileName);
flush_editarea(0);
buffertoScreen(0);
dump_screen(screen1);
}
}//buffertoScreen(0, 0, 0);
return DONT_UPDATE;
}
if(scrollData.itemIndex == OPTION_4) {
//Save file
flush_editarea(0);
buffertoScreen(0);
if (strcmp(fileName, "UNTITLED") == 0) {
countCh=inputWindow("File:", tempfileName, "Save file as...",26,2,44);
if (countCh>0) {
strcpy(fileName, tempfileName);
buffertoFile(fileName);
flush_editarea(0);
buffertoScreen(0);
dump_screen(screen1);
}
} else{
buffertoFile(fileName);
flush_editarea(0);
buffertoScreen(0);
dump_screen(screen1);
}
return DONT_UPDATE;
}
if(scrollData.itemIndex == OPTION_5) {
//Save as option
flush_editarea(0);
buffertoScreen(0);
countCh=inputWindow("File:", fileName, "Save file as...",26,2,44);
if (countCh>0) {
buffertoFile(fileName);
flush_editarea(0);
buffertoScreen(0);
dump_screen(screen1);
}
return DONT_UPDATE;
}
if(scrollData.itemIndex == OPTION_6) {
//Exit option
//if(fileModified == 1)
//exitp = confirmation(); //Shall we exit? Global variable!
//else
programStatus = ENDSIGNAL;
}
//restore previous screen
//dump_screen(screen1);
return ch;
}
/*--------------------------*/
/* Display Options menu */
/*--------------------------*/
char optionsmenu() {
//int setColor;
char ch=0;
write_str(screen1,6, 1, "Options", MENU_SELECTOR, MENU_FOREGROUND1,1);
write_str(screen1, 0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1);
loadmenus(OPT_MENU);
draw_window(screen1,6, 2, 19, 6, MENU_PANEL, MENU_FOREGROUND0,0, 1,0,1,1);
ch = listBox(listBox1, 9, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1, -1, VERTICALWITHBREAK,0,1);
if(scrollData.itemIndex == OPTION_1) {
//File Info
//fileInfoDialog();
}
if(scrollData.itemIndex == OPTION_3) {
//Set Colors
/* setColor = colorsWindow(mylist,COLORSWTITLE);
setColorScheme(setColor);
checkConfigFile(setColor); //save new configuration in config file
*///refresh_screen(1);
}
return ch;
}
/*--------------------------*/
/* Display Help menu */
/*--------------------------*/
char helpmenu() {
char ch= 0;
write_str(screen1,15, 1, "Help", MENU_SELECTOR, MENU_FOREGROUND1,1);
write_str(screen1, 0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1);
loadmenus(HELP_MENU);
draw_window(screen1,15, 2, 25, 5, MENU_PANEL, MENU_FOREGROUND0, 0,1,0,1,1);
ch = listBox(listBox1, 18, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1, -1, VERTICALWITHBREAK,0,1);
if(scrollData.itemIndex == OPTION_1 && ch>0) {
//Help dialog
//help_info();
flush_editarea(0);
buffertoScreen(0);
displayHelp();
}
if(scrollData.itemIndex == OPTION_2 && ch>0) {
//About info
flush_editarea(0);
buffertoScreen(0);
displayAbout();
}
return ch;
}
//ABOUT
int displayAbout(void)
{
char ch = 0;
int i = 0;
int colAnimation = F_BLACK;
int keypressed = 0;
int colCounter = 0;
copy_screen(screen2, screen1);
window(screen1, (new_columns / 2) - 18, (new_rows / 2) - 6,
(new_columns / 2) + 17, (new_rows) / 2 + 3, B_WHITE, F_BLACK,
B_BLACK, 1, 1, 1);
for (i = 0; i < 6; i++) {
write_str(screen1, (new_columns / 2) - 15,
(new_rows / 2) - 5 + i, aboutMSG[i], B_WHITE,
F_BLACK, 0);
}
write_str(screen1, (new_columns / 2) - 11, (new_rows / 2) - 7,
"[+] ABOUT INFORMATION", B_BLACK, FH_WHITE, 1);
// write_str(screen1, (new_columns / 2) - 25, (new_rows / 2) + 2,
//aboutMSG[3], B_YELLOW, F_BLACK, 0);
write_str(screen1, (new_columns / 2) - 1, (new_rows / 2) + 2, "[OK]",
B_RED, FH_WHITE, 1);
dump_screen(screen1);
if (kbhit(100) == 1)
ch = readch();
ch = 0;
i = 0;
colCounter = 0;
//pulsating animation
do {
keypressed = kbhit(30);
if (timerC(&timer2) == TRUE) {
//About animation
write_str(screen1, (new_columns / 2) - 15,
(new_rows / 2) - 5 + i, aboutMSG[i], B_WHITE,
colAnimation, 1);
i++;
if (i == 6) {
i = 0;
switch (colCounter){
case 1:
colAnimation = FH_BLACK;
break;
case 2:
colAnimation = FH_BLACK;
break;
case 3:
colAnimation = FH_BLACK;
break;
case 4:
colAnimation = FH_BLACK;
break;
case 5:
colAnimation = FH_BLACK;
break;
case 6:
colAnimation = FH_WHITE;
break;
case 7:
colAnimation = FH_WHITE;
break;
case 8:
colAnimation = FH_WHITE;
break;
case 9:
colAnimation = F_BLACK;
break;
case 10:
colAnimation = F_BLACK;
break;
}
colCounter++;
if (colCounter ==11) colCounter = 0;
}
//if terminal resizes
if (_animation() == -1)
break;
}
//Process keys
if (keypressed == 1) {
ch = readch();
keypressed = 0;
//Read special keys
if (ch == K_ESCAPE) {
ch = readch();
if (ch == ESC_KEY)
break;
}
}
} while (ch != K_ENTER);
resetch();
copy_screen(screen1, screen2);
if (listBox1 != NULL)
removeList(&listBox1);
dump_screen(screen1);
return ch;
}
void addItemsHelp(LISTCHOICE **listBox1, char textarray[][MAXLINE], int rows)
{
int h=0;
//Load items into the list.
//if (*listBox1 != NULL) removeList(listBox1);
for (h = 0; h < rows-1; h++) {
//*ch = textarray[h];
*listBox1 = addatend(*listBox1, newitem(textarray[h],-1,-1,-1,-1));
}
*listBox1 = addatend(*listBox1, newitem(textarray[rows-1],-1,-1,B_WHITE,FH_BLUE));
}
int displayHelp(void)
{
char ch = 0;
resetScrollData(&scrollData);
if (listBox1 != NULL)
removeList(&listBox1);
setselectorLimit(26*2-1);
//scrollData.selectorLimit = (26 * 2) - 1; //No. of chars per item display
//scrollData.selectorLimit = 100; //No. of chars per item display
//create_screen(&screen2);
copy_screen(screen2, screen1);
window(screen1, (new_columns / 2) - 26, (new_rows / 2) - 8,
(new_columns / 2) + 26, (new_rows) / 2 + 8, B_WHITE, F_BLACK,
B_BLACK, 1, 1, 1);
write_str(screen1, (new_columns / 2) - 12, (new_rows / 2) - 9,
"[+] MAIN HELP INFORMATION", B_BLACK, FH_WHITE, 1);
write_str(screen1, (new_columns / 2) - 1, (new_rows / 2) + 7, "[OK]",
B_RED, F_WHITE, 1);
dump_screen(screen1);
addItemsHelp(&listBox1, help, HELPLINES);
if (listBox1 != NULL)
ch = listBox(listBox1, (new_columns / 2) - 24,
(new_rows / 2) - 7, &scrollData, B_WHITE, F_BLACK,
B_WHITE, FH_WHITE, 14, VERTICAL,1,LOCKED);
copy_screen(screen1, screen2);
// if (screen2 != NULL)
// deleteList(&screen2);
if (listBox1 != NULL)
removeList(&listBox1);
dump_screen(screen1);
return ch;
}
================================================
FILE: src/menu.h
================================================
/*
========================================================================
- HEADER -
Module with all menus on C·EDIT
@author : Velorek
@version : 1.0
Last modified: 06/04/2024
========================================================================
*/
#ifndef _MENU_H_
#define _MENU_H_
#include "scbuf.h"
#include <stdio.h>
void loadmenus(int choice);
char horizontal_menu();
char filemenu();
char optionsmenu();
char helpmenu();
void credits();
void handlemenus(char *returnMenuChar, int *menuCounter, BOOL horizontalMenu);
int displayAbout();
int displayHelp(void);
#endif
================================================
FILE: src/opfile.c
================================================
/*====================================================================*/
/* OPEN FILE MODULE
+ListFiles with double linked list and selection menu in C.
+Scroll function added.
+Integrated with C-EDIT
A window is drawn to the buffer and all of the scroll animations
are drawn to the terminal on raw mode to have a better scrolling
animation. Once the file is selected, the window is closed and the
previous screen is painted to the terminal again.
Last modified : 11/1/2019 - Switch to readch() instead of getch()
06/04/2019 - Corrected all memory leaks
14/04/2019 - Rename headers
22/04/2020 - Added Set File to Open
23/04/2023 - Merged with Lynx and vastly simplified
Coded by Velorek.
Target OS: Linux. */
/*====================================================================*/
/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include "rterm.h"
#include "scbuf.h"
#include "listbox.h"
#include "tm.h"
#include "keyb.h"
#include "global.h"
#include "opfile.h"
#include "ui.h"
#include "fileb.h"
/*====================================================================*/
/* GLOBAL VARIABLES */
/*====================================================================*/
int window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0;
int ndirs=0, nfiles=0;
/*====================================================================*/
/* CODE */
/*====================================================================*/
int listFiles(LISTCHOICE ** listBox1, char *directory) {
DIR *d;
struct dirent *dir;
int i;
char temp[MAX_ITEM_LENGTH];
int lenDir; //length of directory
ndirs=0;
nfiles=0;
if (*listBox1 != NULL) removeList(listBox1);
*listBox1 = addatend(*listBox1, newitem("[..]",-1,-1,FH_BLUE,B_WHITE)); // ".."
//Start at current directory
d = opendir(directory);
//Find directories and add them to list first
if(d) {
while((dir = readdir(d)) != NULL) {
if(dir->d_type == DT_DIR) {
lenDir = strlen(dir->d_name);
//Check length of directory
//Directories are displayed between brackets [directory]
if(lenDir > MAX_ITEM_LENGTH - 2) {
//Directory name is long. CROP
memset(&temp, '\0',sizeof(temp)); //Clear memory for temporary line
strcpy(temp,"\0");
strcpy(temp, "[");
for(i = 1; i < MAX_ITEM_LENGTH - 1; i++) {
temp[i] = dir->d_name[i - 1];
}
temp[MAX_ITEM_LENGTH - 1] = ']';
} else {
//Directory's name is shorter than display
//Add spaces to item string.
memset(&temp, '\0',sizeof(temp)); //Clear memory for temporary line
strcpy(temp,"\0");
strcpy(temp, "[");
for(i = 1; i < lenDir + 1; i++) {
temp[i] = dir->d_name[i - 1];
}
temp[lenDir + 1] = ']';
}
//Add all directories except CURRENTDIR and CHANGEDIR
if(strcmp(dir->d_name, ".") != 0
&& strcmp(dir->d_name, "..") != 0)
{ ndirs++;
*listBox1 =
addatend(*listBox1, newitem(temp, -1,-1,FH_BLUE,B_WHITE));}
}
}
}
closedir(d);
//Find files and add them to list after directories
d = opendir(directory);
if(d) {
while((dir = readdir(d)) != NULL) {
if(dir->d_type == DT_REG) {
//only list valid fiels
if(strlen(dir->d_name) > MAX_ITEM_LENGTH) {
for(i = 0; i < MAX_ITEM_LENGTH; i++) {
temp[i] = dir->d_name[i];
}
} else {
memset(&temp, '\0',sizeof(temp)); //Clear memory for temporary line
strcpy(temp,"\0");
strcpy(temp, dir->d_name);
}
nfiles++;
*listBox1 =
addatend(*listBox1, newitem(temp, -1,-1,-1,-1));
}
}
closedir(d);
}
return 0;
}
void addItems(LISTCHOICE **listBox1)
{
int h=0;
//Load items into the list.
//if (listBox1 != NULL) removeList(listBox1);
for (h = 0; h <10; h++) {
//*ch = textarray[h];
*listBox1 = addatend(*listBox1, newitem("Test",-1,-1,-1,-1));
}
}
int openFileDialog(char fileName[MAXFILENAME], char fullPath[MAXFILENAME]){
char ch=0;
char path[MAXFILENAME];
char bit[MAXFILENAME];
char ndirstr[100];
size_t i=0;
int ok2 =0;
int retvalue=0;
char nfilestr[100];
char currentPath[4] = "./\0";
retvalue =0;
setselectorLimit(23);
window_y1 = (new_rows / 2) - 10;
window_y2 = (new_rows / 2) + 10;
window_x1 = (new_columns / 2) - 13;
window_x2 = (new_columns / 2) + 13;
copy_screen(screen2,screen1);
old_rows = new_rows;
old_columns = new_columns;
do{
draw_window(screen1,window_x1, window_y1, window_x2, window_y2,B_WHITE,F_BLACK,B_BLACK,1,1,1,0);
draw_window(screen1,window_x1, window_y2-3, window_x2, window_y2,B_CYAN,F_WHITE,B_BLACK,1,0,0,0);
dump_screen(screen1);
listFiles(&listBox1,currentPath);
sprintf(ndirstr, "[%d] Directories", ndirs);
sprintf(nfilestr, "[%d] Files", nfiles);
write_str(screen1,window_x1+2,window_y2-2,ndirstr,B_CYAN,FH_WHITE,1);
write_str(screen1,window_x1+2,window_y2-1,nfilestr,B_CYAN,F_WHITE,1);
write_str(screen1,window_x1+1,window_y2-4, " PRESS [ESC] TO EXIT ",B_BLACK,FH_WHITE,1);
write_str(screen1,window_x1+2,window_y1,"Select file...",B_BLACK,FH_WHITE,1);
ch = listBox(listBox1, window_x1+3,window_y1+1, &scrollData, B_WHITE, F_BLACK,B_RED, FH_WHITE, 15, VERTICAL,1,LOCKED);
if (_animation() == -1) {ch=K_ESCAPE; break;}
if (ch == 0x27) {break;}
if (ch == K_ENTER){
if (scrollData.item[0] == '[') {
//directory
memset(&path, '\0',sizeof(path)); //Clear memory for temporary line
memset(&bit, '\0',sizeof(bit)); //Clear memory for temporary line
strcpy(bit,"\0");
strcpy(path,"\0");
for (i=1; i<strlen(scrollData.item)-1; i++) bit[i-1] = scrollData.item[i];
getcwd(path, sizeof(path));
strcat(path, "/");
strcat(path, bit);
chdir(path);
ch=0;
}
else {
break;
}
}
} while (ch!=ESC_KEY);
setselectorLimit(15);
if (ch!=27){
//we pass the values
//memset(&fullPath, '\0',sizeof(fullPath)); //Clear memory for temporary line
memset(fileName, '\0', strlen(fileName) + 1); // Clear memory for temporary line
memset(fullPath, '\0', strlen(fullPath) + 1); // Clear memory for temporary line
// memset(&fileName, '\0',sizeof(fileName)); //Clear memory for temporary line
strcpy(bit,"\0");
strcpy(path,"\0");
strcpy(fileName, scrollData.item);
strcpy(fullPath, path);
//reset scroll values
cursorX=START_CURSOR_X;
cursorY=START_CURSOR_Y;
currentLine=0;
shiftH=0;
posBufX=0;
posBufY = 0;
retvalue = 1;
}
if (listBox1 != NULL) removeList(&listBox1);
copy_screen(screen1,screen2);
//Finally check if it is a binary file
if (openandcheckFile(fileName) == 1){
ok2 = yesnoWindow(WCHECKFILE_MSG, "Alert window");
switch (ok2){
case 0: // open binary file anyway
retvalue=1;
break;
case 1: //don't open binary file
strcpy (fileName,"\0");
strcpy (fullPath,"\0");
retvalue=0;
break;
case 2: //cancel is the same as no here
strcpy (fileName,"\0");
strcpy (fullPath,"\0");
retvalue=0;
break;
}
} else{
//file is a text file
}
return retvalue;
}
================================================
FILE: src/opfile.h
================================================
/*
========================================================================
- HEADER -
Module to open a file by showing a dialogue that allows you to navigate
through directories with a list with scroll.
@author : Velorek
@version : 1.0
Last modified: 23/04/2024 Vastly simplified and integraed with lynx
========================================================================
*/
#ifndef _OPFILE_H_
#define _OPFILE_H_
/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include "rterm.h"
#include "scbuf.h"
#include "listbox.h"
#include "tm.h"
#include "keyb.h"
#include "global.h"
/*====================================================================*/
/* CONSTANTS */
/*====================================================================*/
#define MAX_ITEM_LENGTH 15
/*====================================================================*/
/* CONSTANT VALUES */
/*====================================================================*/
/*====================================================================*/
/* FUNCTION PROTOTYPES */
/*====================================================================*/
int listFiles(LISTCHOICE ** listBox1, char *directory);
void addItems(LISTCHOICE **listBox1);
int openFileDialog(char fileName[MAXFILENAME], char fullPath[MAXFILENAME]);
#endif
================================================
FILE: src/rterm.c
================================================
/*
======================================================================
Module to control some display routines that implement ANSI functions.
on LINUX Terminals
@author : Velorek (routines extracted from the internet)
@version : 1.0
LAST MODIFIED : 18/01/2023 Kbhit with poll control added
======================================================================
*/
/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <locale.h>
#include <sys/ioctl.h>
#include <poll.h>
#include "rterm.h"
#include "keyb.h"
/*====================================================================*/
/* GLOBAL VARIABLES */
/*====================================================================*/
struct winsize max;
static struct termios term, failsafe;
static int peek_character = -1;
/*====================================================================*/
/* FUNCTIONS - CODE */
/*====================================================================*/
/*-------------------------------------*/
/* Initialize new terminal i/o settings*/
/*-------------------------------------*/
void pushTerm() {
//Save terminal settings in failsafe to be retrived at the end
tcgetattr(0, &failsafe);
}
/*---------------------------*/
/* Reset terminal to failsafe*/
/*---------------------------*/
int resetTerm() {
//tcsetattr(0, TCSANOW, &failsafe);
/* flush and reset */
if (tcsetattr(0,TCSAFLUSH,&failsafe) < 0) return -1;
return 0;
}
/*--------------------------------------.*/
/* Detect whether a key has been pressed.*/
/*---------------------------------------*/
int kbhit(int timeout_ms)
{
struct pollfd fds = {STDIN_FILENO, POLLIN, 0};
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
int ret = poll(&fds, 1, timeout_ms);
fcntl(STDIN_FILENO, F_SETFL, 0);
if (ret > 0) {
return 1;
} else if (ret == 0) {
return 0; // timeout occurred
} else {
return -1; // error occurred
}
}
/*----------------------*/
/*Read char with control*/
/*----------------------*/
char readch() {
char ch;
if(peek_character != -1) {
ch = peek_character;
peek_character = -1;
return ch;
}
read(0, &ch, 1);
return ch;
}
void resetch() {
//Clear ch
term.c_cc[VMIN] = 0;
tcsetattr(0, TCSANOW, &term);
peek_character = 0;
}
/*----------------------------------*/
/* Move cursor to specified position*/
/*----------------------------------*/
void gotoxy(int x, int y) {
printf("%c[%d;%df", 0x1B, y, x);
}
/*---------------------*/
/* Change colour output*/
/*---------------------*/
void outputcolor(int foreground, int background) {
printf("%c[%d;%dm", 0x1b, foreground, background);
}
/*-----------------------------------------------------*/
/* Change the whole color of the screen by applying CLS*/
/*-----------------------------------------------------*/
void screencol(int x) {
gotoxy(0, 0);
outputcolor(0, x);
printf("%c[2J", 0x1b);
outputcolor(0, 0);
}
/*-----------------------*/
/* Reset ANSI ATTRIBUTES */
/*-----------------------*/
void resetAnsi(int x) {
switch (x) {
case 0: //reset all colors and attributes
printf("%c[0m", 0x1b);
break;
case 1: //reset only attributes
printf("%c[20m", 0x1b);
break;
case 2: //reset foreg. colors and not attrib.
printf("%c[39m", 0x1b);
break;
case 3: //reset back. colors and not attrib.
printf("%c[49m", 0x1b);
break;
default:
break;
}
}
/*------------------------*/
/* Get terminal dimensions*/
/*------------------------*/
int get_terminal_dimensions(int *rows, int *columns) {
ioctl(0, TIOCGWINSZ, &max);
*columns = max.ws_col;
*rows = max.ws_row;
return 0;
}
/*--------------------------*/
/* Ansi function hide cursor*/
/*--------------------------*/
void hidecursor() {
printf("\e[?25l");
}
/*--------------------------*/
/* Ansi function show cursor*/
/*--------------------------*/
void showcursor() {
printf("\e[?25h");
}
/*----------------------------------*/
/* Get cursor position */
/*----------------------------------*/
int get_pos(int *y, int *x) {
char buf[30]={0};
int ret, i, pow;
char ch;
*y = 0; *x = 0;
struct termios term, restore;
tcgetattr(0, &term);
tcgetattr(0, &restore);
term.c_lflag &= ~(ICANON|ECHO);
tcsetattr(0, TCSANOW, &term);
write(1, "\033[6n", 4);
for( i = 0, ch = 0; ch != 'R'; i++ )
{
ret = read(0, &ch, 1);
if ( !ret ) {
tcsetattr(0, TCSANOW, &restore);
//fprintf(stderr, "getpos: error reading response!\n");
return 1;
}
buf[i] = ch;
//printf("buf[%d]: \t%c \t%d\n", i, ch, ch);
}
if (i < 2) {
tcsetattr(0, TCSANOW, &restore);
//printf("i < 2\n");
return(1);
}
for( i -= 2, pow = 1; buf[i] != ';'; i--, pow *= 10)
*x = *x + ( buf[i] - '0' ) * pow;
for( i-- , pow = 1; buf[i] != '['; i--, pow *= 10)
*y = *y + ( buf[i] - '0' ) * pow;
tcsetattr(0, TCSANOW, &restore);
return 0;
}
/*--------------------------*/
/* Set up terminal */
/*--------------------------*/
//For code simplification purposes
void init_term(void)
{
//switch to alternate screen buffer
printf("\033[?1049h");
hidecursor();
pushTerm();
resetch();
//Setup unicode
setlocale(LC_ALL, "");
}
void close_term(void)
{
showcursor();
resetTerm();
resetAnsi(0);
//restore previous screen
printf("\033[?1049l");
//cls
gotoxy(0,0);
printf("%c[2J\r", 0x1b);
}
/*
void init_term(){
hidecursor();
pushTerm();
resetch();
//Setup unicode
setlocale(LC_ALL, "");
}
void close_term(){
showcursor();
resetTerm();
outputcolor(F_WHITE, B_BLACK);
screencol(B_BLACK);
resetAnsi(0);
printf("\n");
}
*/
================================================
FILE: src/rterm.h
================================================
/*
========================================================================
- HEADER -
Module to control some display routines that implement ANSI functions.
@author : Velorek
@version : 1.0
Last modified: 15/09/2021 + Linux Term
========================================================================
*/
#ifndef _RTERM_H_
#define _RTERM_H_
/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
/*====================================================================*/
/* COLOR CONSTANTS */
/*====================================================================*/
// Background colors low intensity
#define B_BLACK 40
#define B_RED 41
#define B_GREEN 42
#define B_YELLOW 43
#define B_BLUE 44
#define B_MAGENTA 45
#define B_CYAN 46
#define B_WHITE 47
// Foreground colors low intensity
#define F_BLACK 30
#define F_RED 31
#define F_GREEN 32
#define F_YELLOW 33
#define F_BLUE 34
#define F_MAGENTA 35
#define F_CYAN 36
#define F_WHITE 37
//#define F_WHITE 37
#define F_GREY 90
// Background colors high intensity
#define BH_BLACK 100
#define BH_RED 101
#define BH_GREEN 102
#define BH_YELLOW 103
#define BH_BLUE 104
#define BH_MAGENTA 105
#define BH_CYAN 106
#define BH_WHITE 107
// Foreground colors high intensity
#define FH_BLACK 90
#define FH_RED 91
#define FH_GREEN 92
#define FH_YELLOW 93
#define FH_BLUE 94
#define FH_MAGENTA 95
#define FH_CYAN 96
#define FH_WHITE 97
#define TRUE 1
#define FALSE 0
//Keys used.
#define K_ENTER 13
#define K_ENTER2 10
#define K_ESCAPE 27
#define K_UP_TRAIL "\e[A\0\0"
#define K_DOWN_TRAIL "\e[B\0\0"
#define K_RIGHT_TRAIL "\e[C\0\0"
#define K_LEFT_TRAIL "\e[D\0\0"
//#define K_UP_ARROW 'A' // K_ESCAPE + 'A' -> UP_ARROW
//#define K_DOWN_ARROW 'B' // K_ESCAPE + 'B' -> DOWN_ARROW
typedef int BOOL;
/*====================================================================*/
/* FUNCTION PROTOTYPES */
/*====================================================================*/
void pushTerm();
int resetTerm();
int kbhit(int timeout_ms);
char readch();
char getch();
void resetch();
//char getch(void);
void gotoxy(int x, int y);
void outputcolor(int foreground, int background);
void screencol(int x);
void resetAnsi(int x);
int get_terminal_dimensions(int *rows, int *columns);
int get_pos(int *y, int *x);
void showcursor();
void hidecursor();
void init_term();
void close_term();
#endif
================================================
FILE: src/scbuf.c
================================================
/* Module to create a screen buffer
* to act as an intermediate step between screen output and
* the display so as to create a Text User Interface.
* @author:velorek
* Last modified: 1/02/2019
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "rterm.h"
#include "scbuf.h"
#define ROWS_FAILSAFE 25
#define COLUMNS_FAILSAFE 80
#define FILL_CHAR 32
int sc_rows=0, sc_columns=0;
int buffersize=0;
/* SINGLE LINKED LIST ROUTINES */
// create new list element of type SCREENCELL from the supplied text string
SCREENCELL *newelement(SCREENCELL temp)
{
SCREENCELL *newp;
newp = (SCREENCELL *) malloc (sizeof(SCREENCELL));
newp->index = temp.index;
newp->backColor = temp.backColor;
newp->foreColor = temp.foreColor;
newp->toUpdate = 0;
newp->ch = temp.ch;
newp->next = NULL;
return newp;
}
void deleteList(SCREENCELL **head)
{
/* deref head_ref to get the real head */
SCREENCELL *current = *head;
SCREENCELL *next = NULL;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
free(current);
free(next);
current = NULL;
next = NULL;
*head = NULL;
}
/* addfront: add new SCREENCELL to front of list */
/* example usage: start = (addfront(start, newelement("burgers")); */
SCREENCELL *addfront(SCREENCELL *head, SCREENCELL *newp)
{
newp -> next = head;
return newp;
}
/* addend: add new SCREENCELL to the end of a list */
/* usage example: start = (addend(start, newelement("wine")); */
SCREENCELL *addend (SCREENCELL *head, SCREENCELL *newp)
{
SCREENCELL *p2;
if (head == NULL)
return newp;
// now find the end of list
for (p2 = head; p2 -> next != NULL; p2 = p2 -> next)
;
p2 -> next = newp;
return head;
}
int length(SCREENCELL **head)
// this routine uses pointer-to-pointer techniques :-)
{
int count=0;
SCREENCELL **tracer = head;
while ((*tracer) != NULL) {
count = count +1;
tracer = &(*tracer)->next;
}
return count;
}
void reindex(SCREENCELL **head)
{
int count=0;
SCREENCELL *p=NULL;
SCREENCELL **tracer = head;
while ((*tracer) != NULL) {
p = *tracer;
p->index=count;
count = count +1;
tracer = &(*tracer)->next;
}
}
/* SCREEN BUFFER ROUTINES */
int create_screen(SCREENCELL **newScreen){
/*
Get terminal dimensions and create a dynamic list with the size of the screen.
if it is not possible to determine screen dimensions default is set to 80x25.
Insertion happens at the end of the list. */
int i=0;
SCREENCELL temp;
SCREENCELL **aux = newScreen;
//We attempt to get terminal dimensions. If not
//successful failsafe values (80x25) apply.
get_terminal_dimensions(&sc_rows, &sc_columns);
if(sc_rows == 0)
sc_rows = ROWS_FAILSAFE;
if(sc_columns == 0)
sc_columns = COLUMNS_FAILSAFE;
buffersize = sc_rows * sc_columns;
// Assign dummy data to Screen buffer
if(*aux == NULL) {
//All cells have the same init data
temp.ch = FILL_CHAR;
temp.backColor = B_BLACK;
temp.foreColor = F_WHITE;
for(i = 0; i < buffersize; i++) {
//Except for their index
temp.index = buffersize - 1 - i;
*aux = addfront(*aux, newelement(temp));
}
return 1;
} else{
//Pointer is not void
return 0;
}
}
void copy_screen(SCREENCELL *destination,SCREENCELL *source){
int i=0;
SCREENCELL *aux1=destination;
SCREENCELL *aux2=source;
//We attempt to get terminal dimensions. If not
//successful failsafe values (80x25) apply.
if((aux1 != NULL && aux2 != NULL) && (length(&aux1) == length(&aux2)) ) {
for(i = 0; i < buffersize; i++) {
aux1->backColor = aux2->backColor;
aux1->foreColor = aux2->foreColor;
aux1->ch = aux2->ch;
aux1 = aux1->next;
aux2 = aux2->next;
}
}
}
/*------------------------------------------*/
/* Update single char to screen for display */
/*------------------------------------------*/
void update_ch(int x, int y, wchar_t ch, char backcolor, char forecolor) {
//Write Unicode char to screen raw
resetAnsi(0);
gotoxy(x+1, y+1);
outputcolor(forecolor, backcolor);
printf("%lc", ch); //unicode
}
void write_ch(SCREENCELL *newScreen, int x, int y, wchar_t ch, char backcolor, char forecolor,BOOL raw) {
/* Update cell on screenbuffer. It will be shown on screen when it is updated by calling update_screen */
int i, pos;
SCREENCELL *aux = newScreen;
resetAnsi(0);
if (aux != NULL && buffersize <= length(&aux)){
pos = (y - 1) * sc_columns + x; //This is the formula to calculate the position index in the screen buffer
if(pos < buffersize) {
// If it is within buffer limits, otherwise do nothing.
for(i = 0; i <= pos; i++) {
//Run through the buffer until reaching desired position
if (aux->index == pos)
break;
aux = aux->next;
}
//Update cell info at position selected.
//Manage special charaters as well.
aux->ch = ch;
aux->backColor = backcolor;
aux->foreColor = forecolor;
aux->toUpdate = 1;
if(raw==TRUE) {
gotoxy(x+1, y);
outputcolor(forecolor, backcolor);
if (ch>31) printf("%lc", ch); //unicode
}
}
}
}
SCREENCELL read_cell(SCREENCELL *newScreen, int x, int y) {
/* read specific character with attributes from buffer */
int i=0, pos=0;
SCREENCELL *aux=newScreen;
SCREENCELL ret ={};
if (aux != NULL && buffersize <= length(&aux)){
pos = (y - 1) * sc_columns + x; //this is the formula to calculate the position index in the screen buffer
if(pos < buffersize) {
for(i = 0; i <= pos; i++) {
//run through the buffer until reaching desired position
if(aux->index == pos)
break;
aux = aux->next;
}
ret.index = aux->index;
ret.ch = aux->ch;
//for some unknown reason these values have to be inverted
ret.backColor = aux->foreColor;
ret.foreColor = aux->backColor;
ret.next = NULL;
}
}
return ret;
}
wchar_t read_char(SCREENCELL *newScreen, int x, int y) {
/* read specific character from buffer */
int i=0, pos=0;
wchar_t ch = FILL_CHAR;
SCREENCELL *aux=newScreen;
if (aux != NULL && buffersize <= length(&aux)){
pos = (y - 1) * sc_columns + x; //this is the formula to calculate the position index in the screen buffer
if(pos < buffersize) {
for(i = 0; i <= pos; i++) {
//run through the buffer until reaching desired position
if(aux->index == pos)
break;
aux = aux->next;
}
ch = aux->ch;
}
}
return ch;
}
/*------------------------------------------*/
/* Writes a string of characters to buffer. */
/*------------------------------------------*/
void write_str(SCREENCELL *newScreen, int x, int y, char *str, char backcolor, char forecolor, BOOL raw) {
//Writes a string of characters to buffer.
char *astr=NULL;
size_t i=0;
int wherex=0;
SCREENCELL *aux = newScreen;
if (aux!=NULL){
wherex = x;
astr = str;
for(i = 0; i <= strlen(str) - 1; i++) {
write_ch(aux, wherex, y, astr[i], backcolor, forecolor,raw);
wherex = wherex + 1;
}
}
}
/*------------------------------------------*/
/* Writes a string of characters to screen. */
/*------------------------------------------*/
void update_str(int x, int y, char *str, char backcolor, char forecolor) {
//Writes a string of characters to buffer.
char *astr=NULL;
size_t i=0;
int wherex=0;
resetAnsi(0);
wherex = x;
astr = str;
for(i = 0; i <= strlen(str) - 1; i++) {
update_ch(wherex, y, astr[i], backcolor, forecolor);
wherex = wherex + 1;
}
}
/*-----------------------------------------------*/
/* Writes an integer value as a string on screen */
/*-----------------------------------------------*/
int write_num(SCREENCELL *newScreen, int x, int y, int num, char backcolor,
char forecolor, BOOL raw) {
//the length of the string must be passed on the function
char astr[30];
char len=0;
SCREENCELL *aux = newScreen;
if (aux!=NULL){
sprintf(astr, "%d", num);
write_str(newScreen, x, y, astr, backcolor, forecolor,raw);
len = strlen(astr);
}
return len;
}
void screen_color(SCREENCELL *newScreen, char bcolor, char fcolor, wchar_t ch) {
/* Changes the color of all the cells to create the effect of changing color in the background */
int i=0;
SCREENCELL *aux=newScreen;
resetAnsi(0);
//screen should be updated twice to get round the last row glitch
if (aux != NULL && buffersize <= length(&aux)){
for(i = 0; i < buffersize; i++) {
aux->backColor = bcolor;
aux->foreColor = fcolor;
aux->ch = ch;
aux->toUpdate = 1;
aux = aux->next;
}
}
}
/*------------------------------------*/
/* Dumps buffer to screen for display */
/*------------------------------------*/
void dump_screen(SCREENCELL *newScreen) {
/* UPDATES ALL SCREEN CELLS TO DISPLAY */
int i=0;
int wherex=0, wherey=0;
SCREENCELL *aux=newScreen;
if (aux!=NULL && buffersize <= length(&aux)){
for(i = 0; i < buffersize; i++) {
update_ch(wherex,wherey,aux->ch,aux->backColor,aux->foreColor);
wherex = wherex + 1; //line counter
if(wherex == sc_columns) {
//new line
wherex = 0;
wherey = wherey + 1;
}
aux = aux->next;
}
}
}
void update_screen(SCREENCELL *newScreen) {
/* UPDATES ALL SCREEN CELLS TO DISPLAY */
int i=0;
int wherex=0, wherey=0;
SCREENCELL *aux=newScreen;
if (aux!=NULL && buffersize <= length(&aux)){
for(i = 0; i < buffersize; i++) {
if (aux->toUpdate ==1) {aux->toUpdate = 0; update_ch(wherex,wherey,aux->ch,aux->backColor,aux->foreColor);}
wherex = wherex + 1; //line counter
if(wherex == sc_columns) {
//new line
wherex = 0;
wherey = wherey + 1;
}
aux = aux->next;
}
}
}
void xor_update(SCREENCELL *screen1, SCREENCELL *screen2) {
/* UPDATE only the cells that are different */
int i=0;
int wherex=0, wherey=0;
SCREENCELL *aux1=screen1;
SCREENCELL *aux2=screen2;
if ((aux1!=NULL && aux2!=NULL) && (length(&aux1) == length(&aux2))){
for(i = 0; i < buffersize; i++) {
if (aux1->ch != aux2->ch || aux1-> backColor != aux2 -> backColor || aux1-> foreColor != aux2 -> foreColor){
update_ch(wherex,wherey,aux1->ch,aux1->backColor,aux1->foreColor);
}
wherex = wherex + 1; //line counter
if(wherex == sc_columns) {
//new line
wherex = 0;
wherey = wherey + 1;
}
aux1 = aux1->next;
aux2 = aux2->next;
}
}
}
void xor_copy(SCREENCELL *screen1, SCREENCELL *screen2)
{
/* UPDATES ALL SCREEN CELLS TO DISPLAY */
int i = 0;
int wherex = 0, wherey = 0;
SCREENCELL *aux1 = screen1;
SCREENCELL *aux2 = screen2;
if ((aux1 != NULL && aux2 != NULL) && (length(&aux1) == length(&aux2))) {
for (i = 0; i < buffersize; i++) {
if (aux1->ch != aux2->ch
|| aux1->backColor != aux2->backColor
|| aux1->foreColor != aux2->foreColor) {
aux1->ch = aux2->ch;
aux1->backColor = aux2->backColor;
aux1->foreColor = aux2->foreColor;
wherex = wherex + 1; //line counter
if (wherex == sc_columns) {
//new line
wherex = 0;
wherey = wherey + 1;
}
aux1 = aux1->next;
aux2 = aux2->next;
}
}
}
}
/*------------------------------------------*/
/* Draw window area with or without border. */
/*------------------------------------------*/
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) {
/*
Draw a box on screen
*/
SCREENCELL *aux = newScreen;
int i, j;
wchar_t ch=FILL_CHAR;
i = x1;
j = y1;
//shadow
resetAnsi(0);
if (shadow == TRUE){
for(j = y1 + 1; j <= y2 + 1; j++)
for(i = x1 + 1; i <= x2 + 1; i++)
{
ch=read_char(aux, i,j); //dynamic shadow
if ((ch=='\0') || (ch == UNICODEBAR1) || (ch<0)) ch=FILL_CHAR;
//ch=FILL_CHAR;
//if (ch<0) ch = (tempLine.linea[i].specialChar << 8) | tempLine.linea[i].ch;
write_ch(aux, i, j, ch, B_BLACK, F_WHITE,raw);
}
}
//window
for(j = y1; j <= y2; j++)
for(i = x1; i <= x2; i++)
write_ch(aux, i, j, FILL_CHAR, backcolor, bordercolor,raw);
//borders
if(border == TRUE) {
for(i = x1; i <= x2; i++) {
//upper and lower borders
write_ch(aux, i, y1, HOR_LINE, backcolor, bordercolor,raw); //horizontal line box-like char
write_ch(aux, i, y2, HOR_LINE, backcolor, bordercolor,raw);
}
for(j = y1; j <= y2; j++) {
//left and right borders
write_ch(aux, x1, j, VER_LINE, backcolor, bordercolor,raw); //vertical line box-like char
write_ch(aux, x2, j, VER_LINE, backcolor, bordercolor,raw);
}
write_ch(aux, x1, y1, UPPER_LEFT_CORNER, backcolor, bordercolor,raw); //upper-left corner box-like char
write_ch(aux, x1, y2, LOWER_LEFT_CORNER, backcolor, bordercolor,raw); //lower-left corner box-like char
write_ch(aux, x2, y1, UPPER_RIGHT_CORNER, backcolor, bordercolor,raw); //upper-right corner box-like char
write_ch(aux, x2, y2, LOWER_RIGHT_CORNER, backcolor, bordercolor,raw); //lower-right corner box-like char
}
if (title == TRUE) {
for(i = x1+1; i <= x2-1; i++)
write_ch(aux, i, y1, ' ', titlecolor, titlecolor,raw);
}
}
================================================
FILE: src/scbuf.h
================================================
#ifndef _SCBUF_H_
#define _SCBUF_H_
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <wchar.h>
#include "rterm.h"
#define HOR_LINE 9472
#define VER_LINE 9474
#define UPPER_LEFT_CORNER 9484
#define LOWER_LEFT_CORNER 9492
#define UPPER_RIGHT_CORNER 9488
#define LOWER_RIGHT_CORNER 9496
#define UNICODEBAR1 0x2592
typedef struct _screencell
{
int index;
char backColor;
char foreColor;
unsigned char toUpdate;
//int char attrib;
wchar_t ch;
struct _screencell *next;
} SCREENCELL;
/* Adapted from Kernighan and Pike's "The Practice of Programming" pp.46 et
seq. (Addison-Wesley 1999) - computerPhile */
// create new list element of type SCREENCELL from the supplied text string
SCREENCELL *newelement(SCREENCELL temp);
SCREENCELL *addfront(SCREENCELL *head, SCREENCELL *newp);
SCREENCELL *addend (SCREENCELL *head, SCREENCELL *newp);
void deleteList(SCREENCELL **head);
int length(SCREENCELL **head);
void reindex(SCREENCELL **head);
//SCREEN BUFFER ROUTINES
int create_screen(SCREENCELL **newScreen);
void update_ch(int x, int y, wchar_t ch, char backcolor, char forecolor);
void update_screen(SCREENCELL *newScreen);
void dump_screen(SCREENCELL *newScreen);
void write_ch(SCREENCELL *newScreen, int x, int y, wchar_t ch, char backcolor, char forecolor, BOOL raw);
wchar_t read_char(SCREENCELL *newScreen, int x, int y);
SCREENCELL read_cell(SCREENCELL *newScreen, int x, int y);
void write_str(SCREENCELL *newScreen, int x, int y, char *str, char backcolor, char forecolor, BOOL raw);
void update_str(int x, int y, char *str, char backcolor, char forecolor);
int write_num(SCREENCELL *newScreen, int x, int y, int num, char backcolor,
char forecolor, BOOL raw);
void screen_color(SCREENCELL *newScreen, char bcolor, char fcolor, wchar_t ch);
void copy_screen(SCREENCELL *destination,SCREENCELL *source);
void xor_update(SCREENCELL *screen1, SCREENCELL *screen2);
void xor_copy(SCREENCELL *screen1, SCREENCELL *screen2);
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);
#endif
================================================
FILE: src/t.txt
================================================
Hello
there
================================================
FILE: src/tm.c
================================================
/* Module to create a milisecond timer
* @author: velorek
* Last modified: 10/08/2020
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "tm.h"
#include <sys/time.h>
#include <poll.h>
long long epoch_ms(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000LL + (tv.tv_usec + 500) / 1000;
}
int timerC(NTIMER *mytimer1){
long long difference = 0;
long long res;
if (mytimer1->ticks == -1) return 0;
if (mytimer1->ticks == 0){
// First tick, set up values
mytimer1->oldtime = epoch_ms();
mytimer1->ticks = 1;
return 1;
} else {
// Subsequent ticks
long long now = epoch_ms();
difference = now - mytimer1->oldtime;
res = difference;
if (res < mytimer1->ms) {
return 0;
} else {
mytimer1->oldtime = now;
mytimer1->ticks = mytimer1->ticks + 1;
return 1;
}
}
}
void init_timer(NTIMER *mytimer1, int ms){
// Init routine
mytimer1->ticks = 0;
mytimer1->ms = ms;
}
void stop_timer(NTIMER *mytimer1){
// Stop routine
mytimer1->ticks = -1;
}
void resume_timer(NTIMER *mytimer1){
// Resume routine
mytimer1->ticks = 0;
}
================================================
FILE: src/tm.h
================================================
/*
========================================================================
- HEADER -
Module to implement a millisecond TIMER in C.
@author : Velorek
@version : 1.0
Last modified: 15/09/2021 + New technique + init timer
========================================================================
*/
#ifndef _TM_H_
#define _TM_H_
/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
/*====================================================================*/
/* FUNCTION PROTOTYPES */
/*====================================================================*/
typedef struct nTimer{
int ms; //milliseconds
long oldtime; //to calculate increment in time
long ticks; //how many ticks have been made
} NTIMER;
/* Miliseconds timer */
int timerC(NTIMER *mytimer1);
void init_timer(NTIMER *mytimer, int ms);
void stop_timer(NTIMER *mytimer);
void resume_timer(NTIMER *mytimer);
#endif
================================================
FILE: src/ui.c
================================================
/* Module to create different widgets/gadgets
* for a Text User Interface
* TextBox
* Window
* Last modified: 15/04/2023
* @author:velorek
*/
#include <stdio.h>
#include "rterm.h"
#include "scbuf.h"
#include "ui.h"
#include "tm.h"
#include "keyb.h"
#include "global.h"
/*----------------------------*/
/* User Interface - Text Box. */
/*----------------------------*/
int textbox(SCREENCELL *newScreen,int wherex, int wherey, int displayLength,
char *label, char text[MAX_TEXT], int backcolor,
int labelcolor, int textcolor, BOOL raw, BOOL locked) {
int charCount = 0;
int exitFlag = 0;
int cursorON = 1;
int i;
int limitCursor = 0;
int positionx = 0;
int posCursor = 0;
int keypressed = 0;
char chartrail[5];
// char accentchar[2];
char displayChar;
char ch;
NTIMER cursorTime;
SCREENCELL *aux = newScreen;
resetAnsi(0);
init_timer(&cursorTime,150);
positionx = wherex + strlen(label);
limitCursor = wherex+strlen(label)+displayLength+1;
write_str(aux,wherex, wherey, label, backcolor, labelcolor,raw);
write_ch(aux,positionx, wherey, '[', backcolor, textcolor,raw);
for(i = positionx + 1; i <= positionx + displayLength; i++) {
write_ch(aux,i, wherey, '.', backcolor, textcolor,raw);
}
write_ch(aux,positionx + displayLength + 1, wherey, ']', backcolor,
textcolor,raw);
if (raw != TRUE) dump_screen(aux);
//Reset keyboard
if(kbhit(1) == 1) ch = readch();
ch = 0;
do {
if (locked == 0) break;
keypressed = kbhit(1);
if (timerC(&timer2) == TRUE) _animation();
//Cursor Animation
if (keypressed == 0){
if (timerC(&cursorTime) == TRUE){
switch (cursorON) {
case 1:
posCursor = positionx + 1;
displayChar = '.';
if (posCursor == limitCursor) {
posCursor = posCursor - 1;
displayChar = ch;
}
write_ch(aux,posCursor, wherey, displayChar, backcolor, textcolor,raw);
//update_screen(aux);
if (raw != TRUE) dump_screen(aux);
cursorON = 0;
break;
case 0:
posCursor = positionx + 1;
if (posCursor == limitCursor) posCursor = posCursor - 1;
write_ch(aux,posCursor, wherey, '|', backcolor, textcolor,raw);
//update_screen(aux);
if (raw != TRUE) dump_screen(aux);
cursorON = 1;
break;
}
}
}
//Process keys
if(keypressed == 1) {
ch = readch();
keypressed = 0;
//Read special keys
if (ch==K_ESCAPE) {
read_keytrail(chartrail);
}
//Read accents
//if (ch==SPECIAL_CHARSET_1) read_accentchar(&ch, accentchar);
//if (ch==SPECIAL_CHARSET_2) read_accentchar(&ch, accentchar);
if(charCount < displayLength) {
if(ch > 31 && ch < 127) {
write_ch(aux,positionx + 1, wherey, ch, backcolor, textcolor,raw);
text[charCount] = ch;
positionx++;
charCount++;
//update_screen(aux);
if (raw != TRUE) dump_screen(aux);
}
}
}
if (ch==K_CTRL_C){
return ENDSIGNAL;
}
if (ch==K_BACKSPACE){
if (positionx>0 && charCount>0){
ch=0;
positionx--;
charCount--;
text[charCount] = '\0';
write_ch(aux,positionx + 1, wherey, '.', backcolor, textcolor,raw);
if (positionx < limitCursor-2) write_ch(aux,positionx + 2, wherey, '.', backcolor, textcolor,raw);
//update_screen(aux);
if (raw != TRUE) dump_screen(aux);
//resetch();
}
}
if(ch == K_ENTER || ch == K_TAB || ch == K_ESCAPE)
exitFlag = 1;
//ENTER OR TAB FINISH LOOP
} while(exitFlag != 1);
text[charCount] = '\0';
//Clear field
positionx = wherex + strlen(label);
for(i = positionx + 1; i <= positionx + displayLength; i++) {
write_ch(aux,i, wherey, '.', backcolor, textcolor,raw);
}
write_ch(aux,positionx + displayLength + 1, wherey, ']', backcolor,
textcolor,raw);
//resetch();
if (ch == K_ESCAPE) charCount = 0;
return charCount;
}
void window(SCREENCELL *screen1, int x1, int y1, int x2, int y2, int backcolor,
int bordercolor, int titlecolor, int border, int title, int shadow) {
/*
Chars for drawing box-like characters will be passed as negative values.
When the update_screen routine is called, it will check for negative
values and map these chars to Unicode characters.
*/
int i, j;
//char ch=0x20;
wchar_t ch=0x20;
i = x1;
j = y1;
resetAnsi(0);
//shadow
if (shadow==1){
for(j = y1 + 1; j <= y2 + 1; j++)
for(i = x1 + 1; i <= x2 + 1; i++)
{
ch=read_char(screen1, i,j); //dynamic shadow
if ((ch=='\0') || (ch==UNICODEBAR1)) ch=0x20;
write_ch(screen1, i, j, ch, B_BLACK, F_WHITE,0);
}
}
//window
for(j = y1; j <= y2; j++)
for(i = x1; i <= x2; i++)
write_ch(screen1, i, j, ' ', backcolor, bordercolor,0);
//borders
if(border == 1) {
//with borders. ANSI-ASCII 106-121
for(i = x1; i <= x2; i++) {
//upper and lower borders
write_ch(screen1, i, y1, HOR_LINE, backcolor, bordercolor,0); //horizontal line box-like char
write_ch(screen1, i, y2, HOR_LINE, backcolor, bordercolor,0);
}
for(j = y1; j <= y2; j++) {
//left and right borders
write_ch(screen1,x1, j, VER_LINE, backcolor, bordercolor,0); //vertical line box-like char
write_ch(screen1,x2, j, VER_LINE, backcolor, bordercolor,0);
}
write_ch(screen1, x1, y1, UPPER_LEFT_CORNER, backcolor, bordercolor,0); //upper-left corner box-like char
write_ch(screen1, x1, y2, LOWER_LEFT_CORNER, backcolor, bordercolor,0); //lower-left corner box-like char
write_ch(screen1, x2, y1, UPPER_RIGHT_CORNER, backcolor, bordercolor,0); //upper-right corner box-like char
write_ch(screen1, x2, y2, LOWER_RIGHT_CORNER, backcolor, bordercolor,0); //lower-right corner box-like char
}
if (title == 1) {
for(i = x1; i <= x2; i++)
write_ch(screen1, i, y1-1, ' ', titlecolor, titlecolor,0);
}
// dump_screen(screen1);
}
int inputWindow(char *label, char *tempFile, char *windowTitle, int offsetX, int offsetY, int length) {
int window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0;
int count = 0;
resetAnsi(0);
copy_screen(screen2,screen1);
window_y1 = (new_rows / 2) - offsetY;
window_y2 = (new_rows / 2);
window_x1 = (new_columns / 2) - offsetX;
window_x2 = (new_columns / 2) + offsetX;
window(screen1,window_x1, window_y1, window_x2, window_y2, MENU_PANEL, MENU_FOREGROUND0,
WINDOW_TITLEB,1,1,1);
write_str(screen1, (window_x2-window_x1) /2 + window_x1 - (strlen(windowTitle)/2) , window_y1-1, windowTitle, WINDOW_TITLEB, WINDOW_TITLEF,0);
dump_screen(screen1);
count =
textbox(screen1, window_x1 + 1, window_y1 + 1, length, label, tempFile, MENU_PANEL,
MENU_FOREGROUND0, MENU_FOREGROUND0,1,1);
copy_screen(screen1,screen2);
dump_screen(screen1);
return count;
}
int yesnoWindow(char *message, char *windowTitle) {
int window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0;
char ch = 0;
int ok = 0;
size_t i=0;
int j = 0;
int ix = 0;
char tempChar=0;
resetAnsi(0);
copy_screen(screen2,screen1);
window_y1 = (new_rows / 2) - 4;
window_y2 = (new_rows / 2) + 4;
window_x1 = (new_columns / 2) - 16;
window_x2 = (new_columns / 2) + 16;
window(screen1,window_x1, window_y1, window_x2, window_y2, MENU_PANEL, MENU_FOREGROUND0, WINDOW_TITLEB,1,0,1);
dump_screen(screen1);
write_str(screen1, (window_x2-window_x1) /2 + window_x1 - (strlen(windowTitle)/2) , window_y1, windowTitle, WINDOW_TITLEB, WINDOW_TITLEF,1);
//'|' is used as line separator
for(i = 0; i < strlen(message); i++) {
tempChar = message[i];
if (tempChar != '|'){
write_ch(screen1,window_x1 + 1 + ix, window_y1 + 1 + j, tempChar, MENU_PANEL,MENU_FOREGROUND0,1);
ix++;
}else {
j++;
ix = 0;
}
}
printf("\n");
if (listBox1 != NULL) removeList(&listBox1);
listBox1 = addatend(listBox1, newitem("[ YES ]",window_x1+3,window_y2-1,-1,-1));
listBox1 = addatend(listBox1, newitem("[ NO ]",window_x1+13,window_y2-1,-1,-1));
listBox1 = addatend(listBox1, newitem("[CANCEL]",window_x1+23,window_y2-1,-1,-1));
setselectorLimit(8);
ch = listBox(listBox1, window_x1+2,window_y2, &scrollData, MENU_PANEL, MENU_FOREGROUND0,MENU_SELECTOR, MENU_FOREGROUND1, 3, HORIZONTAL,1,LOCKED);
ok = scrollData.itemIndex;
if (listBox1 != NULL) removeList(&listBox1);
ch++;
copy_screen(screen1,screen2);
dump_screen(screen1);
resetScrollData(&scrollData);
return ok;
}
================================================
FILE: src/ui.h
================================================
/*
========================================================================
- HEADER -
Module with different UI gadgets for LYNX.
@author : Velorek
@version : 1.0
Last modified: 06/02/2022
========================================================================
*/
#ifndef _UI_H_
#define _UI_H_
#define MAX_TEXT 255
#include "scbuf.h"
#include <stdio.h>
int textbox(SCREENCELL *newScreen,int wherex, int wherey, int displayLength,
char *label, char text[MAX_TEXT], int backcolor,
int labelcolor, int textcolor, BOOL raw, BOOL locked);
void window(SCREENCELL *screen1, int x1, int y1, int x2, int y2, int backcolor,
int bordercolor, int titlecolor, int border, int title, int shadow);
int inputWindow(char *label, char *tempFile, char *windowTitle, int offsetX, int offsetY, int length);
int yesnoWindow(char *message, char *windowTitle);
#endif
gitextract_9g946023/
├── LICENSE
├── README.md
├── TODO
├── TODO.md
└── 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
SYMBOL INDEX (129 symbols across 19 files)
FILE: src/edbuf.c
function VLINES (line 8) | VLINES *_newline(VLINES temp)
function _RemoveThing (line 20) | void _RemoveThing(VLINES **head, int index)
function _hardupdateLINE (line 38) | void _hardupdateLINE(VLINES **head, int index, VLINES temp)
function _deletetheList (line 60) | void _deletetheList(VLINES **head)
function VLINES (line 81) | VLINES *_update(VLINES *head, int index, VLINES temp)
function VLINES (line 95) | VLINES *_getObject(VLINES *head, int index)
function VLINES (line 110) | VLINES *_deleteline(VLINES *head, int index)
function VLINES (line 130) | VLINES *_addfront(VLINES *head, VLINES *newp)
function VLINES (line 139) | VLINES *_addatend (VLINES *head, VLINES *newp)
function _printlist (line 151) | void _printlist(VLINES **head)
function _length (line 166) | int _length(VLINES **head)
function _reindex (line 179) | void _reindex(VLINES **head)
function _deleteObject (line 192) | void _deleteObject(VLINES **head,int index, BOOL sort){
function _dumpLine (line 201) | int _dumpLine(VLINES *head, long index, VLINES *line){
function _updateLine (line 222) | int _updateLine(VLINES *head, long index, VLINES *line){
function CHARBUF (line 244) | CHARBUF _getSingleChar(VLINES *head, long X, long Y ){
function findEndline (line 268) | int findEndline(VLINES line) {
function BOOL (line 285) | BOOL isLineTerminated(VLINES line) {
FILE: src/edbuf.h
type BOOL (line 9) | typedef int BOOL;
type CHARBUF (line 11) | typedef struct _charbuf
type VLINES (line 18) | typedef struct _vlines
FILE: src/editor.c
function wchar_t (line 21) | wchar_t convertChar(char c1, char c2) {
function linetoScreenRAW (line 35) | void linetoScreenRAW(long whereY, VLINES tempLine){
function linetoScreen (line 60) | void linetoScreen(long whereY, VLINES tempLine){
function cleanScreenLine (line 93) | void cleanScreenLine(long whereY)
function cleanSection (line 105) | void cleanSection(long whereY, long start, int amount)
function buffertoScreen (line 121) | void buffertoScreen(BOOL raw){
function buffertoFile (line 140) | void buffertoFile(char *fileName){
function editor_section (line 166) | int editor_section(char ch){
function filetoBuffer (line 554) | int filetoBuffer(char *fileName) { //EDBUF*
function flush_editarea (line 633) | void flush_editarea(int force_update) {
FILE: src/fileb.c
function file_exists (line 27) | int file_exists(char *fileName) {
function getfileSize (line 41) | long getfileSize(FILE * filePtr) {
function countLinesFile (line 56) | long countLinesFile(FILE * filePtr) {
function checkFile (line 78) | long checkFile(FILE * filePtr) {
function openandcheckFile (line 98) | int openandcheckFile(char *fileName) {
function openFile (line 133) | int openFile(FILE ** filePtr, char fileName[], char *mode)
function closeFile (line 156) | int closeFile(FILE * filePtr) {
FILE: src/global.c
function initCEDIT (line 74) | int initCEDIT(){
function _animation (line 105) | int _animation(){
FILE: src/global.h
type BOOL (line 27) | typedef int BOOL;
FILE: src/keyb.c
function read_keytrail (line 28) | int read_keytrail(char chartrail[5]){
function read_accent (line 56) | int read_accent(char *ch, char accentchar[2])
FILE: src/listbox.c
function LISTCHOICE (line 40) | LISTCHOICE *newitem(char *text,unsigned setX, unsigned setY,unsigned for...
function removeList (line 56) | void removeList(LISTCHOICE ** head) {
function LISTCHOICE (line 70) | LISTCHOICE *addatend(LISTCHOICE * head, LISTCHOICE * newp) {
function gotoIndex (line 89) | void gotoIndex(LISTCHOICE ** aux, SCROLLDATA * scrollData,
function printlist (line 108) | void printlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned disp...
function loadlist (line 132) | void loadlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned index...
function query_length (line 155) | int query_length(LISTCHOICE ** head) {
function displayItem (line 171) | void displayItem(LISTCHOICE * aux, SCROLLDATA * scrollData, int select)
function move_selector (line 227) | int move_selector(LISTCHOICE ** selector, SCROLLDATA * scrollData) {
function selectorMenu (line 340) | char selectorMenu(LISTCHOICE * aux, SCROLLDATA * scrollData) {
function setselectorLimit (line 474) | void setselectorLimit(int num){
function resetScrollData (line 477) | void resetScrollData(SCROLLDATA *scrollData)
function listBox (line 497) | char listBox(LISTCHOICE * head,
FILE: src/listbox.h
type LISTCHOICE (line 42) | typedef struct _listchoice {
type SCROLLDATA (line 53) | typedef struct _scrolldata {
FILE: src/main.c
function draw_screen (line 35) | void draw_screen(){
function cursor_tick (line 106) | void cursor_tick(void){
function update_indicators (line 174) | void update_indicators() {
function main (line 226) | int main(int argc, char *argv[]) {
function control_keys (line 312) | int control_keys(char ch){
function special_keys (line 355) | int special_keys() {
function credits (line 620) | void credits() {
function _resizeScreen (line 674) | void _resizeScreen(){
function displayMessage (line 696) | int displayMessage(char *temporaryMessage, int x, int y, int fColor, int...
FILE: src/menu.c
function loadmenus (line 23) | void loadmenus(int choice) {
function handlemenus (line 83) | void handlemenus(char *returnMenuChar, int *menuCounter, BOOL horizontal...
function horizontal_menu (line 116) | char horizontal_menu() {
function filemenu (line 135) | char filemenu() {
function optionsmenu (line 277) | char optionsmenu() {
function helpmenu (line 305) | char helpmenu() {
function displayAbout (line 332) | int displayAbout(void)
function addItemsHelp (line 439) | void addItemsHelp(LISTCHOICE **listBox1, char textarray[][MAXLINE], int ...
function displayHelp (line 450) | int displayHelp(void)
FILE: src/opfile.c
function listFiles (line 46) | int listFiles(LISTCHOICE ** listBox1, char *directory) {
function addItems (line 125) | void addItems(LISTCHOICE **listBox1)
function openFileDialog (line 136) | int openFileDialog(char fileName[MAXFILENAME], char fullPath[MAXFILENAME]){
FILE: src/rterm.c
type winsize (line 31) | struct winsize
type termios (line 32) | struct termios
function pushTerm (line 42) | void pushTerm() {
function resetTerm (line 50) | int resetTerm() {
function kbhit (line 62) | int kbhit(int timeout_ms)
function readch (line 80) | char readch() {
function resetch (line 91) | void resetch() {
function gotoxy (line 101) | void gotoxy(int x, int y) {
function outputcolor (line 108) | void outputcolor(int foreground, int background) {
function screencol (line 115) | void screencol(int x) {
function resetAnsi (line 125) | void resetAnsi(int x) {
function get_terminal_dimensions (line 147) | int get_terminal_dimensions(int *rows, int *columns) {
function hidecursor (line 157) | void hidecursor() {
function showcursor (line 164) | void showcursor() {
function get_pos (line 171) | int get_pos(int *y, int *x) {
function init_term (line 220) | void init_term(void)
function close_term (line 232) | void close_term(void)
FILE: src/rterm.h
type BOOL (line 85) | typedef int BOOL;
FILE: src/scbuf.c
function SCREENCELL (line 23) | SCREENCELL *newelement(SCREENCELL temp)
function deleteList (line 37) | void deleteList(SCREENCELL **head)
function SCREENCELL (line 59) | SCREENCELL *addfront(SCREENCELL *head, SCREENCELL *newp)
function SCREENCELL (line 68) | SCREENCELL *addend (SCREENCELL *head, SCREENCELL *newp)
function length (line 81) | int length(SCREENCELL **head)
function reindex (line 94) | void reindex(SCREENCELL **head)
function create_screen (line 109) | int create_screen(SCREENCELL **newScreen){
function copy_screen (line 144) | void copy_screen(SCREENCELL *destination,SCREENCELL *source){
function update_ch (line 165) | void update_ch(int x, int y, wchar_t ch, char backcolor, char forecolor) {
function write_ch (line 173) | void write_ch(SCREENCELL *newScreen, int x, int y, wchar_t ch, char back...
function SCREENCELL (line 206) | SCREENCELL read_cell(SCREENCELL *newScreen, int x, int y) {
function wchar_t (line 232) | wchar_t read_char(SCREENCELL *newScreen, int x, int y) {
function write_str (line 256) | void write_str(SCREENCELL *newScreen, int x, int y, char *str, char back...
function update_str (line 277) | void update_str(int x, int y, char *str, char backcolor, char forecolor) {
function write_num (line 296) | int write_num(SCREENCELL *newScreen, int x, int y, int num, char backcolor,
function screen_color (line 311) | void screen_color(SCREENCELL *newScreen, char bcolor, char fcolor, wchar...
function dump_screen (line 333) | void dump_screen(SCREENCELL *newScreen) {
function update_screen (line 352) | void update_screen(SCREENCELL *newScreen) {
function xor_update (line 372) | void xor_update(SCREENCELL *screen1, SCREENCELL *screen2) {
function xor_copy (line 396) | void xor_copy(SCREENCELL *screen1, SCREENCELL *screen2)
function draw_window (line 430) | void draw_window(SCREENCELL *newScreen, int x1, int y1, int x2, int y2, ...
FILE: src/scbuf.h
type SCREENCELL (line 20) | typedef struct _screencell
FILE: src/tm.c
function epoch_ms (line 14) | long long epoch_ms(void)
function timerC (line 20) | int timerC(NTIMER *mytimer1){
function init_timer (line 44) | void init_timer(NTIMER *mytimer1, int ms){
function stop_timer (line 50) | void stop_timer(NTIMER *mytimer1){
function resume_timer (line 55) | void resume_timer(NTIMER *mytimer1){
FILE: src/tm.h
type NTIMER (line 25) | typedef struct nTimer{
FILE: src/ui.c
function textbox (line 18) | int textbox(SCREENCELL *newScreen,int wherex, int wherey, int displayLen...
function window (line 142) | void window(SCREENCELL *screen1, int x1, int y1, int x2, int y2, int bac...
function inputWindow (line 195) | int inputWindow(char *label, char *tempFile, char *windowTitle, int off...
function yesnoWindow (line 217) | int yesnoWindow(char *message, char *windowTitle) {
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (177K chars).
[
{
"path": "LICENSE",
"chars": 1065,
"preview": "MIT License\n\nCopyright (c) 2021 Velorek1\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
},
{
"path": "README.md",
"chars": 3074,
"preview": "C-EDIT Project in C language (NO NCURSES)\n=========================================\nC-EDIT for linux - ALPHA - A linux t"
},
{
"path": "TODO",
"chars": 679,
"preview": "* Top Priority:\nCheck https://github.com/velorek1/ceditbuf/ for latest development implementations (2024(\n\n- Code a more"
},
{
"path": "TODO.md",
"chars": 273,
"preview": "* Top Priority: (2025)\n- Complete menus / dialogs \n- READ MODE\n- FULL UTF 8 - SUPPORT change char to win_t/wchar in edit"
},
{
"path": "src/Makefile",
"chars": 942,
"preview": ".POSIX:\nTARGET = cedit\nCC = cc\nCFLAGS = -Wall -Wextra -fsigned-char \nLDFLAGS =\nLDLIBS =\n\n# The list of object fil"
},
{
"path": "src/TODO.md",
"chars": 55,
"preview": "# ceditbuf\nC-edit with dynamic buffer (in development)\n"
},
{
"path": "src/edbuf.c",
"chars": 7037,
"preview": "#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"edbuf.h\"\n\n\n// create new list element of type VLINE"
},
{
"path": "src/edbuf.h",
"chars": 1383,
"preview": "#ifndef _EDBUF_H_\n#define _EDBUF_H_\n\n#include <stdio.h>\n#include <stdlib.h>\n#define MAX_LINE_SIZE 512\n#define TRUE 1\n#de"
},
{
"path": "src/editor.c",
"chars": 24394,
"preview": "/* Main editor section C·edit \n * for a Text User Interface\n * Last modified: 6/04/2024\n * @author:velorek\n */\n#include "
},
{
"path": "src/editor.h",
"chars": 892,
"preview": "/*\n========================================================================\n- HEADER -\nModule with main editor in C·edit"
},
{
"path": "src/fileb.c",
"chars": 3401,
"preview": "/* \n======================================================================\nModule to describe basic file operations.\n\n@a"
},
{
"path": "src/fileb.h",
"chars": 1409,
"preview": "/*\n========================================================================\n- HEADER - \nModule to handle basic file oper"
},
{
"path": "src/global.c",
"chars": 4393,
"preview": "#include \"global.h\"\n#include \"rterm.h\"\n#include \"time.h\"\n\n// GLOBALS : SCREEN1 : ANIMATED | SCREEN2 : BASE SCREEN\nLISTCH"
},
{
"path": "src/global.h",
"chars": 7460,
"preview": "/*\n * Global variables are intented to be placed here\n * Last modified: 9/7/2022\n * @author: velorek\n *\n */\n#ifndef _GLO"
},
{
"path": "src/keyb.c",
"chars": 2206,
"preview": "/*\n======================================================================\nModule to control keyboard input.\n\n@author : V"
},
{
"path": "src/keyb.h",
"chars": 2556,
"preview": "/*\n========================================================================\n- HEADER -\nModule to handle keyboard input i"
},
{
"path": "src/listbox.c",
"chars": 17204,
"preview": "/*====================================================================*/\n/* +ListBox with double linked list and selecti"
},
{
"path": "src/listbox.h",
"chars": 4416,
"preview": "/*\n========================================================================\n- HEADER -\nModule to implement a listBox int"
},
{
"path": "src/main.c",
"chars": 23714,
"preview": "/* C-edit project\n* Last updated - 29/8/2024\n* New drop-down menu implementation\n* Added more modularisation: editor.c m"
},
{
"path": "src/menu.c",
"chars": 14351,
"preview": "/* Module to display Menus on C·edit \n * for a Text User Interface\n * TextBox\n * Window\n * Last modified: 6/4/2024\n * @a"
},
{
"path": "src/menu.h",
"chars": 583,
"preview": "/*\n========================================================================\n- HEADER -\nModule with all menus on C·EDIT\n@"
},
{
"path": "src/opfile.c",
"chars": 7656,
"preview": "/*====================================================================*/\n/* OPEN FILE MODULE\n +ListFiles with double l"
},
{
"path": "src/opfile.h",
"chars": 1647,
"preview": "/*\n========================================================================\n- HEADER - \nModule to open a file by showing"
},
{
"path": "src/rterm.c",
"chars": 6089,
"preview": "/*\n======================================================================\nModule to control some display routines that i"
},
{
"path": "src/rterm.h",
"chars": 2760,
"preview": "/*\n========================================================================\n- HEADER -\nModule to control some display ro"
},
{
"path": "src/scbuf.c",
"chars": 13522,
"preview": "/* Module to create a screen buffer\n * to act as an intermediate step between screen output and\n * the display so as to "
},
{
"path": "src/scbuf.h",
"chars": 2211,
"preview": "#ifndef _SCBUF_H_\n#define _SCBUF_H_\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#incl"
},
{
"path": "src/t.txt",
"chars": 17,
"preview": "Hello \n\n\nthere\n\n\n"
},
{
"path": "src/tm.c",
"chars": 1259,
"preview": "/* Module to create a milisecond timer\n * @author: velorek\n * Last modified: 10/08/2020\n */\n\n#include <stdio.h>\n#include"
},
{
"path": "src/tm.h",
"chars": 1165,
"preview": "/*\n========================================================================\n- HEADER -\nModule to implement a millisecond"
},
{
"path": "src/ui.c",
"chars": 8681,
"preview": "/* Module to create different widgets/gadgets \n * for a Text User Interface\n * TextBox\n * Window\n * Last modified: 15/04"
},
{
"path": "src/ui.h",
"chars": 877,
"preview": "/*\n========================================================================\n- HEADER -\nModule with different UI gadgets "
}
]
About this extraction
This page contains the full source code of the velorek1/c-edit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (163.4 KB), approximately 48.0k tokens, and a symbol index with 129 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.