Annotation of embedaddon/tmux/layout-set.c, revision 1.1
1.1 ! misho 1: /* $OpenBSD$ */
! 2:
! 3: /*
! 4: * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
! 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
! 27: * one-off and generate a layout tree.
! 28: */
! 29:
! 30: static void layout_set_even_h(struct window *);
! 31: static void layout_set_even_v(struct window *);
! 32: static void layout_set_main_h(struct window *);
! 33: static void layout_set_main_v(struct window *);
! 34: static void layout_set_tiled(struct window *);
! 35:
! 36: static const struct {
! 37: const char *name;
! 38: void (*arrange)(struct window *);
! 39: } layout_sets[] = {
! 40: { "even-horizontal", layout_set_even_h },
! 41: { "even-vertical", layout_set_even_v },
! 42: { "main-horizontal", layout_set_main_h },
! 43: { "main-vertical", layout_set_main_v },
! 44: { "tiled", layout_set_tiled },
! 45: };
! 46:
! 47: int
! 48: layout_set_lookup(const char *name)
! 49: {
! 50: u_int i;
! 51: int matched = -1;
! 52:
! 53: for (i = 0; i < nitems(layout_sets); i++) {
! 54: if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) {
! 55: if (matched != -1) /* ambiguous */
! 56: return (-1);
! 57: matched = i;
! 58: }
! 59: }
! 60:
! 61: return (matched);
! 62: }
! 63:
! 64: u_int
! 65: layout_set_select(struct window *w, u_int layout)
! 66: {
! 67: if (layout > nitems(layout_sets) - 1)
! 68: layout = nitems(layout_sets) - 1;
! 69:
! 70: if (layout_sets[layout].arrange != NULL)
! 71: layout_sets[layout].arrange(w);
! 72:
! 73: w->lastlayout = layout;
! 74: return (layout);
! 75: }
! 76:
! 77: u_int
! 78: layout_set_next(struct window *w)
! 79: {
! 80: u_int layout;
! 81:
! 82: if (w->lastlayout == -1)
! 83: layout = 0;
! 84: else {
! 85: layout = w->lastlayout + 1;
! 86: if (layout > nitems(layout_sets) - 1)
! 87: layout = 0;
! 88: }
! 89:
! 90: if (layout_sets[layout].arrange != NULL)
! 91: layout_sets[layout].arrange(w);
! 92: w->lastlayout = layout;
! 93: return (layout);
! 94: }
! 95:
! 96: u_int
! 97: layout_set_previous(struct window *w)
! 98: {
! 99: u_int layout;
! 100:
! 101: if (w->lastlayout == -1)
! 102: layout = nitems(layout_sets) - 1;
! 103: else {
! 104: layout = w->lastlayout;
! 105: if (layout == 0)
! 106: layout = nitems(layout_sets) - 1;
! 107: else
! 108: layout--;
! 109: }
! 110:
! 111: if (layout_sets[layout].arrange != NULL)
! 112: layout_sets[layout].arrange(w);
! 113: w->lastlayout = layout;
! 114: return (layout);
! 115: }
! 116:
! 117: static void
! 118: layout_set_even_h(struct window *w)
! 119: {
! 120: struct window_pane *wp;
! 121: struct layout_cell *lc, *lcnew;
! 122: u_int i, n, width, xoff;
! 123:
! 124: layout_print_cell(w->layout_root, __func__, 1);
! 125:
! 126: /* Get number of panes. */
! 127: n = window_count_panes(w);
! 128: if (n <= 1)
! 129: return;
! 130:
! 131: /* How many can we fit? */
! 132: width = (w->sx - (n - 1)) / n;
! 133: if (width < PANE_MINIMUM)
! 134: width = PANE_MINIMUM;
! 135:
! 136: /* Free the old root and construct a new. */
! 137: layout_free(w);
! 138: lc = w->layout_root = layout_create_cell(NULL);
! 139: layout_set_size(lc, w->sx, w->sy, 0, 0);
! 140: layout_make_node(lc, LAYOUT_LEFTRIGHT);
! 141:
! 142: /* Build new leaf cells. */
! 143: i = xoff = 0;
! 144: TAILQ_FOREACH(wp, &w->panes, entry) {
! 145: /* Create child cell. */
! 146: lcnew = layout_create_cell(lc);
! 147: layout_set_size(lcnew, width, w->sy, xoff, 0);
! 148: layout_make_leaf(lcnew, wp);
! 149: TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
! 150:
! 151: i++;
! 152: xoff += width + 1;
! 153: }
! 154:
! 155: /* Allocate any remaining space. */
! 156: if (w->sx > xoff - 1) {
! 157: lc = TAILQ_LAST(&lc->cells, layout_cells);
! 158: layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT,
! 159: w->sx - (xoff - 1));
! 160: }
! 161:
! 162: /* Fix cell offsets. */
! 163: layout_fix_offsets(lc);
! 164: layout_fix_panes(w, w->sx, w->sy);
! 165:
! 166: layout_print_cell(w->layout_root, __func__, 1);
! 167:
! 168: server_redraw_window(w);
! 169: }
! 170:
! 171: static void
! 172: layout_set_even_v(struct window *w)
! 173: {
! 174: struct window_pane *wp;
! 175: struct layout_cell *lc, *lcnew;
! 176: u_int i, n, height, yoff;
! 177:
! 178: layout_print_cell(w->layout_root, __func__, 1);
! 179:
! 180: /* Get number of panes. */
! 181: n = window_count_panes(w);
! 182: if (n <= 1)
! 183: return;
! 184:
! 185: /* How many can we fit? */
! 186: height = (w->sy - (n - 1)) / n;
! 187: if (height < PANE_MINIMUM)
! 188: height = PANE_MINIMUM;
! 189:
! 190: /* Free the old root and construct a new. */
! 191: layout_free(w);
! 192: lc = w->layout_root = layout_create_cell(NULL);
! 193: layout_set_size(lc, w->sx, w->sy, 0, 0);
! 194: layout_make_node(lc, LAYOUT_TOPBOTTOM);
! 195:
! 196: /* Build new leaf cells. */
! 197: i = yoff = 0;
! 198: TAILQ_FOREACH(wp, &w->panes, entry) {
! 199: /* Create child cell. */
! 200: lcnew = layout_create_cell(lc);
! 201: layout_set_size(lcnew, w->sx, height, 0, yoff);
! 202: layout_make_leaf(lcnew, wp);
! 203: TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
! 204:
! 205: i++;
! 206: yoff += height + 1;
! 207: }
! 208:
! 209: /* Allocate any remaining space. */
! 210: if (w->sy > yoff - 1) {
! 211: lc = TAILQ_LAST(&lc->cells, layout_cells);
! 212: layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM,
! 213: w->sy - (yoff - 1));
! 214: }
! 215:
! 216: /* Fix cell offsets. */
! 217: layout_fix_offsets(lc);
! 218: layout_fix_panes(w, w->sx, w->sy);
! 219:
! 220: layout_print_cell(w->layout_root, __func__, 1);
! 221:
! 222: server_redraw_window(w);
! 223: }
! 224:
! 225: static void
! 226: layout_set_main_h(struct window *w)
! 227: {
! 228: struct window_pane *wp;
! 229: struct layout_cell *lc, *lcmain, *lcrow, *lcchild;
! 230: u_int n, mainheight, otherheight, width, height;
! 231: u_int used, i, j, columns, rows, totalrows;
! 232:
! 233: layout_print_cell(w->layout_root, __func__, 1);
! 234:
! 235: /* Get number of panes. */
! 236: n = window_count_panes(w);
! 237: if (n <= 1)
! 238: return;
! 239: n--; /* take off main pane */
! 240:
! 241: /* How many rows and columns will be needed, not counting main? */
! 242: columns = (w->sx + 1) / (PANE_MINIMUM + 1); /* maximum columns */
! 243: if (columns == 0)
! 244: columns = 1;
! 245: rows = 1 + (n - 1) / columns;
! 246: columns = 1 + (n - 1) / rows;
! 247: width = (w->sx - (n - 1)) / columns;
! 248:
! 249: /* Get the main pane height and add one for separator line. */
! 250: mainheight = options_get_number(w->options, "main-pane-height") + 1;
! 251:
! 252: /* Get the optional other pane height and add one for separator line. */
! 253: otherheight = options_get_number(w->options, "other-pane-height") + 1;
! 254:
! 255: /*
! 256: * If an other pane height was specified, honour it so long as it
! 257: * doesn't shrink the main height to less than the main-pane-height
! 258: */
! 259: if (otherheight > 1 && w->sy - otherheight > mainheight)
! 260: mainheight = w->sy - otherheight;
! 261: if (mainheight < PANE_MINIMUM + 1)
! 262: mainheight = PANE_MINIMUM + 1;
! 263:
! 264: /* Try and make everything fit. */
! 265: totalrows = rows * (PANE_MINIMUM + 1) - 1;
! 266: if (mainheight + totalrows > w->sy) {
! 267: if (totalrows + PANE_MINIMUM + 1 > w->sy)
! 268: mainheight = PANE_MINIMUM + 2;
! 269: else
! 270: mainheight = w->sy - totalrows;
! 271: height = PANE_MINIMUM;
! 272: } else
! 273: height = (w->sy - mainheight - (rows - 1)) / rows;
! 274:
! 275: /* Free old tree and create a new root. */
! 276: layout_free(w);
! 277: lc = w->layout_root = layout_create_cell(NULL);
! 278: layout_set_size(lc, w->sx, mainheight + rows * (height + 1) - 1, 0, 0);
! 279: layout_make_node(lc, LAYOUT_TOPBOTTOM);
! 280:
! 281: /* Create the main pane. */
! 282: lcmain = layout_create_cell(lc);
! 283: layout_set_size(lcmain, w->sx, mainheight - 1, 0, 0);
! 284: layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
! 285: TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
! 286:
! 287: /* Create a grid of the remaining cells. */
! 288: wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
! 289: for (j = 0; j < rows; j++) {
! 290: /* If this is the last cell, all done. */
! 291: if (wp == NULL)
! 292: break;
! 293:
! 294: /* Create the new row. */
! 295: lcrow = layout_create_cell(lc);
! 296: layout_set_size(lcrow, w->sx, height, 0, 0);
! 297: TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
! 298:
! 299: /* If only one column, just use the row directly. */
! 300: if (columns == 1) {
! 301: layout_make_leaf(lcrow, wp);
! 302: wp = TAILQ_NEXT(wp, entry);
! 303: continue;
! 304: }
! 305:
! 306: /* Add in the columns. */
! 307: layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
! 308: for (i = 0; i < columns; i++) {
! 309: /* Create and add a pane cell. */
! 310: lcchild = layout_create_cell(lcrow);
! 311: layout_set_size(lcchild, width, height, 0, 0);
! 312: layout_make_leaf(lcchild, wp);
! 313: TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
! 314:
! 315: /* Move to the next cell. */
! 316: if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
! 317: break;
! 318: }
! 319:
! 320: /* Adjust the row to fit the full width if necessary. */
! 321: if (i == columns)
! 322: i--;
! 323: used = ((i + 1) * (width + 1)) - 1;
! 324: if (w->sx <= used)
! 325: continue;
! 326: lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
! 327: layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
! 328: w->sx - used);
! 329: }
! 330:
! 331: /* Adjust the last row height to fit if necessary. */
! 332: used = mainheight + (rows * height) + rows - 1;
! 333: if (w->sy > used) {
! 334: lcrow = TAILQ_LAST(&lc->cells, layout_cells);
! 335: layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
! 336: w->sy - used);
! 337: }
! 338:
! 339: /* Fix cell offsets. */
! 340: layout_fix_offsets(lc);
! 341: layout_fix_panes(w, w->sx, w->sy);
! 342:
! 343: layout_print_cell(w->layout_root, __func__, 1);
! 344:
! 345: server_redraw_window(w);
! 346: }
! 347:
! 348: static void
! 349: layout_set_main_v(struct window *w)
! 350: {
! 351: struct window_pane *wp;
! 352: struct layout_cell *lc, *lcmain, *lccolumn, *lcchild;
! 353: u_int n, mainwidth, otherwidth, width, height;
! 354: u_int used, i, j, columns, rows, totalcolumns;
! 355:
! 356: layout_print_cell(w->layout_root, __func__, 1);
! 357:
! 358: /* Get number of panes. */
! 359: n = window_count_panes(w);
! 360: if (n <= 1)
! 361: return;
! 362: n--; /* take off main pane */
! 363:
! 364: /* How many rows and columns will be needed, not counting main? */
! 365: rows = (w->sy + 1) / (PANE_MINIMUM + 1); /* maximum rows */
! 366: if (rows == 0)
! 367: rows = 1;
! 368: columns = 1 + (n - 1) / rows;
! 369: rows = 1 + (n - 1) / columns;
! 370: height = (w->sy - (n - 1)) / rows;
! 371:
! 372: /* Get the main pane width and add one for separator line. */
! 373: mainwidth = options_get_number(w->options, "main-pane-width") + 1;
! 374:
! 375: /* Get the optional other pane width and add one for separator line. */
! 376: otherwidth = options_get_number(w->options, "other-pane-width") + 1;
! 377:
! 378: /*
! 379: * If an other pane width was specified, honour it so long as it
! 380: * doesn't shrink the main width to less than the main-pane-width
! 381: */
! 382: if (otherwidth > 1 && w->sx - otherwidth > mainwidth)
! 383: mainwidth = w->sx - otherwidth;
! 384: if (mainwidth < PANE_MINIMUM + 1)
! 385: mainwidth = PANE_MINIMUM + 1;
! 386:
! 387: /* Try and make everything fit. */
! 388: totalcolumns = columns * (PANE_MINIMUM + 1) - 1;
! 389: if (mainwidth + totalcolumns > w->sx) {
! 390: if (totalcolumns + PANE_MINIMUM + 1 > w->sx)
! 391: mainwidth = PANE_MINIMUM + 2;
! 392: else
! 393: mainwidth = w->sx - totalcolumns;
! 394: width = PANE_MINIMUM;
! 395: } else
! 396: width = (w->sx - mainwidth - (columns - 1)) / columns;
! 397:
! 398: /* Free old tree and create a new root. */
! 399: layout_free(w);
! 400: lc = w->layout_root = layout_create_cell(NULL);
! 401: layout_set_size(lc, mainwidth + columns * (width + 1) - 1, w->sy, 0, 0);
! 402: layout_make_node(lc, LAYOUT_LEFTRIGHT);
! 403:
! 404: /* Create the main pane. */
! 405: lcmain = layout_create_cell(lc);
! 406: layout_set_size(lcmain, mainwidth - 1, w->sy, 0, 0);
! 407: layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
! 408: TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
! 409:
! 410: /* Create a grid of the remaining cells. */
! 411: wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
! 412: for (j = 0; j < columns; j++) {
! 413: /* If this is the last cell, all done. */
! 414: if (wp == NULL)
! 415: break;
! 416:
! 417: /* Create the new column. */
! 418: lccolumn = layout_create_cell(lc);
! 419: layout_set_size(lccolumn, width, w->sy, 0, 0);
! 420: TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry);
! 421:
! 422: /* If only one row, just use the row directly. */
! 423: if (rows == 1) {
! 424: layout_make_leaf(lccolumn, wp);
! 425: wp = TAILQ_NEXT(wp, entry);
! 426: continue;
! 427: }
! 428:
! 429: /* Add in the rows. */
! 430: layout_make_node(lccolumn, LAYOUT_TOPBOTTOM);
! 431: for (i = 0; i < rows; i++) {
! 432: /* Create and add a pane cell. */
! 433: lcchild = layout_create_cell(lccolumn);
! 434: layout_set_size(lcchild, width, height, 0, 0);
! 435: layout_make_leaf(lcchild, wp);
! 436: TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry);
! 437:
! 438: /* Move to the next cell. */
! 439: if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
! 440: break;
! 441: }
! 442:
! 443: /* Adjust the column to fit the full height if necessary. */
! 444: if (i == rows)
! 445: i--;
! 446: used = ((i + 1) * (height + 1)) - 1;
! 447: if (w->sy <= used)
! 448: continue;
! 449: lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells);
! 450: layout_resize_adjust(w, lcchild, LAYOUT_TOPBOTTOM,
! 451: w->sy - used);
! 452: }
! 453:
! 454: /* Adjust the last column width to fit if necessary. */
! 455: used = mainwidth + (columns * width) + columns - 1;
! 456: if (w->sx > used) {
! 457: lccolumn = TAILQ_LAST(&lc->cells, layout_cells);
! 458: layout_resize_adjust(w, lccolumn, LAYOUT_LEFTRIGHT,
! 459: w->sx - used);
! 460: }
! 461:
! 462: /* Fix cell offsets. */
! 463: layout_fix_offsets(lc);
! 464: layout_fix_panes(w, w->sx, w->sy);
! 465:
! 466: layout_print_cell(w->layout_root, __func__, 1);
! 467:
! 468: server_redraw_window(w);
! 469: }
! 470:
! 471: void
! 472: layout_set_tiled(struct window *w)
! 473: {
! 474: struct window_pane *wp;
! 475: struct layout_cell *lc, *lcrow, *lcchild;
! 476: u_int n, width, height, used;
! 477: u_int i, j, columns, rows;
! 478:
! 479: layout_print_cell(w->layout_root, __func__, 1);
! 480:
! 481: /* Get number of panes. */
! 482: n = window_count_panes(w);
! 483: if (n <= 1)
! 484: return;
! 485:
! 486: /* How many rows and columns are wanted? */
! 487: rows = columns = 1;
! 488: while (rows * columns < n) {
! 489: rows++;
! 490: if (rows * columns < n)
! 491: columns++;
! 492: }
! 493:
! 494: /* What width and height should they be? */
! 495: width = (w->sx - (columns - 1)) / columns;
! 496: if (width < PANE_MINIMUM)
! 497: width = PANE_MINIMUM;
! 498: height = (w->sy - (rows - 1)) / rows;
! 499: if (height < PANE_MINIMUM)
! 500: height = PANE_MINIMUM;
! 501:
! 502: /* Free old tree and create a new root. */
! 503: layout_free(w);
! 504: lc = w->layout_root = layout_create_cell(NULL);
! 505: layout_set_size(lc, (width + 1) * columns - 1,
! 506: (height + 1) * rows - 1, 0, 0);
! 507: layout_make_node(lc, LAYOUT_TOPBOTTOM);
! 508:
! 509: /* Create a grid of the cells. */
! 510: wp = TAILQ_FIRST(&w->panes);
! 511: for (j = 0; j < rows; j++) {
! 512: /* If this is the last cell, all done. */
! 513: if (wp == NULL)
! 514: break;
! 515:
! 516: /* Create the new row. */
! 517: lcrow = layout_create_cell(lc);
! 518: layout_set_size(lcrow, w->sx, height, 0, 0);
! 519: TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
! 520:
! 521: /* If only one column, just use the row directly. */
! 522: if (n - (j * columns) == 1 || columns == 1) {
! 523: layout_make_leaf(lcrow, wp);
! 524: wp = TAILQ_NEXT(wp, entry);
! 525: continue;
! 526: }
! 527:
! 528: /* Add in the columns. */
! 529: layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
! 530: for (i = 0; i < columns; i++) {
! 531: /* Create and add a pane cell. */
! 532: lcchild = layout_create_cell(lcrow);
! 533: layout_set_size(lcchild, width, height, 0, 0);
! 534: layout_make_leaf(lcchild, wp);
! 535: TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
! 536:
! 537: /* Move to the next cell. */
! 538: if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
! 539: break;
! 540: }
! 541:
! 542: /*
! 543: * Adjust the row and columns to fit the full width if
! 544: * necessary.
! 545: */
! 546: if (i == columns)
! 547: i--;
! 548: used = ((i + 1) * (width + 1)) - 1;
! 549: if (w->sx <= used)
! 550: continue;
! 551: lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
! 552: layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
! 553: w->sx - used);
! 554: }
! 555:
! 556: /* Adjust the last row height to fit if necessary. */
! 557: used = (rows * height) + rows - 1;
! 558: if (w->sy > used) {
! 559: lcrow = TAILQ_LAST(&lc->cells, layout_cells);
! 560: layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
! 561: w->sy - used);
! 562: }
! 563:
! 564: /* Fix cell offsets. */
! 565: layout_fix_offsets(lc);
! 566: layout_fix_panes(w, w->sx, w->sy);
! 567:
! 568: layout_print_cell(w->layout_root, __func__, 1);
! 569:
! 570: server_redraw_window(w);
! 571: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>