Skip to content

Instantly share code, notes, and snippets.

@ComputerNerd
Last active August 29, 2015 14:14
Show Gist options
  • Save ComputerNerd/411f38726467ee519afe to your computer and use it in GitHub Desktop.
Save ComputerNerd/411f38726467ee519afe to your computer and use it in GitHub Desktop.
Progress on the text editor
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fxcg/display.h>
#include <fxcg/keyboard.h>
#include "textEditGUI.hpp"
#include "graphicsProvider.hpp"
#define CURSOR_BLINK_RATE 128 //in ticks based on RTC_GetTicks();
#define REPEAT_WAIT 128 //see comment for CURSOR_BLINK_RATE
struct linetxt{
char*ptr;//May not be null terminated.
size_t len;//In bytes not characters.
bool newline;
};
struct cursor{
unsigned line;
unsigned chr;//first character on line. In bytes not elements.
};
enum textSize{NORMAL /* PrintMint */,LARGE /* PrintCXY */,TEXTSIZES};
static const int textHeight[]={18,24};
static const int spaceWidth[]={7,18};
static const unsigned maxLinesOnScreen[]={11,8};
static unsigned tabOffset(unsigned tw,unsigned pxsz,unsigned pos){
unsigned posold=pos;
tw*=pxsz;
if(!(pos%tw))
pos+=pxsz;
pos+=tw-(pos%tw);
return pos-posold;
}
#define TEXT_MAX_WIDTH (384-6) //To account for the vertical scrollbar.
static int drawTextLine(const struct linetxt*line,unsigned offset,textSize txtSize,int y){
int x=0;
char*ptr=line->ptr;
while(offset--){
if(*ptr==0)
goto skipLoop;
++ptr;
}
if(*ptr==0)
goto skipLoop;
for(size_t ln=line->len;ln;){
if(*ptr==0){
if(x+spaceWidth[txtSize]>=TEXT_MAX_WIDTH)
break;
drawRectangle(x,y+24,spaceWidth[txtSize],textHeight[txtSize],31<<11);
x+=spaceWidth[txtSize];
++ptr;
--ln;
}else if(*ptr=='\t'){
unsigned off=tabOffset(4,spaceWidth[txtSize],x);
if(x+off>=TEXT_MAX_WIDTH)
break;
drawRectangle(x,y+24,off,textHeight[txtSize],0xFFFF);
x+=off;
++ptr;
--ln;
}else{
switch(txtSize){
case NORMAL:
{
unsigned short width;
void*gl;
if(*ptr&128){
unsigned short*p=(unsigned short*)ptr;
gl=GetMiniGlyphPtr(*p,&width);
}else
gl=GetMiniGlyphPtr(*ptr,&width);
if(x+width>=TEXT_MAX_WIDTH)
break;
else{
PrintMiniGlyph(x,y,gl,0,width,0,0,0,0,0,0xFFFF,0);
x+=width;
}
}
break;
case LARGE:
if(x+18>=TEXT_MAX_WIDTH)
break;
else{
PrintCXY(x,y,ptr,0,-1,0,0xFFFF,1,0);
x+=18;
}
break;
}
if(*ptr&128){
ptr+=2;
if(ln>=2)
ln-=2;
else
break;
}else{
++ptr;
--ln;
}
}
}
skipLoop:
if(x<TEXT_MAX_WIDTH)
drawRectangle(x,y+24,TEXT_MAX_WIDTH-x,textHeight[txtSize],0xFFFF);
return y+textHeight[txtSize];
}
static void drawTextLines(const struct linetxt*firstLine,textSize txtSize,unsigned linesAmt){
int y=0;
unsigned toDraw=maxLinesOnScreen[txtSize];
if(toDraw>linesAmt)
toDraw=linesAmt;
while(toDraw--){
y=drawTextLine(firstLine,0,txtSize,y);
++firstLine;
}
y+=24;//Account for the status area
if(y<216)
drawRectangle(0,y,384,216-y,0xFFFF);
}
static char*nextWord(char*start){//Returns zero if a newline character is before any words
char*end=start;
if(*end=='\r'||*end=='\n')
return 0;
for(;;){
if(*end&128)
end+=2;
else if(!isspace(*end))
break;
else
++end;
}
return end;
}
static const char*strnchrSkipMB(const char*str,size_t len,char chr){
while(len){
if(*str&128){
str+=2;
if(len>=2)
len-=2;
else
return 0;
}else if(*str==chr)
return str;
else{
++str;
--len;
}
}
return 0;
}
static unsigned insertChar(char*start,char*pos,unsigned ln,char c){
memmove(pos+1,pos,ln-(pos-start)+1);
*pos=c;
return ln+1;
}
static bool chkLineAmt(struct linetxt**lines,unsigned&maxLines,unsigned&linesAmt){
if(linesAmt>=(maxLines-1)){
maxLines+=256;
*lines=(struct linetxt*)realloc(*lines,maxLines*sizeof(struct linetxt));
}
return *lines?true:false;
}
static bool contigousToLines(char*buf,char*bufend,struct linetxt**lines,textSize txtSize,unsigned&maxLines,unsigned&linesAmt,size_t txtlen,bool wordWrap){
linesAmt=0;
//Separate the text pointed by buf by line in order to allow for editing an existing text file.
for(char*ptr=buf;txtlen;){
if(!chkLineAmt(lines,maxLines,linesAmt))
return false;
lines[0][linesAmt].ptr=ptr;
char*ptrnew=(char*)strnchrSkipMB(ptr,txtlen,'\n');
if(ptrnew){
lines[0][linesAmt].len=ptrnew-ptr;
if(lines[0][linesAmt].ptr[lines[0][linesAmt].len-1]=='\r')
--lines[0][linesAmt].len;
txtlen-=ptrnew+1-ptr;
ptr=ptrnew+1;
lines[0][linesAmt++].newline=true;
}else{
lines[0][linesAmt].newline=false;
lines[0][linesAmt++].len=txtlen;
break;
}
HourGlass();
}
return true;
}
static int linesToContigous(char*buf,char*bufend,struct linetxt*lines,textSize txtSize,unsigned linesAmt){
while(linesAmt--){
HourGlass();
}
return 0;
}
int textEditGUI(char*buf,size_t buflen,size_t startlen){
/* The speed of random insertions and deletions in a text editor is
* important. This code trades off some processing time upfront for
* faster text editing. Each line is not contiguous in regards to the
* entire text file. When the users leaves the text editor the text is
* rearranged in place in order to form a contiguous text file.
* This code is designed to not rely on null termination of strings and
* instead stores the length of the text.*/
struct linetxt*lines=(struct linetxt*)malloc(256*sizeof(struct linetxt));
if(!lines)
return -1;
struct cursor cursor;
memset(&cursor,0,sizeof(struct cursor));
unsigned maxLines=256;//How many lines before next reallocation
unsigned linesAmt;
textSize txtSize=NORMAL;
char*bufend=buf+buflen;
bool CRLF;//If a CRLF in the text file is detected when the user presses return insert a CRLF instead of a LF.
{
char*ptr=(char*)strnchrSkipMB(buf,buflen,'\r');
CRLF=ptr&&ptr[1]=='\n';
}
if(!contigousToLines(buf,bufend,&lines,txtSize,maxLines,linesAmt,startlen))
return -1;//Failure
bool exit=false,cancel=false;
struct scrollbar sb;
sb.I1 = 0;
sb.I5 = 0;
sb.indicatormaximum = linesAmt;
sb.indicatorheight = 1;
sb.barheight = 216;
sb.bartop = 0;
sb.barleft = 384 - 6;
sb.barwidth = 6;
for(unsigned i=192*384/2,*v=(unsigned*)0xA8004800;i--;*v++=0xFFFFFFFF);
while(!exit){
//Draw the onscreen text.
if(linesAmt>=maxLinesOnScreen[txtSize]+1){
if(cursor.line>(linesAmt-maxLinesOnScreen[txtSize]+1))
cursor.line=linesAmt-maxLinesOnScreen[txtSize]+1;
}else
cursor.line=0;
sb.indicatorpos = cursor.line;
drawTextLines(lines+cursor.line,txtSize,linesAmt-cursor.line);
Scrollbar(&sb);
int key;
GetKey(&key);
switch(key){
case KEY_CTRL_F1:
exit=true;
break;
case KEY_CTRL_F2:
case KEY_CTRL_EXIT:
exit=cancel=true;
break;
case KEY_CTRL_F3:
txtSize=(enum textSize)(int(txtSize)+1);
if(txtSize>LARGE)
txtSize=NORMAL;
break;
case KEY_CTRL_UP:
if(cursor.line>0)
--cursor.line;
break;
case KEY_CTRL_DOWN:
++cursor.line;
break;
}
}
//Convert the text in place to be contiguous
int len=linesToContigous(buf,bufend,lines,txtSize,linesAmt);
free(lines);
return cancel?-1:len;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment