350 lines
8 KiB
C
350 lines
8 KiB
C
/* Copyright (c) 2008, 2009
|
|
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
|
|
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
|
|
* Micah Cowan (micah@cowan.name)
|
|
* Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
|
|
* Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
|
|
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
|
|
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
|
|
* Copyright (c) 1987 Oliver Laumann
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program (see the file COPYING); if not, see
|
|
* https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
|
*
|
|
****************************************************************
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "screen.h"
|
|
#include "extern.h"
|
|
#include "layout.h"
|
|
|
|
extern struct display *display;
|
|
extern int captionalways;
|
|
|
|
struct layout *layouts;
|
|
struct layout *laytab[MAXLAY];
|
|
struct layout *layout_last, layout_last_marker;
|
|
struct layout *layout_attach = &layout_last_marker;
|
|
|
|
void FreeLayoutCv(struct canvas *cv)
|
|
{
|
|
struct canvas *cnext, *c = cv;
|
|
for (; cv; cv = cnext) {
|
|
if (cv->c_slperp) {
|
|
FreeLayoutCv(cv->c_slperp);
|
|
free(cv->c_slperp);
|
|
cv->c_slperp = 0;
|
|
}
|
|
cnext = cv->c_slnext;
|
|
cv->c_slnext = 0;
|
|
if (cv != c)
|
|
free(cv);
|
|
}
|
|
}
|
|
|
|
struct layout *CreateLayout(char *title, int startat)
|
|
{
|
|
struct layout *lay, **pl;
|
|
int i;
|
|
|
|
if (startat >= MAXLAY || startat < 0)
|
|
startat = 0;
|
|
for (i = startat; ;) {
|
|
if (!laytab[i])
|
|
break;
|
|
if (++i == MAXLAY)
|
|
i = 0;
|
|
if (i == startat) {
|
|
Msg(0, "No more layouts\n");
|
|
return 0;
|
|
}
|
|
}
|
|
lay = (struct layout *)calloc(1, sizeof(*lay));
|
|
lay->lay_title = SaveStr(title);
|
|
lay->lay_autosave = 1;
|
|
lay->lay_number = i;
|
|
laytab[i] = lay;
|
|
lay->lay_next = 0;
|
|
|
|
pl = &layouts;
|
|
while (*pl)
|
|
pl = &(*pl)->lay_next;
|
|
*pl = lay;
|
|
return lay;
|
|
}
|
|
|
|
void SaveLayout(char *name, struct canvas *cv)
|
|
{
|
|
struct layout *lay;
|
|
struct canvas *fcv;
|
|
for (lay = layouts; lay; lay = lay->lay_next)
|
|
if (!strcmp(lay->lay_title, name))
|
|
break;
|
|
if (lay)
|
|
FreeLayoutCv(&lay->lay_canvas);
|
|
else
|
|
lay = CreateLayout(name, 0);
|
|
if (!lay)
|
|
return;
|
|
fcv = D_forecv;
|
|
DupLayoutCv(cv, &lay->lay_canvas, 1);
|
|
lay->lay_forecv = D_forecv;
|
|
D_forecv = fcv;
|
|
D_layout = lay;
|
|
}
|
|
|
|
void AutosaveLayout(struct layout *lay)
|
|
{
|
|
struct canvas *fcv;
|
|
if (!lay || !lay->lay_autosave)
|
|
return;
|
|
FreeLayoutCv(&lay->lay_canvas);
|
|
fcv = D_forecv;
|
|
DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
|
|
lay->lay_forecv = D_forecv;
|
|
D_forecv = fcv;
|
|
}
|
|
|
|
struct layout *FindLayout(char *name)
|
|
{
|
|
struct layout *lay;
|
|
char *s;
|
|
int i;
|
|
for (i = 0, s = name; *s >= '0' && *s <= '9'; s++)
|
|
i = i * 10 + (*s - '0');
|
|
if (!*s && s != name && i >= 0 && i < MAXLAY)
|
|
return laytab[i];
|
|
for (lay = layouts; lay; lay = lay->lay_next)
|
|
if (!strcmp(lay->lay_title, name))
|
|
break;
|
|
return lay;
|
|
}
|
|
|
|
void LoadLayout(struct layout *lay, struct canvas *cv)
|
|
{
|
|
AutosaveLayout(D_layout);
|
|
if (!lay) {
|
|
while (D_canvas.c_slperp)
|
|
FreeCanvas(D_canvas.c_slperp);
|
|
MakeDefaultCanvas();
|
|
SetCanvasWindow(D_forecv, 0);
|
|
D_layout = 0;
|
|
return;
|
|
}
|
|
while (D_canvas.c_slperp)
|
|
FreeCanvas(D_canvas.c_slperp);
|
|
D_cvlist = 0;
|
|
D_forecv = lay->lay_forecv;
|
|
if (!D_forecv)
|
|
MakeDefaultCanvas();
|
|
DupLayoutCv(&lay->lay_canvas, &D_canvas, 0);
|
|
D_canvas.c_ys = (D_has_hstatus == HSTATUS_FIRSTLINE);
|
|
D_canvas.c_ye = D_height - 1 - ((D_canvas.c_slperp && D_canvas.c_slperp->c_slnext) ||
|
|
captionalways) - (D_has_hstatus == HSTATUS_LASTLINE);
|
|
ResizeCanvas(&D_canvas);
|
|
RecreateCanvasChain();
|
|
RethinkDisplayViewports();
|
|
PutWindowCv(&D_canvas);
|
|
ResizeLayersToCanvases();
|
|
D_layout = lay;
|
|
}
|
|
|
|
void NewLayout(char *title, int startat)
|
|
{
|
|
struct layout *lay;
|
|
struct canvas *fcv;
|
|
|
|
lay = CreateLayout(title, startat);
|
|
if (!lay)
|
|
return;
|
|
|
|
if (display) {
|
|
LoadLayout(0, &D_canvas);
|
|
fcv = D_forecv;
|
|
DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
|
|
lay->lay_forecv = D_forecv;
|
|
D_forecv = fcv;
|
|
D_layout = lay;
|
|
}
|
|
else
|
|
layout_attach = lay;
|
|
|
|
lay->lay_autosave = 1;
|
|
}
|
|
|
|
|
|
static char *AddLayoutsInfo(char *buf, int len, int where)
|
|
{
|
|
char *s, *ss, *t;
|
|
struct layout *p, **pp;
|
|
int l;
|
|
|
|
s = ss = buf;
|
|
for (pp = laytab; pp < laytab + MAXLAY; pp++) {
|
|
if (pp - laytab == where && ss == buf)
|
|
ss = s;
|
|
if ((p = *pp) == 0)
|
|
continue;
|
|
t = p->lay_title;
|
|
l = strlen(t);
|
|
if (l > 20)
|
|
l = 20;
|
|
if (s - buf + l > len - 24)
|
|
break;
|
|
if (s > buf) {
|
|
*s++ = ' ';
|
|
*s++ = ' ';
|
|
}
|
|
sprintf(s, "%d", p->lay_number);
|
|
if (p->lay_number == where)
|
|
ss = s;
|
|
s += strlen(s);
|
|
if (display && p == D_layout)
|
|
*s++ = '*';
|
|
*s++ = ' ';
|
|
strncpy(s, t, l);
|
|
s += l;
|
|
}
|
|
*s = 0;
|
|
return ss;
|
|
}
|
|
|
|
void ShowLayouts(int where)
|
|
{
|
|
char buf[1024];
|
|
char *s, *ss;
|
|
|
|
if (!display)
|
|
return;
|
|
if (!layouts) {
|
|
Msg(0, "No layouts defined\n");
|
|
return;
|
|
}
|
|
if (where == -1 && D_layout)
|
|
where = D_layout->lay_number;
|
|
ss = AddLayoutsInfo(buf, sizeof(buf), where);
|
|
s = buf + strlen(buf);
|
|
if (ss - buf > D_width / 2) {
|
|
ss -= D_width / 2;
|
|
if (s - ss < D_width) {
|
|
ss = s - D_width;
|
|
if (ss < buf)
|
|
ss = buf;
|
|
}
|
|
}
|
|
else
|
|
ss = buf;
|
|
Msg(0, "%s", ss);
|
|
}
|
|
|
|
void RemoveLayout(struct layout *lay)
|
|
{
|
|
struct layout **layp = &layouts;
|
|
|
|
for (; *layp; layp = &(*layp)->lay_next) {
|
|
if (*layp == lay) {
|
|
*layp = lay->lay_next;
|
|
break;
|
|
}
|
|
}
|
|
laytab[lay->lay_number] = (struct layout *)0;
|
|
|
|
if (display && D_layout == lay)
|
|
D_layout = (struct layout *)0;
|
|
|
|
FreeLayoutCv(&lay->lay_canvas);
|
|
|
|
if (lay->lay_title)
|
|
free(lay->lay_title);
|
|
free(lay);
|
|
|
|
if (layouts)
|
|
LoadLayout((display && D_layout) ? D_layout : *layp ? *layp : layouts,
|
|
display ? &D_canvas : (struct canvas *)0);
|
|
Activate(0);
|
|
}
|
|
|
|
void UpdateLayoutCanvas(struct canvas *cv, struct win * wi)
|
|
{
|
|
for (; cv; cv = cv->c_slnext) {
|
|
if (cv->c_layer && Layer2Window(cv->c_layer) == wi) {
|
|
/* A simplistic version of SetCanvasWindow(cv, 0) */
|
|
struct layer *l = cv->c_layer;
|
|
cv->c_layer = 0;
|
|
if (l->l_cvlist == 0 && (wi == 0 || l != wi->w_savelayer))
|
|
KillLayerChain(l);
|
|
|
|
l = &cv->c_blank;
|
|
l->l_data = 0;
|
|
if (l->l_cvlist != cv) {
|
|
cv->c_lnext = l->l_cvlist;
|
|
l->l_cvlist = cv;
|
|
}
|
|
cv->c_layer = l;
|
|
/* Do not end here. Multiple canvases can have the same window */
|
|
}
|
|
|
|
if (cv->c_slperp)
|
|
UpdateLayoutCanvas(cv->c_slperp, wi);
|
|
}
|
|
}
|
|
|
|
|
|
static void dump_canvas(struct canvas *cv, FILE *file)
|
|
{
|
|
struct canvas *c;
|
|
for (c = cv->c_slperp; c && c->c_slnext; c = c->c_slnext)
|
|
fprintf(file, "split%s\n", c->c_slorient == SLICE_HORI ? " -v" : "");
|
|
|
|
for (c = cv->c_slperp; c; c = c->c_slnext) {
|
|
if (c->c_slperp)
|
|
dump_canvas(c, file);
|
|
else
|
|
fprintf(file, "focus\n");
|
|
}
|
|
}
|
|
|
|
int LayoutDumpCanvas(struct canvas *cv, char *filename)
|
|
{
|
|
FILE *file = secfopen(filename, "a");
|
|
if (!file)
|
|
return 0;
|
|
dump_canvas(cv, file);
|
|
fclose(file);
|
|
return 1;
|
|
}
|
|
|
|
void RenameLayout(struct layout *layout, const char *name)
|
|
{
|
|
free(layout->lay_title);
|
|
layout->lay_title = SaveStr(name);
|
|
}
|
|
|
|
int RenumberLayout(struct layout *layout, int number)
|
|
{
|
|
int old;
|
|
struct layout *lay;
|
|
old = layout->lay_number;
|
|
if (number < 0 || number >= MAXLAY)
|
|
return 0;
|
|
lay = laytab[number];
|
|
laytab[number] = layout;
|
|
layout->lay_number = number;
|
|
laytab[old] = lay;
|
|
if (lay)
|
|
lay->lay_number = old;
|
|
return 1;
|
|
}
|