// === 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 ===
if(!ret) return NULL;
info = ret->RendererInfo;
- // Initialise font.
+ // Initialise font (get an idea of dimensions)
int h;
WM_Render_GetTextDims(NULL, "yY!", 3, NULL, &h);
info->LineHeight = h;
return ret;
}
+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
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;
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, flagset);
- 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);
}
- Text += len;
- //bItalic = !!(flags & (1 << 2));
- //bULine = !!(flags & (1 << 1));
- //bBold = !!(flags & (1 << 0));
flagset = flags & 7;
+ Text += len;
+ 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, flagset);
+ Line, oldtext, Text - oldtext + 1, fg, bg, flagset);
WM_Render_DrawRect(Window, curx, Line * info->LineHeight,
Window->W - curx, info->LineHeight, info->DefaultBG);
}
// TODO: Horizontal scrolling?
// TODO: Formatting
- // NOTE: uses scanf() so commented out for now
- //Renderer_RichText_RenderText(Window, i, line->Text);
- WM_Render_DrawText(Window,
- 0, i*info->LineHeight,
- Window->W, info->LineHeight,
- info->Font, info->DefaultFG,
- line->Data,
- -1);
+ // Formatted text out
+ Renderer_RichText_RenderText(Window, i, line->Data);
_SysDebug("RichText: %p - Render %i '%.*s'", Window,
line->Num, line->ByteLength, line->Data);
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)
if(Len < sizeof(*msg)) return -1;
info->DispLines = msg->H / info->LineHeight;
return 1; }
- case MSG_RICHTEXT_SETATTR: {
- const struct sRichTextMsg_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_SCROLL:
- // TODO: Set scroll flag
- break;
- case _ATTR_LINECOUNT:
- info->nLines = msg->Value;
- break;
- }
- return 1; }
- // Update a line
- case MSG_RICHTEXT_SENDLINE: {
- const struct sRichTextMsg_SendLine *msg = Data;
- if(Len < sizeof(*msg)) return -1;
- _SysDebug("RichText Line %i = '%.*s'", msg->Line, Len - sizeof(*msg), msg->LineData);
- 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));
- return 1; }
+ case WNDMSG_KEYDOWN:
+ case WNDMSG_KEYUP:
+ case WNDMSG_KEYFIRE:
+ return 1;
}
return 0;
}