1 /*
2 * STFL - The Structured Terminal Forms Language/Library
3 * Copyright (C) 2006, 2007 Clifford Wolf <clifford@clifford.at>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 3 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301 USA
19 *
20 * wt_input.c: Widget type 'input'
21 */
22
23 #include "stfl_internals.h"
24
25 #include <string.h>
26 #include <stdlib.h>
27 #include <wctype.h>
28
wt_input_init(struct stfl_widget * w)29 static void wt_input_init(struct stfl_widget *w)
30 {
31 w->allow_focus = 1;
32 }
33
fix_offset_pos(struct stfl_widget * w)34 static void fix_offset_pos(struct stfl_widget *w)
35 {
36 int pos = stfl_widget_getkv_int(w, L"pos", 0);
37 int offset = stfl_widget_getkv_int(w, L"offset", 0);
38 const wchar_t* text = stfl_widget_getkv_str(w, L"text", L"");
39 int text_len = wcslen(text);
40 int changed = 0;
41 int width;
42
43 if (pos > text_len) {
44 pos = text_len;
45 changed = 1;
46 }
47
48 if (offset > pos) {
49 offset = pos;
50 changed = 1;
51 }
52
53 width = wcswidth(text + offset, pos - offset);
54 while (width >= w->w && pos > offset) {
55 width -= wcwidth(text[offset++]);
56 changed = 1;
57 }
58
59 if (changed) {
60 stfl_widget_setkv_int(w, L"pos", pos);
61 stfl_widget_setkv_int(w, L"offset", offset);
62 }
63 }
64
wt_input_prepare(struct stfl_widget * w,struct stfl_form * f)65 static void wt_input_prepare(struct stfl_widget *w, struct stfl_form *f)
66 {
67 int size = stfl_widget_getkv_int(w, L"size", 5);
68
69 w->min_w = size;
70 w->min_h = 1;
71
72 fix_offset_pos(w);
73 }
74
wt_input_draw(struct stfl_widget * w,struct stfl_form * f,WINDOW * win)75 static void wt_input_draw(struct stfl_widget *w, struct stfl_form *f, WINDOW *win)
76 {
77 int pos = stfl_widget_getkv_int(w, L"pos", 0);
78 int blind = stfl_widget_getkv_int(w, L"blind", 0);
79 int offset = stfl_widget_getkv_int(w, L"offset", 0);
80 const wchar_t * const text_off = stfl_widget_getkv_str(w, L"text", L"") + offset;
81 int i;
82
83 stfl_widget_style(w, f, win);
84
85 for (i=0; i<w->w; i++)
86 mvwaddwstr(win, w->y, w->x+i, L" ");
87
88 if (!blind) {
89 const int off_len = wcslen(text_off);
90 int width, len;
91
92 width = wcswidth(text_off, w->w);
93 if (w->w > off_len)
94 len = off_len;
95 else
96 len = w->w;
97 while (width > w->w)
98 width -= wcwidth(text_off[--len]);
99 mvwaddnwstr(win, w->y, w->x, text_off, len);
100 }
101
102 if (f->current_focus_id == w->id) {
103 f->root->cur_x = f->cursor_x = w->x + wcswidth(text_off, pos - offset);
104 f->root->cur_y = f->cursor_y = w->y;
105 }
106 }
107
wt_input_process(struct stfl_widget * w,struct stfl_widget * fw,struct stfl_form * f,wchar_t ch,int isfunckey)108 static int wt_input_process(struct stfl_widget *w, struct stfl_widget *fw, struct stfl_form *f, wchar_t ch, int isfunckey)
109 {
110 int pos = stfl_widget_getkv_int(w, L"pos", 0);
111 const wchar_t *text = stfl_widget_getkv_str(w, L"text", L"");
112 int text_len = wcslen(text);
113
114 if (pos > 0 && stfl_matchbind(w, ch, isfunckey, L"left", L"LEFT")) {
115 stfl_widget_setkv_int(w, L"pos", pos-1);
116 fix_offset_pos(w);
117 return 1;
118 }
119
120 if (pos < text_len && stfl_matchbind(w, ch, isfunckey, L"right", L"RIGHT")) {
121 stfl_widget_setkv_int(w, L"pos", pos+1);
122 fix_offset_pos(w);
123 return 1;
124 }
125
126 // pos1 / home / Ctrl-A
127 if (stfl_matchbind(w, ch, isfunckey, L"home", L"HOME ^A")) {
128 stfl_widget_setkv_int(w, L"pos", 0);
129 fix_offset_pos(w);
130 return 1;
131 }
132
133 // end / Ctrl-E
134 if (stfl_matchbind(w, ch, isfunckey, L"end", L"END ^E")) {
135 stfl_widget_setkv_int(w, L"pos", text_len);
136 fix_offset_pos(w);
137 return 1;
138 }
139
140 // delete
141 if (stfl_matchbind(w, ch, isfunckey, L"delete", L"DC")) {
142 if (pos == text_len)
143 return 0;
144 wchar_t newtext[text_len];
145 wmemcpy(newtext, text, pos);
146 wcscpy(newtext + pos, text + pos + 1);
147 stfl_widget_setkv_str(w, L"text", newtext);
148 fix_offset_pos(w);
149 return 1;
150 }
151
152 // backspace
153 if (stfl_matchbind(w, ch, isfunckey, L"backspace", L"BACKSPACE")) {
154 if (pos == 0)
155 return 0;
156 wchar_t newtext[text_len];
157 wmemcpy(newtext, text, pos-1);
158 wcscpy(newtext + pos - 1, text + pos);
159 stfl_widget_setkv_str(w, L"text", newtext);
160 stfl_widget_setkv_int(w, L"pos", pos-1);
161 fix_offset_pos(w);
162 return 1;
163 }
164
165 // 'normal' characters
166 if (!isfunckey && iswprint(ch)) {
167 wchar_t newtext[text_len + 2];
168 wmemcpy(newtext, text, pos);
169 newtext[pos] = ch;
170 wcscpy(newtext + pos + 1, text + pos);
171 stfl_widget_setkv_str(w, L"text", newtext);
172 stfl_widget_setkv_int(w, L"pos", pos+1);
173 fix_offset_pos(w);
174 return 1;
175 }
176
177 return 0;
178 }
179
180 struct stfl_widget_type stfl_widget_type_input = {
181 L"input",
182 wt_input_init,
183 0, // f_done
184 0, // f_enter
185 0, // f_leave
186 wt_input_prepare,
187 wt_input_draw,
188 wt_input_process
189 };
190
191