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

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