X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FApplications%2Fgui_shell_src%2Fdisplay.c;h=0049608874b77ccb826371548d94a0d44c457fa4;hb=704880994998a15d512860b5bb68d4b7285db510;hp=1665e448d8534d347372d3423eb11e21dee7ee8d;hpb=be5123fe1f4aa66b76ce8ef589362ad21b6bbf72;p=tpg%2Facess2.git diff --git a/Usermode/Applications/gui_shell_src/display.c b/Usermode/Applications/gui_shell_src/display.c index 1665e448..00496088 100644 --- a/Usermode/Applications/gui_shell_src/display.c +++ b/Usermode/Applications/gui_shell_src/display.c @@ -13,17 +13,44 @@ #include #include #include +#include +#include #define UNIMPLIMENTED() do{_SysDebug("UNIMPLIMENTED %s", __func__); exit(-1);}while(0) // === EXTERN == extern tHWND gMainWindow; +typedef struct sLine tLine; + +struct sLine { + char *Data; + // TODO: Cache offsets to avoid scan-forward + size_t Len; + size_t Size; + bool IsDirty; +}; + +struct sTerminal { + int ViewCols; + int ViewRows; + + int CursorRow; + int CursorCol; + + size_t CursorByte; + + bool bUsingAltBuf; + + size_t ViewOffset; + size_t TotalLines; + struct sLine *PriBuf; + + struct sLine *AltBuf; +}; + // === GLOBALS === - int giDisplayCols; - int giDisplayLines; - int giDisplayTotalLines; - int giDisplayBufSize; +tTerminal gMainBuffer; int giCurrentLine; int giCurrentLinePos; // byte offset, not column int giCurrentCol; @@ -34,148 +61,205 @@ char **gasDisplayLines; char *gabDisplayLinesDirty; // === CODE === -void Display_Init(int Cols, int Lines, int ExtraScrollbackLines) +tTerminal *Display_Init(int Cols, int Lines, int ExtraScrollbackLines) { - giDisplayCols = Cols; - giDisplayLines = Lines; - giDisplayTotalLines = Lines + ExtraScrollbackLines; - gasDisplayLines = calloc( sizeof(char*), (Lines + ExtraScrollbackLines) ); - gaiDisplayLineSizes = calloc( sizeof(int), (Lines + ExtraScrollbackLines) ); - gabDisplayLinesDirty = calloc( sizeof(char), (Lines + ExtraScrollbackLines) ); + tTerminal *term = &gMainBuffer; + term->ViewCols = Cols; + term->ViewRows = Lines; + term->TotalLines = Lines + ExtraScrollbackLines; + term->PriBuf = calloc( sizeof(tLine), (Lines + ExtraScrollbackLines) ); AxWin3_RichText_SetLineCount(gMainWindow, Lines+ExtraScrollbackLines); AxWin3_RichText_SetCursorType(gMainWindow, 1); // TODO: enum + return term; } -void Display_int_PushString(int Length, const char *Text) +// Return the byte length of a single on-screen character +size_t _GetCharLength(size_t AvailLength, const char *Text, uint32_t *BaseCodepoint) { - _SysDebug("Line %i += %i '%*C'", giCurrentLine, Length, Length, Text); - if( !gasDisplayLines[giCurrentLine] || giCurrentLinePos + Length >= gaiDisplayLineSizes[giCurrentLine] ) + if( !AvailLength ) + return 0; + + size_t charlen = ReadUTF8(Text, BaseCodepoint); + + while(charlen < AvailLength) { - int reqsize = giCurrentLinePos + Length; - gaiDisplayLineSizes[giCurrentLine] = (reqsize + 32-1) & ~(32-1); - void *tmp = realloc(gasDisplayLines[giCurrentLine], gaiDisplayLineSizes[giCurrentLine]); - if( !tmp ) perror("Display_AddText - realloc"); - gasDisplayLines[giCurrentLine] = tmp; + uint32_t cp; + size_t size = ReadUTF8(Text+charlen, &cp); + if( Unicode_IsPrinting(cp) ) + break; + charlen += size; + } + + return charlen; +} + +tLine *Display_int_GetCurLine(tTerminal *Term) +{ + int lineidx = Term->CursorRow + (Term->bUsingAltBuf ? 0 : Term->ViewOffset); + return (Term->bUsingAltBuf ? Term->AltBuf : Term->PriBuf) + lineidx; +} + +size_t Display_int_PushCharacter(tTerminal *Term, size_t AvailLength, const char *Text) +{ + tLine *lineptr = Display_int_GetCurLine(Term); + uint32_t cp; + 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 ) { + 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; + } + + // Insert into stream + char *base = lineptr->Data + Term->CursorByte; + if( Term->CursorByte == lineptr->Len ) { + // No shifting needed + } + 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); + lineptr->IsDirty = true; + lineptr->Len += shift; + lineptr->Data[lineptr->Len] = 0; // NULL Terminate - memcpy(gasDisplayLines[giCurrentLine]+giCurrentLinePos, Text, Length); - gabDisplayLinesDirty[giCurrentLine] = 1; - gasDisplayLines[giCurrentLine][giCurrentLinePos+Length] = 0; - giCurrentLinePos += Length; + Term->CursorByte += charlen; + // HACKY: Prevents the CursorCol++ in Display_AddText from having an effect + if( !bOverwrite ) + Term->CursorCol --; + + return charlen; } -void Display_AddText(int Length, const char *UTF8Text) +void Display_AddText(tTerminal *Term, size_t Length, const char *UTF8Text) { _SysDebug("%i '%.*s'", Length, Length, UTF8Text); - // Copy as many characters (not bytes, have to trim off the last char) as we can to the current line - // - then roll over to the next line while( Length > 0 ) { - int space = giDisplayCols - giCurrentCol; - int bytes = 0; - while( space && bytes < Length ) - { - uint32_t cp; - bytes += ReadUTF8(UTF8Text+bytes, &cp); - if( Unicode_IsPrinting(cp) ) { - space --; - giCurrentCol ++; - } - } + size_t used = Display_int_PushCharacter(Term, Length, UTF8Text); - Display_int_PushString(bytes, UTF8Text); - - UTF8Text += bytes; - _SysDebug("Length(%i) -= bytes(%i)", Length, bytes); - Length -= bytes; - if( Length != 0 ) - { - // Next line - giCurrentLinePos = 0; - giCurrentCol = 0; - giCurrentLine ++; + Length -= used; + UTF8Text += used; + + Term->CursorCol ++; + if( Term->CursorCol == Term->ViewCols ) { + Display_Newline(Term, 1); } } } -void Display_Newline(int bCarriageReturn) +void Display_Newline(tTerminal *Term, bool bCarriageReturn) { - Display_Flush(); +// Display_Flush(); // Going down! - giCurrentLine ++; - if( giCurrentLine == giDisplayLines ) - giCurrentLine = 0; - if( giCurrentLine == giFirstLine ) - { - giFirstLine ++; - if(giFirstLine == giDisplayLines) - giFirstLine = 0; + Term->CursorRow ++; + if( Term->CursorRow == Term->TotalLines ) { + // TODO: Scrolling } if( bCarriageReturn ) { - giCurrentLinePos = 0; - giCurrentCol = 0; + Term->CursorByte = 0; + Term->CursorCol = 0; + return ; } - else { - giCurrentLinePos = 0; - int i = giCurrentCol; - if( !gasDisplayLines[giCurrentLine] ) - { - giCurrentCol = 0; - while(i--) - Display_AddText(1, " "); - } - else - { - while( i -- ) - { - uint32_t cp; - giCurrentLinePos += ReadUTF8(gasDisplayLines[giCurrentLine]+giCurrentLinePos, &cp); - if( !Unicode_IsPrinting(cp) ) - i ++; - } - } + + 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; + + while( Term->CursorCol < old_col ) + Display_AddText(Term, 1, " "); } -void Display_SetCursor(int Row, int Col) +void Display_SetCursor(tTerminal *Term, int Row, int Col) { UNIMPLIMENTED(); } -void Display_MoveCursor(int RelRow, int RelCol) +void Display_MoveCursor(tTerminal *Term, int RelRow, int RelCol) { - if( RelRow < 0 ) + if( RelRow != 0 ) { - for( ; RelRow < 0; RelRow ++ ) - { - uint32_t cp; - int delta = ReadUTF8Rev(gasDisplayLines[giCurrentLine], giCurrentLinePos, &cp); - if( !Unicode_IsPrinting(cp) ) - RelRow --; - else - giCurrentCol --; - giCurrentLinePos -= delta; - } + UNIMPLIMENTED(); } - else + + if( RelCol != 0 ) { - UNIMPLIMENTED(); + int req_col = Term->CursorCol + RelCol; + if( req_col < 0 ) req_col = 0; + if( req_col > Term->ViewCols ) req_col = Term->ViewCols; + + tLine *line = Display_int_GetCurLine(Term); + size_t ofs = 0; + for( int i = 0; i < req_col; i ++ ) + { + size_t clen = _GetCharLength(line->Len-ofs, line->Data+ofs, NULL); + if( clen == 0 ) { + req_col = i; + break; + } + ofs += clen; + } + + Term->CursorCol = req_col; + Term->CursorByte = ofs; } } -void Display_ClearLine(int Dir) // 0: All, 1: Forward, -1: Reverse +void Display_ClearLine(tTerminal *Term, int Dir) // 0: All, 1: Forward, -1: Reverse { if( Dir == 0 ) { + tLine *line = Display_int_GetCurLine(Term); // Completely clear line - if( gasDisplayLines[giCurrentLine] ) - free(gasDisplayLines[giCurrentLine]); - gasDisplayLines[giCurrentLine] = NULL; - gabDisplayLinesDirty[giCurrentLine] = 1; + if( line->Data ) + free(line->Data); + line->Data = NULL; + line->IsDirty = true; } else if( Dir == 1 ) { @@ -191,7 +275,7 @@ void Display_ClearLine(int Dir) // 0: All, 1: Forward, -1: Reverse } } -void Display_ClearLines(int Dir) // 0: All, 1: Forward, -1: Reverse +void Display_ClearLines(tTerminal *Term, int Dir) // 0: All, 1: Forward, -1: Reverse { if( Dir == 0 ) { @@ -212,38 +296,36 @@ void Display_ClearLines(int Dir) // 0: All, 1: Forward, -1: Reverse } } -void Display_SetForeground(uint32_t RGB) +void Display_SetForeground(tTerminal *Term, uint32_t RGB) { char buf[7+1]; sprintf(buf, "\1%06x", RGB&0xFFFFFF); - Display_int_PushString(7, buf); + Display_AddText(Term, 7, buf); } -void Display_SetBackground(uint32_t RGB) +void Display_SetBackground(tTerminal *Term, uint32_t RGB) { char buf[7+1]; sprintf(buf, "\2%06x", RGB&0xFFFFFF); - Display_int_PushString(7, buf); + Display_AddText(Term, 7, buf); } -void Display_Flush(void) +void Display_Flush(tTerminal *Term) { - int i; - for( i = 0; i < giDisplayCols; i ++ ) + for( int i = 0; i < Term->ViewRows; i ++ ) { - int line = (giFirstLine + i) % giDisplayTotalLines; - if( !gabDisplayLinesDirty[line] ) + int line = (Term->ViewOffset + i) % Term->TotalLines; + tLine *lineptr = &Term->PriBuf[line]; + if( !lineptr->IsDirty ) continue; - _SysDebug("Line %i+%i '%s'", giFirstLine, i, gasDisplayLines[line]); - AxWin3_RichText_SendLine(gMainWindow, giFirstLine + i, gasDisplayLines[line] ); - gabDisplayLinesDirty[line] = 0; + _SysDebug("Line %i+%i '%.*s'", Term->ViewOffset, i, lineptr->Len, lineptr->Data); + AxWin3_RichText_SendLine(gMainWindow, Term->ViewOffset + i, lineptr->Data ); + lineptr->IsDirty = 0; } - - // force redraw? - AxWin3_RichText_SetCursorPos(gMainWindow, giCurrentLine, giCurrentCol); + AxWin3_RichText_SetCursorPos(gMainWindow, Term->CursorRow, Term->CursorCol); } -void Display_ShowAltBuffer(int AltBufEnabled) +void Display_ShowAltBuffer(tTerminal *Term, bool AltBufEnabled) { UNIMPLIMENTED(); }