OpenBSD-4.6/usr.bin/tmux/layout-manual.c

/* $OpenBSD: layout-manual.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */

/*
 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/types.h>

#include "tmux.h"

void	layout_manual_v_update_offsets(struct window *);

void
layout_manual_v_refresh(struct window *w, unused int active_only)
{
	struct window_pane	*wp;
	u_int			 npanes, canfit, total;
	int			 left;

	if (active_only)
		return;

	if (TAILQ_EMPTY(&w->panes))
		return;

	/* Clear hidden flags. */
	TAILQ_FOREACH(wp, &w->panes, entry)
	    	wp->flags &= ~PANE_HIDDEN;

	/* Check the new size. */
	npanes = window_count_panes(w);
	if (w->sy <= PANE_MINIMUM * npanes) {
		/* How many can we fit? */
		canfit = w->sy / PANE_MINIMUM;
		if (canfit == 0) {
			/* None. Just use this size for the first. */
			TAILQ_FOREACH(wp, &w->panes, entry) {
				if (wp == TAILQ_FIRST(&w->panes))
					wp->sy = w->sy;
				else
					wp->flags |= PANE_HIDDEN;
			}
		} else {
			/* >=1, set minimum for them all. */
			TAILQ_FOREACH(wp, &w->panes, entry) {
				if (canfit-- > 0)
					wp->sy = PANE_MINIMUM - 1;
				else
					wp->flags |= PANE_HIDDEN;
			}
			/* And increase the first by the rest. */
			TAILQ_FIRST(&w->panes)->sy += 1 + w->sy % PANE_MINIMUM;
		}
	} else {
		/* In theory they will all fit. Find the current total. */
		total = 0;
		TAILQ_FOREACH(wp, &w->panes, entry)
			total += wp->sy;
		total += npanes - 1;

		/* Growing or shrinking? */
		left = w->sy - total;
		if (left > 0) {
			/* Growing. Expand evenly. */
			while (left > 0) {
				TAILQ_FOREACH(wp, &w->panes, entry) {
					wp->sy++;
					if (--left == 0)
						break;
				}
			}
		} else {
			/* Shrinking. Reduce evenly down to minimum. */
			while (left < 0) {
				TAILQ_FOREACH(wp, &w->panes, entry) {
					if (wp->sy <= PANE_MINIMUM - 1)
						continue;
					wp->sy--;
					if (++left == 0)
						break;
				}
			}
		}
	}

	/* Now do the resize. */
	TAILQ_FOREACH(wp, &w->panes, entry) {
		wp->sy--;
	    	window_pane_resize(wp, w->sx, wp->sy + 1);
	}

	/* Fill in the offsets. */
	layout_manual_v_update_offsets(w);

	/* Switch the active window if necessary. */
	window_set_active_pane(w, w->active);
}

void
layout_manual_v_resize(struct window_pane *wp, int adjust)
{
	struct window		*w = wp->window;
	struct window_pane	*wq;

	if (adjust > 0) {
		/*
		 * If this is not the last pane, keep trying to increase size
		 * and remove it from the next panes. If it is the last, do
		 * so on the previous pane.
		 */
		if (TAILQ_NEXT(wp, entry) == NULL) {
			if (wp == TAILQ_FIRST(&w->panes)) {
				/* Only one pane. */
				return;
			}
			wp = TAILQ_PREV(wp, window_panes, entry);
		}
		while (adjust-- > 0) {
			wq = wp;
			while ((wq = TAILQ_NEXT(wq, entry)) != NULL) {
				if (wq->sy <= PANE_MINIMUM)
					continue;
				window_pane_resize(wq, wq->sx, wq->sy - 1);
				break;
			}
			if (wq == NULL)
				break;
			window_pane_resize(wp, wp->sx, wp->sy + 1);
		}
	} else {
		adjust = -adjust;
		/*
		 * If this is not the last pane, keep trying to reduce size
		 * and add to the following pane. If it is the last, do so on
		 * the previous pane.
		 */
		wq = TAILQ_NEXT(wp, entry);
		if (wq == NULL) {
			if (wp == TAILQ_FIRST(&w->panes)) {
				/* Only one pane. */
				return;
			}
			wq = wp;
			wp = TAILQ_PREV(wq, window_panes, entry);
		}
		while (adjust-- > 0) {
			if (wp->sy <= PANE_MINIMUM)
				break;
			window_pane_resize(wq, wq->sx, wq->sy + 1);
			window_pane_resize(wp, wp->sx, wp->sy - 1);
		}
	}

	layout_manual_v_update_offsets(w);
}

void
layout_manual_v_update_offsets(struct window *w)
{
	struct window_pane     *wp;
	u_int			yoff;

	yoff = 0;
	TAILQ_FOREACH(wp, &w->panes, entry) {
		if (wp->flags & PANE_HIDDEN)
			continue;
		wp->xoff = 0;
		wp->yoff = yoff;
		yoff += wp->sy + 1;
	}
}