Commit | Line | Data |
---|---|---|
ef8f34aa | 1 | #include <slang.h> |
8f9bbc40 ACM |
2 | #include "libslang.h" |
3 | #include <linux/compiler.h> | |
ef8f34aa ACM |
4 | #include <linux/list.h> |
5 | #include <linux/rbtree.h> | |
6 | #include <stdlib.h> | |
7 | #include <sys/ttydefaults.h> | |
8 | #include "browser.h" | |
59e8fe32 | 9 | #include "helpline.h" |
ef8f34aa ACM |
10 | #include "../color.h" |
11 | #include "../util.h" | |
8f9bbc40 | 12 | #include <stdio.h> |
ef8f34aa ACM |
13 | |
14 | newtComponent newt_form__new(void); | |
15 | ||
8f9bbc40 | 16 | static int ui_browser__percent_color(double percent, bool current) |
ef8f34aa ACM |
17 | { |
18 | if (current) | |
19 | return HE_COLORSET_SELECTED; | |
20 | if (percent >= MIN_RED) | |
21 | return HE_COLORSET_TOP; | |
22 | if (percent >= MIN_GREEN) | |
23 | return HE_COLORSET_MEDIUM; | |
24 | return HE_COLORSET_NORMAL; | |
25 | } | |
26 | ||
8f9bbc40 ACM |
27 | void ui_browser__set_color(struct ui_browser *self __used, int color) |
28 | { | |
29 | SLsmg_set_color(color); | |
30 | } | |
31 | ||
32 | void ui_browser__set_percent_color(struct ui_browser *self, | |
33 | double percent, bool current) | |
34 | { | |
35 | int color = ui_browser__percent_color(percent, current); | |
36 | ui_browser__set_color(self, color); | |
37 | } | |
38 | ||
39 | void ui_browser__gotorc(struct ui_browser *self, int y, int x) | |
40 | { | |
41 | SLsmg_gotorc(self->y + y, self->x + x); | |
42 | } | |
43 | ||
ef8f34aa ACM |
44 | void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) |
45 | { | |
46 | struct list_head *head = self->entries; | |
47 | struct list_head *pos; | |
48 | ||
49 | switch (whence) { | |
50 | case SEEK_SET: | |
51 | pos = head->next; | |
52 | break; | |
53 | case SEEK_CUR: | |
d247eb6b | 54 | pos = self->top; |
ef8f34aa ACM |
55 | break; |
56 | case SEEK_END: | |
57 | pos = head->prev; | |
58 | break; | |
59 | default: | |
60 | return; | |
61 | } | |
62 | ||
63 | if (offset > 0) { | |
64 | while (offset-- != 0) | |
65 | pos = pos->next; | |
66 | } else { | |
67 | while (offset++ != 0) | |
68 | pos = pos->prev; | |
69 | } | |
70 | ||
d247eb6b | 71 | self->top = pos; |
ef8f34aa ACM |
72 | } |
73 | ||
74 | void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence) | |
75 | { | |
76 | struct rb_root *root = self->entries; | |
77 | struct rb_node *nd; | |
78 | ||
79 | switch (whence) { | |
80 | case SEEK_SET: | |
81 | nd = rb_first(root); | |
82 | break; | |
83 | case SEEK_CUR: | |
d247eb6b | 84 | nd = self->top; |
ef8f34aa ACM |
85 | break; |
86 | case SEEK_END: | |
87 | nd = rb_last(root); | |
88 | break; | |
89 | default: | |
90 | return; | |
91 | } | |
92 | ||
93 | if (offset > 0) { | |
94 | while (offset-- != 0) | |
95 | nd = rb_next(nd); | |
96 | } else { | |
97 | while (offset++ != 0) | |
98 | nd = rb_prev(nd); | |
99 | } | |
100 | ||
d247eb6b | 101 | self->top = nd; |
ef8f34aa ACM |
102 | } |
103 | ||
104 | unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self) | |
105 | { | |
106 | struct rb_node *nd; | |
107 | int row = 0; | |
108 | ||
d247eb6b ACM |
109 | if (self->top == NULL) |
110 | self->top = rb_first(self->entries); | |
ef8f34aa | 111 | |
d247eb6b | 112 | nd = self->top; |
ef8f34aa ACM |
113 | |
114 | while (nd != NULL) { | |
8f9bbc40 | 115 | ui_browser__gotorc(self, row, 0); |
ef8f34aa ACM |
116 | self->write(self, nd, row); |
117 | if (++row == self->height) | |
118 | break; | |
119 | nd = rb_next(nd); | |
120 | } | |
121 | ||
122 | return row; | |
123 | } | |
124 | ||
125 | bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) | |
126 | { | |
d247eb6b | 127 | return self->top_idx + row == self->index; |
ef8f34aa ACM |
128 | } |
129 | ||
130 | void ui_browser__refresh_dimensions(struct ui_browser *self) | |
131 | { | |
132 | int cols, rows; | |
133 | newtGetScreenSize(&cols, &rows); | |
134 | ||
135 | if (self->width > cols - 4) | |
136 | self->width = cols - 4; | |
137 | self->height = rows - 5; | |
138 | if (self->height > self->nr_entries) | |
139 | self->height = self->nr_entries; | |
d247eb6b ACM |
140 | self->y = (rows - self->height) / 2; |
141 | self->x = (cols - self->width) / 2; | |
ef8f34aa ACM |
142 | } |
143 | ||
144 | void ui_browser__reset_index(struct ui_browser *self) | |
145 | { | |
d247eb6b | 146 | self->index = self->top_idx = 0; |
ef8f34aa ACM |
147 | self->seek(self, 0, SEEK_SET); |
148 | } | |
149 | ||
59e8fe32 ACM |
150 | int ui_browser__show(struct ui_browser *self, const char *title, |
151 | const char *helpline, ...) | |
ef8f34aa | 152 | { |
59e8fe32 ACM |
153 | va_list ap; |
154 | ||
ef8f34aa ACM |
155 | if (self->form != NULL) { |
156 | newtFormDestroy(self->form); | |
157 | newtPopWindow(); | |
158 | } | |
159 | ui_browser__refresh_dimensions(self); | |
160 | newtCenteredWindow(self->width, self->height, title); | |
161 | self->form = newt_form__new(); | |
162 | if (self->form == NULL) | |
163 | return -1; | |
164 | ||
165 | self->sb = newtVerticalScrollbar(self->width, 0, self->height, | |
166 | HE_COLORSET_NORMAL, | |
167 | HE_COLORSET_SELECTED); | |
168 | if (self->sb == NULL) | |
169 | return -1; | |
170 | ||
171 | newtFormAddHotKey(self->form, NEWT_KEY_UP); | |
172 | newtFormAddHotKey(self->form, NEWT_KEY_DOWN); | |
173 | newtFormAddHotKey(self->form, NEWT_KEY_PGUP); | |
174 | newtFormAddHotKey(self->form, NEWT_KEY_PGDN); | |
175 | newtFormAddHotKey(self->form, NEWT_KEY_HOME); | |
176 | newtFormAddHotKey(self->form, NEWT_KEY_END); | |
9e22d637 | 177 | newtFormAddHotKey(self->form, ' '); |
ef8f34aa | 178 | newtFormAddComponent(self->form, self->sb); |
59e8fe32 ACM |
179 | |
180 | va_start(ap, helpline); | |
181 | ui_helpline__vpush(helpline, ap); | |
182 | va_end(ap); | |
ef8f34aa ACM |
183 | return 0; |
184 | } | |
185 | ||
59e8fe32 ACM |
186 | void ui_browser__hide(struct ui_browser *self) |
187 | { | |
188 | newtFormDestroy(self->form); | |
189 | newtPopWindow(); | |
190 | self->form = NULL; | |
191 | ui_helpline__pop(); | |
192 | } | |
193 | ||
ef8f34aa ACM |
194 | int ui_browser__refresh(struct ui_browser *self) |
195 | { | |
196 | int row; | |
197 | ||
198 | newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); | |
199 | row = self->refresh(self); | |
8f9bbc40 | 200 | ui_browser__set_color(self, HE_COLORSET_NORMAL); |
d247eb6b | 201 | SLsmg_fill_region(self->y + row, self->x, |
ef8f34aa ACM |
202 | self->height - row, self->width, ' '); |
203 | ||
204 | return 0; | |
205 | } | |
206 | ||
207 | int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es) | |
208 | { | |
209 | if (ui_browser__refresh(self) < 0) | |
210 | return -1; | |
211 | ||
212 | while (1) { | |
213 | off_t offset; | |
214 | ||
215 | newtFormRun(self->form, es); | |
216 | ||
217 | if (es->reason != NEWT_EXIT_HOTKEY) | |
218 | break; | |
219 | if (is_exit_key(es->u.key)) | |
220 | return es->u.key; | |
221 | switch (es->u.key) { | |
222 | case NEWT_KEY_DOWN: | |
223 | if (self->index == self->nr_entries - 1) | |
224 | break; | |
225 | ++self->index; | |
d247eb6b ACM |
226 | if (self->index == self->top_idx + self->height) { |
227 | ++self->top_idx; | |
ef8f34aa ACM |
228 | self->seek(self, +1, SEEK_CUR); |
229 | } | |
230 | break; | |
231 | case NEWT_KEY_UP: | |
232 | if (self->index == 0) | |
233 | break; | |
234 | --self->index; | |
d247eb6b ACM |
235 | if (self->index < self->top_idx) { |
236 | --self->top_idx; | |
ef8f34aa ACM |
237 | self->seek(self, -1, SEEK_CUR); |
238 | } | |
239 | break; | |
240 | case NEWT_KEY_PGDN: | |
241 | case ' ': | |
d247eb6b | 242 | if (self->top_idx + self->height > self->nr_entries - 1) |
ef8f34aa ACM |
243 | break; |
244 | ||
245 | offset = self->height; | |
246 | if (self->index + offset > self->nr_entries - 1) | |
247 | offset = self->nr_entries - 1 - self->index; | |
248 | self->index += offset; | |
d247eb6b | 249 | self->top_idx += offset; |
ef8f34aa ACM |
250 | self->seek(self, +offset, SEEK_CUR); |
251 | break; | |
252 | case NEWT_KEY_PGUP: | |
d247eb6b | 253 | if (self->top_idx == 0) |
ef8f34aa ACM |
254 | break; |
255 | ||
d247eb6b ACM |
256 | if (self->top_idx < self->height) |
257 | offset = self->top_idx; | |
ef8f34aa ACM |
258 | else |
259 | offset = self->height; | |
260 | ||
261 | self->index -= offset; | |
d247eb6b | 262 | self->top_idx -= offset; |
ef8f34aa ACM |
263 | self->seek(self, -offset, SEEK_CUR); |
264 | break; | |
265 | case NEWT_KEY_HOME: | |
266 | ui_browser__reset_index(self); | |
267 | break; | |
268 | case NEWT_KEY_END: | |
269 | offset = self->height - 1; | |
270 | if (offset >= self->nr_entries) | |
271 | offset = self->nr_entries - 1; | |
272 | ||
273 | self->index = self->nr_entries - 1; | |
d247eb6b | 274 | self->top_idx = self->index - offset; |
ef8f34aa ACM |
275 | self->seek(self, -offset, SEEK_END); |
276 | break; | |
277 | default: | |
278 | return es->u.key; | |
279 | } | |
280 | if (ui_browser__refresh(self) < 0) | |
281 | return -1; | |
282 | } | |
283 | return 0; | |
284 | } | |
285 | ||
286 | unsigned int ui_browser__list_head_refresh(struct ui_browser *self) | |
287 | { | |
288 | struct list_head *pos; | |
289 | struct list_head *head = self->entries; | |
290 | int row = 0; | |
291 | ||
d247eb6b ACM |
292 | if (self->top == NULL || self->top == self->entries) |
293 | self->top = head->next; | |
ef8f34aa | 294 | |
d247eb6b | 295 | pos = self->top; |
ef8f34aa ACM |
296 | |
297 | list_for_each_from(pos, head) { | |
8f9bbc40 | 298 | ui_browser__gotorc(self, row, 0); |
ef8f34aa ACM |
299 | self->write(self, pos, row); |
300 | if (++row == self->height) | |
301 | break; | |
302 | } | |
303 | ||
304 | return row; | |
305 | } | |
306 | ||
307 | static struct newtPercentTreeColors { | |
308 | const char *topColorFg, *topColorBg; | |
309 | const char *mediumColorFg, *mediumColorBg; | |
310 | const char *normalColorFg, *normalColorBg; | |
311 | const char *selColorFg, *selColorBg; | |
312 | const char *codeColorFg, *codeColorBg; | |
313 | } defaultPercentTreeColors = { | |
314 | "red", "lightgray", | |
315 | "green", "lightgray", | |
316 | "black", "lightgray", | |
317 | "lightgray", "magenta", | |
318 | "blue", "lightgray", | |
319 | }; | |
320 | ||
321 | void ui_browser__init(void) | |
322 | { | |
323 | struct newtPercentTreeColors *c = &defaultPercentTreeColors; | |
324 | ||
325 | sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); | |
326 | sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); | |
327 | sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg); | |
328 | sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg); | |
329 | sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg); | |
330 | } |