3e0fa5411a1ab31811d7dc101430648a0933500f
[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.
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
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; i < info->FirstVisCol + info->DispCols; 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                 if( ch <=3 && bRender ) {
118                         // Render previous characters
119                         curx += Renderer_RichText_RenderText_Act(Window, info, curx, Line,
120                                 oldtext, Text - oldtext, fg, bg, flagset);
121                         oldtext = Text;
122                 }
123                 switch(ch)
124                 {
125                 case 1: // FG Select (\1 RRGGBB)
126                         len = sscanf(Text, "%6x", &fg);
127                         if( len != 6 ) {
128                                 // Bad client
129                         }
130                         Text += len;
131                         break ;
132                 case 2: // BG Select (\2 RRGGBB)
133                         len = sscanf(Text, "%6x", &bg);
134                         if( len != 6 ) {
135                                 // Bad client
136                         }
137                         Text += len;
138                         break ;
139                 case 3: // Flagset (0,it,uline,bold)
140                         len = sscanf(Text, "%1x", &flags);
141                         if( len != 1 ) {
142                                 // Bad client
143                         }
144                         Text += len;
145                         //bItalic = !!(flags & (1 << 2));
146                         //bULine = !!(flags & (1 << 1));
147                         //bBold = !!(flags & (1 << 0));
148                         flagset = flags & 7;
149                         break ;
150                 default: // Any char, nop
151                         break;
152                 }
153         }
154         curx += Renderer_RichText_RenderText_Act(Window, info, curx,
155                 Line, oldtext, Text - oldtext, fg, bg, flagset);
156         WM_Render_DrawRect(Window, curx, Line * info->LineHeight,
157                 Window->W - curx, info->LineHeight, info->DefaultBG);
158 }
159
160 void Renderer_RichText_Redraw(tWindow *Window)
161 {
162         tRichText_Window        *info = Window->RendererInfo;
163          int    i;
164         tRichText_Line  *line = info->FirstVisLine;
165         
166         if( !line ) {
167                 line = info->FirstLine;
168                 while(line && line->Num < info->FirstVisRow )
169                         line = line->Next;
170                 info->FirstVisLine = line;
171         }
172         while( line && line->Prev && line->Prev->Num > info->FirstVisRow )
173                 line = line->Prev;
174
175         for( i = 0; i < info->DispLines && line; i ++ )
176         {
177                 if( i >= info->nLines - info->FirstVisRow )
178                         break;
179                 // TODO: Dirty rectangles?
180                 WM_Render_FillRect(Window,
181                         0, i*info->LineHeight,
182                         Window->W, info->LineHeight,
183                         info->DefaultBG
184                         );
185                 if( line->Num > info->FirstVisRow + i )
186                         continue ;
187                 // TODO: Horizontal scrolling?
188                 // TODO: Formatting
189                 
190                 // NOTE: uses scanf() so commented out for now
191                 //Renderer_RichText_RenderText(Window, i, line->Text);
192                 WM_Render_DrawText(Window,
193                         0, i*info->LineHeight,
194                         Window->W, info->LineHeight,
195                         info->Font, info->DefaultFG,
196                         line->Data,
197                         -1);
198                 _SysDebug("RichText: %p - Render %i '%.*s'", Window,
199                         line->Num, line->ByteLength, line->Data);
200
201                 line = line->Next;
202         }
203         // Clear out i -- info->DispLines
204         _SysDebug("RichText: %p - Clear %i px lines with %06x starting at %i",
205                 Window, (info->DispLines-i)*info->LineHeight, info->DefaultBG, i*info->LineHeight);
206         WM_Render_FillRect(Window,
207                 0, i*info->LineHeight,
208                 Window->W, (info->DispLines-i)*info->LineHeight,
209                 info->DefaultBG
210                 );
211 }
212
213 int Renderer_RichText_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
214 {
215         tRichText_Window        *info = Target->RendererInfo;
216         switch(Msg)
217         {
218         case WNDMSG_RESIZE: {
219                 const struct sWndMsg_Resize *msg = Data;
220                 if(Len < sizeof(*msg))  return -1;
221                 info->DispLines = msg->H / info->LineHeight;
222                 return 1; }
223         case MSG_RICHTEXT_SETATTR: {
224                 const struct sRichTextMsg_SetAttr *msg = Data;
225                 if(Len < sizeof(*msg))  return -1;
226                 _SysDebug("RichText Attr %i set to %x", msg->Attr, msg->Value);
227                 switch(msg->Attr)
228                 {
229                 case _ATTR_DEFBG:
230                         info->DefaultBG = msg->Value;
231                         break;
232                 case _ATTR_DEFFG:
233                         info->DefaultFG = msg->Value;
234                         break;
235                 case _ATTR_SCROLL:
236                         // TODO: Set scroll flag
237                         break;
238                 case _ATTR_LINECOUNT:
239                         info->nLines = msg->Value;
240                         break;
241                 }
242                 return 1; }
243         // Update a line
244         case MSG_RICHTEXT_SENDLINE: {
245                 const struct sRichTextMsg_SendLine      *msg = Data;
246                 if(Len < sizeof(*msg))  return -1;
247                 _SysDebug("RichText Line %i = '%.*s'", msg->Line, Len - sizeof(*msg), msg->LineData);
248                 if( msg->Line >= info->nLines ) return 1;       // Bad count
249                 
250                 tRichText_Line  *line = info->FirstLine;
251                 tRichText_Line  *prev = NULL;
252                 while(line && line->Num < msg->Line)
253                         prev = line, line = line->Next;
254                 if( !line || line->Num > msg->Line )
255                 {
256                         // New line!
257                         // Round up to 32
258                          int    space = ((Len - sizeof(*msg)) + 32-1) & ~(32-1);
259                         tRichText_Line  *new = malloc(sizeof(*line) + space);
260                         // TODO: Bookkeeping on how much memory each window uses
261                         new->Next = line;
262                         new->Prev = prev;
263                         new->Num = msg->Line;
264                         new->Space = space;
265                         if(new->Prev)   new->Prev->Next = new;
266                         else    info->FirstLine = new;
267                         if(new->Next)   new->Next->Prev = new;
268                         line = new;
269                 }
270                 else if( line->Space < Len - sizeof(*msg) )
271                 {
272                         // Need to allocate more space
273                          int    space = ((Len - sizeof(*msg)) + 32-1) & ~(32-1);
274                         tRichText_Line *new = realloc(line, space);
275                         // TODO: Bookkeeping on how much memory each window uses
276                         new->Space = space;
277
278                         if(new->Prev)   new->Prev->Next = new;
279                         else    info->FirstLine = new;
280                         if(new->Next)   new->Next->Prev = new;
281                         line = new;
282                 }
283                 else
284                 {
285                         // It fits :)
286                 }
287                 line->ByteLength = Len - sizeof(*msg);
288                 memcpy(line->Data, msg->LineData, Len - sizeof(*msg));
289                 return 1; }
290         }
291         return 0;
292 }

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