3 * - By John Hodge (thePowersGang)
6 * - Abstract display manipulation methods
8 #include "include/display.h"
9 #include <acess/sys.h> // _SysDebug
10 #include <stdlib.h> // exit
14 #include <axwin3/axwin.h>
15 #include <axwin3/richtext.h>
19 #define UNIMPLIMENTED() do{_SysDebug("UNIMPLIMENTED %s", __func__); exit(-1);}while(0)
22 extern tHWND gMainWindow;
24 typedef struct sLine tLine;
28 // TODO: Cache offsets to avoid scan-forward
53 tTerminal gMainBuffer;
55 int giCurrentLinePos; // byte offset, not column
57 int giFirstDispLine; // First displayed line
58 int giFirstLine; // Ring buffer start
59 char **gasDisplayLines;
60 int *gaiDisplayLineSizes;
61 char *gabDisplayLinesDirty;
64 tTerminal *Display_Init(int Cols, int Lines, int ExtraScrollbackLines)
66 tTerminal *term = &gMainBuffer;
67 term->ViewCols = Cols;
68 term->ViewRows = Lines;
69 term->TotalLines = Lines + ExtraScrollbackLines;
70 term->PriBuf = calloc( sizeof(tLine), (Lines + ExtraScrollbackLines) );
72 AxWin3_RichText_SetLineCount(gMainWindow, Lines+ExtraScrollbackLines);
73 AxWin3_RichText_SetCursorType(gMainWindow, 1); // TODO: enum
77 // Return the byte length of a single on-screen character
78 size_t _GetCharLength(size_t AvailLength, const char *Text, uint32_t *BaseCodepoint)
83 size_t charlen = ReadUTF8(Text, BaseCodepoint);
85 while(charlen < AvailLength)
88 size_t size = ReadUTF8(Text+charlen, &cp);
89 if( Unicode_IsPrinting(cp) )
97 tLine *Display_int_GetCurLine(tTerminal *Term)
99 int lineidx = Term->CursorRow + (Term->bUsingAltBuf ? 0 : Term->ViewOffset);
100 return (Term->bUsingAltBuf ? Term->AltBuf : Term->PriBuf) + lineidx;
103 size_t Display_int_PushCharacter(tTerminal *Term, size_t AvailLength, const char *Text)
105 tLine *lineptr = Display_int_GetCurLine(Term);
107 size_t charlen = _GetCharLength(AvailLength, Text, &cp);
108 bool bOverwrite = Unicode_IsPrinting(cp);
110 _SysDebug("Line %b:%i += %i '%.*s'", Term->bUsingAltBuf, Term->CursorRow, charlen, charlen, Text);
112 // Figure out how much we need to shift the stream
115 size_t nextlen = _GetCharLength(
116 lineptr->Len-Term->CursorByte,
117 lineptr->Data+Term->CursorByte,
119 _SysDebug("Char at +%i is %i long (%.*s)", Term->CursorByte, nextlen,
120 nextlen, lineptr->Data+Term->CursorByte);
121 shift = charlen - nextlen;
126 _SysDebug("shift = %i", shift);
128 // Ensure we have space enough
129 if( !lineptr->Data || shift > 0 ) {
130 const size_t size_step = 64;
132 lineptr->Size = (lineptr->Len+shift+1 + size_step-1) & ~(size_step-1);
133 void *tmp = realloc(lineptr->Data, lineptr->Size);
134 if( !tmp ) perror("Display_int_PushCharacter - realloc");
138 // Insert into stream
139 char *base = lineptr->Data + Term->CursorByte;
140 if( Term->CursorByte == lineptr->Len ) {
141 // No shifting needed
143 else if( shift >= 0 ) {
144 size_t bytes = lineptr->Len - (Term->CursorByte+shift);
145 _SysDebug("memmove(base+%i, base, %i)", shift, bytes);
146 memmove(base+shift, base, bytes);
150 size_t bytes = lineptr->Len - (Term->CursorByte+shift);
151 _SysDebug("memmove(base, base+%i, %i)", shift, bytes);
152 memmove(base, base+shift, bytes);
154 memcpy(base, Text, charlen);
155 lineptr->IsDirty = true;
156 lineptr->Len += shift;
157 lineptr->Data[lineptr->Len] = 0; // NULL Terminate
159 Term->CursorByte += charlen;
161 // HACKY: Prevents the CursorCol++ in Display_AddText from having an effect
168 void Display_AddText(tTerminal *Term, size_t Length, const char *UTF8Text)
170 _SysDebug("%i '%.*s'", Length, Length, UTF8Text);
173 size_t used = Display_int_PushCharacter(Term, Length, UTF8Text);
179 if( Term->CursorCol == Term->ViewCols ) {
180 Display_Newline(Term, 1);
185 void Display_Newline(tTerminal *Term, bool bCarriageReturn)
191 if( Term->CursorRow == Term->TotalLines ) {
195 if( bCarriageReturn ) {
196 Term->CursorByte = 0;
201 tLine *line = Display_int_GetCurLine(Term);
203 Term->CursorByte = 0;
204 int old_col = Term->CursorCol;
208 while( Term->CursorCol < old_col && ofs < line->Len ) {
209 ofs += _GetCharLength(line->Len-ofs, line->Data+ofs, NULL);
212 Term->CursorByte = ofs;
214 while( Term->CursorCol < old_col )
215 Display_AddText(Term, 1, " ");
218 void Display_SetCursor(tTerminal *Term, int Row, int Col)
223 void Display_MoveCursor(tTerminal *Term, int RelRow, int RelCol)
232 int req_col = Term->CursorCol + RelCol;
233 if( req_col < 0 ) req_col = 0;
234 if( req_col > Term->ViewCols ) req_col = Term->ViewCols;
236 tLine *line = Display_int_GetCurLine(Term);
238 for( int i = 0; i < req_col; i ++ )
240 size_t clen = _GetCharLength(line->Len-ofs, line->Data+ofs, NULL);
248 Term->CursorCol = req_col;
249 Term->CursorByte = ofs;
253 void Display_ClearLine(tTerminal *Term, int Dir) // 0: All, 1: Forward, -1: Reverse
257 tLine *line = Display_int_GetCurLine(Term);
258 // Completely clear line
262 line->IsDirty = true;
266 // Forward clear (truncate)
270 // Reverse clear (replace with spaces)
278 void Display_ClearLines(tTerminal *Term, int Dir) // 0: All, 1: Forward, -1: Reverse
282 // Push giDisplayLines worth of empty lines
283 // Move cursor back up by giDisplayLines
287 // Push (giDisplayLines - (giCurrentLine-giFirstDispLine)) and reverse
291 // Reverse clear (replace with spaces)
299 void Display_SetForeground(tTerminal *Term, uint32_t RGB)
302 sprintf(buf, "\1%06x", RGB&0xFFFFFF);
303 Display_AddText(Term, 7, buf);
306 void Display_SetBackground(tTerminal *Term, uint32_t RGB)
309 sprintf(buf, "\2%06x", RGB&0xFFFFFF);
310 Display_AddText(Term, 7, buf);
313 void Display_Flush(tTerminal *Term)
315 for( int i = 0; i < Term->ViewRows; i ++ )
317 int line = (Term->ViewOffset + i) % Term->TotalLines;
318 tLine *lineptr = &Term->PriBuf[line];
319 if( !lineptr->IsDirty )
321 _SysDebug("Line %i+%i '%.*s'", Term->ViewOffset, i, lineptr->Len, lineptr->Data);
322 AxWin3_RichText_SendLine(gMainWindow, Term->ViewOffset + i, lineptr->Data );
323 lineptr->IsDirty = 0;
325 AxWin3_RichText_SetCursorPos(gMainWindow, Term->CursorRow, Term->CursorCol);
328 void Display_ShowAltBuffer(tTerminal *Term, bool AltBufEnabled)