Annotation of src/usr.bin/tmux/window-choose.c, Revision 1.2
1.2 ! nicm 1: /* $OpenBSD: window-choose.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <string.h>
22:
23: #include "tmux.h"
24:
25: struct screen *window_choose_init(struct window_pane *);
26: void window_choose_free(struct window_pane *);
27: void window_choose_resize(struct window_pane *, u_int, u_int);
28: void window_choose_key(struct window_pane *, struct client *, int);
29: void window_choose_mouse(
30: struct window_pane *, struct client *, u_char, u_char, u_char);
31:
32: void window_choose_redraw_screen(struct window_pane *);
33: void window_choose_write_line(
34: struct window_pane *, struct screen_write_ctx *, u_int);
35:
36: void window_choose_scroll_up(struct window_pane *);
37: void window_choose_scroll_down(struct window_pane *);
38:
39: const struct window_mode window_choose_mode = {
40: window_choose_init,
41: window_choose_free,
42: window_choose_resize,
43: window_choose_key,
44: window_choose_mouse,
45: NULL,
46: };
47:
48: struct window_choose_mode_item {
49: char *name;
50: int idx;
51: };
52:
53: struct window_choose_mode_data {
54: struct screen screen;
55:
56: struct mode_key_data mdata;
57:
58: ARRAY_DECL(, struct window_choose_mode_item) list;
59: u_int top;
60: u_int selected;
61:
62: void (*callback)(void *, int);
63: void *data;
64: };
65:
66: void
67: window_choose_vadd(struct window_pane *wp, int idx, const char *fmt, va_list ap)
68: {
69: struct window_choose_mode_data *data = wp->modedata;
70: struct window_choose_mode_item *item;
71:
72: ARRAY_EXPAND(&data->list, 1);
73: item = &ARRAY_LAST(&data->list);
74: xvasprintf(&item->name, fmt, ap);
75: item->idx = idx;
76: }
77:
78: void printflike3
79: window_choose_add(struct window_pane *wp, int idx, const char *fmt, ...)
80: {
81: va_list ap;
82:
83: va_start(ap, fmt);
84: window_choose_vadd(wp, idx, fmt, ap);
85: va_end(ap);
86: }
87:
88: void
89: window_choose_ready(struct window_pane *wp,
90: u_int cur, void (*callback)(void *, int), void *cdata)
91: {
92: struct window_choose_mode_data *data = wp->modedata;
93: struct screen *s = &data->screen;
94:
95: data->selected = cur;
96: if (data->selected > screen_size_y(s) - 1)
97: data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s);
98:
99: data->callback = callback;
100: data->data = cdata;
101:
102: window_choose_redraw_screen(wp);
103: }
104:
105: struct screen *
106: window_choose_init(struct window_pane *wp)
107: {
108: struct window_choose_mode_data *data;
109: struct screen *s;
110:
111: wp->modedata = data = xmalloc(sizeof *data);
112: data->callback = NULL;
113: ARRAY_INIT(&data->list);
114: data->top = 0;
115:
116: s = &data->screen;
117: screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
118: s->mode &= ~MODE_CURSOR;
119: s->mode |= MODE_MOUSE;
120:
121: mode_key_init(&data->mdata,
122: options_get_number(&wp->window->options, "mode-keys"),
123: MODEKEY_CHOOSEMODE);
124:
125: return (s);
126: }
127:
128: void
129: window_choose_free(struct window_pane *wp)
130: {
131: struct window_choose_mode_data *data = wp->modedata;
132: u_int i;
133:
134: mode_key_free(&data->mdata);
135:
136: for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
137: xfree(ARRAY_ITEM(&data->list, i).name);
138: ARRAY_FREE(&data->list);
139:
140: screen_free(&data->screen);
141: xfree(data);
142: }
143:
144: void
145: window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
146: {
147: struct window_choose_mode_data *data = wp->modedata;
148: struct screen *s = &data->screen;
149:
150: data->top = 0;
151: if (data->selected > sy - 1)
152: data->top = data->selected - (sy - 1);
153:
154: screen_resize(s, sx, sy);
155: window_choose_redraw_screen(wp);
156: }
157:
158: void
159: window_choose_key(struct window_pane *wp, unused struct client *c, int key)
160: {
161: struct window_choose_mode_data *data = wp->modedata;
162: struct screen *s = &data->screen;
163: struct screen_write_ctx ctx;
164: struct window_choose_mode_item *item;
165: u_int items;
166:
167: items = ARRAY_LENGTH(&data->list);
168:
169: switch (mode_key_lookup(&data->mdata, key)) {
170: case MODEKEYCMD_QUIT:
171: data->callback(data->data, -1);
172: window_pane_reset_mode(wp);
173: break;
174: case MODEKEYCMD_CHOOSE:
175: item = &ARRAY_ITEM(&data->list, data->selected);
176: data->callback(data->data, item->idx);
177: window_pane_reset_mode(wp);
178: break;
179: case MODEKEYCMD_UP:
180: if (items == 0)
181: break;
182: if (data->selected == 0) {
183: data->selected = items - 1;
184: if (data->selected > screen_size_y(s) - 1)
185: data->top = items - screen_size_y(s);
186: window_choose_redraw_screen(wp);
187: break;
188: }
189: data->selected--;
190: if (data->selected < data->top)
191: window_choose_scroll_up(wp);
192: else {
193: screen_write_start(&ctx, wp, NULL);
194: window_choose_write_line(
195: wp, &ctx, data->selected - data->top);
196: window_choose_write_line(
197: wp, &ctx, data->selected + 1 - data->top);
198: screen_write_stop(&ctx);
199: }
200: break;
201: case MODEKEYCMD_DOWN:
202: if (items == 0)
203: break;
204: if (data->selected == items - 1) {
205: data->selected = 0;
206: data->top = 0;
207: window_choose_redraw_screen(wp);
208: break;
209: }
210: data->selected++;
211: if (data->selected >= data->top + screen_size_y(&data->screen))
212: window_choose_scroll_down(wp);
213: else {
214: screen_write_start(&ctx, wp, NULL);
215: window_choose_write_line(
216: wp, &ctx, data->selected - data->top);
217: window_choose_write_line(
218: wp, &ctx, data->selected - 1 - data->top);
219: screen_write_stop(&ctx);
220: }
221: break;
222: case MODEKEYCMD_PREVIOUSPAGE:
223: if (data->selected < screen_size_y(s)) {
224: data->selected = 0;
225: data->top = 0;
226: } else {
227: data->selected -= screen_size_y(s);
228: if (data->top < screen_size_y(s))
229: data->top = 0;
230: else
231: data->top -= screen_size_y(s);
232: }
233: window_choose_redraw_screen(wp);
234: break;
235: case MODEKEYCMD_NEXTPAGE:
236: data->selected += screen_size_y(s);
237: if (data->selected > items - 1)
238: data->selected = items - 1;
239: data->top += screen_size_y(s);
240: if (screen_size_y(s) < items) {
241: if (data->top + screen_size_y(s) > items)
242: data->top = items - screen_size_y(s);
243: } else
244: data->top = 0;
245: if (data->selected < data->top)
246: data->top = data->selected;
247: window_choose_redraw_screen(wp);
248: break;
249: default:
250: break;
251: }
252: }
253:
254: void
255: window_choose_mouse(struct window_pane *wp,
256: unused struct client *c, u_char b, u_char x, u_char y)
257: {
258: struct window_choose_mode_data *data = wp->modedata;
259: struct screen *s = &data->screen;
260: struct window_choose_mode_item *item;
261: u_int idx;
262:
263: if ((b & 3) == 3)
264: return;
265: if (x >= screen_size_x(s))
266: return;
267: if (y >= screen_size_y(s))
268: return;
269:
270: idx = data->top + y;
271: if (idx >= ARRAY_LENGTH(&data->list))
272: return;
273: data->selected = idx;
274:
275: item = &ARRAY_ITEM(&data->list, data->selected);
276: data->callback(data->data, item->idx);
277: window_pane_reset_mode(wp);
278: }
279:
280: void
281: window_choose_write_line(
282: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
283: {
284: struct window_choose_mode_data *data = wp->modedata;
285: struct window_choose_mode_item *item;
286: struct screen *s = &data->screen;
287: struct grid_cell gc;
1.2 ! nicm 288: int utf8flag;
1.1 nicm 289:
290: if (data->callback == NULL)
291: fatalx("called before callback assigned");
292:
1.2 ! nicm 293: utf8flag = options_get_number(&wp->window->options, "utf8");
1.1 nicm 294: memcpy(&gc, &grid_default_cell, sizeof gc);
295: if (data->selected == data->top + py) {
296: gc.fg = options_get_number(&wp->window->options, "mode-bg");
297: gc.bg = options_get_number(&wp->window->options, "mode-fg");
298: gc.attr |= options_get_number(&wp->window->options, "mode-attr");
299: }
300:
301: screen_write_cursormove(ctx, 0, py);
302: if (data->top + py < ARRAY_LENGTH(&data->list)) {
303: item = &ARRAY_ITEM(&data->list, data->top + py);
1.2 ! nicm 304: screen_write_nputs(
! 305: ctx, screen_size_x(s) - 1, &gc, utf8flag, "%s", item->name);
1.1 nicm 306: }
307: while (s->cx < screen_size_x(s))
308: screen_write_putc(ctx, &gc, ' ');
309: }
310:
311: void
312: window_choose_redraw_screen(struct window_pane *wp)
313: {
314: struct window_choose_mode_data *data = wp->modedata;
315: struct screen *s = &data->screen;
316: struct screen_write_ctx ctx;
317: u_int i;
318:
319: screen_write_start(&ctx, wp, NULL);
320: for (i = 0; i < screen_size_y(s); i++)
321: window_choose_write_line(wp, &ctx, i);
322: screen_write_stop(&ctx);
323: }
324:
325: void
326: window_choose_scroll_up(struct window_pane *wp)
327: {
328: struct window_choose_mode_data *data = wp->modedata;
329: struct screen_write_ctx ctx;
330:
331: if (data->top == 0)
332: return;
333: data->top--;
334:
335: screen_write_start(&ctx, wp, NULL);
336: screen_write_cursormove(&ctx, 0, 0);
337: screen_write_insertline(&ctx, 1);
338: window_choose_write_line(wp, &ctx, 0);
339: if (screen_size_y(&data->screen) > 1)
340: window_choose_write_line(wp, &ctx, 1);
341: screen_write_stop(&ctx);
342: }
343:
344: void
345: window_choose_scroll_down(struct window_pane *wp)
346: {
347: struct window_choose_mode_data *data = wp->modedata;
348: struct screen *s = &data->screen;
349: struct screen_write_ctx ctx;
350:
351: if (data->top >= ARRAY_LENGTH(&data->list))
352: return;
353: data->top++;
354:
355: screen_write_start(&ctx, wp, NULL);
356: screen_write_cursormove(&ctx, 0, 0);
357: screen_write_deleteline(&ctx, 1);
358: window_choose_write_line(wp, &ctx, screen_size_y(s) - 1);
359: if (screen_size_y(&data->screen) > 1)
360: window_choose_write_line(wp, &ctx, screen_size_y(s) - 2);
361: screen_write_stop(&ctx);
362: }