1 /* $Id: layout-set.c,v 1.5 2010-02-05 01:29:04 tcunha Exp $ */
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>
26 * Set window layouts - predefined methods to arrange windows. These are one-off
27 * and generate a layout tree.
30 void layout_set_even_h(struct window
*);
31 void layout_set_even_v(struct window
*);
32 void layout_set_main_h(struct window
*);
33 void layout_set_main_v(struct window
*);
37 void (*arrange
)(struct window
*);
39 { "even-horizontal", layout_set_even_h
},
40 { "even-vertical", layout_set_even_v
},
41 { "main-horizontal", layout_set_main_h
},
42 { "main-vertical", layout_set_main_v
},
46 layout_set_name(u_int layout
)
48 return (layout_sets
[layout
].name
);
52 layout_set_lookup(const char *name
)
57 for (i
= 0; i
< nitems(layout_sets
); i
++) {
58 if (strncmp(layout_sets
[i
].name
, name
, strlen(name
)) == 0) {
59 if (matched
!= -1) /* ambiguous */
69 layout_set_select(struct window
*w
, u_int layout
)
71 if (layout
> nitems(layout_sets
) - 1)
72 layout
= nitems(layout_sets
) - 1;
74 if (layout_sets
[layout
].arrange
!= NULL
)
75 layout_sets
[layout
].arrange(w
);
77 w
->lastlayout
= layout
;
82 layout_set_next(struct window
*w
)
86 if (w
->lastlayout
== -1)
89 layout
= w
->lastlayout
+ 1;
90 if (layout
> nitems(layout_sets
) - 1)
94 if (layout_sets
[layout
].arrange
!= NULL
)
95 layout_sets
[layout
].arrange(w
);
96 w
->lastlayout
= layout
;
101 layout_set_previous(struct window
*w
)
105 if (w
->lastlayout
== -1)
106 layout
= nitems(layout_sets
) - 1;
108 layout
= w
->lastlayout
;
110 layout
= nitems(layout_sets
) - 1;
115 if (layout_sets
[layout
].arrange
!= NULL
)
116 layout_sets
[layout
].arrange(w
);
117 w
->lastlayout
= layout
;
122 layout_set_even_h(struct window
*w
)
124 struct window_pane
*wp
;
125 struct layout_cell
*lc
, *lcnew
;
126 u_int i
, n
, width
, xoff
;
128 layout_print_cell(w
->layout_root
, __func__
, 1);
130 /* Get number of panes. */
131 n
= window_count_panes(w
);
135 /* How many can we fit? */
136 if (w
->sx
/ n
< PANE_MINIMUM
+ 1)
137 width
= PANE_MINIMUM
+ 1;
141 /* Free the old root and construct a new. */
143 lc
= w
->layout_root
= layout_create_cell(NULL
);
144 layout_set_size(lc
, w
->sx
, w
->sy
, 0, 0);
145 layout_make_node(lc
, LAYOUT_LEFTRIGHT
);
147 /* Build new leaf cells. */
149 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
150 /* Create child cell. */
151 lcnew
= layout_create_cell(lc
);
152 layout_set_size(lcnew
, width
- 1, w
->sy
, xoff
, 0);
153 layout_make_leaf(lcnew
, wp
);
154 TAILQ_INSERT_TAIL(&lc
->cells
, lcnew
, entry
);
160 /* Allocate any remaining space. */
161 if (w
->sx
> xoff
- 1) {
162 lc
= TAILQ_LAST(&lc
->cells
, layout_cells
);
163 layout_resize_adjust(lc
, LAYOUT_LEFTRIGHT
, w
->sx
- (xoff
- 1));
166 /* Fix cell offsets. */
167 layout_fix_offsets(lc
);
168 layout_fix_panes(w
, w
->sx
, w
->sy
);
170 layout_print_cell(w
->layout_root
, __func__
, 1);
172 server_redraw_window(w
);
176 layout_set_even_v(struct window
*w
)
178 struct window_pane
*wp
;
179 struct layout_cell
*lc
, *lcnew
;
180 u_int i
, n
, height
, yoff
;
182 layout_print_cell(w
->layout_root
, __func__
, 1);
184 /* Get number of panes. */
185 n
= window_count_panes(w
);
189 /* How many can we fit? */
190 if (w
->sy
/ n
< PANE_MINIMUM
+ 1)
191 height
= PANE_MINIMUM
+ 1;
195 /* Free the old root and construct a new. */
197 lc
= w
->layout_root
= layout_create_cell(NULL
);
198 layout_set_size(lc
, w
->sx
, w
->sy
, 0, 0);
199 layout_make_node(lc
, LAYOUT_TOPBOTTOM
);
201 /* Build new leaf cells. */
203 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
204 /* Create child cell. */
205 lcnew
= layout_create_cell(lc
);
206 layout_set_size(lcnew
, w
->sx
, height
- 1, 0, yoff
);
207 layout_make_leaf(lcnew
, wp
);
208 TAILQ_INSERT_TAIL(&lc
->cells
, lcnew
, entry
);
214 /* Allocate any remaining space. */
215 if (w
->sy
> yoff
- 1) {
216 lc
= TAILQ_LAST(&lc
->cells
, layout_cells
);
217 layout_resize_adjust(lc
, LAYOUT_TOPBOTTOM
, w
->sy
- (yoff
- 1));
220 /* Fix cell offsets. */
221 layout_fix_offsets(lc
);
222 layout_fix_panes(w
, w
->sx
, w
->sy
);
224 layout_print_cell(w
->layout_root
, __func__
, 1);
226 server_redraw_window(w
);
230 layout_set_main_h(struct window
*w
)
232 struct window_pane
*wp
;
233 struct layout_cell
*lc
, *lcmain
, *lcrow
, *lcchild
;
234 u_int n
, mainheight
, width
, height
, used
;
235 u_int i
, j
, columns
, rows
, totalrows
;
237 layout_print_cell(w
->layout_root
, __func__
, 1);
239 /* Get number of panes. */
240 n
= window_count_panes(w
);
243 n
--; /* take off main pane */
245 /* How many rows and columns will be needed? */
246 columns
= w
->sx
/ (PANE_MINIMUM
+ 1); /* maximum columns */
249 rows
= 1 + (n
- 1) / columns
;
250 columns
= 1 + (n
- 1) / rows
;
251 width
= w
->sx
/ columns
;
253 /* Get the main pane height and add one for separator line. */
254 mainheight
= options_get_number(&w
->options
, "main-pane-height") + 1;
255 if (mainheight
< PANE_MINIMUM
+ 1)
256 mainheight
= PANE_MINIMUM
+ 1;
258 /* Try and make everything fit. */
259 totalrows
= rows
* (PANE_MINIMUM
+ 1) - 1;
260 if (mainheight
+ totalrows
> w
->sy
) {
261 if (totalrows
+ PANE_MINIMUM
+ 1 > w
->sy
)
262 mainheight
= PANE_MINIMUM
+ 2;
264 mainheight
= w
->sy
- totalrows
;
265 height
= PANE_MINIMUM
+ 1;
267 height
= (w
->sy
- mainheight
) / rows
;
269 /* Free old tree and create a new root. */
271 lc
= w
->layout_root
= layout_create_cell(NULL
);
272 layout_set_size(lc
, w
->sx
, mainheight
+ rows
* height
, 0, 0);
273 layout_make_node(lc
, LAYOUT_TOPBOTTOM
);
275 /* Create the main pane. */
276 lcmain
= layout_create_cell(lc
);
277 layout_set_size(lcmain
, w
->sx
, mainheight
- 1, 0, 0);
278 layout_make_leaf(lcmain
, TAILQ_FIRST(&w
->panes
));
279 TAILQ_INSERT_TAIL(&lc
->cells
, lcmain
, entry
);
281 /* Create a grid of the remaining cells. */
282 wp
= TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
);
283 for (j
= 0; j
< rows
; j
++) {
284 /* If this is the last cell, all done. */
288 /* Create the new row. */
289 lcrow
= layout_create_cell(lc
);
290 layout_set_size(lcrow
, w
->sx
, height
- 1, 0, 0);
291 TAILQ_INSERT_TAIL(&lc
->cells
, lcrow
, entry
);
293 /* If only one column, just use the row directly. */
295 layout_make_leaf(lcrow
, wp
);
296 wp
= TAILQ_NEXT(wp
, entry
);
300 /* Add in the columns. */
301 layout_make_node(lcrow
, LAYOUT_LEFTRIGHT
);
302 for (i
= 0; i
< columns
; i
++) {
303 /* Create and add a pane cell. */
304 lcchild
= layout_create_cell(lcrow
);
305 layout_set_size(lcchild
, width
- 1, height
- 1, 0, 0);
306 layout_make_leaf(lcchild
, wp
);
307 TAILQ_INSERT_TAIL(&lcrow
->cells
, lcchild
, entry
);
309 /* Move to the next cell. */
310 if ((wp
= TAILQ_NEXT(wp
, entry
)) == NULL
)
314 /* Adjust the row to fit the full width if necessary. */
317 used
= ((i
+ 1) * width
) - 1;
320 lcchild
= TAILQ_LAST(&lcrow
->cells
, layout_cells
);
321 layout_resize_adjust(lcchild
, LAYOUT_LEFTRIGHT
, w
->sx
- used
);
324 /* Adjust the last row height to fit if necessary. */
325 used
= mainheight
+ (rows
* height
) - 1;
327 lcrow
= TAILQ_LAST(&lc
->cells
, layout_cells
);
328 layout_resize_adjust(lcrow
, LAYOUT_TOPBOTTOM
, w
->sy
- used
);
331 /* Fix cell offsets. */
332 layout_fix_offsets(lc
);
333 layout_fix_panes(w
, w
->sx
, w
->sy
);
335 layout_print_cell(w
->layout_root
, __func__
, 1);
337 server_redraw_window(w
);
341 layout_set_main_v(struct window
*w
)
343 struct window_pane
*wp
;
344 struct layout_cell
*lc
, *lcmain
, *lccolumn
, *lcchild
;
345 u_int n
, mainwidth
, width
, height
, used
;
346 u_int i
, j
, columns
, rows
, totalcolumns
;
348 layout_print_cell(w
->layout_root
, __func__
, 1);
350 /* Get number of panes. */
351 n
= window_count_panes(w
);
354 n
--; /* take off main pane */
356 /* How many rows and columns will be needed? */
357 rows
= w
->sy
/ (PANE_MINIMUM
+ 1); /* maximum rows */
360 columns
= 1 + (n
- 1) / rows
;
361 rows
= 1 + (n
- 1) / columns
;
362 height
= w
->sy
/ rows
;
364 /* Get the main pane width and add one for separator line. */
365 mainwidth
= options_get_number(&w
->options
, "main-pane-width") + 1;
366 if (mainwidth
< PANE_MINIMUM
+ 1)
367 mainwidth
= PANE_MINIMUM
+ 1;
369 /* Try and make everything fit. */
370 totalcolumns
= columns
* (PANE_MINIMUM
+ 1) - 1;
371 if (mainwidth
+ totalcolumns
> w
->sx
) {
372 if (totalcolumns
+ PANE_MINIMUM
+ 1 > w
->sx
)
373 mainwidth
= PANE_MINIMUM
+ 2;
375 mainwidth
= w
->sx
- totalcolumns
;
376 width
= PANE_MINIMUM
+ 1;
378 width
= (w
->sx
- mainwidth
) / columns
;
380 /* Free old tree and create a new root. */
382 lc
= w
->layout_root
= layout_create_cell(NULL
);
383 layout_set_size(lc
, mainwidth
+ columns
* width
, w
->sy
, 0, 0);
384 layout_make_node(lc
, LAYOUT_LEFTRIGHT
);
386 /* Create the main pane. */
387 lcmain
= layout_create_cell(lc
);
388 layout_set_size(lcmain
, mainwidth
- 1, w
->sy
, 0, 0);
389 layout_make_leaf(lcmain
, TAILQ_FIRST(&w
->panes
));
390 TAILQ_INSERT_TAIL(&lc
->cells
, lcmain
, entry
);
392 /* Create a grid of the remaining cells. */
393 wp
= TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
);
394 for (j
= 0; j
< columns
; j
++) {
395 /* If this is the last cell, all done. */
399 /* Create the new column. */
400 lccolumn
= layout_create_cell(lc
);
401 layout_set_size(lccolumn
, width
- 1, w
->sy
, 0, 0);
402 TAILQ_INSERT_TAIL(&lc
->cells
, lccolumn
, entry
);
404 /* If only one row, just use the row directly. */
406 layout_make_leaf(lccolumn
, wp
);
407 wp
= TAILQ_NEXT(wp
, entry
);
411 /* Add in the rows. */
412 layout_make_node(lccolumn
, LAYOUT_TOPBOTTOM
);
413 for (i
= 0; i
< rows
; i
++) {
414 /* Create and add a pane cell. */
415 lcchild
= layout_create_cell(lccolumn
);
416 layout_set_size(lcchild
, width
- 1, height
- 1, 0, 0);
417 layout_make_leaf(lcchild
, wp
);
418 TAILQ_INSERT_TAIL(&lccolumn
->cells
, lcchild
, entry
);
420 /* Move to the next cell. */
421 if ((wp
= TAILQ_NEXT(wp
, entry
)) == NULL
)
425 /* Adjust the column to fit the full height if necessary. */
428 used
= ((i
+ 1) * height
) - 1;
431 lcchild
= TAILQ_LAST(&lccolumn
->cells
, layout_cells
);
432 layout_resize_adjust(lcchild
, LAYOUT_TOPBOTTOM
, w
->sy
- used
);
435 /* Adjust the last column width to fit if necessary. */
436 used
= mainwidth
+ (columns
* width
) - 1;
438 lccolumn
= TAILQ_LAST(&lc
->cells
, layout_cells
);
439 layout_resize_adjust(lccolumn
, LAYOUT_LEFTRIGHT
, w
->sx
- used
);
442 /* Fix cell offsets. */
443 layout_fix_offsets(lc
);
444 layout_fix_panes(w
, w
->sx
, w
->sy
);
446 layout_print_cell(w
->layout_root
, __func__
, 1);
448 server_redraw_window(w
);