Usermode/AxWin3 - A couple more icons, render fixes
[tpg/acess2.git] / Usermode / Applications / axwin3_src / WM / renderers / richtext.c
index eca5765..8f69c9c 100644 (file)
@@ -7,25 +7,32 @@
  */
 #include <common.h>
 #include <wm_renderer.h>
+#include <wm_messages.h>
 #include <richtext_messages.h>
 #include <stdio.h>     // sscanf
+#include <string.h>    // memcpy
 
 #define LINES_PER_BLOCK        30
 
 // === TYPES ===
-typedef struct sRichText_LineBlock
+typedef struct sRichText_Line
 {
-       struct sRichText_LineBlock      *Next;
-        int    FirstLine;
-       char    *Lines[LINES_PER_BLOCK];
-} tRichText_LineBlock;
+       struct sRichText_Line   *Next;
+       struct sRichText_Line   *Prev;
+        int    Num;
+       // TODO: Pre-rendered cache?
+       short   ByteLength;
+       short   Space;
+       char    Data[];
+} tRichText_Line;
 typedef struct sRichText_Window
 {
         int    DispLines, DispCols;
         int    FirstVisRow, FirstVisCol;
         int    nLines, nCols;
         int    CursorRow, CursorCol;
-       tRichText_LineBlock     FirstBlock;
+       tRichText_Line  *FirstLine;
+       tRichText_Line  *FirstVisLine;
        tColour DefaultFG;
        tColour DefaultBG;
        tFont   *Font;
@@ -36,15 +43,24 @@ typedef struct sRichText_Window
 // === PROTOTYPES ===
  int   Renderer_RichText_Init(void);
 tWindow        *Renderer_RichText_Create(int Flags);
+void   Renderer_RichText_Destroy(tWindow *Window);
 void   Renderer_RichText_Redraw(tWindow *Window);
+ int   Renderer_RichText_HandleIPC_SetAttr(tWindow *Window, size_t Len, const void *Data);
+ int   Renderer_RichText_HandleIPC_WriteLine(tWindow *Window, size_t Len, const void *Data);
  int   Renderer_RichText_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data);
 
 // === GLOBALS ===
 tWMRenderer    gRenderer_RichText = {
        .Name = "RichText",
        .CreateWindow   = Renderer_RichText_Create,
+       .DestroyWindow  = Renderer_RichText_Destroy,
        .Redraw         = Renderer_RichText_Redraw,
-       .HandleMessage  = Renderer_RichText_HandleMessage
+       .HandleMessage  = Renderer_RichText_HandleMessage,
+       .nIPCHandlers = N_IPC_RICHTEXT,
+       .IPCHandlers = {
+               [IPC_RICHTEXT_SETATTR] = Renderer_RichText_HandleIPC_SetAttr,
+               [IPC_RICHTEXT_WRITELINE] = Renderer_RichText_HandleIPC_WriteLine
+       }
 };
 
 // === CODE ===
@@ -60,18 +76,41 @@ tWindow *Renderer_RichText_Create(int Flags)
        tWindow *ret = WM_CreateWindowStruct( sizeof(*info) );
        if(!ret)        return NULL;
        info = ret->RendererInfo;
-       // Everything starts at zero?
+       
+       // Initialise font (get an idea of dimensions)
+       int h;
+       WM_Render_GetTextDims(NULL, "yY!", 3, NULL, &h);
+       info->LineHeight = h;
+       
        return ret;
 }
 
-static inline int Renderer_RichText_RenderText_Act(tWindow *Window, tRichText_Window *info, int X, int Row, const char *Text, int Bytes, tColour FG, tColour BG)
+void Renderer_RichText_Destroy(tWindow *Window)
+{
+       tRichText_Window        *info = Window->RendererInfo;
+
+       // TODO: Is locking needed? WM_Destroy should have taken us off the render tree
+       while( info->FirstLine )
+       {
+               tRichText_Line *line = info->FirstLine;
+               info->FirstLine = line->Next;
+
+               free(line);
+       }
+
+       if( info->Font )
+               _SysDebug("RichText_Destroy - TODO: Free font");
+}
+
+static inline int Renderer_RichText_RenderText_Act(tWindow *Window, tRichText_Window *info, int X, int Row, const char *Text, int Bytes, tColour FG, tColour BG, int Flags)
 {
         int    rwidth;
-       // TODO: Fill only what is needed
+       // TODO: Fill only what is needed? What about the rest of the line?
        WM_Render_DrawRect(Window, X, Row*info->LineHeight,
                Window->W - X, info->LineHeight,
                BG
                );
+       // TODO: Bold, Italic, Underline
        rwidth = WM_Render_DrawText(Window,
                X, Row*info->LineHeight,
                Window->W - X, info->LineHeight,
@@ -86,14 +125,12 @@ void Renderer_RichText_RenderText(tWindow *Window, int Line, const char *Text)
        tRichText_Window        *info = Window->RendererInfo;
        tColour fg = info->DefaultFG;
        tColour bg = info->DefaultBG;
-        int    bBold = 0;
-        int    bULine = 0;
-        int    bItalic = 0;
+        int    flagset = 0;
         int    bRender = 0;
         int    curx = 0;
        const char      *oldtext = Text;
        
-       for( int i = 0; i < info->FirstVisCol + info->DispCols; i ++ )
+       for( int i = 0; curx < Window->W; i ++ )
        {
                char    ch, flags;
                 int    len;
@@ -103,93 +140,228 @@ void Renderer_RichText_RenderText(tWindow *Window, int Line, const char *Text)
 
                ch = *Text++;
                if( ch == 0 )   break;
-               if( ch <=3 && bRender ) {
+
+               // Not an escape - move along
+               if( ch > 4 )
+                       continue ;              
+
+               if( bRender ) {
                        // Render previous characters
                        curx += Renderer_RichText_RenderText_Act(Window, info, curx, Line,
-                               oldtext, Text - oldtext, fg, bg);
-                       oldtext = Text;
+                               oldtext, Text - oldtext - 1, fg, bg, flagset);
+                       if( curx >= Window->W )
+                               break;
                }
+               oldtext = Text;
                switch(ch)
                {
                case 1: // FG Select (\1 RRGGBB)
-                       len = sscanf(Text, "%6x", &fg);
-                       if( len != 6 ) {
+                       if( sscanf(Text, "%6x%n", &fg, &len) != 1 || len != 6 ) {
                                // Bad client
+                               _SysDebug("foreground scanf failed - len=%i", len);
+                               len = 0;
                        }
                        Text += len;
+                       oldtext = Text;
+                       _SysDebug("FG update to %x", fg);
                        break ;
                case 2: // BG Select (\2 RRGGBB)
-                       len = sscanf(Text, "%6x", &bg);
-                       if( len != 6 ) {
+                       if( sscanf(Text, "%6x%n", &bg, &len) != 1 || len != 6 ) {
                                // Bad client
+                               _SysDebug("background scanf failed - len=%i", len);
+                               len = 0;
                        }
                        Text += len;
+                       oldtext = Text;
+                       _SysDebug("BG update to %x", bg);
                        break ;
                case 3: // Flagset (0,it,uline,bold)
-                       len = sscanf(Text, "%1x", &flags);
-                       if( len != 1 ) {
+                       if( sscanf(Text, "%1hhx%n", &flags, &len) != 1 || len != 1 ) {
                                // Bad client
+                               _SysDebug("Flagset scanf failed - len=%i", len);
                        }
+                       flagset = flags & 7;
                        Text += len;
-                       bItalic = !!(flags & (1 << 2));
-                       bULine = !!(flags & (1 << 1));
-                       bBold = !!(flags & (1 << 0));
+                       oldtext = Text;
                        break ;
-               default: // Any char, nop
+               case 4: // Escape (do nothing)
+                       Text ++;
+                       // NOTE: No update to oldtext
+                       break;
+               default: // Error.
                        break;
                }
        }
-       curx += Renderer_RichText_RenderText_Act(Window, info, curx, Line, oldtext, Text - oldtext, fg, bg);
-       WM_Render_DrawRect(Window, curx, Line * info->LineHeight, Window->W - curx, info->LineHeight, info->DefaultBG);
+       curx += Renderer_RichText_RenderText_Act(Window, info, curx,
+               Line, oldtext, Text - oldtext + 1, fg, bg, flagset);
+       WM_Render_DrawRect(Window, curx, Line * info->LineHeight,
+               Window->W - curx, info->LineHeight, info->DefaultBG);
 }
 
 void Renderer_RichText_Redraw(tWindow *Window)
 {
        tRichText_Window        *info = Window->RendererInfo;
         int    i;
-       tRichText_LineBlock     *lines = &info->FirstBlock;
+       tRichText_Line  *line = info->FirstVisLine;
        
-       // Locate the first line block
-       for( i = info->FirstVisRow; i > LINES_PER_BLOCK && lines; i -= LINES_PER_BLOCK )
-               lines = lines->Next;
+       if( !line ) {
+               line = info->FirstLine;
+               while(line && line->Num < info->FirstVisRow )
+                       line = line->Next;
+               info->FirstVisLine = line;
+       }
+       while( line && line->Prev && line->Prev->Num > info->FirstVisRow )
+               line = line->Prev;
 
-       for( i = 0; i < info->DispLines && lines; i ++ )
+       for( i = 0; i < info->DispLines && line; i ++ )
        {
                if( i >= info->nLines - info->FirstVisRow )
                        break;
                // TODO: Dirty rectangles?
-               WM_Render_DrawRect(Window,
+               WM_Render_FillRect(Window,
                        0, i*info->LineHeight,
                        Window->W, info->LineHeight,
                        info->DefaultBG
                        );
+               if( line->Num > info->FirstVisRow + i )
+                       continue ;
                // TODO: Horizontal scrolling?
                // TODO: Formatting
-               //Renderer_RichText_RenderText(Window, i, lines->Lines[i % LINES_PER_BLOCK]);
-               WM_Render_DrawText(Window,
-                       0, i*info->LineHeight,
-                       Window->W, info->LineHeight,
-                       info->Font, info->DefaultFG,
-                       lines->Lines[i % LINES_PER_BLOCK],
-                       -1);
-       
-               if( (i + 1) % LINES_PER_BLOCK == 0 )
-                       lines = lines->Next;
+               
+               // Formatted text out
+               Renderer_RichText_RenderText(Window, i, line->Data);
+               _SysDebug("RichText: %p - Render %i '%.*s'", Window,
+                       line->Num, line->ByteLength, line->Data);
+
+               line = line->Next;
        }
        // Clear out i -- info->DispLines
-       WM_Render_DrawRect(Window,
+       _SysDebug("RichText: %p - Clear %i px lines with %06x starting at %i",
+               Window, (info->DispLines-i)*info->LineHeight, info->DefaultBG, i*info->LineHeight);
+       WM_Render_FillRect(Window,
                0, i*info->LineHeight,
                Window->W, (info->DispLines-i)*info->LineHeight,
                info->DefaultBG
                );
+
+       // HACK!
+       info->DispCols = Window->W / 8; 
+
+       // TODO: Text cursor
+       _SysDebug("Cursor at %i,%i", info->CursorCol, info->CursorRow);
+       _SysDebug(" Range [%i+%i],[%i+%i]", info->FirstVisRow, info->DispLines, info->FirstVisCol, info->DispCols);
+       if( info->CursorRow >= info->FirstVisRow && info->CursorRow < info->FirstVisRow + info->DispLines )
+       {
+               if( info->CursorCol >= info->FirstVisCol && info->CursorCol < info->FirstVisCol + info->DispCols )
+               {
+                       // TODO: Kill hardcoded 8 with cached text distance
+                       WM_Render_FillRect(Window,
+                               (info->CursorCol - info->FirstVisCol) * 8,
+                               (info->CursorRow - info->FirstVisRow) * info->LineHeight,
+                               1,
+                               info->LineHeight,
+                               info->DefaultFG
+                               );
+               }
+       }
+}
+
+int Renderer_RichText_HandleIPC_SetAttr(tWindow *Window, size_t Len, const void *Data)
+{
+       tRichText_Window        *info = Window->RendererInfo;
+       const struct sRichTextIPC_SetAttr *msg = Data;
+       if(Len < sizeof(*msg))  return -1;
+
+       _SysDebug("RichText Attr %i set to %x", msg->Attr, msg->Value);
+       switch(msg->Attr)
+       {
+       case _ATTR_DEFBG:
+               info->DefaultBG = msg->Value;
+               break;
+       case _ATTR_DEFFG:
+               info->DefaultFG = msg->Value;
+               break;
+       case _ATTR_CURSORPOS:
+               info->CursorRow = msg->Value >> 12;
+               info->CursorCol = msg->Value & 0xFFF;
+               break;
+       case _ATTR_SCROLL:
+               // TODO: Set scroll flag
+               break;
+       case _ATTR_LINECOUNT:
+               info->nLines = msg->Value;
+               break;
+       }
+       
+       return 0;
+}
+
+int Renderer_RichText_HandleIPC_WriteLine(tWindow *Window, size_t Len, const void *Data)
+{
+       tRichText_Window        *info = Window->RendererInfo;
+       const struct sRichTextIPC_WriteLine     *msg = Data;
+       if( Len < sizeof(*msg) )        return -1;
+       if( msg->Line >= info->nLines ) return 1;       // Bad count
+
+       tRichText_Line  *line = info->FirstLine;
+       tRichText_Line  *prev = NULL;
+       while(line && line->Num < msg->Line)
+               prev = line, line = line->Next;
+       if( !line || line->Num > msg->Line )
+       {
+               // New line!
+               // Round up to 32
+                int    space = ((Len - sizeof(*msg)) + 32-1) & ~(32-1);
+               tRichText_Line  *new = malloc(sizeof(*line) + space);
+               // TODO: Bookkeeping on how much memory each window uses
+               new->Next = line;
+               new->Prev = prev;
+               new->Num = msg->Line;
+               new->Space = space;
+               if(new->Prev)   new->Prev->Next = new;
+               else    info->FirstLine = new;
+               if(new->Next)   new->Next->Prev = new;
+               line = new;
+       }
+       else if( line->Space < Len - sizeof(*msg) )
+       {
+               // Need to allocate more space
+                int    space = ((Len - sizeof(*msg)) + 32-1) & ~(32-1);
+               tRichText_Line *new = realloc(line, space);
+               // TODO: Bookkeeping on how much memory each window uses
+               new->Space = space;
+
+               if(new->Prev)   new->Prev->Next = new;
+               else    info->FirstLine = new;
+               if(new->Next)   new->Next->Prev = new;
+               line = new;
+       }
+       else
+       {
+               // It fits :)
+       }
+       line->ByteLength = Len - sizeof(*msg);
+       memcpy(line->Data, msg->LineData, Len - sizeof(*msg));
+
+       WM_Invalidate( Window );
+
+       return  0;
 }
 
 int Renderer_RichText_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
 {
+       tRichText_Window        *info = Target->RendererInfo;
        switch(Msg)
        {
-       case MSG_RICHTEXT_SETATTR:
-               break;
+       case WNDMSG_RESIZE: {
+               const struct sWndMsg_Resize *msg = Data;
+               if(Len < sizeof(*msg))  return -1;
+               info->DispLines = msg->H / info->LineHeight;
+               return 1; }
+       case WNDMSG_KEYDOWN:
+       case WNDMSG_KEYUP:
+       case WNDMSG_KEYFIRE:
+               return 1;
        }
        return 0;
 }

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