Annotation of src/usr.bin/tmux/layout-set.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: /*
! 26: * Set window layouts - predefined methods to arrange windows. These are one-off
! 27: * and generate a layout tree.
! 28: */
! 29:
! 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 *);
! 34:
! 35: const struct {
! 36: const char *name;
! 37: void (*arrange)(struct window *);
! 38: } layout_sets[] = {
! 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 },
! 43: };
! 44:
! 45: const char *
! 46: layout_set_name(u_int layout)
! 47: {
! 48: return (layout_sets[layout].name);
! 49: }
! 50:
! 51: int
! 52: layout_set_lookup(const char *name)
! 53: {
! 54: u_int i;
! 55: int matched = -1;
! 56:
! 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 */
! 60: return (-1);
! 61: matched = i;
! 62: }
! 63: }
! 64:
! 65: return (matched);
! 66: }
! 67:
! 68: u_int
! 69: layout_set_select(struct window *w, u_int layout)
! 70: {
! 71: if (layout > nitems(layout_sets) - 1)
! 72: layout = nitems(layout_sets) - 1;
! 73:
! 74: if (layout_sets[layout].arrange != NULL)
! 75: layout_sets[layout].arrange(w);
! 76:
! 77: w->layout = layout;
! 78: return (layout);
! 79: }
! 80:
! 81: u_int
! 82: layout_set_next(struct window *w)
! 83: {
! 84: u_int layout = w->layout;
! 85:
! 86: if (layout_sets[layout].arrange != NULL)
! 87: layout_sets[layout].arrange(w);
! 88:
! 89: w->layout++;
! 90: if (w->layout > nitems(layout_sets) - 1)
! 91: w->layout = 0;
! 92: return (layout);
! 93: }
! 94:
! 95: u_int
! 96: layout_set_previous(struct window *w)
! 97: {
! 98: u_int layout = w->layout;
! 99:
! 100: if (layout_sets[layout].arrange != NULL)
! 101: layout_sets[layout].arrange(w);
! 102:
! 103: if (w->layout == 0)
! 104: w->layout = nitems(layout_sets) - 1;
! 105: else
! 106: w->layout--;
! 107: return (layout);
! 108: }
! 109:
! 110: void
! 111: layout_set_even_h(struct window *w)
! 112: {
! 113: struct window_pane *wp;
! 114: struct layout_cell *lc, *lcnew;
! 115: u_int i, n, width, xoff;
! 116:
! 117: layout_print_cell(w->layout_root, __func__, 1);
! 118:
! 119: /* Get number of panes. */
! 120: n = window_count_panes(w);
! 121: if (n <= 1)
! 122: return;
! 123:
! 124: /* How many can we fit? */
! 125: if (w->sx / n < PANE_MINIMUM + 1) {
! 126: width = PANE_MINIMUM + 1;
! 127: n = UINT_MAX;
! 128: } else
! 129: width = w->sx / n;
! 130:
! 131: /* Free the old root and construct a new. */
! 132: layout_free(w);
! 133: lc = w->layout_root = layout_create_cell(NULL);
! 134: layout_set_size(lc, w->sx, w->sy, 0, 0);
! 135: layout_make_node(lc, LAYOUT_LEFTRIGHT);
! 136:
! 137: /* Build new leaf cells. */
! 138: i = xoff = 0;
! 139: TAILQ_FOREACH(wp, &w->panes, entry) {
! 140: /* Create child cell. */
! 141: lcnew = layout_create_cell(lc);
! 142: layout_set_size(lcnew, width - 1, w->sy, xoff, 0);
! 143: layout_make_leaf(lcnew, wp);
! 144: TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
! 145:
! 146: i++;
! 147: xoff += width;
! 148: }
! 149:
! 150: /* Allocate any remaining space. */
! 151: if (w->sx > xoff - 1) {
! 152: lc = TAILQ_LAST(&lc->cells, layout_cells);
! 153: layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, w->sx - (xoff - 1));
! 154: }
! 155:
! 156: /* Fix cell offsets. */
! 157: layout_fix_offsets(lc);
! 158: layout_fix_panes(w, w->sx, w->sy);
! 159:
! 160: layout_print_cell(w->layout_root, __func__, 1);
! 161:
! 162: server_redraw_window(w);
! 163: }
! 164:
! 165: void
! 166: layout_set_even_v(struct window *w)
! 167: {
! 168: struct window_pane *wp;
! 169: struct layout_cell *lc, *lcnew;
! 170: u_int i, n, height, yoff;
! 171:
! 172: layout_print_cell(w->layout_root, __func__, 1);
! 173:
! 174: /* Get number of panes. */
! 175: n = window_count_panes(w);
! 176: if (n <= 1)
! 177: return;
! 178:
! 179: /* How many can we fit? */
! 180: if (w->sy / n < PANE_MINIMUM + 1) {
! 181: height = PANE_MINIMUM + 1;
! 182: n = UINT_MAX;
! 183: } else
! 184: height = w->sy / n;
! 185:
! 186: /* Free the old root and construct a new. */
! 187: layout_free(w);
! 188: lc = w->layout_root = layout_create_cell(NULL);
! 189: layout_set_size(lc, w->sx, w->sy, 0, 0);
! 190: layout_make_node(lc, LAYOUT_TOPBOTTOM);
! 191:
! 192: /* Build new leaf cells. */
! 193: i = yoff = 0;
! 194: TAILQ_FOREACH(wp, &w->panes, entry) {
! 195: /* Create child cell. */
! 196: lcnew = layout_create_cell(lc);
! 197: layout_set_size(lcnew, w->sx, height - 1, 0, yoff);
! 198: layout_make_leaf(lcnew, wp);
! 199: TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
! 200:
! 201: i++;
! 202: yoff += height;
! 203: }
! 204:
! 205: /* Allocate any remaining space. */
! 206: if (w->sy > yoff - 1) {
! 207: lc = TAILQ_LAST(&lc->cells, layout_cells);
! 208: layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, w->sy - (yoff - 1));
! 209: }
! 210:
! 211: /* Fix cell offsets. */
! 212: layout_fix_offsets(lc);
! 213: layout_fix_panes(w, w->sx, w->sy);
! 214:
! 215: layout_print_cell(w->layout_root, __func__, 1);
! 216:
! 217: server_redraw_window(w);
! 218: }
! 219:
! 220: void
! 221: layout_set_main_h(struct window *w)
! 222: {
! 223: struct window_pane *wp;
! 224: struct layout_cell *lc, *lcmain, *lcrow, *lcchild;
! 225: u_int n, mainheight, width, height, used;
! 226: u_int i, j, columns, rows, totalrows;
! 227:
! 228: layout_print_cell(w->layout_root, __func__, 1);
! 229:
! 230: /* Get number of panes. */
! 231: n = window_count_panes(w);
! 232: if (n <= 1)
! 233: return;
! 234: n--; /* take off main pane */
! 235:
! 236: /* How many rows and columns will be needed? */
! 237: columns = w->sx / (PANE_MINIMUM + 1); /* maximum columns */
! 238: rows = 1 + (n - 1) / columns;
! 239: columns = 1 + (n - 1) / rows;
! 240: width = w->sx / columns;
! 241:
! 242: /* Get the main pane height and add one for separator line. */
! 243: mainheight = options_get_number(&w->options, "main-pane-height") + 1;
! 244: if (mainheight < PANE_MINIMUM + 1)
! 245: mainheight = PANE_MINIMUM + 1;
! 246:
! 247: /* Try and make everything fit. */
! 248: totalrows = rows * (PANE_MINIMUM + 1) - 1;
! 249: if (mainheight + totalrows > w->sy) {
! 250: if (totalrows + PANE_MINIMUM + 1 > w->sy)
! 251: mainheight = PANE_MINIMUM + 2;
! 252: else
! 253: mainheight = w->sy - totalrows;
! 254: height = PANE_MINIMUM + 1;
! 255: } else
! 256: height = (w->sy - mainheight) / rows;
! 257:
! 258: /* Free old tree and create a new root. */
! 259: layout_free(w);
! 260: lc = w->layout_root = layout_create_cell(NULL);
! 261: layout_set_size(lc, w->sx, mainheight + rows * height, 0, 0);
! 262: layout_make_node(lc, LAYOUT_TOPBOTTOM);
! 263:
! 264: /* Create the main pane. */
! 265: lcmain = layout_create_cell(lc);
! 266: layout_set_size(lcmain, w->sx, mainheight - 1, 0, 0);
! 267: layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
! 268: TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
! 269:
! 270: /* Create a grid of the remaining cells. */
! 271: wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
! 272: for (j = 0; j < rows; j++) {
! 273: /* If this is the last cell, all done. */
! 274: if (wp == NULL)
! 275: break;
! 276:
! 277: /* Create the new row. */
! 278: lcrow = layout_create_cell(lc);
! 279: layout_set_size(lcrow, w->sx, height - 1, 0, 0);
! 280: TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
! 281:
! 282: /* If only one column, just use the row directly. */
! 283: if (columns == 1) {
! 284: layout_make_leaf(lcrow, wp);
! 285: wp = TAILQ_NEXT(wp, entry);
! 286: continue;
! 287: }
! 288:
! 289: /* Add in the columns. */
! 290: layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
! 291: for (i = 0; i < columns; i++) {
! 292: /* Create and add a pane cell. */
! 293: lcchild = layout_create_cell(lcrow);
! 294: layout_set_size(lcchild, width - 1, height - 1, 0, 0);
! 295: layout_make_leaf(lcchild, wp);
! 296: TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
! 297:
! 298: /* Move to the next cell. */
! 299: if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
! 300: break;
! 301: }
! 302:
! 303: /* Adjust the row to fit the full width if necessary. */
! 304: if (i == columns)
! 305: i--;
! 306: used = ((i + 1) * width) - 1;
! 307: if (w->sx <= used)
! 308: continue;
! 309: lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
! 310: layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used);
! 311: }
! 312:
! 313: /* Adjust the last row height to fit if necessary. */
! 314: used = mainheight + (rows * height) - 1;
! 315: if (w->sy > used) {
! 316: lcrow = TAILQ_LAST(&lc->cells, layout_cells);
! 317: layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
! 318: }
! 319:
! 320: /* Fix cell offsets. */
! 321: layout_fix_offsets(lc);
! 322: layout_fix_panes(w, w->sx, w->sy);
! 323:
! 324: layout_print_cell(w->layout_root, __func__, 1);
! 325:
! 326: server_redraw_window(w);
! 327: }
! 328:
! 329: void
! 330: layout_set_main_v(struct window *w)
! 331: {
! 332: struct window_pane *wp;
! 333: struct layout_cell *lc, *lcmain, *lccolumn, *lcchild;
! 334: u_int n, mainwidth, width, height, used;
! 335: u_int i, j, columns, rows, totalcolumns;
! 336:
! 337: layout_print_cell(w->layout_root, __func__, 1);
! 338:
! 339: /* Get number of panes. */
! 340: n = window_count_panes(w);
! 341: if (n <= 1)
! 342: return;
! 343: n--; /* take off main pane */
! 344:
! 345: /* How many rows and columns will be needed? */
! 346: rows = w->sy / (PANE_MINIMUM + 1); /* maximum rows */
! 347: columns = 1 + (n - 1) / rows;
! 348: rows = 1 + (n - 1) / columns;
! 349: height = w->sy / rows;
! 350:
! 351: /* Get the main pane width and add one for separator line. */
! 352: mainwidth = options_get_number(&w->options, "main-pane-width") + 1;
! 353: if (mainwidth < PANE_MINIMUM + 1)
! 354: mainwidth = PANE_MINIMUM + 1;
! 355:
! 356: /* Try and make everything fit. */
! 357: totalcolumns = columns * (PANE_MINIMUM + 1) - 1;
! 358: if (mainwidth + totalcolumns > w->sx) {
! 359: if (totalcolumns + PANE_MINIMUM + 1 > w->sx)
! 360: mainwidth = PANE_MINIMUM + 2;
! 361: else
! 362: mainwidth = w->sx - totalcolumns;
! 363: width = PANE_MINIMUM + 1;
! 364: } else
! 365: width = (w->sx - mainwidth) / columns;
! 366:
! 367: /* Free old tree and create a new root. */
! 368: layout_free(w);
! 369: lc = w->layout_root = layout_create_cell(NULL);
! 370: layout_set_size(lc, mainwidth + columns * width, w->sy, 0, 0);
! 371: layout_make_node(lc, LAYOUT_LEFTRIGHT);
! 372:
! 373: /* Create the main pane. */
! 374: lcmain = layout_create_cell(lc);
! 375: layout_set_size(lcmain, mainwidth - 1, w->sy, 0, 0);
! 376: layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
! 377: TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
! 378:
! 379: /* Create a grid of the remaining cells. */
! 380: wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
! 381: for (j = 0; j < columns; j++) {
! 382: /* If this is the last cell, all done. */
! 383: if (wp == NULL)
! 384: break;
! 385:
! 386: /* Create the new column. */
! 387: lccolumn = layout_create_cell(lc);
! 388: layout_set_size(lccolumn, width - 1, w->sy, 0, 0);
! 389: TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry);
! 390:
! 391: /* If only one row, just use the row directly. */
! 392: if (rows == 1) {
! 393: layout_make_leaf(lccolumn, wp);
! 394: wp = TAILQ_NEXT(wp, entry);
! 395: continue;
! 396: }
! 397:
! 398: /* Add in the rows. */
! 399: layout_make_node(lccolumn, LAYOUT_TOPBOTTOM);
! 400: for (i = 0; i < rows; i++) {
! 401: /* Create and add a pane cell. */
! 402: lcchild = layout_create_cell(lccolumn);
! 403: layout_set_size(lcchild, width - 1, height - 1, 0, 0);
! 404: layout_make_leaf(lcchild, wp);
! 405: TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry);
! 406:
! 407: /* Move to the next cell. */
! 408: if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
! 409: break;
! 410: }
! 411:
! 412: /* Adjust the column to fit the full height if necessary. */
! 413: if (i == rows)
! 414: i--;
! 415: used = ((i + 1) * height) - 1;
! 416: if (w->sy <= used)
! 417: continue;
! 418: lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells);
! 419: layout_resize_adjust(lcchild, LAYOUT_TOPBOTTOM, w->sy - used);
! 420: }
! 421:
! 422: /* Adjust the last column width to fit if necessary. */
! 423: used = mainwidth + (columns * width) - 1;
! 424: if (w->sx > used) {
! 425: lccolumn = TAILQ_LAST(&lc->cells, layout_cells);
! 426: layout_resize_adjust(lccolumn, LAYOUT_LEFTRIGHT, w->sx - used);
! 427: }
! 428:
! 429: /* Fix cell offsets. */
! 430: layout_fix_offsets(lc);
! 431: layout_fix_panes(w, w->sx, w->sy);
! 432:
! 433: layout_print_cell(w->layout_root, __func__, 1);
! 434:
! 435: server_redraw_window(w);
! 436: }