mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-27 19:09:47 +00:00
4524 lines
91 KiB
C
4524 lines
91 KiB
C
/* -*- 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; i<cnt; i++)
|
|
{
|
|
char *ptr;
|
|
char *end_ptr;
|
|
|
|
ptr = strchr(tptr, ',');
|
|
if (ptr != NULL)
|
|
{
|
|
*ptr = '\0';
|
|
}
|
|
|
|
/*
|
|
* Need the end of the string to check if the number
|
|
* ends in '%', '*', or 'p'.
|
|
*/
|
|
if (ptr != NULL)
|
|
{
|
|
end_ptr = (char *)(ptr - 1);
|
|
if (end_ptr < tptr)
|
|
{
|
|
end_ptr = tptr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
end_ptr = (char *)(str + XP_STRLEN(str) - 1);
|
|
}
|
|
|
|
if (*end_ptr == '*')
|
|
{
|
|
percent_list[i].type = LO_PERCENT_FREE;
|
|
percent_list[i].original_value = (int32)XP_ATOI(tptr);
|
|
if (percent_list[i].original_value < 1)
|
|
{
|
|
percent_list[i].original_value = 1;
|
|
}
|
|
}
|
|
else if (*end_ptr == '%')
|
|
{
|
|
percent_list[i].type = LO_PERCENT_NORMAL;
|
|
percent_list[i].original_value = (int32)XP_ATOI(tptr);
|
|
if (percent_list[i].original_value <= 0)
|
|
{
|
|
percent_list[i].original_value = 100 / cnt;
|
|
if (percent_list[i].original_value == 0)
|
|
{
|
|
percent_list[i].original_value = 1;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Default is in "pixels"
|
|
*/
|
|
else
|
|
{
|
|
int32 val;
|
|
|
|
percent_list[i].type = LO_PERCENT_FIXED;
|
|
val = (int32)XP_ATOI(tptr);
|
|
val = FEUNITS_X(val, context);
|
|
if (val < 1)
|
|
{
|
|
val = 1;
|
|
}
|
|
percent_list[i].original_value = val;
|
|
}
|
|
|
|
if (ptr != NULL)
|
|
{
|
|
*ptr = ',';
|
|
tptr = (char *)(ptr + 1);
|
|
}
|
|
}
|
|
return(percent_list);
|
|
}
|
|
|
|
|
|
void
|
|
lo_FreeGridEdge(lo_GridEdge *edge)
|
|
{
|
|
if (edge->cell_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);
|
|
}
|
|
|