+ // 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
+ && 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
+ );
+ }
+}
+
+tRichText_Line *Renderer_RichText_int_GetLine(tWindow *Window, int LineNum, tRichText_Line **Prev)
+{
+ tRichText_Window *info = Window->RendererInfo;
+ tRichText_Line *line = info->FirstLine;
+ tRichText_Line *prev = NULL;
+ while(line && line->Num < LineNum)
+ prev = line, line = line->Next;
+
+ if( Prev )
+ *Prev = prev;
+
+ if( !line || line->Num > LineNum )
+ return NULL;
+ return line;
+}
+
+void Renderer_RichText_int_UpdateCursorOfs(tRichText_Window *Info)
+{
+ tRichText_Line *line = Info->CursorLine;
+ size_t ofs = 0;
+ if( line )
+ {
+ for( int i = 0; i < Info->CursorCol && ofs < line->ByteLength; i ++ )
+ {
+ ofs += ReadUTF8(line->Data + ofs, NULL);
+ }
+ }
+ Info->CursorBytePos = ofs;
+}
+
+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: {
+ int newRow = msg->Value >> 12;
+ int newCol = msg->Value & 0xFFF;
+ // Force redraw of old and new row
+ tRichText_Line *line = Renderer_RichText_int_GetLine(Window, info->CursorRow, NULL);
+ if( line )
+ line->bIsClean = 0;
+ if( newRow != info->CursorRow ) {
+ line = Renderer_RichText_int_GetLine(Window, newRow, NULL);
+ if(line)
+ line->bIsClean = 0;
+ }
+ info->CursorRow = newRow;
+ info->CursorCol = newCol;
+ info->CursorLine = line;
+ Renderer_RichText_int_UpdateCursorOfs(info);
+ WM_Invalidate(Window, 1);
+ 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 *prev = NULL;
+ tRichText_Line *line = Renderer_RichText_int_GetLine(Window, msg->Line, &prev);
+ size_t data_bytes = Len - sizeof(*msg);
+ int reqspace = (data_bytes + LINE_SPACE_UNIT-1) & ~(LINE_SPACE_UNIT-1);
+ tRichText_Line *new = NULL;
+ if( !line )
+ {
+ // New line!
+ new = malloc(sizeof(*line) + reqspace);
+ new->Next = (prev ? prev->Next : NULL);
+ new->Prev = prev;
+ new->Num = msg->Line;
+ }
+ else if( line->Space < reqspace )
+ {
+ // Need to allocate more space
+ new = realloc(line, sizeof(*line) + reqspace);
+ }
+ else
+ {
+ // It fits :)
+ }
+ if( new )
+ {
+ // TODO: Bookkeeping on how much memory each window uses
+ new->Space = reqspace;
+ if(new->Prev) new->Prev->Next = new;
+ else info->FirstLine = new;
+ if(new->Next) new->Next->Prev = new;
+ line = new;
+ }
+ line->ByteLength = data_bytes - 1;
+ memcpy(line->Data, msg->LineData, data_bytes);
+ line->bIsClean = 0;
+
+ _SysDebug("RichText: %p - Write %i %i'%.*s'", Window, line->Num, line->ByteLength,
+ line->ByteLength, line->Data);
+
+ if( line->Num == info->CursorRow ) {
+ info->CursorLine = line;
+ info->CursorBytePos = MIN(info->CursorBytePos, line->ByteLength);
+ }
+
+// WM_Invalidate(Window, 1);
+
+ return 0;
+}
+
+int Renderer_RichText_HandleIPC_ScrollRange(tWindow *Window, size_t Len, const void *Data)
+{
+ tRichText_Window *info = Window->RendererInfo;
+ const struct sRichTextIPC_ScrollRange *msg = Data;
+ if( Len < sizeof(*msg) ) return -1;
+
+ if( msg->First >= info->nLines )
+ return 1; // Bad start
+ if( msg->Count > info->nLines - msg->First )
+ return 1; // Bad count
+ if( msg->Count == 0 ) {
+ // No-op
+ return 0;
+ }
+
+ // Find the range start
+ tRichText_Line *line = info->FirstLine;
+ tRichText_Line *prev = NULL;
+ while( line && line->Num < msg->First ) {
+ prev = line;