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