Minor misc fixes
[tpg/acess2.git] / Usermode / Applications / axwin3_src / WM / renderers / widget / textinput.c
1 /*
2  * Acess2 Window Manager v3
3  * - By John Hodge (thePowersGang)
4  * 
5  * renderer/widget/textinput.c
6  * - Single line text box
7  *
8  * TODO: Support Right-to-Left text
9  */
10 #include <common.h>
11 #include "./common.h"
12 #include "./colours.h"
13 #include <unicode.h>
14 #include <string.h>
15
16 // TODO: Include a proper keysym header
17 #define KEYSYM_LEFTARROW        0x50
18 #define KEYSYM_RIGHTARROW       0x4F
19
20 struct sTextInputInfo
21 {
22          int    DrawOfs;        // Byte offset for the leftmost character
23          int    CursorXOfs;     // Pixel offset of the cursor
24         
25          int    CursorByteOfs;
26          int    Length;
27 };
28
29 // === CONSTANTS ===
30 const int       ciTextInput_MarginT = 3;
31 const int       ciTextInput_MarginB = 3;
32 const int       ciTextInput_MarginV = 6;        // Sum of above
33 const int       ciTextInput_MarginL = 3;
34 const int       ciTextInput_MarginR = 3;
35 const int       ciTextInput_MarginH = 6;
36
37 // === GLOBALS ===
38 tFont   *gpTextInput_Font = NULL;
39
40 // === CODE ===
41 void Widget_TextInput_Render(tWindow *Window, tElement *Element)
42 {
43         struct sTextInputInfo   *info = (void*)Element->Data;
44         struct sWidgetWin       *wininfo = Window->RendererInfo;
45         
46         // Scroll view when X offset reaches either end
47         while(info->CursorXOfs >= Element->CachedW - ciTextInput_MarginH)
48         {
49                  int    w;
50                 uint32_t        cp;
51                 info->DrawOfs += ReadUTF8( &Element->Text[info->DrawOfs], &cp );
52                 WM_Render_GetTextDims(
53                         gpTextInput_Font,
54                         &Element->Text[info->DrawOfs], info->CursorByteOfs - info->DrawOfs,
55                         &w, NULL
56                         );
57                 info->CursorXOfs = w;
58         }
59         if(info->CursorXOfs < 0)
60         {
61                 info->DrawOfs = info->CursorByteOfs;
62                 info->CursorXOfs = 0;
63         }
64         
65
66         // Borders
67         WM_Render_FillRect(Window, 
68                 Element->CachedX, Element->CachedY,
69                 Element->CachedW, Element->CachedH,
70                 TEXTINPUT_BACKGROUND
71                 );
72         WM_Render_DrawRect(Window, 
73                 Element->CachedX, Element->CachedY,
74                 Element->CachedW, Element->CachedH,
75                 TEXTINPUT_BORDER_OUT
76                 );
77         WM_Render_DrawRect(Window, 
78                 Element->CachedX+1, Element->CachedY+1,
79                 Element->CachedW-2, Element->CachedH-2,
80                 TEXTINPUT_BORDER_IN
81                 );
82         
83         // Text
84         // - Pre-cursor
85         WM_Render_DrawText(Window,
86                 Element->CachedX+ciTextInput_MarginL, Element->CachedY+ciTextInput_MarginT,
87                 Element->CachedW-ciTextInput_MarginH, Element->CachedH-ciTextInput_MarginV,
88                 gpTextInput_Font, TEXTINPUT_TEXT,
89                 &Element->Text[info->DrawOfs], -1
90                 );
91
92         // Cursor
93         if( wininfo->FocusedElement == Element )
94         {
95                 WM_Render_SetTextCursor(Window,
96                         Element->CachedX+ciTextInput_MarginL+info->CursorXOfs,
97                         Element->CachedY+ciTextInput_MarginR,
98                         1, Element->CachedH-ciTextInput_MarginV,
99                         TEXTINPUT_TEXT
100                         );
101         }
102 }
103
104 void Widget_TextInput_Init(tElement *Element)
105 {
106         struct sTextInputInfo   *info;
107          int    h;
108
109         // TODO: Select font correctly  
110         WM_Render_GetTextDims(gpTextInput_Font, "jy|qJ", -1, NULL, &h);
111
112         h += ciTextInput_MarginV;       // Border padding
113
114         Element->MinH = h;
115         Element->MinW = ciTextInput_MarginH;
116
117         info = Element->Data = malloc(sizeof(*info));
118         info->DrawOfs = 0;
119         info->CursorXOfs = 0;
120         info->CursorByteOfs = 0;
121         info->Length = 0;
122
123         // No need to explicitly update parent min dims, as the AddElement routine does that    
124 }
125
126 int Widget_TextInput_KeyFire(tElement *Element, int KeySym, int Character)
127 {
128         struct sTextInputInfo   *info = Element->Data;
129          int    len;
130          int    w;
131         char    *dest;
132         uint32_t        cp;
133
134 //      _SysDebug("Key 0x%x fired ('%c')", Character, Character);
135         
136         if( Character == 0 )
137         {
138                 switch(KeySym)
139                 {
140                 case KEYSYM_LEFTARROW:
141                         if( info->CursorByteOfs > 0 )
142                         {
143                                 len = ReadUTF8Rev(Element->Text, info->CursorByteOfs, &cp);
144                                 info->CursorByteOfs -= len;
145                                 WM_Render_GetTextDims(
146                                         gpTextInput_Font,
147                                         Element->Text+info->CursorByteOfs,
148                                         len, &w, 0
149                                         );
150                                 info->CursorXOfs -= w;
151                         }
152                         break;
153                 case KEYSYM_RIGHTARROW:
154                         if( info->CursorByteOfs < info->Length )
155                         {
156                                 len = ReadUTF8(Element->Text + info->CursorByteOfs, &cp);
157                                 WM_Render_GetTextDims(
158                                         gpTextInput_Font,
159                                         Element->Text+info->CursorByteOfs,
160                                         len, &w, 0
161                                         );
162                                 info->CursorByteOfs += len;
163                                 info->CursorXOfs += w;
164                         }
165                         break;
166                 }
167                 return 0;
168         }
169
170         // TODO: Don't hard code
171         if(Character > 0x30000000)      return 0;
172
173         switch(Character)
174         {
175         case '\t':
176                 return 0;
177         
178         case '\b':
179                 // Check if there is anything to delete
180                 if( info->CursorByteOfs == 0 )  return 0;
181                 // Get character to be deleted
182                 len = ReadUTF8Rev(Element->Text, info->CursorByteOfs, &cp);
183                 info->CursorByteOfs -= len;
184                 dest = &Element->Text[info->CursorByteOfs];
185 //              _SysDebug("\\b, len = %i, removing '%.*s'", len, len, dest);
186                 WM_Render_GetTextDims(gpTextInput_Font, dest, len, &w, 0);
187                 // Remove from buffer
188                 memmove(dest, &dest[len], info->Length - info->CursorByteOfs - len);
189                 info->Length -= len;
190                 Element->Text[info->Length] = '\0';
191                 // Adjust cursor
192                 info->CursorXOfs -= w;
193                 break;
194         default:
195                 if(Character >= 0x30000000)     return 0;
196                 if(Character < ' ')     return 0;
197
198                 // Get required length
199                 len = WriteUTF8(NULL, Character);
200
201                 // Create space (possibly in the middle)        
202                 Element->Text = realloc(Element->Text, info->Length + len + 1);
203                 dest = &Element->Text[info->CursorByteOfs];
204                 memmove(&dest[len], dest, info->Length - info->CursorByteOfs);
205                 // Add the character
206                 WriteUTF8(dest, Character);
207                 info->CursorByteOfs += len;
208                 info->Length += len;
209                 Element->Text[info->Length] = '\0';
210
211                 // Update the cursor position
212                 // - Scrolling is implemented in render function (CachedW/CachedH are invalid atm)
213                 WM_Render_GetTextDims(gpTextInput_Font, dest, len, &w, NULL);
214                 info->CursorXOfs += w;
215         }
216
217         // TODO: Have a Widget_ function to do this instead
218         WM_Invalidate(Element->Window, 1);
219         
220         return 0;
221 }
222
223 DEFWIDGETTYPE(ELETYPE_TEXTINPUT, "TextInput",
224         WIDGETTYPE_FLAG_NOCHILDREN,
225         .Render = Widget_TextInput_Render,
226         .Init = Widget_TextInput_Init,
227         .KeyFire = Widget_TextInput_KeyFire
228         );
229

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