window-choose.c revision 1.1.1.2
1239310Sdim/* $Id: window-choose.c,v 1.1.1.2 2011/08/17 18:40:05 jmmv Exp $ */ 2239310Sdim 3239310Sdim/* 4239310Sdim * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> 5239310Sdim * 6239310Sdim * Permission to use, copy, modify, and distribute this software for any 7239310Sdim * purpose with or without fee is hereby granted, provided that the above 8239310Sdim * copyright notice and this permission notice appear in all copies. 9239310Sdim * 10239310Sdim * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11239310Sdim * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12239310Sdim * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13239310Sdim * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14239310Sdim * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15239310Sdim * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16239310Sdim * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17249423Sdim */ 18249423Sdim 19249423Sdim#include <sys/types.h> 20249423Sdim 21239310Sdim#include <string.h> 22239310Sdim 23239310Sdim#include "tmux.h" 24239310Sdim 25239310Sdimstruct screen *window_choose_init(struct window_pane *); 26249423Sdimvoid window_choose_free(struct window_pane *); 27239310Sdimvoid window_choose_resize(struct window_pane *, u_int, u_int); 28239310Sdimvoid window_choose_key(struct window_pane *, struct session *, int); 29239310Sdimvoid window_choose_mouse( 30239310Sdim struct window_pane *, struct session *, struct mouse_event *); 31239310Sdim 32239310Sdimvoid window_choose_redraw_screen(struct window_pane *); 33239310Sdimvoid window_choose_write_line( 34239310Sdim struct window_pane *, struct screen_write_ctx *, u_int); 35239310Sdim 36239310Sdimvoid window_choose_scroll_up(struct window_pane *); 37239310Sdimvoid window_choose_scroll_down(struct window_pane *); 38239310Sdim 39239310Sdimconst struct window_mode window_choose_mode = { 40239310Sdim window_choose_init, 41239310Sdim window_choose_free, 42239310Sdim window_choose_resize, 43239310Sdim window_choose_key, 44239310Sdim window_choose_mouse, 45239310Sdim NULL, 46239310Sdim}; 47239310Sdim 48239310Sdimstruct window_choose_mode_item { 49239310Sdim char *name; 50239310Sdim int idx; 51239310Sdim}; 52239310Sdim 53239310Sdimstruct window_choose_mode_data { 54239310Sdim struct screen screen; 55239310Sdim 56239310Sdim struct mode_key_data mdata; 57239310Sdim 58239310Sdim ARRAY_DECL(, struct window_choose_mode_item) list; 59239310Sdim u_int top; 60239310Sdim u_int selected; 61239310Sdim 62239310Sdim void (*callbackfn)(void *, int); 63239310Sdim void (*freefn)(void *); 64239310Sdim void *data; 65239310Sdim}; 66249423Sdim 67239310Sdimint window_choose_key_index(struct window_choose_mode_data *, u_int); 68239310Sdimint window_choose_index_key(struct window_choose_mode_data *, int); 69239310Sdim 70239310Sdimvoid 71239310Sdimwindow_choose_vadd(struct window_pane *wp, int idx, const char *fmt, va_list ap) 72239310Sdim{ 73239310Sdim struct window_choose_mode_data *data = wp->modedata; 74239310Sdim struct window_choose_mode_item *item; 75239310Sdim 76239310Sdim ARRAY_EXPAND(&data->list, 1); 77239310Sdim item = &ARRAY_LAST(&data->list); 78239310Sdim xvasprintf(&item->name, fmt, ap); 79249423Sdim item->idx = idx; 80249423Sdim} 81239310Sdim 82239310Sdimvoid printflike3 83239310Sdimwindow_choose_add(struct window_pane *wp, int idx, const char *fmt, ...) 84239310Sdim{ 85239310Sdim va_list ap; 86239310Sdim 87239310Sdim va_start(ap, fmt); 88239310Sdim window_choose_vadd(wp, idx, fmt, ap); 89239310Sdim va_end(ap); 90239310Sdim} 91239310Sdim 92239310Sdimvoid 93window_choose_ready(struct window_pane *wp, u_int cur, 94 void (*callbackfn)(void *, int), void (*freefn)(void *), void *cdata) 95{ 96 struct window_choose_mode_data *data = wp->modedata; 97 struct screen *s = &data->screen; 98 99 data->selected = cur; 100 if (data->selected > screen_size_y(s) - 1) 101 data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s); 102 103 data->callbackfn = callbackfn; 104 data->freefn = freefn; 105 data->data = cdata; 106 107 window_choose_redraw_screen(wp); 108} 109 110struct screen * 111window_choose_init(struct window_pane *wp) 112{ 113 struct window_choose_mode_data *data; 114 struct screen *s; 115 int keys; 116 117 wp->modedata = data = xmalloc(sizeof *data); 118 119 data->callbackfn = NULL; 120 data->freefn = NULL; 121 data->data = NULL; 122 123 ARRAY_INIT(&data->list); 124 data->top = 0; 125 126 s = &data->screen; 127 screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); 128 s->mode &= ~MODE_CURSOR; 129 if (options_get_number(&wp->window->options, "mode-mouse")) 130 s->mode |= MODE_MOUSE_STANDARD; 131 132 keys = options_get_number(&wp->window->options, "mode-keys"); 133 if (keys == MODEKEY_EMACS) 134 mode_key_init(&data->mdata, &mode_key_tree_emacs_choice); 135 else 136 mode_key_init(&data->mdata, &mode_key_tree_vi_choice); 137 138 return (s); 139} 140 141void 142window_choose_free(struct window_pane *wp) 143{ 144 struct window_choose_mode_data *data = wp->modedata; 145 u_int i; 146 147 if (data->freefn != NULL && data->data != NULL) 148 data->freefn(data->data); 149 150 for (i = 0; i < ARRAY_LENGTH(&data->list); i++) 151 xfree(ARRAY_ITEM(&data->list, i).name); 152 ARRAY_FREE(&data->list); 153 154 screen_free(&data->screen); 155 xfree(data); 156} 157 158void 159window_choose_resize(struct window_pane *wp, u_int sx, u_int sy) 160{ 161 struct window_choose_mode_data *data = wp->modedata; 162 struct screen *s = &data->screen; 163 164 data->top = 0; 165 if (data->selected > sy - 1) 166 data->top = data->selected - (sy - 1); 167 168 screen_resize(s, sx, sy); 169 window_choose_redraw_screen(wp); 170} 171 172/* ARGSUSED */ 173void 174window_choose_key(struct window_pane *wp, unused struct session *sess, int key) 175{ 176 struct window_choose_mode_data *data = wp->modedata; 177 struct screen *s = &data->screen; 178 struct screen_write_ctx ctx; 179 struct window_choose_mode_item *item; 180 u_int items; 181 int idx; 182 183 items = ARRAY_LENGTH(&data->list); 184 185 switch (mode_key_lookup(&data->mdata, key)) { 186 case MODEKEYCHOICE_CANCEL: 187 data->callbackfn(data->data, -1); 188 window_pane_reset_mode(wp); 189 break; 190 case MODEKEYCHOICE_CHOOSE: 191 item = &ARRAY_ITEM(&data->list, data->selected); 192 data->callbackfn(data->data, item->idx); 193 window_pane_reset_mode(wp); 194 break; 195 case MODEKEYCHOICE_UP: 196 if (items == 0) 197 break; 198 if (data->selected == 0) { 199 data->selected = items - 1; 200 if (data->selected > screen_size_y(s) - 1) 201 data->top = items - screen_size_y(s); 202 window_choose_redraw_screen(wp); 203 break; 204 } 205 data->selected--; 206 if (data->selected < data->top) 207 window_choose_scroll_up(wp); 208 else { 209 screen_write_start(&ctx, wp, NULL); 210 window_choose_write_line( 211 wp, &ctx, data->selected - data->top); 212 window_choose_write_line( 213 wp, &ctx, data->selected + 1 - data->top); 214 screen_write_stop(&ctx); 215 } 216 break; 217 case MODEKEYCHOICE_DOWN: 218 if (items == 0) 219 break; 220 if (data->selected == items - 1) { 221 data->selected = 0; 222 data->top = 0; 223 window_choose_redraw_screen(wp); 224 break; 225 } 226 data->selected++; 227 228 if (data->selected < data->top + screen_size_y(s)) { 229 screen_write_start(&ctx, wp, NULL); 230 window_choose_write_line( 231 wp, &ctx, data->selected - data->top); 232 window_choose_write_line( 233 wp, &ctx, data->selected - 1 - data->top); 234 screen_write_stop(&ctx); 235 } else 236 window_choose_scroll_down(wp); 237 break; 238 case MODEKEYCHOICE_SCROLLUP: 239 if (items == 0 || data->top == 0) 240 break; 241 if (data->selected == data->top + screen_size_y(s) - 1) { 242 data->selected--; 243 window_choose_scroll_up(wp); 244 screen_write_start(&ctx, wp, NULL); 245 window_choose_write_line( 246 wp, &ctx, screen_size_y(s) - 1); 247 screen_write_stop(&ctx); 248 } else 249 window_choose_scroll_up(wp); 250 break; 251 case MODEKEYCHOICE_SCROLLDOWN: 252 if (items == 0 || 253 data->top + screen_size_y(&data->screen) >= items) 254 break; 255 if (data->selected == data->top) { 256 data->selected++; 257 window_choose_scroll_down(wp); 258 screen_write_start(&ctx, wp, NULL); 259 window_choose_write_line(wp, &ctx, 0); 260 screen_write_stop(&ctx); 261 } else 262 window_choose_scroll_down(wp); 263 break; 264 case MODEKEYCHOICE_PAGEUP: 265 if (data->selected < screen_size_y(s)) { 266 data->selected = 0; 267 data->top = 0; 268 } else { 269 data->selected -= screen_size_y(s); 270 if (data->top < screen_size_y(s)) 271 data->top = 0; 272 else 273 data->top -= screen_size_y(s); 274 } 275 window_choose_redraw_screen(wp); 276 break; 277 case MODEKEYCHOICE_PAGEDOWN: 278 data->selected += screen_size_y(s); 279 if (data->selected > items - 1) 280 data->selected = items - 1; 281 data->top += screen_size_y(s); 282 if (screen_size_y(s) < items) { 283 if (data->top + screen_size_y(s) > items) 284 data->top = items - screen_size_y(s); 285 } else 286 data->top = 0; 287 if (data->selected < data->top) 288 data->top = data->selected; 289 window_choose_redraw_screen(wp); 290 break; 291 default: 292 idx = window_choose_index_key(data, key); 293 if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list)) 294 break; 295 data->selected = idx; 296 297 item = &ARRAY_ITEM(&data->list, data->selected); 298 data->callbackfn(data->data, item->idx); 299 window_pane_reset_mode(wp); 300 break; 301 } 302} 303 304/* ARGSUSED */ 305void 306window_choose_mouse( 307 struct window_pane *wp, unused struct session *sess, struct mouse_event *m) 308{ 309 struct window_choose_mode_data *data = wp->modedata; 310 struct screen *s = &data->screen; 311 struct window_choose_mode_item *item; 312 u_int idx; 313 314 if ((m->b & 3) == 3) 315 return; 316 if (m->x >= screen_size_x(s)) 317 return; 318 if (m->y >= screen_size_y(s)) 319 return; 320 321 idx = data->top + m->y; 322 if (idx >= ARRAY_LENGTH(&data->list)) 323 return; 324 data->selected = idx; 325 326 item = &ARRAY_ITEM(&data->list, data->selected); 327 data->callbackfn(data->data, item->idx); 328 window_pane_reset_mode(wp); 329} 330 331void 332window_choose_write_line( 333 struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) 334{ 335 struct window_choose_mode_data *data = wp->modedata; 336 struct window_choose_mode_item *item; 337 struct options *oo = &wp->window->options; 338 struct screen *s = &data->screen; 339 struct grid_cell gc; 340 int utf8flag, key; 341 342 if (data->callbackfn == NULL) 343 fatalx("called before callback assigned"); 344 345 utf8flag = options_get_number(&wp->window->options, "utf8"); 346 memcpy(&gc, &grid_default_cell, sizeof gc); 347 if (data->selected == data->top + py) { 348 colour_set_fg(&gc, options_get_number(oo, "mode-fg")); 349 colour_set_bg(&gc, options_get_number(oo, "mode-bg")); 350 gc.attr |= options_get_number(oo, "mode-attr"); 351 } 352 353 screen_write_cursormove(ctx, 0, py); 354 if (data->top + py < ARRAY_LENGTH(&data->list)) { 355 item = &ARRAY_ITEM(&data->list, data->top + py); 356 key = window_choose_key_index(data, data->top + py); 357 if (key != -1) { 358 screen_write_nputs(ctx, screen_size_x(s) - 1, 359 &gc, utf8flag, "(%c) %s", key, item->name); 360 } else { 361 screen_write_nputs(ctx, screen_size_x(s) - 1, 362 &gc, utf8flag, " %s", item->name); 363 } 364 365 } 366 while (s->cx < screen_size_x(s)) 367 screen_write_putc(ctx, &gc, ' '); 368} 369 370int 371window_choose_key_index(struct window_choose_mode_data *data, u_int idx) 372{ 373 static const char keys[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 374 const char *ptr; 375 int mkey; 376 377 for (ptr = keys; *ptr != '\0'; ptr++) { 378 mkey = mode_key_lookup(&data->mdata, *ptr); 379 if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) 380 continue; 381 if (idx-- == 0) 382 return (*ptr); 383 } 384 return (-1); 385} 386 387int 388window_choose_index_key(struct window_choose_mode_data *data, int key) 389{ 390 static const char keys[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 391 const char *ptr; 392 int mkey; 393 u_int idx = 0; 394 395 for (ptr = keys; *ptr != '\0'; ptr++) { 396 mkey = mode_key_lookup(&data->mdata, *ptr); 397 if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) 398 continue; 399 if (key == *ptr) 400 return (idx); 401 idx++; 402 } 403 return (-1); 404} 405 406void 407window_choose_redraw_screen(struct window_pane *wp) 408{ 409 struct window_choose_mode_data *data = wp->modedata; 410 struct screen *s = &data->screen; 411 struct screen_write_ctx ctx; 412 u_int i; 413 414 screen_write_start(&ctx, wp, NULL); 415 for (i = 0; i < screen_size_y(s); i++) 416 window_choose_write_line(wp, &ctx, i); 417 screen_write_stop(&ctx); 418} 419 420void 421window_choose_scroll_up(struct window_pane *wp) 422{ 423 struct window_choose_mode_data *data = wp->modedata; 424 struct screen_write_ctx ctx; 425 426 if (data->top == 0) 427 return; 428 data->top--; 429 430 screen_write_start(&ctx, wp, NULL); 431 screen_write_cursormove(&ctx, 0, 0); 432 screen_write_insertline(&ctx, 1); 433 window_choose_write_line(wp, &ctx, 0); 434 if (screen_size_y(&data->screen) > 1) 435 window_choose_write_line(wp, &ctx, 1); 436 screen_write_stop(&ctx); 437} 438 439void 440window_choose_scroll_down(struct window_pane *wp) 441{ 442 struct window_choose_mode_data *data = wp->modedata; 443 struct screen *s = &data->screen; 444 struct screen_write_ctx ctx; 445 446 if (data->top >= ARRAY_LENGTH(&data->list)) 447 return; 448 data->top++; 449 450 screen_write_start(&ctx, wp, NULL); 451 screen_write_cursormove(&ctx, 0, 0); 452 screen_write_deleteline(&ctx, 1); 453 window_choose_write_line(wp, &ctx, screen_size_y(s) - 1); 454 if (screen_size_y(&data->screen) > 1) 455 window_choose_write_line(wp, &ctx, screen_size_y(s) - 2); 456 screen_write_stop(&ctx); 457} 458