Usermode/AxWin3 - Changed to use SysSpawn and detect crap server PIDs
[tpg/acess2.git] / Usermode / Applications / axwin3_src / WM / renderers / richtext.c
1 /*
2  * Acess2 Window Manager v3
3  * - By John Hodge (thePowersGang)
4  *
5  * render/richtext.c
6  * - Formatted Line Editor
7  */
8 #include <common.h>
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
14
15 #define LINES_PER_BLOCK 30
16
17 // === TYPES ===
18 typedef struct sRichText_Line
19 {
20         struct sRichText_Line   *Next;
21         struct sRichText_Line   *Prev;
22          int    Num;
23         // TODO: Pre-rendered cache?
24         short   ByteLength;
25         short   Space;
26         char    Data[];
27 } tRichText_Line;
28 typedef struct sRichText_Window
29 {
30          int    DispLines, DispCols;
31          int    FirstVisRow, FirstVisCol;
32          int    nLines, nCols;
33          int    CursorRow, CursorCol;
34         tRichText_Line  *FirstLine;
35         tRichText_Line  *FirstVisLine;
36         tColour DefaultFG;
37         tColour DefaultBG;
38         tFont   *Font;
39         
40         short   LineHeight;
41 } tRichText_Window;
42
43 // === PROTOTYPES ===
44  int    Renderer_RichText_Init(void);
45 tWindow *Renderer_RichText_Create(int Flags);
46 void    Renderer_RichText_Redraw(tWindow *Window);
47  int    Renderer_RichText_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data);
48
49 // === GLOBALS ===
50 tWMRenderer     gRenderer_RichText = {
51         .Name = "RichText",
52         .CreateWindow   = Renderer_RichText_Create,
53         .Redraw         = Renderer_RichText_Redraw,
54         .HandleMessage  = Renderer_RichText_HandleMessage
55 };
56
57 // === CODE ===
58 int Renderer_RichText_Init(void)
59 {
60         WM_RegisterRenderer(&gRenderer_RichText);       
61         return 0;
62 }
63
64 tWindow *Renderer_RichText_Create(int Flags)
65 {
66         tRichText_Window        *info;
67         tWindow *ret = WM_CreateWindowStruct( sizeof(*info) );
68         if(!ret)        return NULL;
69         info = ret->RendererInfo;
70         
71         // Initialise font (get an idea of dimensions)
72         int h;
73         WM_Render_GetTextDims(NULL, "yY!", 3, NULL, &h);
74         info->LineHeight = h;
75         
76         return ret;
77 }
78
79 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)
80 {
81          int    rwidth;
82         // TODO: Fill only what is needed? What about the rest of the line?
83         WM_Render_DrawRect(Window, X, Row*info->LineHeight,
84                 Window->W - X, info->LineHeight,
85                 BG
86                 );
87         // TODO: Bold, Italic, Underline
88         rwidth = WM_Render_DrawText(Window,
89                 X, Row*info->LineHeight,
90                 Window->W - X, info->LineHeight,
91                 info->Font, FG,
92                 Text, Bytes
93                 );
94         return rwidth;
95 }
96
97 void Renderer_RichText_RenderText(tWindow *Window, int Line, const char *Text)
98 {
99         tRichText_Window        *info = Window->RendererInfo;
100         tColour fg = info->DefaultFG;
101         tColour bg = info->DefaultBG;
102          int    flagset = 0;
103          int    bRender = 0;
104          int    curx = 0;
105         const char      *oldtext = Text;
106         
107         for( int i = 0; curx < Window->W; i ++ )
108         {
109                 char    ch, flags;
110                  int    len;
111
112                 if( i == info->FirstVisCol )
113                         bRender = 1;
114
115                 ch = *Text++;
116                 if( ch == 0 )   break;
117
118                 // Not an escape - move along
119                 if( ch > 4 )
120                         continue ;              
121
122                 if( bRender ) {
123                         // Render previous characters
124                         curx += Renderer_RichText_RenderText_Act(Window, info, curx, Line,
125                                 oldtext, Text - oldtext - 1, fg, bg, flagset);
126                         if( curx >= Window->W )
127                                 break;
128                 }
129                 oldtext = Text;
130                 switch(ch)
131                 {
132                 case 1: // FG Select (\1 RRGGBB)
133                         if( sscanf(Text, "%6x%n", &fg, &len) != 1 || len != 6 ) {
134                                 // Bad client
135                                 _SysDebug("foreground scanf failed - len=%i", len);
136                                 len = 0;
137                         }
138                         Text += len;
139                         oldtext = Text;
140                         _SysDebug("FG update to %x", fg);
141                         break ;
142                 case 2: // BG Select (\2 RRGGBB)
143                         if( sscanf(Text, "%6x%n", &bg, &len) != 1 || len != 6 ) {
144                                 // Bad client
145                                 _SysDebug("background scanf failed - len=%i", len);
146                                 len = 0;
147                         }
148                         Text += len;
149                         oldtext = Text;
150                         _SysDebug("BG update to %x", bg);
151                         break ;
152                 case 3: // Flagset (0,it,uline,bold)
153                         if( sscanf(Text, "%1hhx%n", &flags, &len) != 1 || len != 1 ) {
154                                 // Bad client
155                                 _SysDebug("Flagset scanf failed - len=%i", len);
156                         }
157                         flagset = flags & 7;
158                         Text += len;
159                         oldtext = Text;
160                         break ;
161                 case 4: // Escape (do nothing)
162                         Text ++;
163                         // NOTE: No update to oldtext
164                         break;
165                 default: // Error.
166                         break;
167                 }
168         }
169         curx += Renderer_RichText_RenderText_Act(Window, info, curx,
170                 Line, oldtext, Text - oldtext + 1, fg, bg, flagset);
171         WM_Render_DrawRect(Window, curx, Line * info->LineHeight,
172                 Window->W - curx, info->LineHeight, info->DefaultBG);
173 }
174
175 void Renderer_RichText_Redraw(tWindow *Window)
176 {
177         tRichText_Window        *info = Window->RendererInfo;
178          int    i;
179         tRichText_Line  *line = info->FirstVisLine;
180         
181         if( !line ) {
182                 line = info->FirstLine;
183                 while(line && line->Num < info->FirstVisRow )
184                         line = line->Next;
185                 info->FirstVisLine = line;
186         }
187         while( line && line->Prev && line->Prev->Num > info->FirstVisRow )
188                 line = line->Prev;
189
190         for( i = 0; i < info->DispLines && line; i ++ )
191         {
192                 if( i >= info->nLines - info->FirstVisRow )
193                         break;
194                 // TODO: Dirty rectangles?
195                 WM_Render_FillRect(Window,
196                         0, i*info->LineHeight,
197                         Window->W, info->LineHeight,
198                         info->DefaultBG
199                         );
200                 if( line->Num > info->FirstVisRow + i )
201                         continue ;
202                 // TODO: Horizontal scrolling?
203                 // TODO: Formatting
204                 
205                 // Formatted text out
206                 Renderer_RichText_RenderText(Window, i, line->Data);
207                 _SysDebug("RichText: %p - Render %i '%.*s'", Window,
208                         line->Num, line->ByteLength, line->Data);
209
210                 line = line->Next;
211         }
212         // Clear out i -- info->DispLines
213         _SysDebug("RichText: %p - Clear %i px lines with %06x starting at %i",
214                 Window, (info->DispLines-i)*info->LineHeight, info->DefaultBG, i*info->LineHeight);
215         WM_Render_FillRect(Window,
216                 0, i*info->LineHeight,
217                 Window->W, (info->DispLines-i)*info->LineHeight,
218                 info->DefaultBG
219                 );
220 }
221
222 int Renderer_RichText_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
223 {
224         tRichText_Window        *info = Target->RendererInfo;
225         switch(Msg)
226         {
227         case WNDMSG_RESIZE: {
228                 const struct sWndMsg_Resize *msg = Data;
229                 if(Len < sizeof(*msg))  return -1;
230                 info->DispLines = msg->H / info->LineHeight;
231                 return 1; }
232         case MSG_RICHTEXT_SETATTR: {
233                 const struct sRichTextMsg_SetAttr *msg = Data;
234                 if(Len < sizeof(*msg))  return -1;
235                 _SysDebug("RichText Attr %i set to %x", msg->Attr, msg->Value);
236                 switch(msg->Attr)
237                 {
238                 case _ATTR_DEFBG:
239                         info->DefaultBG = msg->Value;
240                         break;
241                 case _ATTR_DEFFG:
242                         info->DefaultFG = msg->Value;
243                         break;
244                 case _ATTR_SCROLL:
245                         // TODO: Set scroll flag
246                         break;
247                 case _ATTR_LINECOUNT:
248                         info->nLines = msg->Value;
249                         break;
250                 }
251                 return 1; }
252         // Update a line
253         case MSG_RICHTEXT_SENDLINE: {
254                 const struct sRichTextMsg_SendLine      *msg = Data;
255                 if(Len < sizeof(*msg))  return -1;
256                 _SysDebug("RichText Line %i = '%.*s'", msg->Line, Len - sizeof(*msg), msg->LineData);
257                 if( msg->Line >= info->nLines ) return 1;       // Bad count
258                 
259                 tRichText_Line  *line = info->FirstLine;
260                 tRichText_Line  *prev = NULL;
261                 while(line && line->Num < msg->Line)
262                         prev = line, line = line->Next;
263                 if( !line || line->Num > msg->Line )
264                 {
265                         // New line!
266                         // Round up to 32
267                          int    space = ((Len - sizeof(*msg)) + 32-1) & ~(32-1);
268                         tRichText_Line  *new = malloc(sizeof(*line) + space);
269                         // TODO: Bookkeeping on how much memory each window uses
270                         new->Next = line;
271                         new->Prev = prev;
272                         new->Num = msg->Line;
273                         new->Space = space;
274                         if(new->Prev)   new->Prev->Next = new;
275                         else    info->FirstLine = new;
276                         if(new->Next)   new->Next->Prev = new;
277                         line = new;
278                 }
279                 else if( line->Space < Len - sizeof(*msg) )
280                 {
281                         // Need to allocate more space
282                          int    space = ((Len - sizeof(*msg)) + 32-1) & ~(32-1);
283                         tRichText_Line *new = realloc(line, space);
284                         // TODO: Bookkeeping on how much memory each window uses
285                         new->Space = space;
286
287                         if(new->Prev)   new->Prev->Next = new;
288                         else    info->FirstLine = new;
289                         if(new->Next)   new->Next->Prev = new;
290                         line = new;
291                 }
292                 else
293                 {
294                         // It fits :)
295                 }
296                 line->ByteLength = Len - sizeof(*msg);
297                 memcpy(line->Data, msg->LineData, Len - sizeof(*msg));
298                 return 1; }
299         }
300         return 0;
301 }

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