Annotation of src/usr.bin/tmux/window-choose.c, Revision 1.4
1.4 ! nicm 1: /* $OpenBSD: window-choose.c,v 1.3 2009/07/17 07:05:58 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:
1.3 nicm 62: void (*callbackfn)(void *, int);
63: void (*freefn)(void *);
1.1 nicm 64: void *data;
65: };
66:
67: void
68: window_choose_vadd(struct window_pane *wp, int idx, const char *fmt, va_list ap)
69: {
70: struct window_choose_mode_data *data = wp->modedata;
71: struct window_choose_mode_item *item;
72:
73: ARRAY_EXPAND(&data->list, 1);
74: item = &ARRAY_LAST(&data->list);
75: xvasprintf(&item->name, fmt, ap);
76: item->idx = idx;
77: }
78:
79: void printflike3
80: window_choose_add(struct window_pane *wp, int idx, const char *fmt, ...)
81: {
82: va_list ap;
83:
84: va_start(ap, fmt);
85: window_choose_vadd(wp, idx, fmt, ap);
86: va_end(ap);
87: }
88:
89: void
1.3 nicm 90: window_choose_ready(struct window_pane *wp, u_int cur,
91: void (*callbackfn)(void *, int), void (*freefn)(void *), void *cdata)
1.1 nicm 92: {
93: struct window_choose_mode_data *data = wp->modedata;
94: struct screen *s = &data->screen;
95:
96: data->selected = cur;
97: if (data->selected > screen_size_y(s) - 1)
98: data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s);
99:
1.3 nicm 100: data->callbackfn = callbackfn;
101: data->freefn = freefn;
1.1 nicm 102: data->data = cdata;
103:
104: window_choose_redraw_screen(wp);
105: }
106:
107: struct screen *
108: window_choose_init(struct window_pane *wp)
109: {
110: struct window_choose_mode_data *data;
111: struct screen *s;
112:
113: wp->modedata = data = xmalloc(sizeof *data);
1.3 nicm 114:
115: data->callbackfn = NULL;
116: data->freefn = NULL;
117: data->data = NULL;
118:
1.1 nicm 119: ARRAY_INIT(&data->list);
120: data->top = 0;
121:
122: s = &data->screen;
123: screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
124: s->mode &= ~MODE_CURSOR;
125: s->mode |= MODE_MOUSE;
126:
127: mode_key_init(&data->mdata,
128: options_get_number(&wp->window->options, "mode-keys"),
129: MODEKEY_CHOOSEMODE);
130:
131: return (s);
132: }
133:
134: void
135: window_choose_free(struct window_pane *wp)
136: {
137: struct window_choose_mode_data *data = wp->modedata;
138: u_int i;
139:
1.3 nicm 140: if (data->freefn != NULL && data->data != NULL)
141: data->freefn(data->data);
1.1 nicm 142:
143: for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
144: xfree(ARRAY_ITEM(&data->list, i).name);
145: ARRAY_FREE(&data->list);
146:
147: screen_free(&data->screen);
148: xfree(data);
149: }
150:
151: void
152: window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
153: {
154: struct window_choose_mode_data *data = wp->modedata;
155: struct screen *s = &data->screen;
156:
157: data->top = 0;
158: if (data->selected > sy - 1)
159: data->top = data->selected - (sy - 1);
160:
161: screen_resize(s, sx, sy);
162: window_choose_redraw_screen(wp);
163: }
164:
165: void
166: window_choose_key(struct window_pane *wp, unused struct client *c, int key)
167: {
168: struct window_choose_mode_data *data = wp->modedata;
169: struct screen *s = &data->screen;
170: struct screen_write_ctx ctx;
171: struct window_choose_mode_item *item;
172: u_int items;
173:
174: items = ARRAY_LENGTH(&data->list);
175:
176: switch (mode_key_lookup(&data->mdata, key)) {
177: case MODEKEYCMD_QUIT:
1.3 nicm 178: data->callbackfn(data->data, -1);
1.1 nicm 179: window_pane_reset_mode(wp);
180: break;
181: case MODEKEYCMD_CHOOSE:
182: item = &ARRAY_ITEM(&data->list, data->selected);
1.3 nicm 183: data->callbackfn(data->data, item->idx);
1.1 nicm 184: window_pane_reset_mode(wp);
185: break;
186: case MODEKEYCMD_UP:
187: if (items == 0)
188: break;
189: if (data->selected == 0) {
190: data->selected = items - 1;
191: if (data->selected > screen_size_y(s) - 1)
192: data->top = items - screen_size_y(s);
193: window_choose_redraw_screen(wp);
194: break;
195: }
196: data->selected--;
197: if (data->selected < data->top)
198: window_choose_scroll_up(wp);
199: else {
200: screen_write_start(&ctx, wp, NULL);
201: window_choose_write_line(
202: wp, &ctx, data->selected - data->top);
203: window_choose_write_line(
204: wp, &ctx, data->selected + 1 - data->top);
205: screen_write_stop(&ctx);
206: }
207: break;
208: case MODEKEYCMD_DOWN:
209: if (items == 0)
210: break;
211: if (data->selected == items - 1) {
212: data->selected = 0;
213: data->top = 0;
214: window_choose_redraw_screen(wp);
215: break;
216: }
217: data->selected++;
218: if (data->selected >= data->top + screen_size_y(&data->screen))
219: window_choose_scroll_down(wp);
220: else {
221: screen_write_start(&ctx, wp, NULL);
222: window_choose_write_line(
223: wp, &ctx, data->selected - data->top);
224: window_choose_write_line(
225: wp, &ctx, data->selected - 1 - data->top);
226: screen_write_stop(&ctx);
227: }
228: break;
229: case MODEKEYCMD_PREVIOUSPAGE:
230: if (data->selected < screen_size_y(s)) {
231: data->selected = 0;
232: data->top = 0;
233: } else {
234: data->selected -= screen_size_y(s);
235: if (data->top < screen_size_y(s))
236: data->top = 0;
237: else
238: data->top -= screen_size_y(s);
239: }
240: window_choose_redraw_screen(wp);
241: break;
242: case MODEKEYCMD_NEXTPAGE:
243: data->selected += screen_size_y(s);
244: if (data->selected > items - 1)
245: data->selected = items - 1;
246: data->top += screen_size_y(s);
247: if (screen_size_y(s) < items) {
248: if (data->top + screen_size_y(s) > items)
249: data->top = items - screen_size_y(s);
250: } else
251: data->top = 0;
252: if (data->selected < data->top)
253: data->top = data->selected;
254: window_choose_redraw_screen(wp);
255: break;
256: default:
257: break;
258: }
259: }
260:
261: void
262: window_choose_mouse(struct window_pane *wp,
263: unused struct client *c, u_char b, u_char x, u_char y)
264: {
265: struct window_choose_mode_data *data = wp->modedata;
266: struct screen *s = &data->screen;
267: struct window_choose_mode_item *item;
268: u_int idx;
269:
270: if ((b & 3) == 3)
271: return;
272: if (x >= screen_size_x(s))
273: return;
274: if (y >= screen_size_y(s))
275: return;
276:
277: idx = data->top + y;
278: if (idx >= ARRAY_LENGTH(&data->list))
279: return;
280: data->selected = idx;
281:
282: item = &ARRAY_ITEM(&data->list, data->selected);
1.3 nicm 283: data->callbackfn(data->data, item->idx);
1.1 nicm 284: window_pane_reset_mode(wp);
285: }
286:
287: void
288: window_choose_write_line(
289: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
290: {
291: struct window_choose_mode_data *data = wp->modedata;
292: struct window_choose_mode_item *item;
293: struct screen *s = &data->screen;
294: struct grid_cell gc;
1.2 nicm 295: int utf8flag;
1.1 nicm 296:
1.3 nicm 297: if (data->callbackfn == NULL)
1.1 nicm 298: fatalx("called before callback assigned");
299:
1.2 nicm 300: utf8flag = options_get_number(&wp->window->options, "utf8");
1.1 nicm 301: memcpy(&gc, &grid_default_cell, sizeof gc);
302: if (data->selected == data->top + py) {
303: gc.fg = options_get_number(&wp->window->options, "mode-bg");
304: gc.bg = options_get_number(&wp->window->options, "mode-fg");
305: gc.attr |= options_get_number(&wp->window->options, "mode-attr");
306: }
307:
308: screen_write_cursormove(ctx, 0, py);
309: if (data->top + py < ARRAY_LENGTH(&data->list)) {
310: item = &ARRAY_ITEM(&data->list, data->top + py);
1.2 nicm 311: screen_write_nputs(
312: ctx, screen_size_x(s) - 1, &gc, utf8flag, "%s", item->name);
1.1 nicm 313: }
314: while (s->cx < screen_size_x(s))
315: screen_write_putc(ctx, &gc, ' ');
316: }
317:
318: void
319: window_choose_redraw_screen(struct window_pane *wp)
320: {
321: struct window_choose_mode_data *data = wp->modedata;
322: struct screen *s = &data->screen;
323: struct screen_write_ctx ctx;
324: u_int i;
325:
326: screen_write_start(&ctx, wp, NULL);
327: for (i = 0; i < screen_size_y(s); i++)
328: window_choose_write_line(wp, &ctx, i);
329: screen_write_stop(&ctx);
330: }
331:
332: void
333: window_choose_scroll_up(struct window_pane *wp)
334: {
335: struct window_choose_mode_data *data = wp->modedata;
336: struct screen_write_ctx ctx;
337:
338: if (data->top == 0)
339: return;
340: data->top--;
341:
342: screen_write_start(&ctx, wp, NULL);
343: screen_write_cursormove(&ctx, 0, 0);
344: screen_write_insertline(&ctx, 1);
345: window_choose_write_line(wp, &ctx, 0);
346: if (screen_size_y(&data->screen) > 1)
347: window_choose_write_line(wp, &ctx, 1);
348: screen_write_stop(&ctx);
349: }
350:
351: void
352: window_choose_scroll_down(struct window_pane *wp)
353: {
354: struct window_choose_mode_data *data = wp->modedata;
355: struct screen *s = &data->screen;
356: struct screen_write_ctx ctx;
357:
358: if (data->top >= ARRAY_LENGTH(&data->list))
359: return;
360: data->top++;
361:
362: screen_write_start(&ctx, wp, NULL);
363: screen_write_cursormove(&ctx, 0, 0);
364: screen_write_deleteline(&ctx, 1);
365: window_choose_write_line(wp, &ctx, screen_size_y(s) - 1);
366: if (screen_size_y(&data->screen) > 1)
367: window_choose_write_line(wp, &ctx, screen_size_y(s) - 2);
368: screen_write_stop(&ctx);
369: }