Annotation of src/usr.bin/tmux/window-choose.c, Revision 1.1
1.1 ! nicm 1: /* $OpenBSD$ */
! 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;
! 288:
! 289: if (data->callback == NULL)
! 290: fatalx("called before callback assigned");
! 291:
! 292: memcpy(&gc, &grid_default_cell, sizeof gc);
! 293: if (data->selected == data->top + py) {
! 294: gc.fg = options_get_number(&wp->window->options, "mode-bg");
! 295: gc.bg = options_get_number(&wp->window->options, "mode-fg");
! 296: gc.attr |= options_get_number(&wp->window->options, "mode-attr");
! 297: }
! 298:
! 299: screen_write_cursormove(ctx, 0, py);
! 300: if (data->top + py < ARRAY_LENGTH(&data->list)) {
! 301: item = &ARRAY_ITEM(&data->list, data->top + py);
! 302: screen_write_puts(
! 303: ctx, &gc, "%.*s", (int) screen_size_x(s), item->name);
! 304: }
! 305: while (s->cx < screen_size_x(s))
! 306: screen_write_putc(ctx, &gc, ' ');
! 307:
! 308: }
! 309:
! 310: void
! 311: window_choose_redraw_screen(struct window_pane *wp)
! 312: {
! 313: struct window_choose_mode_data *data = wp->modedata;
! 314: struct screen *s = &data->screen;
! 315: struct screen_write_ctx ctx;
! 316: u_int i;
! 317:
! 318: screen_write_start(&ctx, wp, NULL);
! 319: for (i = 0; i < screen_size_y(s); i++)
! 320: window_choose_write_line(wp, &ctx, i);
! 321: screen_write_stop(&ctx);
! 322: }
! 323:
! 324: void
! 325: window_choose_scroll_up(struct window_pane *wp)
! 326: {
! 327: struct window_choose_mode_data *data = wp->modedata;
! 328: struct screen_write_ctx ctx;
! 329:
! 330: if (data->top == 0)
! 331: return;
! 332: data->top--;
! 333:
! 334: screen_write_start(&ctx, wp, NULL);
! 335: screen_write_cursormove(&ctx, 0, 0);
! 336: screen_write_insertline(&ctx, 1);
! 337: window_choose_write_line(wp, &ctx, 0);
! 338: if (screen_size_y(&data->screen) > 1)
! 339: window_choose_write_line(wp, &ctx, 1);
! 340: screen_write_stop(&ctx);
! 341: }
! 342:
! 343: void
! 344: window_choose_scroll_down(struct window_pane *wp)
! 345: {
! 346: struct window_choose_mode_data *data = wp->modedata;
! 347: struct screen *s = &data->screen;
! 348: struct screen_write_ctx ctx;
! 349:
! 350: if (data->top >= ARRAY_LENGTH(&data->list))
! 351: return;
! 352: data->top++;
! 353:
! 354: screen_write_start(&ctx, wp, NULL);
! 355: screen_write_cursormove(&ctx, 0, 0);
! 356: screen_write_deleteline(&ctx, 1);
! 357: window_choose_write_line(wp, &ctx, screen_size_y(s) - 1);
! 358: if (screen_size_y(&data->screen) > 1)
! 359: window_choose_write_line(wp, &ctx, screen_size_y(s) - 2);
! 360: screen_write_stop(&ctx);
! 361: }