Merge branch 'master' of git://localhost/acess2
[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
121         // No need to explicitly update parent min dims, as the AddElement routine does that    
122 }
123
124 int Widget_TextInput_KeyFire(tElement *Element, int KeySym, int Character)
125 {
126         struct sTextInputInfo   *info = Element->Data;
127          int    len;
128          int    w;
129         char    *dest;
130         uint32_t        cp;
131
132 //      _SysDebug("Key 0x%x fired ('%c')", Character, Character);
133         
134         if( Character == 0 )
135         {
136                 switch(KeySym)
137                 {
138                 case KEYSYM_LEFTARROW:
139                         if( info->CursorByteOfs > 0 )
140                         {
141                                 len = ReadUTF8Rev(Element->Text, info->CursorByteOfs, &cp);
142                                 info->CursorByteOfs -= len;
143                                 WM_Render_GetTextDims(
144                                         gpTextInput_Font,
145                                         Element->Text+info->CursorByteOfs,
146                                         len, &w, 0
147                                         );
148                                 info->CursorXOfs -= w;
149                         }
150                         break;
151                 case KEYSYM_RIGHTARROW:
152                         if( info->CursorByteOfs < info->Length )
153                         {
154                                 len = ReadUTF8(Element->Text + info->CursorByteOfs, &cp);
155                                 WM_Render_GetTextDims(
156                                         gpTextInput_Font,
157                                         Element->Text+info->CursorByteOfs,
158                                         len, &w, 0
159                                         );
160                                 info->CursorByteOfs += len;
161                                 info->CursorXOfs += w;
162                         }
163                         break;
164                 }
165                 return 0;
166         }
167
168         // TODO: Don't hard code
169         if(Character > 0x30000000)      return 0;
170
171         switch(Character)
172         {
173         case '\t':
174                 return 0;
175         
176         case '\b':
177                 // Check if there is anything to delete
178                 if( info->CursorByteOfs == 0 )  return 0;
179                 // Get character to be deleted
180                 len = ReadUTF8Rev(Element->Text, info->CursorByteOfs, &cp);
181                 info->CursorByteOfs -= len;
182                 dest = &Element->Text[info->CursorByteOfs];
183 //              _SysDebug("\\b, len = %i, removing '%.*s'", len, len, dest);
184                 WM_Render_GetTextDims(gpTextInput_Font, dest, len, &w, 0);
185                 // Remove from buffer
186                 memmove(dest, &dest[len], info->Length - info->CursorByteOfs - len);
187                 info->Length -= len;
188                 Element->Text[info->Length] = '\0';
189                 // Adjust cursor
190                 info->CursorXOfs -= w;
191                 break;
192         default:
193                 if(Character >= 0x30000000)     return 0;
194                 if(Character < ' ')     return 0;
195
196                 // Get required length
197                 len = WriteUTF8(NULL, Character);
198
199                 // Create space (possibly in the middle)        
200                 Element->Text = realloc(Element->Text, info->Length + len + 1);
201                 dest = &Element->Text[info->CursorByteOfs];
202                 memmove(&dest[len], dest, info->Length - info->CursorByteOfs);
203                 // Add the character
204                 WriteUTF8(dest, Character);
205                 info->CursorByteOfs += len;
206                 info->Length += len;
207                 Element->Text[info->Length] = '\0';
208
209                 // Update the cursor position
210                 // - Scrolling is implemented in render function (CachedW/CachedH are invalid atm)
211                 WM_Render_GetTextDims(gpTextInput_Font, dest, len, &w, NULL);
212                 info->CursorXOfs += w;
213         }
214
215         // TODO: Have a Widget_ function to do this instead
216         WM_Invalidate(Element->Window, 1);
217         
218         return 0;
219 }
220
221 DEFWIDGETTYPE(ELETYPE_TEXTINPUT,
222         WIDGETTYPE_FLAG_NOCHILDREN,
223         .Render = Widget_TextInput_Render,
224         .Init = Widget_TextInput_Init,
225         .KeyFire = Widget_TextInput_KeyFire
226         );
227

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