4 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
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
*, struct mouse_event
*);
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
);
36 void window_choose_scroll_up(struct window_pane
*);
37 void window_choose_scroll_down(struct window_pane
*);
39 const struct window_mode window_choose_mode
= {
48 struct window_choose_mode_item
{
53 struct window_choose_mode_data
{
56 struct mode_key_data mdata
;
58 ARRAY_DECL(, struct window_choose_mode_item
) list
;
62 void (*callbackfn
)(void *, int);
63 void (*freefn
)(void *);
67 int window_choose_key_index(struct window_choose_mode_data
*, u_int
);
68 int window_choose_index_key(struct window_choose_mode_data
*, int);
71 window_choose_vadd(struct window_pane
*wp
, int idx
, const char *fmt
, va_list ap
)
73 struct window_choose_mode_data
*data
= wp
->modedata
;
74 struct window_choose_mode_item
*item
;
76 ARRAY_EXPAND(&data
->list
, 1);
77 item
= &ARRAY_LAST(&data
->list
);
78 xvasprintf(&item
->name
, fmt
, ap
);
83 window_choose_add(struct window_pane
*wp
, int idx
, const char *fmt
, ...)
88 window_choose_vadd(wp
, idx
, fmt
, ap
);
93 window_choose_ready(struct window_pane
*wp
, u_int cur
,
94 void (*callbackfn
)(void *, int), void (*freefn
)(void *), void *cdata
)
96 struct window_choose_mode_data
*data
= wp
->modedata
;
97 struct screen
*s
= &data
->screen
;
100 if (data
->selected
> screen_size_y(s
) - 1)
101 data
->top
= ARRAY_LENGTH(&data
->list
) - screen_size_y(s
);
103 data
->callbackfn
= callbackfn
;
104 data
->freefn
= freefn
;
107 window_choose_redraw_screen(wp
);
111 window_choose_init(struct window_pane
*wp
)
113 struct window_choose_mode_data
*data
;
117 wp
->modedata
= data
= xmalloc(sizeof *data
);
119 data
->callbackfn
= NULL
;
123 ARRAY_INIT(&data
->list
);
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
;
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
);
136 mode_key_init(&data
->mdata
, &mode_key_tree_vi_choice
);
142 window_choose_free(struct window_pane
*wp
)
144 struct window_choose_mode_data
*data
= wp
->modedata
;
147 if (data
->freefn
!= NULL
&& data
->data
!= NULL
)
148 data
->freefn(data
->data
);
150 for (i
= 0; i
< ARRAY_LENGTH(&data
->list
); i
++)
151 xfree(ARRAY_ITEM(&data
->list
, i
).name
);
152 ARRAY_FREE(&data
->list
);
154 screen_free(&data
->screen
);
159 window_choose_resize(struct window_pane
*wp
, u_int sx
, u_int sy
)
161 struct window_choose_mode_data
*data
= wp
->modedata
;
162 struct screen
*s
= &data
->screen
;
165 if (data
->selected
> sy
- 1)
166 data
->top
= data
->selected
- (sy
- 1);
168 screen_resize(s
, sx
, sy
);
169 window_choose_redraw_screen(wp
);
174 window_choose_key(struct window_pane
*wp
, unused
struct client
*c
, int key
)
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
;
183 items
= ARRAY_LENGTH(&data
->list
);
185 switch (mode_key_lookup(&data
->mdata
, key
)) {
186 case MODEKEYCHOICE_CANCEL
:
187 data
->callbackfn(data
->data
, -1);
188 window_pane_reset_mode(wp
);
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
);
195 case MODEKEYCHOICE_UP
:
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
);
206 if (data
->selected
< data
->top
)
207 window_choose_scroll_up(wp
);
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
);
217 case MODEKEYCHOICE_DOWN
:
220 if (data
->selected
== items
- 1) {
223 window_choose_redraw_screen(wp
);
228 if (data
->selected
>= data
->top
+ screen_size_y(&data
->screen
))
229 window_choose_scroll_down(wp
);
231 screen_write_start(&ctx
, wp
, NULL
);
232 window_choose_write_line(
233 wp
, &ctx
, data
->selected
- data
->top
);
234 window_choose_write_line(
235 wp
, &ctx
, data
->selected
- 1 - data
->top
);
236 screen_write_stop(&ctx
);
239 case MODEKEYCHOICE_PAGEUP
:
240 if (data
->selected
< screen_size_y(s
)) {
244 data
->selected
-= screen_size_y(s
);
245 if (data
->top
< screen_size_y(s
))
248 data
->top
-= screen_size_y(s
);
250 window_choose_redraw_screen(wp
);
252 case MODEKEYCHOICE_PAGEDOWN
:
253 data
->selected
+= screen_size_y(s
);
254 if (data
->selected
> items
- 1)
255 data
->selected
= items
- 1;
256 data
->top
+= screen_size_y(s
);
257 if (screen_size_y(s
) < items
) {
258 if (data
->top
+ screen_size_y(s
) > items
)
259 data
->top
= items
- screen_size_y(s
);
262 if (data
->selected
< data
->top
)
263 data
->top
= data
->selected
;
264 window_choose_redraw_screen(wp
);
267 idx
= window_choose_index_key(data
, key
);
268 if (idx
< 0 || (u_int
) idx
>= ARRAY_LENGTH(&data
->list
))
270 data
->selected
= idx
;
272 item
= &ARRAY_ITEM(&data
->list
, data
->selected
);
273 data
->callbackfn(data
->data
, item
->idx
);
274 window_pane_reset_mode(wp
);
282 struct window_pane
*wp
, unused
struct client
*c
, struct mouse_event
*m
)
284 struct window_choose_mode_data
*data
= wp
->modedata
;
285 struct screen
*s
= &data
->screen
;
286 struct window_choose_mode_item
*item
;
291 if (m
->x
>= screen_size_x(s
))
293 if (m
->y
>= screen_size_y(s
))
296 idx
= data
->top
+ m
->y
;
297 if (idx
>= ARRAY_LENGTH(&data
->list
))
299 data
->selected
= idx
;
301 item
= &ARRAY_ITEM(&data
->list
, data
->selected
);
302 data
->callbackfn(data
->data
, item
->idx
);
303 window_pane_reset_mode(wp
);
307 window_choose_write_line(
308 struct window_pane
*wp
, struct screen_write_ctx
*ctx
, u_int py
)
310 struct window_choose_mode_data
*data
= wp
->modedata
;
311 struct window_choose_mode_item
*item
;
312 struct options
*oo
= &wp
->window
->options
;
313 struct screen
*s
= &data
->screen
;
317 if (data
->callbackfn
== NULL
)
318 fatalx("called before callback assigned");
320 utf8flag
= options_get_number(&wp
->window
->options
, "utf8");
321 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
322 if (data
->selected
== data
->top
+ py
) {
323 colour_set_fg(&gc
, options_get_number(oo
, "mode-fg"));
324 colour_set_bg(&gc
, options_get_number(oo
, "mode-bg"));
325 gc
.attr
|= options_get_number(oo
, "mode-attr");
328 screen_write_cursormove(ctx
, 0, py
);
329 if (data
->top
+ py
< ARRAY_LENGTH(&data
->list
)) {
330 item
= &ARRAY_ITEM(&data
->list
, data
->top
+ py
);
331 key
= window_choose_key_index(data
, data
->top
+ py
);
333 screen_write_nputs(ctx
, screen_size_x(s
) - 1,
334 &gc
, utf8flag
, "(%c) %s", key
, item
->name
);
336 screen_write_nputs(ctx
, screen_size_x(s
) - 1,
337 &gc
, utf8flag
, " %s", item
->name
);
341 while (s
->cx
< screen_size_x(s
))
342 screen_write_putc(ctx
, &gc
, ' ');
346 window_choose_key_index(struct window_choose_mode_data
*data
, u_int idx
)
348 static const char keys
[] = "0123456789abcdefghijklmnopqrstuvwxyz";
352 for (ptr
= keys
; *ptr
!= '\0'; ptr
++) {
353 mkey
= mode_key_lookup(&data
->mdata
, *ptr
);
354 if (mkey
!= MODEKEY_NONE
&& mkey
!= MODEKEY_OTHER
)
363 window_choose_index_key(struct window_choose_mode_data
*data
, int key
)
365 static const char keys
[] = "0123456789abcdefghijklmnopqrstuvwxyz";
370 for (ptr
= keys
; *ptr
!= '\0'; ptr
++) {
371 mkey
= mode_key_lookup(&data
->mdata
, *ptr
);
372 if (mkey
!= MODEKEY_NONE
&& mkey
!= MODEKEY_OTHER
)
382 window_choose_redraw_screen(struct window_pane
*wp
)
384 struct window_choose_mode_data
*data
= wp
->modedata
;
385 struct screen
*s
= &data
->screen
;
386 struct screen_write_ctx ctx
;
389 screen_write_start(&ctx
, wp
, NULL
);
390 for (i
= 0; i
< screen_size_y(s
); i
++)
391 window_choose_write_line(wp
, &ctx
, i
);
392 screen_write_stop(&ctx
);
396 window_choose_scroll_up(struct window_pane
*wp
)
398 struct window_choose_mode_data
*data
= wp
->modedata
;
399 struct screen_write_ctx ctx
;
405 screen_write_start(&ctx
, wp
, NULL
);
406 screen_write_cursormove(&ctx
, 0, 0);
407 screen_write_insertline(&ctx
, 1);
408 window_choose_write_line(wp
, &ctx
, 0);
409 if (screen_size_y(&data
->screen
) > 1)
410 window_choose_write_line(wp
, &ctx
, 1);
411 screen_write_stop(&ctx
);
415 window_choose_scroll_down(struct window_pane
*wp
)
417 struct window_choose_mode_data
*data
= wp
->modedata
;
418 struct screen
*s
= &data
->screen
;
419 struct screen_write_ctx ctx
;
421 if (data
->top
>= ARRAY_LENGTH(&data
->list
))
425 screen_write_start(&ctx
, wp
, NULL
);
426 screen_write_cursormove(&ctx
, 0, 0);
427 screen_write_deleteline(&ctx
, 1);
428 window_choose_write_line(wp
, &ctx
, screen_size_y(s
) - 1);
429 if (screen_size_y(&data
->screen
) > 1)
430 window_choose_write_line(wp
, &ctx
, screen_size_y(s
) - 2);
431 screen_write_stop(&ctx
);