[BACK]Return to layout-set.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

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: }