/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "xp.h" #include "shist.h" #include "pa_parse.h" #include "layout.h" #include "libmocha.h" #define TOP_EDGE 0 #define BOTTOM_EDGE 1 #define LEFT_EDGE 2 #define RIGHT_EDGE 3 static lo_GridPercent * lo_parse_percent_list(MWContext *context, char *str, int32 *rows) { char *tptr; int32 i, cnt; lo_GridPercent *percent_list; if ((str == NULL)||(*str == '\0')) { return((lo_GridPercent *)NULL); } cnt = 0; tptr = strchr(str, ','); while (tptr != NULL) { cnt++; tptr++; tptr = strchr(tptr, ','); } cnt++; *rows = cnt; percent_list = (lo_GridPercent *)XP_ALLOC(cnt * sizeof(lo_GridPercent)); if (percent_list == NULL) { return((lo_GridPercent *)NULL); } tptr = str; for (i=0; icell_array != NULL) { XP_FREE(edge->cell_array); } XP_DELETE(edge); } void lo_FreeGridRec(lo_GridRec *grid) { if (grid == NULL) { return; } if (grid->row_percents != NULL) { XP_FREE(grid->row_percents); } if (grid->col_percents != NULL) { XP_FREE(grid->col_percents); } if (grid->edge_list != NULL) { lo_GridEdge *tmp_edge; lo_GridEdge *edge_list; edge_list = grid->edge_list; while (edge_list != NULL) { tmp_edge = edge_list; edge_list = edge_list->next; lo_FreeGridEdge(tmp_edge); } } XP_DELETE(grid); } void lo_FreeGridCellRec(MWContext *context, lo_GridRec *grid, lo_GridCellRec *cell) { History_entry *hist; if (cell == NULL) { return; } if (cell->url != NULL) { XP_FREE(cell->url); } if (cell->name != NULL) { XP_FREE(cell->name); } if (cell->context != NULL) { /* * If the cell has a context, use it instead of the * parent's context. Otherwise use the parent context. * This is bogus but needed to keep the winfe from * dumping because it blindly dereferences the context * even though it doesn't use it. */ context = cell->context; } if (cell->hist_list != NULL) { XP_List *list_ptr; list_ptr = (XP_List *)cell->hist_list; hist = (History_entry *)XP_ListRemoveTopObject(list_ptr); while (hist != NULL) { SHIST_DropEntry(context, hist); hist =(History_entry *)XP_ListRemoveTopObject(list_ptr); } XP_ListDestroy(list_ptr); } if (cell->hist_array != NULL) { int32 i; for (i = 0; i < grid->hist_size; i++) { hist = (History_entry *)cell->hist_array[i].hist; SHIST_DropEntry(context, hist); } XP_FREE(cell->hist_array); } XP_DELETE(cell); } static lo_GridEdge * lo_new_horizontal_edge(MWContext *context, lo_DocState *state, int32 cols, int32 x, int32 y, int32 width, int32 height) { lo_GridEdge *edge; LO_EdgeStruct *fe_edge; edge = XP_NEW(lo_GridEdge); if (edge == NULL) { return(NULL); } fe_edge = (LO_EdgeStruct *)lo_NewElement(context, state, LO_EDGE, NULL, 0); if (fe_edge == NULL) { XP_DELETE(edge); return(NULL); } edge->x = x; edge->y = y; edge->width = width; edge->height = height; edge->is_vertical = FALSE; edge->left_top_bound = 0; edge->right_bottom_bound = 0; edge->cell_cnt = 0; edge->cell_max = 0; edge->cell_array = NULL; edge->next = NULL; if (cols > 0) { int32 cells; cells = 2 * cols; edge->cell_array = (lo_GridCellRec **)XP_ALLOC(cells * sizeof(lo_GridCellRec *)); if (edge->cell_array != NULL) { edge->cell_max = cells; } } fe_edge->type = LO_EDGE; fe_edge->ele_id = NEXT_ELEMENT; fe_edge->x = x; fe_edge->x_offset = 0; fe_edge->y = y; fe_edge->y_offset = 0; fe_edge->width = edge->width; fe_edge->height = edge->height; fe_edge->line_height = 0; fe_edge->next = NULL; fe_edge->prev = NULL; fe_edge->FE_Data = NULL; fe_edge->lo_edge_info = (void *)edge; fe_edge->is_vertical = edge->is_vertical; fe_edge->visible = TRUE; fe_edge->movable = TRUE; fe_edge->left_top_bound = 0; fe_edge->right_bottom_bound = 0; edge->fe_edge = fe_edge; return(edge); } static lo_GridEdge * lo_new_vertical_edge(MWContext *context, lo_DocState *state, int32 rows, int32 x, int32 y, int32 width, int32 height) { lo_GridEdge *edge; LO_EdgeStruct *fe_edge; edge = XP_NEW(lo_GridEdge); if (edge == NULL) { return(NULL); } fe_edge = (LO_EdgeStruct *)lo_NewElement(context, state, LO_EDGE, NULL, 0); if (fe_edge == NULL) { XP_DELETE(edge); return(NULL); } edge->x = x; edge->y = y; edge->width = width; edge->height = height; edge->is_vertical = TRUE; edge->left_top_bound = 0; edge->right_bottom_bound = 0; edge->cell_cnt = 0; edge->cell_max = 0; edge->cell_array = NULL; edge->next = NULL; if (rows > 0) { int32 cells; cells = 2 * rows; edge->cell_array = (lo_GridCellRec **)XP_ALLOC(cells * sizeof(lo_GridCellRec *)); if (edge->cell_array != NULL) { edge->cell_max = cells; } } fe_edge->type = LO_EDGE; fe_edge->ele_id = NEXT_ELEMENT; fe_edge->x = x; fe_edge->x_offset = 0; fe_edge->y = y; fe_edge->y_offset = 0; fe_edge->width = edge->width; fe_edge->height = edge->height; fe_edge->line_height = 0; fe_edge->next = NULL; fe_edge->prev = NULL; fe_edge->FE_Data = NULL; fe_edge->lo_edge_info = (void *)edge; fe_edge->is_vertical = edge->is_vertical; fe_edge->visible = TRUE; fe_edge->movable = TRUE; fe_edge->left_top_bound = 0; fe_edge->right_bottom_bound = 0; edge->fe_edge = fe_edge; return(edge); } static void lo_grow_edge_cell_array(lo_GridEdge *edge, int32 more) { lo_GridCellRec **old_array; lo_GridCellRec **new_array; int32 new_size; /* * Error condition, punt. */ if (more <= 0) { return; } /* * If we are not growing the array, but instead allocating a new * array. */ if (edge->cell_max == 0) { edge->cell_array = (lo_GridCellRec **)XP_ALLOC(more * sizeof(lo_GridCellRec *)); if (edge->cell_array != NULL) { edge->cell_max = more; } return; } /* * Attempt to grow the old array. */ new_size = edge->cell_max + more; old_array = edge->cell_array; new_array = (lo_GridCellRec **)XP_REALLOC(old_array, (new_size * sizeof(lo_GridCellRec *))); /* * If realloc fails, punt. */ if (new_array == NULL) { return; } edge->cell_array = new_array; edge->cell_max = new_size; } static void lo_add_cell_to_edge(lo_GridEdge *edge, lo_GridCellRec *cell) { /* * Error. */ if ((cell == NULL)||(edge == NULL)) { return; } /* * If I did my math right earlier, this will never happen. */ if (edge->cell_cnt >= edge->cell_max) { lo_grow_edge_cell_array(edge, 1); /* * This may fail */ if (edge->cell_cnt >= edge->cell_max) { return; } } edge->cell_array[edge->cell_cnt] = cell; edge->cell_cnt++; } static void lo_adjust_percents(int32 count, lo_GridPercent *percents, int32 max) { int32 i; int32 fixed_percent; int32 free_percent; int32 total; if (max == 0) max = 1; /* * Total up the three different type of grid cell percentages. */ fixed_percent = 0; free_percent = 0; total = 0; for (i=0; i < count; i++) { if (percents[i].type == LO_PERCENT_FIXED) { /* * Now that we know the max dimension turn * fixed pixel dimensions into percents. */ percents[i].value = 100 * percents[i].original_value / max; if (percents[i].value < 1) { percents[i].value = 1; } fixed_percent += percents[i].value; } else if (percents[i].type == LO_PERCENT_FREE) { percents[i].value = percents[i].original_value; free_percent += percents[i].original_value; } else { percents[i].value = percents[i].original_value; total += percents[i].original_value; } } /* * If the user didn't explicitly use up all the space. */ if ((total + fixed_percent) < 100) { int32 val; /* * We have some free percentage cells that want to * soak up the excess space. */ if (free_percent > 0) { int32 used; int32 last_i; last_i = -1; used = 0; val = 100 - (total + fixed_percent); for (i=0; i < count; i++) { if (percents[i].type == LO_PERCENT_FREE) { percents[i].value *= val; percents[i].value /= free_percent; if (percents[i].value < 1) { percents[i].value = 1; } used += percents[i].value; last_i = i; } } /* * Slop the extra into the last qualifying cell. */ if (((used + total + fixed_percent) < 100)&& (last_i >= 0)) { percents[last_i].value += (100 - total - fixed_percent - used); } } /* * Else we have no free cells, but have some normal * percentage cells, distribute the extra space among them. */ else if (total > 0) { int32 used; int32 last_i; last_i = -1; used = 0; val = (100 - fixed_percent); for (i=0; i < count; i++) { if (percents[i].type == LO_PERCENT_NORMAL) { percents[i].value *= val; percents[i].value /= total; used += percents[i].value; last_i = i; } } /* * Slop the extra into the last qualifying cell. */ if ((used < val)&&(last_i >= 0)) { percents[last_i].value += (val - used); } } /* * Else all we have are fixed percentage cells, we will * have to grow them. */ else { int32 used; used = 0; for (i=0; i < count; i++) { percents[i].value *= 100; percents[i].value /= (total + fixed_percent); used += percents[i].value; } /* * Slop the extra into the last cell. */ if ((used < 100)&&(count > 0)) { percents[count - 1].value += (100 - used); } } } /* * Else if the user allocated too much space, we need to shrink * something. */ else if ((total + fixed_percent) > 100) { int32 val; /* * If there is not too much fixed percentage * added, we can just shrink the normal percentage * cells to make things fit. */ if (fixed_percent <= 100) { int32 used; int32 last_i; last_i = -1; used = 0; val = (100 - fixed_percent); for (i=0; i < count; i++) { if (percents[i].type == LO_PERCENT_NORMAL) { percents[i].value *= val; percents[i].value /= total; used += percents[i].value; } } /* * Since integer division always truncates, we either * made it fit exactly, or overcompensated and made * it too small. */ if ((used < val)&&(last_i >= 0)) { percents[last_i].value += (val - used); } } /* * Else there is too much fixed percentage as well, we will * just shrink all the cells. */ else { int32 used; used = 0; for (i=0; i < count; i++) { if (percents[i].type == LO_PERCENT_FREE) { percents[i].value = 0; } else { percents[i].value *= 100; percents[i].value /= (total + fixed_percent); } used += percents[i].value; } /* * Since integer division always truncates, we either * made it fit exactly, or overcompensated and made * it too small. */ if (used < 100) { percents[count - 1].value += (100 - used); } } } } static void lo_adjust_subpercents(int32 count, lo_GridPercent *percents, int32 percent, int32 max) { int32 i; int32 fixed_percent; int32 free_percent; int32 total; if (max == 0) max = 1; /* * Total up the three different type of grid cell percentages. */ fixed_percent = 0; free_percent = 0; total = 0; for (i=0; i < count; i++) { if (percents[i].type == LO_PERCENT_FIXED) { /* * Now that we know the max dimension turn * fixed pixel dimensions into percents. */ percents[i].value = percent * percents[i].original_value / max; if (percents[i].value < 1) { percents[i].value = 1; } fixed_percent += percents[i].value; } else if (percents[i].type == LO_PERCENT_FREE) { percents[i].value = percents[i].original_value; free_percent += percents[i].original_value; } else { percents[i].value = percent * percents[i].original_value / 100; total += percents[i].original_value; } } /* * If the user didn't explicitly use up all the space. */ if ((total + fixed_percent) < 100) { int32 val; /* * We have some free percentage cells that want to * soak up the excess space. */ if (free_percent > 0) { int32 used; int32 last_i; last_i = -1; used = 0; val = 100 - (total + fixed_percent); for (i=0; i < count; i++) { if (percents[i].type == LO_PERCENT_FREE) { percents[i].value *= val; percents[i].value /= free_percent; if (percents[i].value < 1) { percents[i].value = 1; } used += percents[i].value; last_i = i; } } /* * Slop the extra into the last qualifying cell. */ if (((used + total + fixed_percent) < 100)&& (last_i >= 0)) { percents[last_i].value += (100 - total - fixed_percent - used); } } /* * Else we have no free cells, but have some normal * percentage cells, distribute the extra space among them. */ else if (total > 0) { int32 used; int32 last_i; last_i = -1; used = 0; val = (100 - fixed_percent); for (i=0; i < count; i++) { if (percents[i].type == LO_PERCENT_NORMAL) { percents[i].value *= val; percents[i].value /= total; used += percents[i].value; last_i = i; } } /* * Slop the extra into the last qualifying cell. */ if ((used < val)&&(last_i >= 0)) { percents[last_i].value += (val - used); } } /* * Else all we have are fixed percentage cells, we will * have to grow them. */ else { int32 used; used = 0; for (i=0; i < count; i++) { percents[i].value *= 100; percents[i].value /= (total + fixed_percent); used += percents[i].value; } /* * Slop the extra into the last cell. */ if ((used < 100)&&(count > 0)) { percents[count - 1].value += (100 - used); } } } /* * Else if the user allocated too much space, we need to shrink * something. */ else if ((total + fixed_percent) > 100) { int32 val; /* * If there is not too much fixed percentage * added, we can just shrink the normal percentage * cells to make things fit. */ if (fixed_percent <= 100) { int32 used; int32 last_i; last_i = -1; used = 0; val = (100 - fixed_percent); for (i=0; i < count; i++) { if (percents[i].type == LO_PERCENT_NORMAL) { percents[i].value *= val; percents[i].value /= total; used += percents[i].value; } } /* * Since integer division always truncates, we either * made it fit exactly, or overcompensated and made * it too small. */ if ((used < val)&&(last_i >= 0)) { percents[last_i].value += (val - used); } } /* * Else there is too much fixed percentage as well, we will * just shrink all the cells. */ else { int32 used; used = 0; for (i=0; i < count; i++) { if (percents[i].type == LO_PERCENT_FREE) { percents[i].value = 0; } else { percents[i].value *= 100; percents[i].value /= (total + fixed_percent); } used += percents[i].value; } /* * Since integer division always truncates, we either * made it fit exactly, or overcompensated and made * it too small. */ if (used < 100) { percents[count - 1].value += (100 - used); } } } } PRIVATE void lo_LayoutGridCells(MWContext *context, lo_DocState *state, int32 x, int32 y, int32 width, int32 height, lo_GridRec *grid, lo_GridEdge **edges) { int32 cols, rows; int32 col_cnt, row_cnt; int32 orig_x, orig_y; lo_GridCellRec *cell_parent; lo_GridCellRec *cell_list; lo_GridEdge **col_edges; lo_GridEdge *top_edge; lo_GridEdge *new_edges[4]; /* top, bottom, left, right */ new_edges[TOP_EDGE] = NULL; new_edges[BOTTOM_EDGE] = NULL; new_edges[LEFT_EDGE] = NULL; new_edges[RIGHT_EDGE] = NULL; if (grid == NULL) { return; } cols = grid->cols; rows = grid->rows; cell_list = grid->cell_list; /* * Allocate space for the temporary array of column * edge pointer we will need here. */ col_edges = (lo_GridEdge **)XP_ALLOC(sizeof(lo_GridEdge *) * cols); if (col_edges == NULL) { return; } top_edge = NULL; /* * If we came in with bounding edges, we are a sub-grid, and we need * to increase the size of the cell arrays in those edges to reflect * the extra cells now bordering them. */ if (edges[TOP_EDGE] != NULL) { int32 more; more = (cols * 2) - 1; lo_grow_edge_cell_array(edges[TOP_EDGE], more); } if (edges[BOTTOM_EDGE] != NULL) { int32 more; more = (cols * 2) - 1; lo_grow_edge_cell_array(edges[BOTTOM_EDGE], more); } if (edges[LEFT_EDGE] != NULL) { int32 more; more = (rows * 2) - 1; lo_grow_edge_cell_array(edges[LEFT_EDGE], more); } if (edges[RIGHT_EDGE] != NULL) { int32 more; more = (rows * 2) - 1; lo_grow_edge_cell_array(edges[RIGHT_EDGE], more); } orig_x = x; orig_y = y; col_cnt = 0; row_cnt = 0; cell_parent = NULL; while (cell_list != NULL) { lo_GridEdge *tmp_edge; tmp_edge = NULL; /* make gcc happy */ cell_list->width_percent = (intn)grid->col_percents[col_cnt].value; cell_list->has_percent_width = (grid->col_percents[col_cnt].type != LO_PERCENT_FIXED); cell_list->height_percent = (intn)grid->row_percents[row_cnt].value; cell_list->has_percent_height = (grid->row_percents[row_cnt].type != LO_PERCENT_FIXED); cell_list->x = x; if (col_cnt != 0) { cell_list->x += grid->grid_cell_border; } cell_list->y = y; if (row_cnt != 0) { cell_list->y += grid->grid_cell_border; } cell_list->width = width * (float)cell_list->width_percent / 100.0; if (cell_list->width < grid->grid_cell_min_dim) { cell_list->width = grid->grid_cell_min_dim; } if (col_cnt > 0) { cell_list->width -= grid->grid_cell_border; } if (col_cnt < (cols - 1)) { cell_list->width -= grid->grid_cell_border; } /* * Make sure the last column uses all the remaining space. * We subtract orig_x to get cell_list->x into the same coord * space as width. */ if (col_cnt == (cols - 1)) { cell_list->width = width - (cell_list->x - orig_x); } cell_list->height = height * (float)cell_list->height_percent / 100.0; if (cell_list->height < grid->grid_cell_min_dim) { cell_list->height = grid->grid_cell_min_dim; } if (row_cnt > 0) { cell_list->height -= grid->grid_cell_border; } if (row_cnt < (rows - 1)) { cell_list->height -= grid->grid_cell_border; } /* * Make sure the last row uses all the remaining space. * We subtract orig_y to get cell_list->y into the same coord * space as height. */ if (row_cnt == (rows - 1)) { cell_list->height = height - (cell_list->y - orig_y); } /* * If this is the first column, for any row but the * last row, create a new edge to be the bottom of this * row. */ if ((col_cnt == 0)&&(row_cnt < (rows - 1))) { tmp_edge = lo_new_horizontal_edge(context, state, cols, x, (cell_list->y + cell_list->height), width, (2 * grid->grid_cell_border)); if (tmp_edge != NULL) { tmp_edge->next = grid->edge_list; grid->edge_list = tmp_edge; } } /* * When in the first row, create a new side edge on * each column but the last one. */ if ((row_cnt == 0)&&(col_cnt < (cols - 1))) { lo_GridEdge *v_edge; v_edge = lo_new_vertical_edge(context, state, rows, (cell_list->x + cell_list->width), y, (2 * grid->grid_cell_border), height); if (v_edge != NULL) { v_edge->next = grid->edge_list; grid->edge_list = v_edge; } col_edges[col_cnt] = v_edge; } /* * If this is the first column in the row, we need to * set top and bottom edges, for later columns in * the same row, they remain unchanged. */ if (col_cnt == 0) { new_edges[TOP_EDGE] = top_edge; if (row_cnt == 0) { new_edges[TOP_EDGE] = edges[TOP_EDGE]; } new_edges[BOTTOM_EDGE] = tmp_edge; if (row_cnt == (rows - 1)) { new_edges[BOTTOM_EDGE] = edges[BOTTOM_EDGE]; } /* * Set top_edge for next time around. */ top_edge = tmp_edge; } /* * Set the left and right edges for this column. */ if (col_cnt == 0) { new_edges[LEFT_EDGE] = edges[LEFT_EDGE]; } else { new_edges[LEFT_EDGE] = col_edges[(col_cnt - 1)]; } if (col_cnt == (cols - 1)) { new_edges[RIGHT_EDGE] = edges[RIGHT_EDGE]; } else { new_edges[RIGHT_EDGE] = col_edges[col_cnt]; } x += cell_list->width; if (col_cnt > 0) { x += grid->grid_cell_border; } if (col_cnt < (cols - 1)) { x += grid->grid_cell_border; } col_cnt++; if (col_cnt >= cols) { x = orig_x; y += cell_list->height; if (row_cnt > 0) { y += grid->grid_cell_border; } if (row_cnt < (rows - 1)) { y += grid->grid_cell_border; } col_cnt = 0; row_cnt++; } if (cell_list->subgrid != NULL) { lo_GridRec *subgrid; lo_GridCellRec *dummy_cell; subgrid = cell_list->subgrid; dummy_cell = cell_list; subgrid->grid_cell_border = grid->grid_cell_border; subgrid->grid_cell_min_dim = grid->grid_cell_min_dim; /* * Make sure the subgrid percentages add up to our percent * height. */ lo_adjust_subpercents(subgrid->rows, subgrid->row_percents, cell_list->height_percent, cell_list->height); /* * Make sure the subgrid percentages add up to our percent * height. */ lo_adjust_subpercents(subgrid->cols, subgrid->col_percents, cell_list->width_percent, cell_list->width); lo_LayoutGridCells(context, state, cell_list->x, cell_list->y, cell_list->width, cell_list->height, subgrid, new_edges); /* ** XXXX ** There next two if statements attempt to solve a problem -- that ** a frameset that defines columns is given a percentage height of 100%. ** and one that defines rows is given a percentage width of 100%. ** Unfortunately, this breaks resizing when the sub frameset was given a fixed ** width. ** ** So, we go through all the cells and make sure they ** don't have a percent_width/percent_height if their ** parent grid didn't have one. */ if (!cell_list->has_percent_width) { lo_GridCellRec *sub_cell_list = subgrid->cell_list; /* make sure none of the subgrid cells has percent width set. */ while (sub_cell_list) { sub_cell_list->has_percent_width = FALSE; sub_cell_list = sub_cell_list->next; } } if (!cell_list->has_percent_height) { /* make sure none of the subgrid cells has percent height set. */ lo_GridCellRec *sub_cell_list = subgrid->cell_list; /* make sure none of the subgrid cells has percent width set. */ while (sub_cell_list) { sub_cell_list->has_percent_height = FALSE; sub_cell_list = sub_cell_list->next; } } /* * Merge the edge list of the sub-grid with that of * the parent grid. */ if (subgrid->edge_list != NULL) { lo_GridEdge *a_edge; a_edge = subgrid->edge_list; while (a_edge->next != NULL) { a_edge = a_edge->next; } a_edge->next = grid->edge_list; grid->edge_list = subgrid->edge_list; subgrid->edge_list = NULL; } /* * Replace the subgrid cell in the list with its * own list of member cells. */ /* * If the cell to be replace is not the head of the * list. */ if (cell_parent != NULL) { /* * If the cell is being replaced with a list * of one or more cells. */ if (subgrid->cell_list != NULL) { cell_parent->next = subgrid->cell_list; subgrid->cell_list_last->next = cell_list->next; /* * If the cell being replaced was the end of * the list, set the new end properly. */ if (grid->cell_list_last == cell_list) { grid->cell_list_last = subgrid->cell_list_last; } cell_parent = subgrid->cell_list_last; cell_list = cell_list->next; } /* * If the cell is being replaced with * no cells (just remove it.) */ else { cell_parent->next = cell_list->next; /* * If the cell being replaced was the end of * the list, set the new end properly. */ if (grid->cell_list_last == cell_list) { grid->cell_list_last = cell_parent; } cell_parent = cell_parent; cell_list = cell_list->next; } } /* * Else we are replacing the head of the list. */ else { /* * If the cell is being replaced with a list * of one or more cells. */ if (subgrid->cell_list != NULL) { grid->cell_list = subgrid->cell_list; subgrid->cell_list_last->next = cell_list->next; /* * If the cell being replaced was the end of * the list, set the new end properly. */ if (grid->cell_list_last == cell_list) { grid->cell_list_last = subgrid->cell_list_last; } cell_parent = subgrid->cell_list_last; cell_list = cell_list->next; } /* * If the cell is being replaced with * no cells (just remove it.) */ else { grid->cell_list = cell_list->next; /* * If the cell being replaced was the end of * the list, set the new end properly. */ if (grid->cell_list_last == cell_list) { grid->cell_list_last = cell_list->next; } cell_parent = cell_parent; cell_list = cell_list->next; } } lo_FreeGridRec(subgrid); lo_FreeGridCellRec(context, grid, dummy_cell); } /* * Else this was a normal cell. */ else { /* * Add this cell to the cell array for each edge * it borders. */ if (new_edges[TOP_EDGE] != NULL) { lo_add_cell_to_edge(new_edges[TOP_EDGE], cell_list); } if (new_edges[BOTTOM_EDGE] != NULL) { lo_add_cell_to_edge(new_edges[BOTTOM_EDGE], cell_list); } if (new_edges[LEFT_EDGE] != NULL) { lo_add_cell_to_edge(new_edges[LEFT_EDGE], cell_list); } if (new_edges[RIGHT_EDGE] != NULL) { lo_add_cell_to_edge(new_edges[RIGHT_EDGE], cell_list); } cell_list->side_edges[TOP_EDGE] = new_edges[TOP_EDGE]; cell_list->side_edges[BOTTOM_EDGE] = new_edges[BOTTOM_EDGE]; cell_list->side_edges[LEFT_EDGE] = new_edges[LEFT_EDGE]; cell_list->side_edges[RIGHT_EDGE] = new_edges[RIGHT_EDGE]; cell_parent = cell_list; cell_list = cell_list->next; } } if (col_edges != NULL) { XP_FREE(col_edges); } } static void lo_set_edge_bounds(lo_GridEdge *edge) { int32 i; int32 min, max; Bool visible; Bool movable; int16 size; int8 color_priority; LO_Color *bg_color; if (edge == NULL) { return; } visible = FALSE; movable = TRUE; size = -1; color_priority = 0; bg_color = NULL; min = -1; max = -1; /* * For horizontal edges */ if (edge->is_vertical == FALSE) { for (i=0; i < edge->cell_cnt; i++) { lo_GridCellRec *cell; cell = edge->cell_array[i]; if (cell == NULL) { continue; } /* * If a cell on this edge is not resizable, * this edge is not movable. */ if (cell->resizable == FALSE) { movable = FALSE; } /* * If a cell on this edge has visible edges, * this edge is visible. */ if (cell->no_edges == FALSE) { visible = TRUE; } /* * A cell's size is the max of the edge_size * of all cells next to it. */ if (cell->edge_size > size) { size = cell->edge_size; } /* * A cell sets a color on an edge that doesn't * already have a color, or has a lower * priority, it wins. */ if ((cell->border_color != NULL)&& ((bg_color == NULL)|| (cell->color_priority > color_priority))) { bg_color = XP_NEW(LO_Color); if (bg_color != NULL) { bg_color->red = cell->border_color->red; bg_color->green = cell->border_color->green; bg_color->blue = cell->border_color->blue; color_priority = cell->color_priority; } } /* * If the cell is above the edge. */ if (cell->y < edge->y) { if ((cell->y > min)||(min == -1)) { min = cell->y; } } /* * Else the cell is below the edge. */ else { int32 bottom; bottom = cell->y + cell->height - 1; if ((bottom < max)||(max == -1)) { max = bottom; } } } /* * Make min and max be the inclusive bounds through * which edge->y can move. * We should never move an edge so that cell->y * becomes equal to edge->y or else in the future we * will thing that cell is on the wrong side of the * edge. To prevent this, it min is set by a cell's * bounds, we increment it by one. */ if (min == -1) { min = edge->y; } else { min = min + 1; } if (max == -1) { max = edge->y + edge->height - 1; } else { max = max - edge->height + 1; } /* * Sanity check bounds */ if (max < min) { max = min; } edge->left_top_bound = min; edge->right_bottom_bound = max; } /* * Else for vertical edges. */ else { for (i=0; i < edge->cell_cnt; i++) { lo_GridCellRec *cell; cell = edge->cell_array[i]; if (cell == NULL) { continue; } /* * If a cell on this edge is not resizable, * this edge is not movable. */ if (cell->resizable == FALSE) { movable = FALSE; } /* * If a cell on this edge has visible edges, * this edge is visible. */ if (cell->no_edges == FALSE) { visible = TRUE; } /* * A cells size is the max of the edge_size * of all cells next to it. */ if (cell->edge_size > size) { size = cell->edge_size; } /* * A cell sets a color on an edge that doesn't * already have a color, or has a lower * priority, it wins. */ if ((cell->border_color != NULL)&& ((bg_color == NULL)|| (cell->color_priority > color_priority))) { bg_color = XP_NEW(LO_Color); if (bg_color != NULL) { bg_color->red = cell->border_color->red; bg_color->green = cell->border_color->green; bg_color->blue = cell->border_color->blue; color_priority = cell->color_priority; } } /* * If the cell is left of the edge. */ if (cell->x < edge->x) { if ((cell->x > min)||(min == -1)) { min = cell->x; } } /* * Else the cell is right of the edge. */ else { int32 right; right = cell->x + cell->width - 1; if ((right < max)||(max == -1)) { max = right; } } } /* * Make min and max be the inclusive bounds through * which edge->x can move. * We should never move an edge so that cell->x * becomes equal to edge->x or else in the future we * will thing that cell is on the wrong side of the * edge. To prevent this, it min is set by a cell's * bounds, we increment it by one. */ if (min == -1) { min = edge->x; } else { min = min + 1; } if (max == -1) { max = edge->x + edge->width - 1; } else { max = max - edge->width + 1; } /* * Sanity check bounds */ if (max < min) { max = min; } edge->left_top_bound = min; edge->right_bottom_bound = max; } edge->fe_edge->left_top_bound = edge->left_top_bound; edge->fe_edge->right_bottom_bound = edge->right_bottom_bound; edge->fe_edge->visible = visible; edge->fe_edge->movable = movable; edge->fe_edge->size = size; edge->fe_edge->bg_color = bg_color; } static void lo_set_all_edge_bounds(MWContext *context, lo_DocState *state, lo_GridRec *grid) { lo_GridEdge *edge_list; if ((grid == NULL)||(grid->edge_list == NULL)) { return; } edge_list = grid->edge_list; while (edge_list != NULL) { lo_set_edge_bounds(edge_list); /* * Insert this edge into the float list. */ edge_list->fe_edge->next = state->float_list; state->float_list = (LO_Element *)edge_list->fe_edge; lo_DisplayEdge(context, edge_list->fe_edge); edge_list = edge_list->next; } } /* * Use the cell's history index to reload the document * it should now be currently displaying. * (Note, history index starts at 1, and array starts at 0). */ static void lo_reload_cell_from_history(lo_GridCellRec *cell_ptr, NET_ReloadMethod force_reload) { void *hist; hist = cell_ptr->hist_array[cell_ptr->hist_indx - 1].hist; /* * If we have a history entry, and a context to load * it into, have the FE load it now. */ if ((hist != NULL)&&(cell_ptr->context != NULL)) { FE_LoadGridCellFromHistory(cell_ptr->context, hist, force_reload); } } static lo_GridCellRec *reconnecting_cell = NULL; PRIVATE void lo_MakeGrid(MWContext *context, lo_DocState *state, lo_GridRec *grid) { int32 x, y; int32 edge_size; int32 width, height; lo_GridCellRec *cell_ptr; lo_GridEdge *edges[4]; /* top, bottom, left, right */ width = state->win_width; height = state->win_height; FE_GetFullWindowSize(context, &width, &height); if (width <= 0) width = 1; if (height <= 0) height = 1; grid->main_width = width; grid->main_height = height; #ifdef NO_FRAMESET_BORDER edge_size = 1; FE_GetEdgeMinSize(context, &edge_size); if (edge_size < 1) { edge_size = 1; } #else if (grid->edge_size < 0) { edge_size = 1; FE_GetEdgeMinSize(context, &edge_size #if defined(XP_WIN) || defined(XP_OS2) /* need this information here under windows */ , grid->no_edges #endif ); } else { edge_size = grid->edge_size; } if (edge_size < 0) { edge_size = 0; } #endif /* NO_FRAMESET_BORDER */ grid->grid_cell_border = (edge_size + 1) / 2; grid->grid_cell_min_dim = (2 * grid->grid_cell_border) + 1; x = 0; y = 0; /* * Make sure all the row percentages total up * to 100% */ lo_adjust_percents(grid->rows, grid->row_percents, height); /* * Make sure all the col percentages total up * to 100% */ lo_adjust_percents(grid->cols, grid->col_percents, width); edges[TOP_EDGE] = NULL; edges[BOTTOM_EDGE] = NULL; edges[LEFT_EDGE] = NULL; edges[RIGHT_EDGE] = NULL; lo_LayoutGridCells(context, state, x, y, width, height, grid, edges); lo_set_all_edge_bounds(context, state, grid); /* * If there is an old_grid in the top_state, that means we restored * from history with the sizes changed. Go through that old_grid * now, and put those urls back into the cells, then free the old_grid. */ if (state->top_state->old_grid != NULL) { lo_GridRec *old_grid; lo_GridCellRec *old_cell_ptr; lo_SavedGridData tmp_saved_grid; old_grid = state->top_state->old_grid; grid->current_hist = old_grid->current_hist; grid->max_hist = old_grid->max_hist; grid->hist_size = old_grid->hist_size; old_cell_ptr = old_grid->cell_list; cell_ptr = grid->cell_list; while ((cell_ptr != NULL)&&(old_cell_ptr != NULL)) { /* * Free any initial URL loaded, and move the old * url in place. Make sure to clear the old URL * so we don't accidentally free it later. */ if (cell_ptr->url != NULL) { XP_FREE(cell_ptr->url); cell_ptr->url = NULL; } cell_ptr->url = old_cell_ptr->url; old_cell_ptr->url = NULL; /* * Also copy over the old history. */ cell_ptr->hist_indx = old_cell_ptr->hist_indx; cell_ptr->hist_array = old_cell_ptr->hist_array; old_cell_ptr->hist_array = NULL; cell_ptr->hist_list = old_cell_ptr->hist_list; old_cell_ptr->hist_list = NULL; cell_ptr = cell_ptr->next; old_cell_ptr = old_cell_ptr->next; } /* * Free up the old saved grid. */ tmp_saved_grid.main_width = 0; tmp_saved_grid.main_height = 0; tmp_saved_grid.the_grid = state->top_state->old_grid; state->top_state->old_grid = NULL; lo_FreeDocumentGridData(context, &tmp_saved_grid); } /* * Go through all the cells creating them where specified. */ cell_ptr = grid->cell_list; while (cell_ptr != NULL) { /* * Have the front end create the grid cell. */ if (cell_ptr->url != NULL) { void *history; void *hist_list; history = NULL; hist_list = NULL; if (cell_ptr->hist_list != NULL) { hist_list = cell_ptr->hist_list; cell_ptr->hist_indx = grid->current_hist; history = cell_ptr->hist_array[cell_ptr->hist_indx - 1].hist; if (history == NULL) { hist_list = NULL; } } reconnecting_cell = cell_ptr; cell_ptr->context = FE_MakeGridWindow (context, hist_list, history, cell_ptr->x, cell_ptr->y, cell_ptr->width, cell_ptr->height, (char *)cell_ptr->url, (char *)cell_ptr->name, cell_ptr->scrolling, FORCE_RELOAD_FLAG(state->top_state), cell_ptr->no_edges); reconnecting_cell = NULL; if (cell_ptr->context) { XP_ASSERT(cell_ptr->context->forceJSEnabled == context->forceJSEnabled); if (history) { cell_ptr->context->hist.cur_doc_ptr = history; } } } else { cell_ptr->context = NULL; } cell_ptr = cell_ptr->next; } } void lo_BeginGrid(MWContext *context, lo_DocState *state, PA_Tag *tag) { PA_Block buff; char *str; int32 rows, cols; lo_GridPercent *row_percents; lo_GridPercent *col_percents; lo_GridRec *grid; rows = 1; cols = 1; grid = XP_NEW(lo_GridRec); if (grid == NULL) { state->top_state->out_of_memory = TRUE; return; } grid->no_edges = FALSE; grid->edge_size = -1; grid->color_priority = 0; grid->border_color = NULL; grid->edge_list = NULL; grid->cell_list = NULL; grid->cell_list_last = NULL; grid->subgrid = NULL; buff = lo_FetchParamValue(context, tag, PARAM_FRAMEBORDER); if (buff != NULL) { Bool no_edges; no_edges = FALSE; PA_LOCK(str, char *, buff); if (pa_TagEqual("no", str)) { no_edges = TRUE; } else if (pa_TagEqual("0", str)) { no_edges = TRUE; } PA_UNLOCK(buff); PA_FREE(buff); grid->no_edges = no_edges; } buff = lo_FetchParamValue(context, tag, PARAM_BORDER); if (buff != NULL) { int32 border; PA_LOCK(str, char *, buff); border = XP_ATOI(str); PA_UNLOCK(buff); PA_FREE(buff); if (border < 0) { border = 0; } if (border > 100) { border = 100; } grid->edge_size = (int16)border; } /* * A borderwidth of zero automatically turns off edges. */ if (grid->edge_size == 0) { grid->no_edges = TRUE; } /* * Check for a border color attribute */ buff = lo_FetchParamValue(context, tag, PARAM_BORDERCOLOR); if (buff != NULL) { uint8 red, green, blue; PA_LOCK(str, char *, buff); LO_ParseRGB(str, &red, &green, &blue); PA_UNLOCK(buff); PA_FREE(buff); grid->border_color = XP_NEW(LO_Color); if (grid->border_color != NULL) { grid->border_color->red = red; grid->border_color->green = green; grid->border_color->blue = blue; grid->color_priority = 1; } } buff = lo_FetchParamValue(context, tag, PARAM_ROWS); if (buff != NULL) { int32 len; PA_LOCK(str, char *, buff); len = lo_StripTextWhitespace(str, XP_STRLEN(str)); row_percents = lo_parse_percent_list(context, str, &rows); if ((row_percents == NULL)&&(rows >= 1)) { PA_UNLOCK(buff); PA_FREE(buff); XP_DELETE(grid); state->top_state->out_of_memory = TRUE; return; } PA_UNLOCK(buff); PA_FREE(buff); if (rows <= 0) { row_percents = (lo_GridPercent *) XP_ALLOC(sizeof(lo_GridPercent)); if (row_percents == NULL) { XP_DELETE(grid); state->top_state->out_of_memory = TRUE; return; } row_percents[0].type = LO_PERCENT_NORMAL; row_percents[0].original_value = 100; rows = 1; } } else { row_percents = (lo_GridPercent *) XP_ALLOC(sizeof(lo_GridPercent)); if (row_percents == NULL) { XP_DELETE(grid); state->top_state->out_of_memory = TRUE; return; } row_percents[0].type = LO_PERCENT_NORMAL; row_percents[0].original_value = 100; rows = 1; } buff = lo_FetchParamValue(context, tag, PARAM_COLS); if (buff != NULL) { int32 len; PA_LOCK(str, char *, buff); len = lo_StripTextWhitespace(str, XP_STRLEN(str)); col_percents = lo_parse_percent_list(context, str, &cols); if ((col_percents == NULL)&&(cols >= 1)) { PA_UNLOCK(buff); PA_FREE(buff); if (row_percents != NULL) { XP_FREE(row_percents); } XP_DELETE(grid); state->top_state->out_of_memory = TRUE; return; } PA_UNLOCK(buff); PA_FREE(buff); if (cols <= 0) { col_percents = (lo_GridPercent *) XP_ALLOC(sizeof(lo_GridPercent)); if (col_percents == NULL) { if (row_percents != NULL) { XP_FREE(row_percents); } XP_DELETE(grid); state->top_state->out_of_memory = TRUE; return; } col_percents[0].type = LO_PERCENT_NORMAL; col_percents[0].original_value = 100; cols = 1; } } else { col_percents = (lo_GridPercent *) XP_ALLOC(sizeof(lo_GridPercent)); if (col_percents == NULL) { if (row_percents != NULL) { XP_FREE(row_percents); } XP_DELETE(grid); state->top_state->out_of_memory = TRUE; return; } col_percents[0].type = LO_PERCENT_NORMAL; col_percents[0].original_value = 100; cols = 1; } if ((rows == 1)&&(cols == 1)) { if (row_percents != NULL) { XP_FREE(row_percents); } if (col_percents != NULL) { XP_FREE(col_percents); } XP_DELETE(grid); return; } (void)lo_ProcessContextEventHandlers(context, state, tag); grid->rows = rows; grid->row_percents = row_percents; grid->cols = cols; grid->col_percents = col_percents; grid->cell_count = 0; grid->current_hist = 0; grid->max_hist = 0; grid->hist_size = 10; grid->main_width = state->win_width; grid->main_height = state->win_height; grid->current_cell_margin_width = 0; grid->current_cell_margin_height = 0; state->current_grid = grid; } void lo_EndGrid(MWContext *context, lo_DocState *state, lo_GridRec *grid) { int32 cell_cnt; if (grid == NULL) { return; } cell_cnt = grid->rows * grid->cols; state->top_state->the_grid = grid; lo_MakeGrid(context, state, grid); } static Bool lo_is_grid_recursion(MWContext *context, lo_DocState *state, char *url) { MWContext *cptr; /* * If this cell has its parent's URL, it is recursion. */ if ((state->top_state->url != NULL)&& (XP_STRCMP(url, state->top_state->url) == 0)) { return(TRUE); } cptr = context->grid_parent; while (cptr != NULL) { int32 doc_id; lo_TopState *top_state; char *anc_url; /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(cptr); top_state = lo_FetchTopState(doc_id); /* * We have to get the ancenstor URL from the state because * context->url doesn't seem to be reliable. */ if (top_state == NULL) { anc_url = NULL; } else { anc_url = top_state->url; } /* * if this cell has the same URL as any of its ancestors * this is recursion. */ if ((anc_url != NULL)&&(XP_STRCMP(url, anc_url) == 0)) { return(TRUE); } cptr = cptr->grid_parent; } return(FALSE); } void lo_BeginGridCell(MWContext *context, lo_DocState *state, PA_Tag *tag) { PA_Block buff; char *str; lo_GridRec *grid; int32 col_cnt, row_cnt; lo_GridCellRec *cell; /* * Get the current grid, if there is none, error out. */ grid = state->current_grid; if (grid == NULL) { return; } /* * If we have subgrids, the deepest one is at the TOP of the * subgrid stack. */ if (grid->subgrid != NULL) { grid = grid->subgrid; } /* * If this grid has its full complement of cells, ignore * this cell. */ if (grid->cell_count >= (grid->rows * grid->cols)) { return; } cell = XP_NEW(lo_GridCellRec); if (cell == NULL) { state->top_state->out_of_memory = TRUE; return; } row_cnt = grid->cell_count / grid->cols; col_cnt = grid->cell_count - (row_cnt * grid->cols); cell->x = 0; cell->y = 0; cell->width = 0; cell->height = 0; cell->margin_width = 0; cell->margin_height = 0; cell->width_percent = 0; cell->height_percent = 0; cell->url = NULL; cell->name = NULL; cell->context = NULL; cell->hist_list = NULL; cell->hist_array = (lo_GridHistory *)XP_ALLOC(grid->hist_size * sizeof(lo_GridHistory)); if (cell->hist_array == NULL) { XP_DELETE(cell); state->top_state->out_of_memory = TRUE; return; } XP_MEMSET(cell->hist_array, 0, grid->hist_size * sizeof(lo_GridHistory)); cell->hist_indx = 0; cell->next = NULL; cell->subgrid = NULL; cell->side_edges[TOP_EDGE] = NULL; cell->side_edges[BOTTOM_EDGE] = NULL; cell->side_edges[LEFT_EDGE] = NULL; cell->side_edges[RIGHT_EDGE] = NULL; cell->scrolling = LO_SCROLL_AUTO; cell->no_edges = grid->no_edges; cell->resizable = TRUE; cell->edge_size = -1; cell->color_priority = 0; cell->border_color = NULL; buff = lo_FetchParamValue(context, tag, PARAM_FRAMEBORDER); if (buff != NULL) { Bool no_edges; no_edges = FALSE; PA_LOCK(str, char *, buff); if (pa_TagEqual("no", str)) { no_edges = TRUE; } else if (pa_TagEqual("0", str)) { no_edges = TRUE; } PA_UNLOCK(buff); PA_FREE(buff); cell->no_edges = no_edges; } buff = lo_FetchParamValue(context, tag, PARAM_BORDER); if (buff != NULL) { int32 border; PA_LOCK(str, char *, buff); border = XP_ATOI(str); PA_UNLOCK(buff); PA_FREE(buff); if (border < 0) { border = 0; } if (border > 100) { border = 100; } cell->edge_size = (int16)border; } /* * A borderwidth of zero automatically turns off edges. */ if (cell->edge_size == 0) { cell->no_edges = TRUE; } /* * Check for a border color attribute */ buff = lo_FetchParamValue(context, tag, PARAM_BORDERCOLOR); if (buff != NULL) { uint8 red, green, blue; PA_LOCK(str, char *, buff); LO_ParseRGB(str, &red, &green, &blue); PA_UNLOCK(buff); PA_FREE(buff); cell->border_color = XP_NEW(LO_Color); if (cell->border_color != NULL) { cell->border_color->red = red; cell->border_color->green = green; cell->border_color->blue = blue; cell->color_priority = 3; } } /* * Else we might inherit a border color from parent. */ else if (grid->border_color != NULL) { cell->border_color = XP_NEW(LO_Color); if (cell->border_color != NULL) { cell->border_color->red = grid->border_color->red; cell->border_color->green = grid->border_color->green; cell->border_color->blue = grid->border_color->blue; cell->color_priority = grid->color_priority; } } buff = lo_FetchParamValue(context, tag, PARAM_NORESIZE); if (buff != NULL) { PA_FREE(buff); cell->resizable = FALSE; } buff = lo_FetchParamValue(context, tag, PARAM_SCROLLING); if (buff != NULL) { int8 scrolling; scrolling = LO_SCROLL_AUTO; PA_LOCK(str, char *, buff); if (pa_TagEqual("yes", str)) { scrolling = LO_SCROLL_YES; } else if (pa_TagEqual("scroll", str)) { scrolling = LO_SCROLL_YES; } else if (pa_TagEqual("no", str)) { scrolling = LO_SCROLL_NO; } else if (pa_TagEqual("noscroll", str)) { scrolling = LO_SCROLL_NO; } else if (pa_TagEqual("on", str)) { scrolling = LO_SCROLL_YES; } else if (pa_TagEqual("off", str)) { scrolling = LO_SCROLL_NO; } PA_UNLOCK(buff); PA_FREE(buff); cell->scrolling = scrolling; } buff = lo_FetchParamValue(context, tag, PARAM_SRC); if (buff != NULL) { char *new_str; PA_LOCK(str, char *, buff); if (str != NULL) { int32 len; len = lo_StripTextWhitespace(str, XP_STRLEN(str)); } new_str = NET_MakeAbsoluteURL(state->top_state->base_url, str); PA_UNLOCK(buff); PA_FREE(buff); cell->url = new_str; /* * Don't allow cells to have the same URL as their parent * or any of their ancestors as that would cause infinite * recursion. */ if (lo_is_grid_recursion(context, state, cell->url) != FALSE) { XP_FREE(new_str); cell->url = NULL; } } else { cell->url = NULL; } buff = lo_FetchParamValue(context, tag, PARAM_NAME); if (buff != NULL) { char *name; PA_LOCK(str, char *, buff); if (str != NULL) { int32 len; len = lo_StripTextWhitespace(str, XP_STRLEN(str)); } name = (char *)XP_ALLOC(XP_STRLEN(str) + 1); if (name == NULL) { cell->name = NULL; } else { XP_STRCPY(name, str); cell->name = name; } PA_UNLOCK(buff); PA_FREE(buff); } else { cell->name = NULL; } /* * Get the margin width. */ buff = lo_FetchParamValue(context, tag, PARAM_MARGINWIDTH); if (buff != NULL) { int32 val; PA_LOCK(str, char *, buff); val = XP_ATOI(str); if (val < 1) { val = 1; } cell->margin_width = val; PA_UNLOCK(buff); PA_FREE(buff); } cell->margin_width = FEUNITS_X(cell->margin_width, context); /* * Get the margin height. */ buff = lo_FetchParamValue(context, tag, PARAM_MARGINHEIGHT); if (buff != NULL) { int32 val; PA_LOCK(str, char *, buff); val = XP_ATOI(str); if (val < 1) { val = 1; } cell->margin_height = val; PA_UNLOCK(buff); PA_FREE(buff); } cell->margin_height = FEUNITS_Y(cell->margin_height, context); grid->cell_count++; if (grid->cell_list_last == NULL) { grid->cell_list = cell; grid->cell_list_last = cell; } else { grid->cell_list_last->next = cell; grid->cell_list_last = cell; } } void lo_BeginSubgrid(MWContext *context, lo_DocState *state, PA_Tag *tag) { PA_Block buff; char *str; lo_GridRec *grid; int32 col_cnt, row_cnt; lo_GridRec *subgrid; int32 rows, cols; lo_GridPercent *row_percents; lo_GridPercent *col_percents; lo_GridCellRec *cell; /* * Get the current grid, if there is none, error out. */ grid = state->current_grid; if (grid == NULL) { return; } /* * If we have subgrids, the deepest one is at the TOP of the * subgrid stack. */ if (grid->subgrid != NULL) { grid = grid->subgrid; } /* * If this grid has its full complement of cells, ignore * this subgrid cell. */ if (grid->cell_count >= (grid->rows * grid->cols)) { return; } /* ******************************** * Create and parse the subgrid * ******************************** */ rows = 1; cols = 1; subgrid = XP_NEW(lo_GridRec); if (subgrid == NULL) { state->top_state->out_of_memory = TRUE; return; } subgrid->no_edges = grid->no_edges; subgrid->edge_size = grid->edge_size; subgrid->color_priority = 0; subgrid->border_color = NULL; subgrid->edge_list = NULL; subgrid->cell_list = NULL; subgrid->cell_list_last = NULL; subgrid->subgrid = NULL; /* * Check for a border color attribute */ buff = lo_FetchParamValue(context, tag, PARAM_BORDERCOLOR); if (buff != NULL) { uint8 red, green, blue; PA_LOCK(str, char *, buff); LO_ParseRGB(str, &red, &green, &blue); PA_UNLOCK(buff); PA_FREE(buff); subgrid->border_color = XP_NEW(LO_Color); if (subgrid->border_color != NULL) { subgrid->border_color->red = red; subgrid->border_color->green = green; subgrid->border_color->blue = blue; subgrid->color_priority = 2; } } /* * Else we might inherit a border color from parent. */ else if (grid->border_color != NULL) { subgrid->border_color = XP_NEW(LO_Color); if (subgrid->border_color != NULL) { subgrid->border_color->red = grid->border_color->red; subgrid->border_color->green = grid->border_color->green; subgrid->border_color->blue = grid->border_color->blue; subgrid->color_priority = grid->color_priority; } } buff = lo_FetchParamValue(context, tag, PARAM_FRAMEBORDER); if (buff != NULL) { Bool no_edges; no_edges = FALSE; PA_LOCK(str, char *, buff); if (pa_TagEqual("no", str)) { no_edges = TRUE; } else if (pa_TagEqual("0", str)) { no_edges = TRUE; } PA_UNLOCK(buff); PA_FREE(buff); subgrid->no_edges = no_edges; } buff = lo_FetchParamValue(context, tag, PARAM_ROWS); if (buff != NULL) { int32 len; PA_LOCK(str, char *, buff); len = lo_StripTextWhitespace(str, XP_STRLEN(str)); row_percents = lo_parse_percent_list(context, str, &rows); if ((row_percents == NULL)&&(rows >= 1)) { PA_UNLOCK(buff); PA_FREE(buff); XP_DELETE(subgrid); state->top_state->out_of_memory = TRUE; return; } PA_UNLOCK(buff); PA_FREE(buff); if (rows <= 0) { row_percents = (lo_GridPercent *) XP_ALLOC(sizeof(lo_GridPercent)); if (row_percents == NULL) { XP_DELETE(subgrid); state->top_state->out_of_memory = TRUE; return; } row_percents[0].type = LO_PERCENT_NORMAL; row_percents[0].original_value = 100; rows = 1; } } else { row_percents = (lo_GridPercent *) XP_ALLOC(sizeof(lo_GridPercent)); if (row_percents == NULL) { XP_DELETE(subgrid); state->top_state->out_of_memory = TRUE; return; } row_percents[0].type = LO_PERCENT_NORMAL; row_percents[0].original_value = 100; rows = 1; } buff = lo_FetchParamValue(context, tag, PARAM_COLS); if (buff != NULL) { int32 len; PA_LOCK(str, char *, buff); len = lo_StripTextWhitespace(str, XP_STRLEN(str)); col_percents = lo_parse_percent_list(context, str, &cols); if ((col_percents == NULL)&&(cols >= 1)) { PA_UNLOCK(buff); PA_FREE(buff); if (row_percents != NULL) { XP_FREE(row_percents); } XP_DELETE(subgrid); state->top_state->out_of_memory = TRUE; return; } PA_UNLOCK(buff); PA_FREE(buff); if (cols <= 0) { col_percents = (lo_GridPercent *) XP_ALLOC(sizeof(lo_GridPercent)); if (col_percents == NULL) { if (row_percents != NULL) { XP_FREE(row_percents); } XP_DELETE(subgrid); state->top_state->out_of_memory = TRUE; return; } col_percents[0].type = LO_PERCENT_NORMAL; col_percents[0].original_value = 100; cols = 1; } } else { col_percents = (lo_GridPercent *) XP_ALLOC(sizeof(lo_GridPercent)); if (col_percents == NULL) { if (row_percents != NULL) { XP_FREE(row_percents); } XP_DELETE(subgrid); state->top_state->out_of_memory = TRUE; return; } col_percents[0].type = LO_PERCENT_NORMAL; col_percents[0].original_value = 100; cols = 1; } if ((rows == 1)&&(cols == 1)) { if (row_percents != NULL) { XP_FREE(row_percents); } if (col_percents != NULL) { XP_FREE(col_percents); } XP_DELETE(subgrid); return; } (void)lo_ProcessContextEventHandlers(context, state, tag); subgrid->rows = rows; subgrid->row_percents = row_percents; subgrid->cols = cols; subgrid->col_percents = col_percents; subgrid->cell_count = 0; subgrid->current_hist = 0; subgrid->max_hist = 0; subgrid->hist_size = 10; subgrid->main_width = state->win_width; subgrid->main_height = state->win_height; subgrid->current_cell_margin_width = 0; subgrid->current_cell_margin_height = 0; subgrid->subgrid = state->current_grid->subgrid; state->current_grid->subgrid = subgrid; /* ****************************************** * Subgrid parsing done. * * Create a dummy cell to hang it off of. * ****************************************** */ cell = XP_NEW(lo_GridCellRec); if (cell == NULL) { state->top_state->out_of_memory = TRUE; return; } row_cnt = grid->cell_count / grid->cols; col_cnt = grid->cell_count - (row_cnt * grid->cols); cell->x = 0; cell->y = 0; cell->width = 0; cell->height = 0; cell->margin_width = 0; cell->margin_height = 0; cell->width_percent = 0; cell->height_percent = 0; cell->url = NULL; cell->name = NULL; cell->context = NULL; cell->hist_list = NULL; cell->hist_array = (lo_GridHistory *)XP_ALLOC(grid->hist_size * sizeof(lo_GridHistory)); if (cell->hist_array == NULL) { XP_DELETE(cell); state->top_state->out_of_memory = TRUE; return; } XP_MEMSET(cell->hist_array, 0, grid->hist_size * sizeof(lo_GridHistory)); cell->hist_indx = 0; cell->next = NULL; cell->subgrid = subgrid; cell->side_edges[TOP_EDGE] = NULL; cell->side_edges[BOTTOM_EDGE] = NULL; cell->side_edges[LEFT_EDGE] = NULL; cell->side_edges[RIGHT_EDGE] = NULL; cell->scrolling = LO_SCROLL_AUTO; cell->no_edges = subgrid->no_edges; cell->resizable = TRUE; cell->edge_size = -1; cell->color_priority = 0; cell->border_color = NULL; grid->cell_count++; if (grid->cell_list_last == NULL) { grid->cell_list = cell; grid->cell_list_last = cell; } else { grid->cell_list_last->next = cell; grid->cell_list_last = cell; } } void lo_EndSubgrid(MWContext *context, lo_DocState *state, lo_GridRec *grid) { lo_GridRec *subgrid; if ((grid == NULL)||(grid->subgrid == NULL)) { return; } subgrid = grid->subgrid; grid->subgrid = grid->subgrid->subgrid; subgrid->subgrid = NULL; } #ifdef DEBUG_EDGES static void lo_print_edge_info(lo_GridEdge *edge) { int32 i; fprintf(stderr, "\nEdge %ld,%ld %ldx%ld; Range is %ld to %ld\n", (long) edge->x, (long) edge->y, (long) edge->width, (long) edge->height, (long) edge->left_top_bound, (long) edge->right_bottom_bound); fprintf(stderr, "\tBounds %ld cells\n", (long) edge->cell_cnt); for (i=0; i < edge->cell_cnt; i++) { lo_GridCellRec *cell; cell = edge->cell_array[i]; fprintf(stderr, "\t(%ld) %ld,%ld %ldx%ld\n", (long) i, (long) cell->x, (long) cell->y, (long) cell->width, (long) cell->height); } fprintf(stderr, "\n"); } #endif /* DEBUG_EDGES */ LO_Element * lo_XYToGridEdge(MWContext *context, lo_DocState *state, int32 x, int32 y) { lo_GridRec *grid; lo_GridEdge *edge_list; if ((state->top_state->is_grid == FALSE)|| (state->top_state->the_grid == NULL)) { return(NULL); } grid = state->top_state->the_grid; edge_list = grid->edge_list; while (edge_list != NULL) { /* * You cannot grab invisible edges. */ if (edge_list->fe_edge->visible == FALSE) { edge_list = edge_list->next; continue; } if (edge_list->is_vertical == FALSE) { if ((y >= edge_list->y)&& (y < (edge_list->y + edge_list->height))&& (x >= edge_list->x)&& (x < (edge_list->x + edge_list->width))) { break; } } else { if ((x >= edge_list->x)&& (x < (edge_list->x + edge_list->width))&& (y >= edge_list->y)&& (y < (edge_list->y + edge_list->height))) { break; } } edge_list = edge_list->next; } if (edge_list != NULL) { #ifdef DEBUG_EDGES lo_print_edge_info(edge_list); #endif /* DEBUG_EDGES */ return((LO_Element *)edge_list->fe_edge); } else { return(NULL); } } /* * Edges left of a moved vertical edge may need to be shrunk * or grown with the edge. */ static void lo_change_left_edges(MWContext *context, lo_GridEdge *edge, int32 bound, int32 diff, Bool call_display_edge) { if (edge != NULL) { /* * If this edge abuts the edge moved, * change this edges width just like * the cell. */ if ((edge->x + edge->width) == bound) { edge->width += diff; edge->fe_edge->width += diff; if (call_display_edge) /* * Display the edge that was just changed. */ lo_DisplayEdge(context, edge->fe_edge); } } } /* * Edges right of a moved vertical edge may need to be moved and shrunk * or grown with the edge. */ static void lo_change_right_edges(MWContext *context, lo_GridEdge *edge, int32 bound, int32 diff, Bool call_display_edge) { if (edge != NULL) { /* * If this edge abuts the edge moved, * change this edges position and width just like * the cell. */ if ((edge->x - 1) == bound) { edge->x += diff; edge->width -= diff; edge->fe_edge->x += diff; edge->fe_edge->width -= diff; if (call_display_edge) /* * Display the edge that was just changed. */ lo_DisplayEdge(context, edge->fe_edge); } } } /* * Edges above a moved vertical edge may need to be shrunk * or grown with the edge. */ static void lo_change_top_edges(MWContext *context, lo_GridEdge *edge, int32 bound, int32 diff, Bool call_display_edge) { if (edge != NULL) { /* * If this edge abuts the edge moved, * change this edges width just like * the cell. */ if ((edge->y + edge->height) == bound) { edge->height += diff; edge->fe_edge->height += diff; if (call_display_edge) /* * Display the edge that was just changed. */ lo_DisplayEdge(context, edge->fe_edge); } } } /* * Edges below a moved horizontal edge may need to be moved and shrunk * or grown with the edge. */ static void lo_change_bottom_edges(MWContext *context, lo_GridEdge *edge, int32 bound, int32 diff, Bool call_display_edge) { if (edge != NULL) { /* * If this edge abuts the edge moved, * change this edges position and width just like * the cell. */ if ((edge->y - 1) == bound) { edge->y += diff; edge->height -= diff; edge->fe_edge->y += diff; edge->fe_edge->height -= diff; if (call_display_edge) /* * Display the edge that was just changed. */ lo_DisplayEdge(context, edge->fe_edge); } } } void LO_MoveGridEdge(MWContext *context, LO_EdgeStruct *fe_edge, int32 x, int32 y) { int32 doc_id; lo_TopState *top_state; lo_DocState *state; int32 i; lo_GridEdge *edge; /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(context); top_state = lo_FetchTopState(doc_id); if ((top_state == NULL)||(top_state->doc_state == NULL)) { return; } state = top_state->doc_state; edge = (lo_GridEdge *)fe_edge->lo_edge_info; if (edge == NULL) { return; } /* * For horizontal edges */ if (edge->is_vertical == FALSE) { int32 diff; diff = y - edge->y; for (i=0; i < edge->cell_cnt; i++) { lo_GridCellRec *cell; cell = edge->cell_array[i]; if (cell == NULL) { continue; } /* * If the cell is above the edge. * Grow the cell and any abutting * edges. */ if (cell->y < edge->y) { cell->height += diff; lo_change_top_edges(context, cell->side_edges[LEFT_EDGE], edge->y, diff, TRUE); lo_change_top_edges(context, cell->side_edges[RIGHT_EDGE], edge->y, diff, TRUE); /* * The bounds of this edge are effected */ lo_set_edge_bounds(cell->side_edges[TOP_EDGE]); } /* * Else the cell is below the edge. * Move and shrink the cell and any abutting * edges. */ else { cell->y += diff; cell->height -= diff; lo_change_bottom_edges(context, cell->side_edges[LEFT_EDGE], (edge->y + edge->height - 1), diff, TRUE); lo_change_bottom_edges(context, cell->side_edges[RIGHT_EDGE], (edge->y + edge->height - 1), diff, TRUE); /* * The bounds of this edge are effected */ lo_set_edge_bounds(cell->side_edges[BOTTOM_EDGE]); } /* * Only restructure cells that have windows(contexts) */ if (cell->context != NULL) { FE_RestructureGridWindow (cell->context, cell->x, cell->y, cell->width, cell->height); } } edge->y = y; edge->fe_edge->y = y; } /* * Else for vertical edges. */ else { int32 diff; diff = x - edge->x; for (i=0; i < edge->cell_cnt; i++) { lo_GridCellRec *cell; cell = edge->cell_array[i]; if (cell == NULL) { continue; } /* * If the cell is left of the edge. * Grow the cell and any abutting * edges. */ if (cell->x < edge->x) { cell->width += diff; lo_change_left_edges(context, cell->side_edges[TOP_EDGE], edge->x, diff, TRUE); lo_change_left_edges(context, cell->side_edges[BOTTOM_EDGE], edge->x, diff, TRUE); /* * The bounds of this edge are effected */ lo_set_edge_bounds(cell->side_edges[LEFT_EDGE]); } /* * Else the cell is right of the edge. * Move and shrink the cell and any abutting * edges. */ else { cell->x += diff; cell->width -= diff; lo_change_right_edges(context, cell->side_edges[TOP_EDGE], (edge->x + edge->width - 1), diff, TRUE); lo_change_right_edges(context, cell->side_edges[BOTTOM_EDGE], (edge->x + edge->width - 1), diff, TRUE); /* * The bounds of this edge are effected */ lo_set_edge_bounds(cell->side_edges[RIGHT_EDGE]); } /* * Only restructure cells that have windows(contexts) */ if (cell->context != NULL) { FE_RestructureGridWindow (cell->context, cell->x, cell->y, cell->width, cell->height); } } edge->x = x; edge->fe_edge->x = x; } /* * Display the edge that was just moved. */ lo_DisplayEdge(context, edge->fe_edge); } intn lo_GetCurrentGridCellStatus(lo_GridCellRec *cell) { int32 doc_id; lo_TopState *top_state; /* * This is a blank cell, always considered complete. */ if ((cell == NULL)||(cell->context == NULL)) { return(PA_COMPLETE); } /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(cell->context); top_state = lo_FetchTopState(doc_id); if (top_state == NULL) { return(-1); } return(top_state->layout_status); } char * lo_GetCurrentGridCellUrl(lo_GridCellRec *cell) { int32 doc_id; lo_TopState *top_state; char *url; if ((cell == NULL)||(cell->context == NULL)) { return(NULL); } /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(cell->context); top_state = lo_FetchTopState(doc_id); if (top_state == NULL) { return(NULL); } if (top_state->url == NULL) { url = NULL; } else { url = XP_STRDUP(top_state->url); } return(url); } void lo_GetGridCellMargins(MWContext *context, int32 *margin_width, int32 *margin_height) { int32 doc_id; lo_TopState *top_state; MWContext *parent; lo_GridCellRec *cell_ptr; if ((context == NULL)||(context->grid_parent == NULL)) { return; } parent = context->grid_parent; /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(parent); top_state = lo_FetchTopState(doc_id); if ((top_state == NULL)||(top_state->the_grid == NULL)) { return; } /* * Find the cell whose context matches the passed in context. */ cell_ptr = top_state->the_grid->cell_list; while (cell_ptr != NULL) { if (cell_ptr->context == context) { break; } cell_ptr = cell_ptr->next; } /* * If we found the cell, set our margins. */ if (cell_ptr != NULL) { *margin_width = cell_ptr->margin_width; *margin_height = cell_ptr->margin_height; } /* * If we didn't find the cell, it is * in the middle of creation, get the * margins from the parent grid. */ else { *margin_width = top_state->the_grid->current_cell_margin_width; *margin_height = top_state->the_grid->current_cell_margin_height; } } static void lo_reset_all_edge_bounds(MWContext *context, lo_DocState *state, lo_GridRec *grid) { lo_GridEdge *edge_list; if ((grid == NULL)||(grid->edge_list == NULL)) { return; } edge_list = grid->edge_list; while (edge_list != NULL) { LO_EdgeStruct *fe_edge; fe_edge = (LO_EdgeStruct *)lo_NewElement(context, state, LO_EDGE, NULL, 0); if (fe_edge == NULL) { } fe_edge->type = LO_EDGE; fe_edge->ele_id = NEXT_ELEMENT; fe_edge->x = edge_list->x; fe_edge->x_offset = 0; fe_edge->y = edge_list->y; fe_edge->y_offset = 0; fe_edge->width = edge_list->width; fe_edge->height = edge_list->height; fe_edge->line_height = 0; fe_edge->next = NULL; fe_edge->prev = NULL; fe_edge->FE_Data = NULL; fe_edge->lo_edge_info = (void *)edge_list; fe_edge->is_vertical = edge_list->is_vertical; fe_edge->movable = TRUE; fe_edge->left_top_bound = 0; fe_edge->right_bottom_bound = 0; edge_list->fe_edge = fe_edge; lo_set_edge_bounds(edge_list); /* * Insert this edge into the float list. */ edge_list->fe_edge->next = state->float_list; state->float_list = (LO_Element *)edge_list->fe_edge; lo_DisplayEdge(context, edge_list->fe_edge); edge_list = edge_list->next; } } void lo_RecreateGrid(MWContext *context, lo_DocState *state, lo_GridRec *grid) { lo_GridCellRec *cell_ptr; int32 width, height; width = state->win_width; height = state->win_height; FE_GetFullWindowSize(context, &width, &height); if (width <= 0) width = 1; if (height <= 0) height = 1; /* already set. grid->main_width = width; grid->main_height = height; */ lo_reset_all_edge_bounds(context, state, grid); state->top_state->the_grid = grid; /* * Go through all the cells creating them where specified. */ cell_ptr = grid->cell_list; while (cell_ptr != NULL) { /* * Have the front end create the grid cell. */ if (cell_ptr->url != NULL) { void *history; void *hist_list; history = NULL; hist_list = NULL; if (cell_ptr->hist_list != NULL) { hist_list = cell_ptr->hist_list; cell_ptr->hist_indx = grid->current_hist; history = cell_ptr->hist_array[cell_ptr->hist_indx - 1].hist; if (history == NULL) { hist_list = NULL; } } grid->current_cell_margin_width = cell_ptr->margin_width; grid->current_cell_margin_height = cell_ptr->margin_height; reconnecting_cell = cell_ptr; cell_ptr->context = FE_MakeGridWindow (context, hist_list, history, cell_ptr->x, cell_ptr->y, cell_ptr->width, cell_ptr->height, (char *)cell_ptr->url, (char *)cell_ptr->name, cell_ptr->scrolling, FORCE_RELOAD_FLAG(state->top_state), cell_ptr->no_edges); reconnecting_cell = NULL; grid->current_cell_margin_width = 0; grid->current_cell_margin_height = 0; if (cell_ptr->context) { XP_ASSERT(cell_ptr->context->forceJSEnabled == context->forceJSEnabled); if (history) { cell_ptr->context->hist.cur_doc_ptr = history; } } } else { cell_ptr->context = NULL; } cell_ptr = cell_ptr->next; } } lo_GridCellRec * lo_ContextToCell(MWContext *context, Bool reconnect, lo_GridRec **grid_ptr) { int32 doc_id; lo_TopState *top_state; MWContext *parent; lo_GridCellRec *cell_ptr; *grid_ptr = NULL; if ((context == NULL)||(context->grid_parent == NULL)) { return((lo_GridCellRec *)NULL); } parent = context->grid_parent; /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(parent); top_state = lo_FetchTopState(doc_id); if ((top_state == NULL)||(top_state->the_grid == NULL)) { return((lo_GridCellRec *)NULL); } *grid_ptr = top_state->the_grid; /* * Find the cell whose context matches the passed in context. */ cell_ptr = top_state->the_grid->cell_list; while (cell_ptr != NULL) { if (cell_ptr->context == context) { return(cell_ptr); } cell_ptr = cell_ptr->next; } if (reconnect && (cell_ptr = reconnecting_cell) != NULL) { cell_ptr->context = context; if (context->grid_parent) { context->forceJSEnabled = context->grid_parent->forceJSEnabled; } return(cell_ptr); } return(NULL); } static void lo_set_hist(MWContext *context, void **hep, History_entry *hist) { History_entry *oldhist = *hep; if (oldhist == hist) return; *hep = SHIST_HoldEntry(hist); SHIST_DropEntry(context, oldhist); } PRIVATE void lo_UpdateOtherCells(lo_GridRec *grid, lo_GridCellRec *the_cell) { lo_GridCellRec *cell_ptr; cell_ptr = grid->cell_list; while (cell_ptr != NULL) { if ((cell_ptr != the_cell)&& (cell_ptr->hist_indx < grid->current_hist)) { int32 i; int32 old; /* * Make sure se don't go backwards off the beginning * of the array. */ old = cell_ptr->hist_indx - 1; if (old < 0) { old = 0; } for (i = cell_ptr->hist_indx; i < grid->current_hist; i++) { lo_set_hist(cell_ptr->context, &cell_ptr->hist_array[i].hist, cell_ptr->hist_array[old].hist); cell_ptr->hist_array[i].position = cell_ptr->hist_array[old].position; } /* * If we got here and hist_indx is zero, that means * we are trying to update this cell, before it ever * had its initializing load. In that case, we * want to leave hist_indx zero so we will be able to * detect that initializing load when it occurs. */ if (cell_ptr->hist_indx > 0) { cell_ptr->hist_indx = grid->current_hist; } } cell_ptr = cell_ptr->next; } } static void lo_grow_grid_hist_arrays(lo_GridRec *grid) { int32 new_size; lo_GridCellRec *cell_ptr; if (grid == NULL) { return; } new_size = grid->hist_size + 10; cell_ptr = grid->cell_list; while (cell_ptr != NULL) { lo_GridHistory *new_array; new_array = (lo_GridHistory *)XP_REALLOC(cell_ptr->hist_array, (new_size * sizeof(lo_GridHistory))); if (new_array == NULL) { /* XXX should set top_state->out_of_memory somehow */ return; } XP_MEMSET(new_array + grid->hist_size, 0, (10 * sizeof(lo_GridHistory))); cell_ptr->hist_array = new_array; cell_ptr = cell_ptr->next; } grid->hist_size = new_size; } void LO_UpdateGridHistory(MWContext *context) { lo_GridRec *grid; lo_GridCellRec *cell_ptr; History_entry *hist; cell_ptr = lo_ContextToCell(context, TRUE, &grid); if (cell_ptr == NULL) { return; } hist = SHIST_GetCurrent(&context->hist); if (hist == NULL) { return; } if (cell_ptr->hist_indx >= grid->current_hist) { if (grid->current_hist >= grid->hist_size) { lo_grow_grid_hist_arrays(grid); } grid->current_hist = cell_ptr->hist_indx + 1; if (grid->current_hist > grid->max_hist) { grid->max_hist = grid->current_hist; } else if (grid->current_hist < grid->max_hist) { grid->max_hist = grid->current_hist; } if (grid->current_hist > 1) { lo_UpdateOtherCells(grid, cell_ptr); if ((context->grid_parent != NULL)&& (context->grid_parent->is_grid_cell != FALSE)) { LO_UpdateGridHistory(context->grid_parent); } } } lo_set_hist(context, &cell_ptr->hist_array[cell_ptr->hist_indx].hist, hist); if (cell_ptr->hist_indx == 0) { cell_ptr->hist_array[cell_ptr->hist_indx].position = 1; /* * This means some other grid cell already progressed before * we got our first load, now that we are loaded, catch up. */ if (grid->current_hist > 1) { int32 i; for (i = 1; i < grid->current_hist; i++) { lo_set_hist(context, &cell_ptr->hist_array[i].hist, cell_ptr->hist_array[0].hist); cell_ptr->hist_array[i].position = cell_ptr->hist_array[0].position; } cell_ptr->hist_indx = grid->current_hist - 1; } } else { /* * Drop held MochaDecoder if any, we needed it only during * resize-reload and don't now that we've moved forward in * this frame context's history. */ hist = cell_ptr->hist_array[cell_ptr->hist_indx - 1].hist; if (hist && hist->savedData.Window) { LM_DropSavedWindow(context, hist->savedData.Window); hist->savedData.Window = NULL; } cell_ptr->hist_array[cell_ptr->hist_indx].position = cell_ptr->hist_array[cell_ptr->hist_indx - 1].position + 1; } cell_ptr->hist_indx++; } PRIVATE void lo_BackupGridHistory(lo_GridRec *grid) { lo_GridCellRec *cell_ptr; cell_ptr = grid->cell_list; while (cell_ptr != NULL) { if (cell_ptr->hist_indx > 1) { int32 indx; cell_ptr->hist_indx--; indx = cell_ptr->hist_indx - 1; if (cell_ptr->hist_array[indx].hist != cell_ptr->hist_array[cell_ptr->hist_indx].hist) { lo_reload_cell_from_history(cell_ptr, NET_DONT_RELOAD); } else if ((cell_ptr->hist_array[indx].position != cell_ptr->hist_array[cell_ptr->hist_indx].position)&& (cell_ptr->context != NULL)&& (cell_ptr->context->grid_children != NULL)) { (void)LO_BackInGrid(cell_ptr->context); } } cell_ptr = cell_ptr->next; } } PRIVATE void lo_ForwardGridHistory(lo_GridRec *grid) { lo_GridCellRec *cell_ptr; cell_ptr = grid->cell_list; while (cell_ptr != NULL) { if (cell_ptr->hist_indx < grid->max_hist) { int32 indx; cell_ptr->hist_indx++; indx = cell_ptr->hist_indx - 1; if (cell_ptr->hist_array[indx].hist != cell_ptr->hist_array[indx - 1].hist) { lo_reload_cell_from_history(cell_ptr, NET_DONT_RELOAD); } else if ((cell_ptr->hist_array[indx].position != cell_ptr->hist_array[indx - 1].position)&& (cell_ptr->context != NULL)&& (cell_ptr->context->grid_children != NULL)) { (void)LO_ForwardInGrid(cell_ptr->context); } } cell_ptr = cell_ptr->next; } } Bool LO_BackInGrid(MWContext *context) { int32 doc_id; lo_TopState *top_state; lo_GridRec *grid; if ((context == NULL)||(context->grid_children == NULL)) { return(FALSE); } /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(context); top_state = lo_FetchTopState(doc_id); if ((top_state == NULL)||(top_state->the_grid == NULL)) { return(FALSE); } grid = top_state->the_grid; if (grid->current_hist <= 1) { return(FALSE); } lo_BackupGridHistory(grid); grid->current_hist--; return(TRUE); } Bool LO_ForwardInGrid(MWContext *context) { int32 doc_id; lo_TopState *top_state; lo_GridRec *grid; if ((context == NULL)||(context->grid_children == NULL)) { return(FALSE); } /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(context); top_state = lo_FetchTopState(doc_id); if ((top_state == NULL)||(top_state->the_grid == NULL)) { return(FALSE); } grid = top_state->the_grid; if (grid->current_hist >= grid->max_hist) { return(FALSE); } lo_ForwardGridHistory(grid); grid->current_hist++; return(TRUE); } Bool LO_GridCanGoForward(MWContext *context) { int32 doc_id; lo_TopState *top_state; lo_GridRec *grid; if ((context == NULL)||(context->grid_children == NULL)) { return(FALSE); } /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(context); top_state = lo_FetchTopState(doc_id); if ((top_state == NULL)||(top_state->the_grid == NULL)) { return(FALSE); } grid = top_state->the_grid; if (grid->current_hist < grid->max_hist) { return(TRUE); } return(FALSE); } Bool LO_GridCanGoBackward(MWContext *context) { int32 doc_id; lo_TopState *top_state; lo_GridRec *grid; if ((context == NULL)||(context->grid_children == NULL)) { return(FALSE); } /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(context); top_state = lo_FetchTopState(doc_id); if ((top_state == NULL)||(top_state->the_grid == NULL)) { return(FALSE); } grid = top_state->the_grid; if (grid->current_hist > 1) { return(TRUE); } return(FALSE); } static void lo_cleanup_grid_history(MWContext *context, lo_GridRec *grid) { lo_GridCellRec *cell_ptr; if (grid == NULL) { return; } /* * Set the current history to be the new maximum. */ grid->max_hist = grid->current_hist; /* * Go through all the cells, truncating their history lists */ cell_ptr = grid->cell_list; while (cell_ptr != NULL) { int32 indx, count; XP_List *list_ptr; History_entry *cell_hist; list_ptr = (XP_List *)cell_ptr->hist_list; cell_hist = cell_ptr->hist_array[grid->current_hist - 1].hist; if ((list_ptr != NULL)&&(cell_hist != NULL)) { indx = XP_ListGetNumFromObject(list_ptr, cell_hist); for (count = XP_ListCount(list_ptr); count > indx; count--) { History_entry *old_entry; old_entry = (History_entry *)XP_ListRemoveEndObject(list_ptr); SHIST_DropEntry(context, old_entry); } } /* * If the last history entry in the cells chain * is itself a grid, it may need to be cleaned * up recursively. */ if (cell_hist != NULL) { lo_SavedGridData *saved_grid; saved_grid =(lo_SavedGridData *)(cell_hist->savedData.Grid); if ((saved_grid != NULL)&&(saved_grid->the_grid != NULL)) { lo_cleanup_grid_history(context, saved_grid->the_grid); } } cell_ptr = cell_ptr->next; } } /* * When we have just added a session history after * this one, clean up the grid's history chains if * it is the parent we just left. */ void LO_CleanupGridHistory(MWContext *context) { History_entry *hist; lo_SavedGridData *saved_grid; lo_GridRec *grid; /* * Look back one, if the is no back, return. */ hist = SHIST_GetPrevious(context); if (hist == NULL) { return; } /* * Is the document back one in history a valid grid, * if not, return. */ saved_grid = (lo_SavedGridData *)(hist->savedData.Grid); if ((saved_grid == NULL)||(saved_grid->the_grid == NULL)) { return; } /* * Since we are appending after this history stage, * the current history chains must be * clipped so this is the new max. */ grid = saved_grid->the_grid; lo_cleanup_grid_history(context, grid); } static void lo_MoveGridEdgeForRelayout(MWContext *context, LO_EdgeStruct *fe_edge, int32 x, int32 y) { int32 doc_id; lo_TopState *top_state; lo_DocState *state; int32 i; lo_GridEdge *edge; /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(context); top_state = lo_FetchTopState(doc_id); if ((top_state == NULL)||(top_state->doc_state == NULL)) { return; } state = top_state->doc_state; edge = (lo_GridEdge *)fe_edge->lo_edge_info; if (edge == NULL) { return; } /* * For horizontal edges */ if (edge->is_vertical == FALSE) { int32 diff; diff = y - edge->y; for (i=0; i < edge->cell_cnt; i++) { lo_GridCellRec *cell; cell = edge->cell_array[i]; if (cell == NULL) { continue; } /* * If the cell is above the edge. * Grow the cell and any abutting * edges. */ if (cell->y < edge->y) { #if 0 cell->height += diff; #endif lo_change_top_edges(context, cell->side_edges[LEFT_EDGE], edge->y, diff, FALSE); lo_change_top_edges(context, cell->side_edges[RIGHT_EDGE], edge->y, diff, FALSE); /* * The bounds of this edge are effected */ lo_set_edge_bounds(cell->side_edges[TOP_EDGE]); } /* * Else the cell is below the edge. * Move and shrink the cell and any abutting * edges. */ else { #if 0 cell->y += diff; cell->height -= diff; #endif lo_change_bottom_edges(context, cell->side_edges[LEFT_EDGE], (edge->y + edge->height - 1), diff, FALSE); lo_change_bottom_edges(context, cell->side_edges[RIGHT_EDGE], (edge->y + edge->height - 1), diff, FALSE); /* * The bounds of this edge are effected */ lo_set_edge_bounds(cell->side_edges[BOTTOM_EDGE]); } /* * Only restructure cells that have windows(contexts) */ if (cell->context != NULL) { cell->needs_restructuring = TRUE; } } edge->y = y; edge->fe_edge->y = y; } /* * Else for vertical edges. */ else { int32 diff; diff = x - edge->x; for (i=0; i < edge->cell_cnt; i++) { lo_GridCellRec *cell; cell = edge->cell_array[i]; if (cell == NULL) { continue; } /* * If the cell is left of the edge. * Grow the cell and any abutting * edges. */ if (cell->x < edge->x) { #if 0 cell->width += diff; #endif lo_change_left_edges(context, cell->side_edges[TOP_EDGE], edge->x, diff, FALSE); lo_change_left_edges(context, cell->side_edges[BOTTOM_EDGE], edge->x, diff, FALSE); /* * The bounds of this edge are effected */ lo_set_edge_bounds(cell->side_edges[LEFT_EDGE]); } /* * Else the cell is right of the edge. * Move and shrink the cell and any abutting * edges. */ else { #if 0 cell->x += diff; cell->width -= diff; #endif lo_change_right_edges(context, cell->side_edges[TOP_EDGE], (edge->x + edge->width - 1), diff, FALSE); lo_change_right_edges(context, cell->side_edges[BOTTOM_EDGE], (edge->x + edge->width - 1), diff, FALSE); /* * The bounds of this edge are effected */ lo_set_edge_bounds(cell->side_edges[RIGHT_EDGE]); } /* * Only restructure cells that have windows(contexts) */ if (cell->context != NULL) { cell->needs_restructuring = TRUE; } } edge->x = x; edge->fe_edge->x = x; } } PRIVATE void lo_ReLayoutGridCells(MWContext *context, int32 width, int32 height, lo_GridRec *grid) { int32 orig_x, orig_y; lo_GridCellRec *cell_list; int32 new_cell_width, new_cell_height; if (grid == NULL) { return; } cell_list = grid->cell_list; orig_x = 0; orig_y = 0; while (cell_list != NULL) { if (cell_list->side_edges[TOP_EDGE]) { cell_list->y = (cell_list->side_edges[TOP_EDGE]->y + grid->grid_cell_border * 2); } else { cell_list->y = 0; } if (cell_list->side_edges[LEFT_EDGE]) { cell_list->x = (cell_list->side_edges[LEFT_EDGE]->x + grid->grid_cell_border * 2); } else { cell_list->x = 0; } if (cell_list->has_percent_width) { new_cell_width = width * (float)cell_list->width_percent / 100.0; if (new_cell_width < grid->grid_cell_min_dim) { new_cell_width = grid->grid_cell_min_dim; } if (cell_list->side_edges[LEFT_EDGE]) { new_cell_width -= grid->grid_cell_border; } if (cell_list->side_edges[RIGHT_EDGE]) { new_cell_width -= grid->grid_cell_border; } else { /* * Make sure the last column uses all the remaining space. * We subtract orig_x to get cell_list->x into the same coord * space as width. */ new_cell_width = width - (cell_list->x - orig_x); } } else new_cell_width = cell_list->width; if (cell_list->has_percent_height) { new_cell_height = height * (float)cell_list->height_percent / 100.0; if (new_cell_height < grid->grid_cell_min_dim) { new_cell_height = grid->grid_cell_min_dim; } if (cell_list->side_edges[TOP_EDGE]) { new_cell_height -= grid->grid_cell_border; } if (cell_list->side_edges[BOTTOM_EDGE]) { new_cell_height -= grid->grid_cell_border; } else { /* * Make sure the last row uses all the remaining space. * We subtract orig_y to get cell_list->y into the same coord * space as height. */ new_cell_height = height - (cell_list->y - orig_y); } } else new_cell_height = cell_list->height; cell_list->width = new_cell_width; cell_list->height = new_cell_height; if (cell_list->side_edges[RIGHT_EDGE]) { if (cell_list->side_edges[RIGHT_EDGE]->dealt_with_in_relayout == FALSE) { lo_MoveGridEdgeForRelayout(context, cell_list->side_edges[RIGHT_EDGE]->fe_edge, cell_list->x + cell_list->width, cell_list->side_edges[RIGHT_EDGE]->y); cell_list->side_edges[RIGHT_EDGE]->dealt_with_in_relayout = TRUE; } } if (cell_list->side_edges[BOTTOM_EDGE]) { if (cell_list->side_edges[BOTTOM_EDGE]->dealt_with_in_relayout == FALSE) { lo_MoveGridEdgeForRelayout(context, cell_list->side_edges[BOTTOM_EDGE]->fe_edge, cell_list->side_edges[BOTTOM_EDGE]->x, cell_list->y + cell_list->height); cell_list->side_edges[BOTTOM_EDGE]->dealt_with_in_relayout = TRUE; } } cell_list = cell_list->next; } } static void lo_PrepareGridForRelayout(MWContext *context, lo_GridRec *grid) { lo_GridEdge *edge_list; lo_GridCellRec *cell_list; cell_list = grid->cell_list; while(cell_list) { cell_list->needs_restructuring = FALSE; cell_list = cell_list->next; } edge_list = grid->edge_list; while (edge_list != NULL) { /* FE_HideEdge(context, FE_VIEW, edge_list->fe_edge);*/ edge_list->dealt_with_in_relayout = FALSE; edge_list = edge_list->next; } } static void lo_ResyncEdgeSizes(MWContext *context, lo_GridRec *grid) { lo_GridEdge *edge_list; edge_list = grid->edge_list; while (edge_list != NULL) { int i; lo_set_edge_bounds(edge_list); if (edge_list->is_vertical == FALSE) /* horizontal edge */ { int32 width = 0; for (i = 0; i < edge_list->cell_cnt; i ++) { lo_GridCellRec *cell; cell = edge_list->cell_array[i]; if (cell == NULL) { continue; } if (cell->x + cell->width > edge_list->x + width) width = cell->x + cell->width - edge_list->x; } edge_list->width = width; edge_list->fe_edge->width = width; } else /* vertical edge */ { int32 height = 0; for (i = 0; i < edge_list->cell_cnt; i ++) { lo_GridCellRec *cell; cell = edge_list->cell_array[i]; if (cell == NULL) { continue; } if (cell->y + cell->height > edge_list->y + height) height = cell->y + cell->height - edge_list->y; } edge_list->height = height; edge_list->fe_edge->height = height; } lo_DisplayEdge(context, edge_list->fe_edge); edge_list = edge_list->next; } } static void lo_RestructureCells(MWContext *context, lo_GridRec *grid) { lo_GridCellRec *cell_list; cell_list = grid->cell_list; while(cell_list) { if (cell_list->needs_restructuring && cell_list->context != NULL) { FE_RestructureGridWindow (cell_list->context, cell_list->x, cell_list->y, cell_list->width, cell_list->height); } cell_list = cell_list->next; } } void lo_RelayoutGridDocumentOnResize(MWContext *context, lo_TopState *top_state, int32 width, int32 height) { lo_GridRec *grid = top_state->the_grid; lo_PrepareGridForRelayout(context, grid); lo_ReLayoutGridCells(context, width, height, grid); lo_RestructureCells(context, grid); lo_ResyncEdgeSizes(context, grid); }