2 * Acess2 Window Manager v3
3 * - By John Hodge (thePowersGang)
6 * - Formatted Line Editor
9 #include <wm_renderer.h>
10 #include <wm_messages.h>
11 #include <richtext_messages.h>
12 #include <stdio.h> // sscanf
13 #include <string.h> // memcpy
15 #define LINES_PER_BLOCK 30
18 typedef struct sRichText_Line
20 struct sRichText_Line *Next;
21 struct sRichText_Line *Prev;
24 // TODO: Pre-rendered cache?
29 typedef struct sRichText_Window
31 int DispLines, DispCols;
32 int FirstVisRow, FirstVisCol;
34 int CursorRow, CursorCol;
35 tRichText_Line *FirstLine;
36 tRichText_Line *FirstVisLine;
40 char bNeedsFullRedraw;
46 int Renderer_RichText_Init(void);
47 tWindow *Renderer_RichText_Create(int Flags);
48 void Renderer_RichText_Destroy(tWindow *Window);
49 void Renderer_RichText_Redraw(tWindow *Window);
50 int Renderer_RichText_HandleIPC_SetAttr(tWindow *Window, size_t Len, const void *Data);
51 int Renderer_RichText_HandleIPC_WriteLine(tWindow *Window, size_t Len, const void *Data);
52 int Renderer_RichText_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data);
55 tWMRenderer gRenderer_RichText = {
57 .CreateWindow = Renderer_RichText_Create,
58 .DestroyWindow = Renderer_RichText_Destroy,
59 .Redraw = Renderer_RichText_Redraw,
60 .HandleMessage = Renderer_RichText_HandleMessage,
61 .nIPCHandlers = N_IPC_RICHTEXT,
63 [IPC_RICHTEXT_SETATTR] = Renderer_RichText_HandleIPC_SetAttr,
64 [IPC_RICHTEXT_WRITELINE] = Renderer_RichText_HandleIPC_WriteLine
69 int Renderer_RichText_Init(void)
71 WM_RegisterRenderer(&gRenderer_RichText);
75 tWindow *Renderer_RichText_Create(int Flags)
77 tRichText_Window *info;
78 tWindow *ret = WM_CreateWindowStruct( sizeof(*info) );
80 info = ret->RendererInfo;
82 // Initialise font (get an idea of dimensions)
84 WM_Render_GetTextDims(NULL, "yY!", 3, NULL, &h);
90 void Renderer_RichText_Destroy(tWindow *Window)
92 tRichText_Window *info = Window->RendererInfo;
94 // TODO: Is locking needed? WM_Destroy should have taken us off the render tree
95 while( info->FirstLine )
97 tRichText_Line *line = info->FirstLine;
98 info->FirstLine = line->Next;
104 _SysDebug("RichText_Destroy - TODO: Free font");
107 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)
110 // TODO: Fill only what is needed? What about the rest of the line?
111 WM_Render_DrawRect(Window, X, Row*info->LineHeight,
112 Window->W - X, info->LineHeight,
115 // TODO: Bold, Italic, Underline
116 rwidth = WM_Render_DrawText(Window,
117 X, Row*info->LineHeight,
118 Window->W - X, info->LineHeight,
125 void Renderer_RichText_RenderText(tWindow *Window, int Line, const char *Text)
127 tRichText_Window *info = Window->RendererInfo;
128 tColour fg = info->DefaultFG;
129 tColour bg = info->DefaultBG;
133 const char *oldtext = Text;
135 for( int i = 0; curx < Window->W; i ++ )
140 if( i == info->FirstVisCol )
146 // Not an escape - move along
151 // Render previous characters
152 curx += Renderer_RichText_RenderText_Act(Window, info, curx, Line,
153 oldtext, Text - oldtext - 1, fg, bg, flagset);
154 if( curx >= Window->W )
160 case 1: // FG Select (\1 RRGGBB)
161 if( sscanf(Text, "%6x%n", &fg, &len) != 1 || len != 6 ) {
163 _SysDebug("foreground scanf failed - len=%i", len);
168 _SysDebug("FG update to %x", fg);
170 case 2: // BG Select (\2 RRGGBB)
171 if( sscanf(Text, "%6x%n", &bg, &len) != 1 || len != 6 ) {
173 _SysDebug("background scanf failed - len=%i", len);
178 _SysDebug("BG update to %x", bg);
180 case 3: // Flagset (0,it,uline,bold)
181 if( sscanf(Text, "%1hhx%n", &flags, &len) != 1 || len != 1 ) {
183 _SysDebug("Flagset scanf failed - len=%i", len);
189 case 4: // Escape (do nothing)
191 // NOTE: No update to oldtext
197 curx += Renderer_RichText_RenderText_Act(Window, info, curx,
198 Line, oldtext, Text - oldtext + 1, fg, bg, flagset);
199 WM_Render_DrawRect(Window, curx, Line * info->LineHeight,
200 Window->W - curx, info->LineHeight, info->DefaultBG);
203 void Renderer_RichText_Redraw(tWindow *Window)
205 tRichText_Window *info = Window->RendererInfo;
206 tRichText_Line *line = info->FirstVisLine;
209 line = info->FirstLine;
210 while(line && line->Num < info->FirstVisRow )
212 info->FirstVisLine = line;
214 while( line && line->Prev && line->Prev->Num > info->FirstVisRow )
218 for( i = 0; i < info->DispLines && line; i ++ )
220 if( i >= info->nLines - info->FirstVisRow )
222 // Empty line is noted by a discontinuity
223 if( line->Num > info->FirstVisRow + i ) {
224 // Clear line if window needs full redraw
225 if( info->bNeedsFullRedraw ) {
226 WM_Render_FillRect(Window,
227 0, i*info->LineHeight,
228 Window->W, info->LineHeight,
233 // Hack to clear cursor on NULL lines
234 WM_Render_FillRect(Window,
235 0, i*info->LineHeight,
243 if( info->bNeedsFullRedraw || !line->bIsClean )
245 WM_Render_FillRect(Window,
246 0, i*info->LineHeight,
247 Window->W, info->LineHeight,
251 // Formatted text out
252 Renderer_RichText_RenderText(Window, i, line->Data);
253 _SysDebug("RichText: %p - Render %i '%.*s'", Window,
254 line->Num, line->ByteLength, line->Data);
260 // Clear out lines i to info->DispLines-1
261 if( info->bNeedsFullRedraw )
263 _SysDebug("RichText: %p - Clear %i px lines with %06x starting at %i",
264 Window, (info->DispLines-i)*info->LineHeight, info->DefaultBG, i*info->LineHeight);
265 WM_Render_FillRect(Window,
266 0, i*info->LineHeight,
267 Window->W, (info->DispLines-i)*info->LineHeight,
271 info->bNeedsFullRedraw = 0;
273 // HACK: Hardcoded text width of 8
274 info->DispCols = Window->W / 8;
277 _SysDebug("Cursor at %i,%i", info->CursorCol, info->CursorRow);
278 _SysDebug(" Range [%i+%i],[%i+%i]", info->FirstVisRow, info->DispLines, info->FirstVisCol, info->DispCols);
279 if( info->CursorRow >= info->FirstVisRow && info->CursorRow < info->FirstVisRow + info->DispLines )
281 if( info->CursorCol >= info->FirstVisCol && info->CursorCol < info->FirstVisCol + info->DispCols )
283 // TODO: Kill hardcoded 8 with cached text distance
284 WM_Render_FillRect(Window,
285 (info->CursorCol - info->FirstVisCol) * 8,
286 (info->CursorRow - info->FirstVisRow) * info->LineHeight,
295 tRichText_Line *Renderer_RichText_int_GetLine(tWindow *Window, int LineNum, tRichText_Line **Prev)
297 tRichText_Window *info = Window->RendererInfo;
298 tRichText_Line *line = info->FirstLine;
299 tRichText_Line *prev = NULL;
300 while(line && line->Num < LineNum)
301 prev = line, line = line->Next;
306 if( !line || line->Num > LineNum )
311 int Renderer_RichText_HandleIPC_SetAttr(tWindow *Window, size_t Len, const void *Data)
313 tRichText_Window *info = Window->RendererInfo;
314 const struct sRichTextIPC_SetAttr *msg = Data;
315 if(Len < sizeof(*msg)) return -1;
317 _SysDebug("RichText Attr %i set to %x", msg->Attr, msg->Value);
321 info->DefaultBG = msg->Value;
324 info->DefaultFG = msg->Value;
326 case _ATTR_CURSORPOS: {
327 int newRow = msg->Value >> 12;
328 int newCol = msg->Value & 0xFFF;
329 // Force redraw of old and new row
330 tRichText_Line *line = Renderer_RichText_int_GetLine(Window, info->CursorRow, NULL);
333 if( newRow != info->CursorRow ) {
334 line = Renderer_RichText_int_GetLine(Window, newRow, NULL);
338 info->CursorRow = newRow;
339 info->CursorCol = newCol;
340 WM_Invalidate(Window, 1);
343 // TODO: Set scroll flag
345 case _ATTR_LINECOUNT:
346 info->nLines = msg->Value;
353 int Renderer_RichText_HandleIPC_WriteLine(tWindow *Window, size_t Len, const void *Data)
355 tRichText_Window *info = Window->RendererInfo;
356 const struct sRichTextIPC_WriteLine *msg = Data;
357 if( Len < sizeof(*msg) ) return -1;
358 if( msg->Line >= info->nLines ) return 1; // Bad count
360 tRichText_Line *prev = NULL;
361 tRichText_Line *line = Renderer_RichText_int_GetLine(Window, msg->Line, &prev);
366 int space = ((Len - sizeof(*msg)) + 32-1) & ~(32-1);
367 tRichText_Line *new = malloc(sizeof(*line) + space);
368 // TODO: Bookkeeping on how much memory each window uses
369 new->Next = (prev ? prev->Next : NULL);
371 new->Num = msg->Line;
373 if(new->Prev) new->Prev->Next = new;
374 else info->FirstLine = new;
375 if(new->Next) new->Next->Prev = new;
378 else if( line->Space < Len - sizeof(*msg) )
380 // Need to allocate more space
381 int space = ((Len - sizeof(*msg)) + 32-1) & ~(32-1);
382 tRichText_Line *new = realloc(line, space);
383 // TODO: Bookkeeping on how much memory each window uses
386 if(new->Prev) new->Prev->Next = new;
387 else info->FirstLine = new;
388 if(new->Next) new->Next->Prev = new;
395 line->ByteLength = Len - sizeof(*msg);
396 memcpy(line->Data, msg->LineData, Len - sizeof(*msg));
399 // WM_Invalidate(Window, 1);
404 int Renderer_RichText_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
406 tRichText_Window *info = Target->RendererInfo;
409 case WNDMSG_RESIZE: {
410 const struct sWndMsg_Resize *msg = Data;
411 if(Len < sizeof(*msg)) return -1;
412 info->DispLines = msg->H / info->LineHeight;
413 info->bNeedsFullRedraw = 1; // force full rerender