Usermode/GUI - Hack in attribute reset
[tpg/acess2.git] / Usermode / Applications / gui_terminal_src / display.c
index 0049608..5e3410b 100644 (file)
@@ -5,6 +5,7 @@
  * display.c
  * - Abstract display manipulation methods
  */
+#define DEBUG  0
 #include "include/display.h"
 #include <acess/sys.h> // _SysDebug
 #include <stdlib.h>    // exit
 #include <stdbool.h>
 #include <assert.h>
 
+#if DEBUG
+# define DEBUGS(v...)  _SysDebug(v)
+#else
+# define DEBUGS(v...)  do{}while(0)
+#endif
+
 #define UNIMPLIMENTED()        do{_SysDebug("UNIMPLIMENTED %s", __func__); exit(-1);}while(0)
 
+static inline int MIN(int a, int b) { return (a < b ? a : b); }
+static inline int MAX(int a, int b) { return (a > b ? a : b); }
+
 // === EXTERN ==
 extern tHWND   gMainWindow;
 
@@ -32,15 +42,27 @@ struct sLine {
 };
 
 struct sTerminal {
+       void    *TermState;
+       
         int    ViewCols;
         int    ViewRows;
 
+        int    ScrollTop;
+        int    ScrollRows;
+
         int    CursorRow;
         int    CursorCol;
 
+        int    SavedRow;
+        int    SavedCol;
+
        size_t  CursorByte;
 
        bool    bUsingAltBuf;
+       bool    bHaveSwappedBuffers;
+       
+        int    OtherBufRow;
+        int    OtherBufCol;
 
        size_t  ViewOffset;     
        size_t  TotalLines;
@@ -49,6 +71,9 @@ struct sTerminal {
        struct sLine    *AltBuf;
 };
 
+// === PROTOTYPES ===
+void   Display_int_SetCursor(tTerminal *Term, int Row, int Col);
+
 // === GLOBALS ===
 tTerminal      gMainBuffer;
  int   giCurrentLine;
@@ -74,6 +99,13 @@ tTerminal *Display_Init(int Cols, int Lines, int ExtraScrollbackLines)
        return term;
 }
 
+void *Display_GetTermState(tTerminal *Term) {
+       return Term->TermState;
+}
+void Display_SetTermState(tTerminal *Term, void *State) {
+       Term->TermState = State;
+}
+
 // Return the byte length of a single on-screen character
 size_t _GetCharLength(size_t AvailLength, const char *Text, uint32_t *BaseCodepoint)
 {
@@ -97,6 +129,7 @@ size_t _GetCharLength(size_t AvailLength, const char *Text, uint32_t *BaseCodepo
 tLine *Display_int_GetCurLine(tTerminal *Term)
 {
         int    lineidx = Term->CursorRow + (Term->bUsingAltBuf ? 0 : Term->ViewOffset);
+       //_SysDebug("lineidx = %i", lineidx);
        return (Term->bUsingAltBuf ? Term->AltBuf : Term->PriBuf) + lineidx;
 }
 
@@ -107,32 +140,36 @@ size_t Display_int_PushCharacter(tTerminal *Term, size_t AvailLength, const char
        size_t  charlen = _GetCharLength(AvailLength, Text, &cp);
        bool    bOverwrite = Unicode_IsPrinting(cp);
        
-       _SysDebug("Line %b:%i += %i '%.*s'", Term->bUsingAltBuf, Term->CursorRow, charlen, charlen, Text);
-
        // Figure out how much we need to shift the stream
         int    shift;
        if( bOverwrite ) {
+               //_SysDebug("GetCharLen(%i-%i, %p+%i, NULL)", lineptr->Len, Term->CursorByte,
+               //      lineptr->Data, Term->CursorByte);
+               if( Term->CursorByte )
+                       assert(lineptr->Data);
                size_t nextlen = _GetCharLength(
                        lineptr->Len-Term->CursorByte,
                        lineptr->Data+Term->CursorByte,
                        NULL);
-               _SysDebug("Char at +%i is %i long (%.*s)", Term->CursorByte, nextlen,
-                               nextlen, lineptr->Data+Term->CursorByte);
                shift = charlen - nextlen;
        }
        else {
                shift = charlen;
        }
-       _SysDebug("shift = %i", shift);
        
        // Ensure we have space enough
        if( !lineptr->Data || shift > 0 ) {
                const size_t    size_step = 64;
                assert(shift > 0);
-               lineptr->Size = (lineptr->Len+shift+1 + size_step-1) & ~(size_step-1);
-               void *tmp = realloc(lineptr->Data, lineptr->Size);
-               if( !tmp )      perror("Display_int_PushCharacter - realloc");
-               lineptr->Data = tmp;
+               size_t  newsize = (lineptr->Len+shift+1 + size_step-1) & ~(size_step-1);
+               if( newsize > lineptr->Size ) {
+                       lineptr->Size = newsize;
+                       void *tmp = realloc(lineptr->Data, lineptr->Size);
+                       if( !tmp )      perror("Display_int_PushCharacter - realloc");
+                       //_SysDebug("realloc gave %p from %p for line %i", tmp, lineptr->Data,
+                       //      Term->CursorRow);
+                       lineptr->Data = tmp;
+               }
        }
        
        // Insert into stream
@@ -142,13 +179,11 @@ size_t Display_int_PushCharacter(tTerminal *Term, size_t AvailLength, const char
        }
        else if( shift >= 0 ) {
                size_t  bytes = lineptr->Len - (Term->CursorByte+shift);
-               _SysDebug("memmove(base+%i, base, %i)", shift, bytes);
                memmove(base+shift, base, bytes);
        }
        else {
                shift = -shift;
                size_t  bytes = lineptr->Len - (Term->CursorByte+shift);
-               _SysDebug("memmove(base, base+%i, %i)", shift, bytes);
                memmove(base, base+shift, bytes);
        }
        memcpy(base, Text, charlen);
@@ -167,57 +202,181 @@ size_t Display_int_PushCharacter(tTerminal *Term, size_t AvailLength, const char
 
 void Display_AddText(tTerminal *Term, size_t Length, const char *UTF8Text)
 {
-       _SysDebug("%i '%.*s'", Length, Length, UTF8Text);
+       DEBUGS("%i += %i '%.*s'", Term->CursorRow, Length, Length, UTF8Text);
        while( Length > 0 )
        {
+               if( Term->CursorCol == Term->ViewCols ) {
+                       Display_Newline(Term, 1);
+               }
                size_t used = Display_int_PushCharacter(Term, Length, UTF8Text);
        
                Length -= used;
                UTF8Text += used;
                
                Term->CursorCol ++;
-               if( Term->CursorCol == Term->ViewCols ) {
-                       Display_Newline(Term, 1);
-               }
        }
 }
 
 void Display_Newline(tTerminal *Term, bool bCarriageReturn)
 {
-//     Display_Flush();
-
        // Going down!
-       Term->CursorRow ++;
-       if( Term->CursorRow == Term->TotalLines ) {
-               // TODO: Scrolling
+       if( Term->bUsingAltBuf )
+       {
+               if( Term->CursorRow == Term->ScrollTop + Term->ScrollRows-1 ) {
+                       Display_ScrollDown(Term, 1);
+               }
+               else if( Term->CursorRow == Term->ViewRows-1 ) {
+                       if( Term->ScrollRows == 0 ) {
+                               // Scroll entire buffer
+                               Display_ScrollDown(Term, 1);
+                       }
+                       else {
+                               // Don't go down a line
+                       }
+               }
+               else {
+                       // No scroll needed
+                       Term->CursorRow ++;
+               }
+       }
+       else
+       {
+               if( Term->CursorRow == Term->TotalLines-1 ) {
+                       Display_ScrollDown(Term, 1);
+               }
+               else {
+                       Term->CursorRow ++;
+               }
        }
        
-       if( bCarriageReturn ) {
+       if( bCarriageReturn )
+       {
                Term->CursorByte = 0;
                Term->CursorCol = 0;
-               return ;
        }
+       else
+       {
+               tLine   *line = Display_int_GetCurLine(Term);
+               
+               Term->CursorByte = 0;
+                int    old_col = Term->CursorCol;
+               Term->CursorCol = 0;
 
-       tLine   *line = Display_int_GetCurLine(Term);
-       
-       Term->CursorByte = 0;
-        int    old_col = Term->CursorCol;
-       Term->CursorCol = 0;
+               size_t  ofs = 0;
+               while( Term->CursorCol < old_col && ofs < line->Len ) {
+                       ofs += _GetCharLength(line->Len-ofs, line->Data+ofs, NULL);
+                       Term->CursorCol ++;
+               }
+               Term->CursorByte = ofs;
 
-       size_t  ofs = 0;
-       while( Term->CursorCol < old_col && ofs < line->Len ) {
-               ofs += _GetCharLength(line->Len-ofs, line->Data+ofs, NULL);
-               Term->CursorCol ++;
+               while( Term->CursorCol < old_col )
+                       Display_AddText(Term, 1, " ");
        }
-       Term->CursorByte = ofs;
+}
+
+void Display_SetScrollArea(tTerminal *Term, int Start, int Count)
+{
+       assert(Start >= 0);
+       assert(Count >= 0);
+       Term->ScrollTop = Start;
+       Term->ScrollRows = MIN(Count, Term->ViewRows - Start);
+}
+
+void Display_ScrollDown(tTerminal *Term, int Count)
+{
+        int    top, max;
+       tLine   *buffer;
+       
+       if( Term->bUsingAltBuf )
+       {
+               top = (Term->ScrollRows == 0 ? 0 : Term->ScrollTop);
+               max = (Term->ScrollRows == 0 ? Term->ViewRows : Term->ScrollRows);
+               buffer = Term->AltBuf;
+       }
+       else
+       {
+               top = 0;
+               max = Term->TotalLines;
+               buffer = Term->PriBuf;
+       }
+       
+       assert(Count < max);
+       assert(Count > -max);
 
-       while( Term->CursorCol < old_col )
-               Display_AddText(Term, 1, " ");
+       DEBUGS("Scroll %p %i-%i down by %i", buffer, top, max, Count);
+       
+       buffer += top;
+
+        int    clear_top, clear_max;
+       if( Count < 0 )
+       {
+               // -ve: Scroll up, move buffer contents down
+               Count = -Count;
+               for( int i = max-Count; i < max; i ++ )
+                       free(buffer[i].Data);
+               memmove(buffer+Count, buffer, (max-Count)*sizeof(*buffer));
+               
+               clear_top = 0;
+               clear_max = Count;
+       }
+       else
+       {
+               for( int i = 0; i < Count; i ++ )
+                       free(buffer[i].Data);
+               memmove(buffer, buffer+Count, (max-Count)*sizeof(*buffer));
+               clear_top = max-Count;
+               clear_max = max;
+       }
+       // Clear exposed lines
+       for( int i = clear_top; i < clear_max; i ++ )
+       {
+               buffer[i].Data = NULL;
+               buffer[i].Len = 0;
+               buffer[i].Size = 0;
+               buffer[i].IsDirty = true;
+       }
+       // Send scroll command to GUI
+       AxWin3_RichText_ScrollRange(gMainWindow, top, max, Count);
+       
+       Display_int_SetCursor(Term, Term->CursorRow, Term->CursorCol);
 }
 
 void Display_SetCursor(tTerminal *Term, int Row, int Col)
 {
-       UNIMPLIMENTED();
+       assert(Row >= 0);
+       assert(Col >= 0);
+
+       DEBUGS("Set cursor R%i,C%i", Row, Col); 
+
+       if( !Term->bUsingAltBuf ) {
+               _SysDebug("NOTE: Using \\e[%i;%iH outside of alternat buffer is undefined", Row, Col);
+       }
+       
+       // NOTE: This may be interesting outside of AltBuffer
+       Display_int_SetCursor(Term, Row, Col);  
+}
+void Display_int_SetCursor(tTerminal *Term, int Row, int Col)
+{
+       Term->CursorRow = Row;
+       tLine   *line = Display_int_GetCurLine(Term);
+       size_t ofs = 0;
+        int    i;
+       for( i = 0; i < Col; i ++ )
+       {
+       
+               size_t clen = _GetCharLength(line->Len-ofs, line->Data+ofs, NULL);
+               if( clen == 0 ) {
+                       break;
+               }
+               ofs += clen;
+       }
+       Term->CursorCol = i;
+       Term->CursorByte = ofs;
+       // Move to exactly the column specified
+       for( ; i < Col; i ++ ) {
+               Display_int_PushCharacter(Term, 1, " ");
+               Term->CursorCol ++;
+       }
 }
 
 void Display_MoveCursor(tTerminal *Term, int RelRow, int RelCol)
@@ -250,6 +409,16 @@ void Display_MoveCursor(tTerminal *Term, int RelRow, int RelCol)
        }
 }
 
+void Display_SaveCursor(tTerminal *Term)
+{
+       Term->SavedRow = Term->CursorRow;
+       Term->SavedCol = Term->CursorCol;
+}
+void Display_RestoreCursor(tTerminal *Term)
+{
+       Display_SetCursor(Term, Term->SavedRow, Term->SavedCol);
+}
+
 void Display_ClearLine(tTerminal *Term, int Dir)       // 0: All, 1: Forward, -1: Reverse
 {
        if( Dir == 0 )
@@ -260,6 +429,8 @@ void Display_ClearLine(tTerminal *Term, int Dir)    // 0: All, 1: Forward, -1: Reve
                        free(line->Data);
                line->Data = NULL;
                line->IsDirty = true;
+               Term->CursorCol = 0;
+               Term->CursorByte = 0;
        }
        else if( Dir == 1 )
        {
@@ -296,6 +467,11 @@ void Display_ClearLines(tTerminal *Term, int Dir)  // 0: All, 1: Forward, -1: Rev
        }
 }
 
+void Display_ResetAttributes(tTerminal *Term)
+{
+       Display_SetForeground(Term, 0xFFFFFF);
+       Display_SetBackground(Term, 0x000000);
+}
 void Display_SetForeground(tTerminal *Term, uint32_t RGB)
 {
        char    buf[7+1];
@@ -312,21 +488,57 @@ void Display_SetBackground(tTerminal *Term, uint32_t RGB)
 
 void Display_Flush(tTerminal *Term)
 {
+        int    viewOfs = (Term->bUsingAltBuf ? 0 : Term->ViewOffset);
+       tLine   *buffer = (Term->bUsingAltBuf ? Term->AltBuf : Term->PriBuf );
+       AxWin3_RichText_SetLineCount(gMainWindow, (Term->bUsingAltBuf ? Term->ViewRows : Term->TotalLines));
        for( int i = 0; i < Term->ViewRows; i ++ )
        {
-                int    line = (Term->ViewOffset + i) % Term->TotalLines;
-               tLine   *lineptr = &Term->PriBuf[line];
-               if( !lineptr->IsDirty )
+                int    line = (viewOfs + i) % Term->TotalLines;
+               tLine   *lineptr = &buffer[line];
+               // Swapping buffers should cause a full resend
+               if( !Term->bHaveSwappedBuffers && !lineptr->IsDirty )
                        continue;
-               _SysDebug("Line %i+%i '%.*s'", Term->ViewOffset, i, lineptr->Len, lineptr->Data);
-               AxWin3_RichText_SendLine(gMainWindow, Term->ViewOffset + i, lineptr->Data );
-               lineptr->IsDirty = 0;
+               DEBUGS("Line %i+%i %p '%.*s'", viewOfs, i, lineptr->Data, lineptr->Len, lineptr->Data);
+               AxWin3_RichText_SendLine(gMainWindow, viewOfs + i,
+                       lineptr->Data ? lineptr->Data : "" );
+               lineptr->IsDirty = false;
        }
        AxWin3_RichText_SetCursorPos(gMainWindow, Term->CursorRow, Term->CursorCol);
+       Term->bHaveSwappedBuffers = false;
 }
 
 void Display_ShowAltBuffer(tTerminal *Term, bool AltBufEnabled)
 {
-       UNIMPLIMENTED();
+       if( Term->bUsingAltBuf == AltBufEnabled )
+       {
+               // Nothing to do, so do nothing
+               return ;
+       }
+
+       int row = Term->OtherBufRow;
+       int col = Term->OtherBufCol;
+       Term->OtherBufRow = Term->CursorRow;
+       Term->OtherBufCol = Term->CursorCol;
+       
+       Term->bUsingAltBuf = AltBufEnabled;
+       Term->bHaveSwappedBuffers = true;
+       if( AltBufEnabled )
+       {
+               if( !Term->AltBuf )
+               {
+                       Term->AltBuf = calloc( sizeof(Term->AltBuf[0]), Term->ViewRows );
+               }
+               AxWin3_RichText_SetLineCount(gMainWindow, Term->ViewRows);
+       }
+       else
+       {
+               AxWin3_RichText_SetLineCount(gMainWindow, Term->TotalLines);
+       }
+       Display_int_SetCursor(Term, row, col);
+}
+
+void Display_SetTitle(tTerminal *Term, const char *Title)
+{
+       _SysDebug("TODO: Set window title to '%s'", Title);
 }
 

UCC git Repository :: git.ucc.asn.au