#include #include #include #include "newt.h" #include "newt_pr.h" struct gridField { enum newtGridElement type; union { newtGrid grid; newtComponent co; } u; int padLeft, padTop, padRight, padBottom; int anchor; int flags; }; struct grid_s { int rows, cols; int width, height; /* totals, -1 means unknown */ struct gridField ** fields; }; /* this is a bit of a hack */ extern struct componentOps formOps[]; newtGrid newtCreateGrid(int cols, int rows) { newtGrid grid; grid = malloc(sizeof(*grid)); grid->rows = rows; grid->cols = cols; grid->fields = malloc(sizeof(*grid->fields) * cols); while (cols--) { grid->fields[cols] = malloc(sizeof(**(grid->fields)) * rows); memset(grid->fields[cols], 0, sizeof(**(grid->fields)) * rows); } grid->width = grid->height = -1; return grid; } void newtGridSetField(newtGrid grid, int col, int row, enum newtGridElement type, void * val, int padLeft, int padTop, int padRight, int padBottom, int anchor, int flags) { struct gridField * field = &grid->fields[col][row]; if (field->type == NEWT_GRID_SUBGRID) newtGridFree(field->u.grid, 1); field->type = type; field->u.co = (void *) val; field->padLeft = padLeft; field->padRight = padRight; field->padTop = padTop; field->padBottom = padBottom; field->anchor = anchor; field->flags = flags; grid->width = grid->height = -1; } static void distSpace(int extra, int items, int * list) { int all, some, i; all = extra / items; some = extra % items; for (i = 0; i < items; i++) { list[i] += all; if (some) { list[i]++; some--; } } } static void shuffleGrid(newtGrid grid, int left, int top, int set) { struct gridField * field; int row, col; int i, j; int minWidth, minHeight; int * widths, * heights; int thisLeft, thisTop; int x, y, remx, remy; widths = alloca(sizeof(*widths) * grid->cols); memset(widths, 0, sizeof(*widths) * grid->cols); heights = alloca(sizeof(*heights) * grid->rows); memset(heights, 0, sizeof(*heights) * grid->rows); minWidth = 0; for (row = 0; row < grid->rows; row++) { i = 0; for (col = 0; col < grid->cols; col++) { field = &grid->fields[col][row]; if (field->type == NEWT_GRID_SUBGRID) { /* we'll have to redo this later */ if (field->u.grid->width == -1) shuffleGrid(field->u.grid, left, top, 0); j = field->u.grid->width; } else if (field->type == NEWT_GRID_COMPONENT) { if (field->u.co->ops == formOps) newtFormSetSize(field->u.co); j = field->u.co->width; } else j = 0; j += field->padLeft + field->padRight; if (j > widths[col]) widths[col] = j; i += widths[col]; } if (i > minWidth) minWidth = i; } minHeight = 0; for (col = 0; col < grid->cols; col++) { i = 0; for (row = 0; row < grid->rows; row++) { field = &grid->fields[col][row]; if (field->type == NEWT_GRID_SUBGRID) { /* we'll have to redo this later */ if (field->u.grid->height == -1) shuffleGrid(field->u.grid, 0, 0, 0); j = field->u.grid->height; } else if (field->type == NEWT_GRID_COMPONENT){ j = field->u.co->height; } else j = 0; j += field->padTop + field->padBottom; if (j > heights[row]) heights[row] = j; i += heights[row]; } if (i > minHeight) minHeight = i; } /* this catches the -1 case */ if (grid->width < minWidth) grid->width = minWidth; /* ack! */ if (grid->height < minHeight) grid->height = minHeight; /* ditto! */ if (!set) return; distSpace(grid->width - minWidth, grid->cols, widths); distSpace(grid->height - minHeight, grid->rows, heights); thisTop = top; for (row = 0; row < grid->rows; row++) { i = 0; thisLeft = left; for (col = 0; col < grid->cols; col++) { field = &grid->fields[col][row]; if (field->type == NEWT_GRID_EMPTY) continue; x = thisLeft + field->padLeft; remx = widths[col] - field->padLeft - field->padRight; y = thisTop + field->padTop; remy = heights[row] - field->padTop - field->padBottom; if (field->type == NEWT_GRID_SUBGRID) { remx -= field->u.grid->width; remy -= field->u.grid->height; } else if (field->type == NEWT_GRID_COMPONENT) { remx -= field->u.co->width; remy -= field->u.co->height; } if (!(field->flags & NEWT_GRID_FLAG_GROWX)) { if (field->anchor & NEWT_ANCHOR_RIGHT) x += remx; else if (!(field->anchor & NEWT_ANCHOR_LEFT)) x += (remx / 2); } if (!(field->flags & NEWT_GRID_FLAG_GROWY)) { if (field->anchor & NEWT_ANCHOR_BOTTOM) y += remx; else if (!(field->anchor & NEWT_ANCHOR_TOP)) y += (remy / 2); } if (field->type == NEWT_GRID_SUBGRID) { if (field->flags & NEWT_GRID_FLAG_GROWX) field->u.grid->width = widths[col] - field->padLeft - field->padRight; if (field->flags & NEWT_GRID_FLAG_GROWY) field->u.grid->height = heights[col] - field->padTop - field->padBottom; shuffleGrid(field->u.grid, x, y, 1); } else if (field->type == NEWT_GRID_COMPONENT) { field->u.co->ops->place(field->u.co, x, y); } thisLeft += widths[col]; } thisTop += heights[row]; } } void newtGridPlace(newtGrid grid, int left, int top) { shuffleGrid(grid, left, top, 1); } void newtGridFree(newtGrid grid, int recurse) { int row, col; for (col = 0; col < grid->cols; col++) { if (recurse) { for (row = 0; row < grid->rows; row++) { if (grid->fields[col][row].type == NEWT_GRID_SUBGRID) newtGridFree(grid->fields[col][row].u.grid, 1); } } free(grid->fields[col]); } free(grid->fields); free(grid); } void newtGridGetSize(newtGrid grid, int * width, int * height) { if (grid->width == -1 || grid->height == -1) { grid->width = grid->height = -1; shuffleGrid(grid, 0, 0, 1); } *width = grid->width; *height = grid->height; } void newtGridWrappedWindow(newtGrid grid, char * title) { int width, height, offset = 0; newtGridGetSize(grid, &width, &height); if ((size_t)width < strlen(title) + 2) { offset = ((strlen(title) + 2) - width) / 2; width = strlen(title) + 2; } newtCenteredWindow(width + 2, height + 2, title); newtGridPlace(grid, 1 + offset, 1); } void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top) { int width, height; newtGridGetSize(grid, &width, &height); newtOpenWindow(left, top, width + 2, height + 2, title); newtGridPlace(grid, 1, 1); } void newtGridAddComponentsToForm(newtGrid grid, newtComponent form, int recurse) { int row, col; for (col = 0; col < grid->cols; col++) { for (row = 0; row < grid->rows; row++) { if (grid->fields[col][row].type == NEWT_GRID_SUBGRID && recurse) newtGridAddComponentsToForm(grid->fields[col][row].u.grid, form, 1); else if (grid->fields[col][row].type == NEWT_GRID_COMPONENT) newtFormAddComponent(form, grid->fields[col][row].u.co); } } } /* this handles up to 50 items */ static newtGrid stackem(int isVert, enum newtGridElement type1, void * what1, va_list args, int close) { struct item { enum newtGridElement type; void * what; } items[50]; int i, num; newtGrid grid; items[0].type = type1, items[0].what = what1, num = 1; while (1) { items[num].type = va_arg(args, enum newtGridElement); if (items[num].type == NEWT_GRID_EMPTY) break; items[num].what = va_arg(args, void *); num++; } grid = newtCreateGrid(isVert ? 1 : num, isVert ? num : 1); for (i = 0; i < num; i++) { newtGridSetField(grid, isVert ? 0 : i, isVert ? i : 0, items[i].type, items[i].what, close ? 0 : (i ? (isVert ? 0 : 1) : 0), close ? 0 : (i ? (isVert ? 1 : 0) : 0), 0, 0, 0, 0); } return grid; } newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...) { va_list args; newtGrid grid; va_start(args, what1); grid = stackem(0, type1, what1, args, 1); va_start(args, what1); return grid; } newtGrid newtGridVCloseStacked(enum newtGridElement type1, void * what1, ...) { va_list args; newtGrid grid; va_start(args, what1); grid = stackem(1, type1, what1, args, 1); va_start(args, what1); return grid; } newtGrid newtGridVStacked(enum newtGridElement type1, void * what1, ...) { va_list args; newtGrid grid; va_start(args, what1); grid = stackem(1, type1, what1, args, 0); va_start(args, what1); return grid; } newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...) { va_list args; newtGrid grid; va_start(args, what1); grid = stackem(0, type1, what1, args, 0); va_start(args, what1); return grid; } newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle, newtGrid buttons) { newtGrid grid; grid = newtCreateGrid(1, 3); newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, middle, 0, 1, 0, 0, 0, 0); newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons, 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX); return grid; } newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle, newtGrid buttons) { newtGrid grid; grid = newtCreateGrid(1, 3); newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, middle, 0, 1, 0, 0, 0, 0); newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons, 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX); return grid; }