campo-sirio/xi/xilm2.c
alex 18c8e52948 This commit was generated by cvs2svn to compensate for changes in r5757,
which included commits to RCS files with non-trunk default branches.

git-svn-id: svn://10.65.10.50/trunk@5758 c028cbd2-c16b-5b4b-a496-9718f37d4682
1997-12-17 10:43:31 +00:00

4914 lines
144 KiB
C
Executable File

/*******************************************************************************
* Copyright 1991-1995 by ORCA Software, Inc. *
* *
* All rights reserved. May not be reproduced or distribfuted, in printed or *
* electronic form, without permission of ORCA Software, Inc. May not be *
* distributed as object code, separately or linked with other object modules, *
* without permission. *
*******************************************************************************/
#define XI_INTERNAL
#include "xi.h"
#include "xitext.h"
#include "xilm.h"
#include "xiutils.h"
#include "xidisply.h"
#define REALIZED_ROWS_GRANULE 4
#define REC_AT_TOP 1
#define REC_AT_BOTTOM 0
#define CELL_VERTICAL_MARGIN (RULE_Y_OFFSET_TOP + RULE_Y_OFFSET_BOTTOM + 2)
static void adjust_rows(LM_DATA *lmp, int delta );
/*-------------------------------------------------------------------------
function: lm_allocate_rec_info
lmp: current lmp
realized_rows_array_len: number of realized rows in the realized rows array
-------------------------------------------------------------------------*/
void
lm_allocate_rec_info(LM_DATA *lmp, int realized_rows_array_len)
{
int old_len = lmp->realized_rows_array_len;
int i;
lmp->realized_rows_array_len = realized_rows_array_len;
/* recs */
if (lmp->recs)
{
lmp->recs = (long *)xi_tree_realloc(lmp->recs, sizeof(long) * realized_rows_array_len);
for (i = old_len; i < realized_rows_array_len; ++i)
lmp->recs[i] = 0L;
}
else
lmp->recs = (long *)xi_tree_malloc(sizeof(long) * realized_rows_array_len, lmp);
/* pix_offsets */
if (lmp->pix_offsets)
lmp->pix_offsets = (int *)xi_tree_realloc(lmp->pix_offsets,
sizeof(int) * realized_rows_array_len);
else
lmp->pix_offsets = (int *)xi_tree_malloc(sizeof(int) * realized_rows_array_len, lmp);
/* pix_heights */
if (lmp->pix_heights)
lmp->pix_heights = (int *)xi_tree_realloc(lmp->pix_heights,
sizeof(int) * realized_rows_array_len);
else
lmp->pix_heights = (int *)xi_tree_malloc(sizeof(int) * realized_rows_array_len, lmp);
/* set_heights */
if (lmp->set_heights)
lmp->set_heights = (short *)xi_tree_realloc(lmp->set_heights,
sizeof(int) * realized_rows_array_len);
else
lmp->set_heights = (short *)xi_tree_malloc(sizeof(int) * realized_rows_array_len, lmp);
/* buffer */
if (lmp->buffer)
{
for (i = realized_rows_array_len; i < old_len; ++i)
xi_tree_free(lmp->buffer[i]);
lmp->buffer = (char * *)xi_tree_realloc(lmp->buffer,
sizeof(char *) * realized_rows_array_len);
for (i = old_len; i < realized_rows_array_len; ++i)
lmp->buffer[i] = (char *)xi_tree_malloc(lmp->text_size, lmp);
}
else
lmp->buffer = (char * *)xi_tree_malloc(sizeof(char *) * realized_rows_array_len,
lmp);
/* row_attribs */
if (lmp->row_attribs)
{
lmp->row_attribs = (unsigned long *)xi_tree_realloc(lmp->row_attribs,
sizeof(unsigned long) * realized_rows_array_len);
for (i = old_len; i < realized_rows_array_len; ++i)
lmp->row_attribs[i] = LM_ROW_ATR_ENABLED;
}
else
lmp->row_attribs = (unsigned long *)xi_tree_malloc(sizeof(unsigned long) * realized_rows_array_len,
lmp);
/* row_colors */
if (lmp->row_colors)
{
lmp->row_colors = (COLOR *)xi_tree_realloc(lmp->row_colors,
sizeof(COLOR) * realized_rows_array_len);
for (i = old_len; i < realized_rows_array_len; ++i)
lmp->row_colors[i] = 0L;
}
else
lmp->row_colors = (COLOR *)xi_tree_malloc(sizeof(COLOR) * realized_rows_array_len,
lmp);
/* cell_data */
if (lmp->cell_data)
{
for (i = realized_rows_array_len; i < old_len; ++i)
xi_tree_free(lmp->cell_data[i]);
lmp->cell_data = (LM_CELL_DATA * *)xi_tree_realloc(lmp->cell_data,
sizeof(LM_CELL_DATA *) * realized_rows_array_len);
for (i = old_len; i < realized_rows_array_len; ++i)
lmp->cell_data[i] = (LM_CELL_DATA *)xi_tree_malloc((lmp->nbr_columns + 1) * sizeof(LM_CELL_DATA),
lmp);
}
else
lmp->cell_data = (LM_CELL_DATA * *)xi_tree_malloc(sizeof(LM_CELL_DATA *) * realized_rows_array_len,
lmp);
}
/*-------------------------------------------------------------------------
function: lm_create
win: window in which to put list
lm_def: list definition
parent: tree memory parent
-------------------------------------------------------------------------*/
LM
lm_create(WINDOW win, LM_DEF *lm_def, void *parent)
{
LM_DATA *lmp;
int i, font_height, leading, ascent, descent, mch, realized_rows_array_len;
lmp = LMP(xi_tree_malloc(sizeof(LM_DATA), parent));
lmp->cid = lm_def->cid;
lmp->list_obj = lm_def->list_obj;
lmp->itf_obj = lm_def->itf_obj;
lmp->win = win;
lmp->font = lm_def->font;
lmp->back_color = lm_def->back_color;
lmp->enabled_color = lm_def->enabled_color;
lmp->disabled_color = lm_def->disabled_color;
lmp->disabled_back_color = lm_def->disabled_back_color;
lmp->active_color = lm_def->active_color;
lmp->active_back_color = lm_def->active_back_color;
lmp->white_space_color = lm_def->white_space_color;
lmp->rule_color = lm_def->rule_color;
lmp->attrib = lm_def->attrib;
lmp->lm_cb = lm_def->lm_cb;
lmp->no_heading = lm_def->no_heading;
lmp->sizable_columns = lm_def->sizable_columns;
lmp->movable_columns = lm_def->movable_columns;
lmp->fixed_columns = lm_def->fixed_columns;
lmp->resize_with_window = lm_def->resize_with_window;
lmp->horz_sync_list = lm_def->horz_sync_list;
lmp->vert_sync_list = lm_def->vert_sync_list;
lmp->row_focus_border = lm_def->row_focus_border;
lmp->row_focus_border_color = lm_def->row_focus_border_color;
lmp->single_select = lm_def->single_select;
lmp->pixel_width = lm_def->pixel_width;
lmp->pixel_height = lm_def->pixel_height;
#if XI_IS_CH
CTOS_IS_CH;
lmp->min_cell_height = 0;
lmp->min_heading_height = lm_def->min_heading_height;
CTOS_END
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
lmp->min_cell_height = lm_def->min_cell_height;
lmp->min_heading_height = lm_def->min_heading_height;
CTOS_END;
#endif
lmp->no_horz_lines = lm_def->no_horz_lines;
lmp->no_vert_lines = lm_def->no_vert_lines;
lmp->first_vis = lmp->fixed_columns;
lmp->drop_and_delete = lm_def->drop_and_delete;
lmp->select_cells = lm_def->select_cells;
lmp->get_all_records = lm_def->get_all_records;
lmp->keep_all_records = lm_def->keep_all_records;
lmp->retain_back_color_on_select = lm_def->retain_back_color_on_select;
lmp->max_lines_in_cell = lm_def->max_lines_in_cell;
if (! lmp->max_lines_in_cell)
lmp->max_lines_in_cell =
(int)xi_get_pref(XI_PREF_DEFAULT_MAX_LINES_IN_CELL);
xi_set_xvt_font(win, lm_def->font, FALSE);
xi_get_font_metrics(win, &leading, &ascent, &descent);
lmp->leading = leading;
lmp->ascent = ascent;
lmp->descent = descent;
font_height = lmp->ascent + lmp->leading + lmp->descent;
/* we add two to the following line so that there is room in the cell for the
row focus border */
#if XVTWS == WMWS
lmp->pix_cell_height = font_height;
#else
lmp->pix_cell_height = font_height + CELL_VERTICAL_MARGIN;
#endif
#if XI_IS_CH
CTOS_IS_CH;
mch = 8;
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
mch = lm_def->min_cell_height;
CTOS_END;
#endif
lmp->pix_cell_height = max(lmp->pix_cell_height, mch);
lmp->pix_row_spacing = lmp->pix_cell_height + RULE_WIDTH_H;
lmp->pix_top = lm_def->pnt.v;
#if XVTWS == WMWS
lmp->pix_hdr_bottom = lm_def->pnt.v + lmp->leading + lmp->ascent +
lmp->descent + BORDER_WIDTH +
RULE_Y_OFFSET_BOTTOM + RULE_Y_OFFSET_TOP;
lmp->pix_hdr_bottom = max(lmp->pix_hdr_bottom, (lm_def->pnt.v
+ lmp->min_heading_height - BORDER_WIDTH));
#else
lmp->pix_hdr_bottom = lm_def->pnt.v + lmp->leading + lmp->ascent +
lmp->descent + BORDER_WIDTH + RULE_Y_OFFSET_BOTTOM + RULE_Y_OFFSET_TOP;
lmp->pix_hdr_bottom = max( lmp->pix_hdr_bottom, (lm_def->pnt.v + lmp->min_heading_height));
#endif
if (lmp->no_heading)
lmp->pix_row1_top = lm_def->pnt.v + BORDER_WIDTH;
else
lmp->pix_row1_top = lmp->pix_hdr_bottom + BORDER_WIDTH;
lmp->pix_char_width = lm_def->pix_char_width;
lmp->nbr_columns = 0;
lmp->lm_column_data = NULL;
/* compute number of rows */
lmp->nbr_rows = lm_def->nbr_rows;
if (lm_def->nbr_rows)
lmp->nbr_rows = lm_def->nbr_rows;
else
lmp->nbr_rows = (lm_def->pixel_height - (lmp->pix_row1_top - lm_def->pnt.v)
- BORDER_WIDTH) / lmp->pix_row_spacing;
if (lm_def->one_row_list)
lmp->nbr_rows = 1;
lmp->rct.left = lm_def->pnt.h;
lmp->rct.top = lm_def->pnt.v;
#if XI_IS_NOT_CH
CTOS_IS_PM;
lmp->rct.right = lm_def->pnt.h + 2 * BORDER_WIDTH;
if (lm_def->resize_with_window)
lmp->rct.bottom = lm_def->pnt.v + lm_def->pixel_height;
else
lmp->rct.bottom = lmp->pix_row1_top + lmp->nbr_rows * lmp->pix_row_spacing +
(BORDER_WIDTH - RULE_WIDTH_H);
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
lmp->rct.right = lm_def->pnt.h + BORDER_WIDTH;
if (lm_def->resize_with_window)
lmp->rct.bottom = lm_def->pnt.v + lm_def->pixel_height;
else
lmp->rct.bottom = lmp->pix_row1_top + lmp->nbr_rows * lmp->pix_row_spacing
+ BORDER_WIDTH;
CTOS_END;
#endif
lmp->vir_left = lmp->rct.left + BORDER_WIDTH;
lmp->vir_right = lmp->vir_left + lmp->pixel_width;
lmp->text_size = 0;
realized_rows_array_len = lm_def->realized_rows_array_len;
if (! realized_rows_array_len)
realized_rows_array_len = lmp->nbr_rows + 1;
lm_allocate_rec_info(lmp, realized_rows_array_len);
/* calculate mathematical list rectangle */
lmp->mlr.top = lmp->pix_row1_top;
#if XI_IS_NOT_CH
CTOS_IS_PM;
lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH;
lmp->mlr.left = lmp->rct.left + BORDER_WIDTH;
lmp->mlr.right = lmp->rct.right - BORDER_WIDTH;
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
if (lmp->pixel_width)
lmp->mlr.bottom = lmp->rct.bottom;
else
lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH;
lmp->mlr.left = lmp->rct.left;
lmp->mlr.right = lmp->rct.right;
CTOS_END;
#endif
lmp->mlr_height = lmp->mlr.bottom - lmp->mlr.top;
for (i = 0; i < lmp->realized_rows_array_len; ++i)
{
lmp->cell_data[i] = (LM_CELL_DATA *)xi_tree_malloc(
lmp->nbr_columns * sizeof(LM_CELL_DATA), lmp);
lmp->row_attribs[i] = LM_ROW_ATR_ENABLED;
}
return((LM)PTR_LONG(lmp));
}
/*-------------------------------------------------------------------------
function: do_rec_event
lmp: current lmp
row: row to do event on
type: XI_EVENT_TYPE
notes: In this case, row is not really a row. It is an index into the
realized rows array.
-------------------------------------------------------------------------*/
static void
do_rec_event(LM_DATA *lmp, int row, XI_EVENT_TYPE type)
{
LM_CELL_DATA *lmcdp;
int i;
if (type == XIE_REC_FREE)
{
if (lmp->recs[row] != lmp->focus_rec)
do_lm_cb((LM)lmp, LM_CB_REC_FREE, row, 0, NULL, NULL, 0);
lmcdp = lmp->cell_data[row];
for (i = 0; i < lmp->nbr_columns; ++i, ++lmcdp)
{
if (lmcdp->font)
{
xi_free_font_id(lmp->itf_obj, *lmcdp->font);
xi_tree_free(lmcdp->font);
}
if (lmcdp->string)
xi_tree_free(lmcdp->string);
if (lmcdp->line_breaks)
xi_tree_free(lmcdp->line_breaks);
memset((char *)lmcdp, '\0', sizeof(LM_CELL_DATA));
}
lmp->recs[row] = 0L;
/* we technically do not need to do the following lines. it just keeps the data structures clean. */
lmp->pix_heights[row] = 0;
lmp->set_heights[row] = FALSE;
lmp->pix_offsets[row] = 0;
memset(lmp->buffer[row], '\0', lmp->text_size);
lmp->row_attribs[row] = 0L;
lmp->row_colors[row] = 0L;
}
if (type == XIE_REC_ALLOCATE)
{
do_lm_cb((LM)lmp, LM_CB_REC_ALLOCATE, row, 0, NULL, NULL, 0);
lmcdp = lmp->cell_data[row];
for (i = 0; i < lmp->nbr_columns; ++i, ++lmcdp)
memset((char *)lmcdp, '\0', sizeof(LM_CELL_DATA));
}
}
/*-------------------------------------------------------------------------
function: row_copy
lmp: current lmp
source_row: row from which to copy
dest_row: destination row
-------------------------------------------------------------------------*/
static void
row_copy(LM_DATA *lmp, int source_row, int dest_row)
{
int idx;
LM_CELL_DATA *lmcdpd, *lmcdps;
lmp->recs[dest_row] = lmp->recs[source_row];
lmp->pix_heights[dest_row] = lmp->pix_heights[source_row];
lmp->set_heights[dest_row] = lmp->set_heights[source_row];
lmp->pix_offsets[dest_row] = lmp->pix_offsets[source_row];
memcpy(lmp->buffer[dest_row], lmp->buffer[source_row], lmp->text_size);
lmp->row_attribs[dest_row] = lmp->row_attribs[source_row];
lmp->row_colors[dest_row] = lmp->row_colors[source_row];
for (idx = 0,
lmcdpd = lmp->cell_data[dest_row],
lmcdps = lmp->cell_data[source_row];
idx < lmp->nbr_columns;
++idx,
++lmcdpd,
++lmcdps)
{
*lmcdpd = *lmcdps;
}
}
/*-------------------------------------------------------------------------
function: init_row
lmp: current lmp
row: row to init
-------------------------------------------------------------------------*/
static void
init_row(LM_DATA *lmp, int row)
{
int idx;
LM_CELL_DATA *lmcdp;
lmp->recs[row] = 0L;
lmp->pix_heights[row] = 0;
lmp->set_heights[row] = 0;
lmp->pix_offsets[row] = 0;
lmp->row_attribs[row] = LM_ROW_ATR_ENABLED;
lmp->row_colors[row] = 0;
for (idx = 0,
lmcdp = lmp->cell_data[row];
idx < lmp->nbr_columns;
++idx,
++lmcdp)
{
memset((char *)lmcdp, '\0', sizeof(LM_CELL_DATA));
}
}
/*-------------------------------------------------------------------------
function: make_rec_available
lmp: current lmp
top: record to become available is at the top of the realized_row array,
else the record to become available is at the bottom of the realized
row array.
allocate_rec: if TRUE, then send XIE_REC_ALLOCATE event
notes: if, in order to get a record at the bottom of the realized row array,
we must discard a record at the beginning of the rrr array, then
we must change lmp->rrr_offset.
whenever we make a record be available, make sure that we free
fonts in cell_data.
Also, clear cell_data.
-------------------------------------------------------------------------*/
static void make_rec_available( LM_DATA *lmp, BOOLEAN top, BOOLEAN allocate_rec,
BOOLEAN doing_scroll_first)
{
int cnt;
if (top)
{
int idx;
if (! lmp->get_all_records)
{
int nbr_to_free;
nbr_to_free = lmp->nbr_realized_rows - (lmp->last_fully_vis + 2);
if (nbr_to_free > 0)
{
/* free as many records at the end of the list as possible */
for (idx = lmp->last_fully_vis + 2; idx < lmp->nbr_realized_rows;
++idx)
do_rec_event(lmp, idx, XIE_REC_FREE);
lmp->nbr_realized_rows -= nbr_to_free;
}
if (lmp->nbr_realized_rows >= lmp->realized_rows_array_len)
lm_allocate_rec_info(lmp, lmp->realized_rows_array_len + 1);
/* copy all the records, making room at the beginning of the realized_row array */
++lmp->nbr_realized_rows;
for (idx = lmp->nbr_realized_rows - 1;
idx > 0; --idx)
row_copy(lmp, idx - 1, idx);
adjust_rows(lmp, 1);
init_row(lmp, 0);
if (allocate_rec)
do_rec_event(lmp, 0, XIE_REC_ALLOCATE);
return;
}
}
else
{
if (! lmp->get_all_records || doing_scroll_first)
{
/* free as many records at the beginning of the list as possible */
cnt = lmp->first_fully_vis - 2;
if (cnt > 0)
{
int idx, jidx;
for (idx = 0; idx < cnt; ++idx)
{
lmp->rrr_offset += lmp->pix_heights[idx];
do_rec_event(lmp, idx, XIE_REC_FREE);
}
lmp->nbr_realized_rows -= cnt;
/* copy all the records, making room at the end of the realized row array */
for (idx = cnt, jidx = 0;
jidx < lmp->nbr_realized_rows;
++idx, ++jidx)
row_copy(lmp, idx, idx - cnt);
adjust_rows(lmp, -cnt);
}
if (lmp->nbr_realized_rows >= lmp->realized_rows_array_len)
lm_allocate_rec_info(lmp, lmp->realized_rows_array_len + 1);
++lmp->nbr_realized_rows;
init_row(lmp, lmp->nbr_realized_rows - 1);
if (allocate_rec)
do_rec_event(lmp, lmp->nbr_realized_rows - 1, XIE_REC_ALLOCATE);
return;
}
}
}
/*-------------------------------------------------------------------------
function: get_next_rec
lmp: current lmp
returns: TRUE if next record was available
FALSE if not
-------------------------------------------------------------------------*/
static BOOLEAN
get_next_rec(LM_DATA *lmp, BOOLEAN doing_scroll_first)
{
int idx, row_height;
make_rec_available(lmp, REC_AT_BOTTOM, TRUE, doing_scroll_first);
idx = lmp->nbr_realized_rows - 1;
if (do_lm_cb_get((LM)lmp, LM_CB_GET_NEXT,
&lmp->recs[idx - 1], &lmp->recs[idx], 0, &lmp->row_colors[idx],
&lmp->row_attribs[idx], &row_height))
{
do_rec_event(lmp, lmp->nbr_realized_rows - 1, XIE_REC_FREE);
--lmp->nbr_realized_rows;
return FALSE;
}
if (row_height)
{
lmp->pix_heights[idx] = row_height;
lmp->set_heights[idx] = TRUE;
}
else
{
lmp->pix_heights[idx] = 0;
lmp->set_heights[idx] = FALSE;
}
lm_invalidate_rows_internal((LM)lmp, idx, idx, FALSE, -1, TRUE );
return TRUE;
}
/*-------------------------------------------------------------------------
function: get_previous_rec
lmp: current lmp
returns: TRUE if previous record was available
FALSE if not
-------------------------------------------------------------------------*/
static BOOLEAN get_previous_rec(LM_DATA *lmp)
{
int row_height, cnt;
make_rec_available(lmp, REC_AT_TOP, TRUE, FALSE);
if (do_lm_cb_get((LM)lmp, LM_CB_GET_PREV,
&lmp->recs[1], &lmp->recs[0], 0, &lmp->row_colors[0],
&lmp->row_attribs[0], &row_height))
{
do_rec_event(lmp, 0, XIE_REC_FREE);
for (cnt = 0; cnt < lmp->nbr_realized_rows - 1; ++cnt)
row_copy(lmp, cnt + 1, cnt);
adjust_rows(lmp, -1);
--lmp->nbr_realized_rows;
return FALSE;
}
if (row_height)
{
lmp->pix_heights[0] = row_height;
lmp->set_heights[0] = TRUE;
}
else
{
lmp->pix_heights[0] = 0;
lmp->set_heights[0] = FALSE;
}
lm_invalidate_rows_internal((LM)lmp, 0, 0, FALSE, -1, TRUE );
return TRUE;
}
/*-------------------------------------------------------------------------
function: calculate_cell_height
lmp: current lmp
row: row number of cell to calculate
column: column number of cell to calculate
returns: height of cell in pixels
notes: this function does not need to take into consideration the
variable fixed_row_height. This function is only used by
lm_calculate_row_height, and will only be called if
fixed_row_height is false.
notes: In the future, we may wish to support word wrap. At this
point, the only way to have multiple lines in a cell is to
have '\n' characters in the text.
-------------------------------------------------------------------------*/
static int
calculate_cell_height(LM_DATA *lmp, int row, int column)
{
int pix_height; /* pix_height does include the width of the rules */
int nbr_lines;
LM_CELL_DATA *cell_data;
cell_data = &lmp->cell_data[row][column];
if (lmp->lm_column_data[column]->wrap_text)
{
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, column, TRUE );
lm_wrap_text(lmp, row, column, TRUE);
nbr_lines = min(cell_data->nbr_lines, lmp->max_lines_in_cell);
}
else
{
nbr_lines = 1;
if (! cell_data->font_height)
{
FONT_OBJ *font;
int leading, ascent, descent, char_width;
if (cell_data->font)
font = cell_data->font;
else
font = lmp->font;
xi_get_font_metrics_font(font, &leading, &ascent, &descent, &char_width);
cell_data->font_height = leading + ascent + descent;
}
}
#if XVTWS != WMWS
pix_height = nbr_lines * cell_data->font_height + CELL_VERTICAL_MARGIN
+ RULE_WIDTH_H;
#else
pix_height = nbr_lines * cell_data->font_height;
#endif
pix_height = max(pix_height, lmp->pix_row_spacing);
return pix_height;
}
/*-------------------------------------------------------------------------
function: lm_calculate_row_height
lmp: current lmp
row: row number to calculate
returns: height of row in pixels
notes: if fixed_row_height is TRUE, then the calculation is easy.
if fixed_row_height is FALSE, then the calculation must take
word wrap into consideration, etc.
row height includes the height of the horizontal rule below
the row.
-------------------------------------------------------------------------*/
int
lm_calculate_row_height(LM_DATA *lmp, int row)
{
int pix_height;
if (lmp->fixed_row_height)
pix_height = lmp->pix_row_spacing;
else if (lmp->set_heights[row])
pix_height = lmp->pix_heights[row];
else
{
int cnt;
int cell_height;
pix_height = 0;
for (cnt = 0; cnt < lmp->nbr_columns; ++cnt)
{
cell_height = calculate_cell_height(lmp, row, cnt);
pix_height = max(pix_height, cell_height);
}
}
if (pix_height > lmp->mlr_height)
pix_height = lmp->mlr_height;
return pix_height;
}
/*-------------------------------------------------------------------------
function: calculate_visibles
lmp: current lmp
process: calculates lmp->first_fully_vis
calculates lmp->last_fully_vis
-------------------------------------------------------------------------*/
void
calculate_visibles(LM_DATA *lmp)
{
int i, idx;
int *pix_offsetsp;
int *pix_heightsp;
BOOLEAN have_first;
have_first = FALSE;
lmp->first_fully_vis = 0;
lmp->last_fully_vis = 0;
for (i = 0,
pix_offsetsp = &lmp->pix_offsets[i],
pix_heightsp = &lmp->pix_heights[i];
i < lmp->nbr_realized_rows;
++i, ++pix_offsetsp, ++pix_heightsp)
{
if (! have_first && *pix_offsetsp >= (-lmp->rrr_offset))
{
have_first = TRUE;
lmp->first_fully_vis = i;
}
/*
should be <, because we are dealing with mathematical rects, but we don't care if
the rule is not on the list.
*pix_offsetp + *pix_heightsp is the mathematical rect of the row, in rrr terms.
lmp->rrr_offset + lmp->mlr_height is the mathematical rect of the list, in rrr terms.
*/
#if XI_IS_CH
CTOS_IS_CH;
if (*pix_offsetsp + *pix_heightsp + lmp->rrr_offset <= lmp->mlr_height)
lmp->last_fully_vis = i;
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
if (*pix_offsetsp + *pix_heightsp - 1 + lmp->rrr_offset <= lmp->mlr_height)
lmp->last_fully_vis = i;
CTOS_END;
#endif
}
if (lmp->nbr_realized_rows)
{
idx = lmp->nbr_realized_rows - 1;
lmp->rrr_bottom = lmp->pix_offsets[idx] + lmp->pix_heights[idx];
}
else
lmp->rrr_bottom = 0;
}
/*-------------------------------------------------------------------------
function: calculate_pix_offsets
lmp: current lmp
process: calculates the lmp->pix_offsets array
calculates lmp->first_fully_vis
calculates lmp->last_fully_vis
-------------------------------------------------------------------------*/
void
calculate_pix_offsets(LM_DATA *lmp, BOOLEAN draw_changes )
{
int i, cur_pix, idx;
int *pix_offsetsp;
int *pix_heightsp;
BOOLEAN have_first;
cur_pix = 0;
have_first = FALSE;
for (i = 0,
pix_offsetsp = &lmp->pix_offsets[i],
pix_heightsp = &lmp->pix_heights[i];
i < lmp->nbr_realized_rows;
++i, ++pix_offsetsp, ++pix_heightsp)
{
int new_height;
new_height = lm_calculate_row_height(lmp, i);
if ( draw_changes &&
(*pix_offsetsp != cur_pix || *pix_heightsp != new_height ))
{
RCT rect;
lm_get_row_rect( &rect, (LM)lmp, i );
lm_invalidate_rect( lmp, &rect, FALSE );
rect.top = cur_pix;
rect.bottom = cur_pix + new_height;
lm_invalidate_rect( lmp, &rect, FALSE );
}
*pix_offsetsp = cur_pix;
*pix_heightsp = new_height;
if (! have_first && cur_pix >= (-lmp->rrr_offset))
{
have_first = TRUE;
lmp->first_fully_vis = i;
}
cur_pix += new_height;
/*
should be <=, because we are dealing with mathematical rects, but we don't care if
the rule is not on the list.
*pix_offsetp + *pix_heightsp is the mathematical rect of the row, in rrr terms.
lmp->rrr_offset + lmp->mlr_height is the mathematical rect of the list, in rrr terms.
*/
#if XI_IS_CH
CTOS_IS_CH;
if (cur_pix + lmp->rrr_offset <= lmp->mlr_height)
lmp->last_fully_vis = i;
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
if ( cur_pix - 1 + lmp->rrr_offset <= lmp->mlr_height)
lmp->last_fully_vis = i;
CTOS_END;
#endif
}
if (lmp->nbr_realized_rows)
{
idx = lmp->nbr_realized_rows - 1;
lmp->rrr_bottom = lmp->pix_offsets[idx] + lmp->pix_heights[idx];
}
else
lmp->rrr_bottom = 0;
}
/*-------------------------------------------------------------------------
function: make_rrr_room_pix
lmp: current lmp
pixels: number of additional pixels desired in realized row rect
pixels may be negative, in which case, the desired pixels
are above the realized row rect
pixels may be positive, in which case, the desired pixels
are below the realized row rect
returns: recs read
-------------------------------------------------------------------------*/
int
lm_make_rrr_room_pix(LM_DATA *lmp, int pixels, BOOLEAN do_redraw )
{
int recs_read = 0;
int idx;
if (lmp->nbr_realized_rows == 0)
{
lmp->rrr_bottom = 0;
calculate_pix_offsets(lmp, FALSE );
return 0;
}
idx = lmp->nbr_realized_rows - 1;
lmp->rrr_bottom = lmp->pix_offsets[idx] + lmp->pix_heights[idx];
if (pixels < 0)
{
while (TRUE)
{
if (pixels >= lmp->rrr_offset)
return recs_read;
if (get_previous_rec(lmp))
{
int row_height;
row_height = lm_calculate_row_height(lmp, 0);
lmp->rrr_offset -= row_height;
calculate_pix_offsets(lmp, do_redraw);
calculate_visibles(lmp);
++recs_read;
}
else
return recs_read;
}
}
else
{
while (TRUE)
{
if (lmp->rrr_bottom - lmp->mlr_height + lmp->rrr_offset >= pixels)
return recs_read;
if (lmp->get_all_records) return recs_read;
if (get_next_rec(lmp, FALSE))
{
calculate_pix_offsets(lmp, do_redraw);
calculate_visibles(lmp);
++recs_read;
}
else
return recs_read;
}
}
}
/*-------------------------------------------------------------------------
function: make_rrr_room_rows
lmp: current lmp
nbr_rows: nbr of rows to scroll
returns: pixels to scroll
-------------------------------------------------------------------------*/
static int
make_rrr_room_rows(LM_DATA *lmp, int* rows, BOOLEAN do_redraw)
{
int nbr_rows = *rows;
if (nbr_rows < 0)
{
/* convert nbr_rows to positive, for ease of programming */
nbr_rows = -nbr_rows;
while (TRUE)
{
if (! nbr_rows )
{
*rows = 0;
return 0;
}
if (lmp->first_fully_vis - nbr_rows >= 0)
{
int pixels;
pixels = -(lmp->pix_offsets[lmp->first_fully_vis] -
lmp->pix_offsets[lmp->first_fully_vis - nbr_rows]);
lmp->update_rows_at_top = nbr_rows;
*rows = nbr_rows;
return pixels;
}
else
{
if (!lmp->get_all_records && get_previous_rec(lmp))
{
lmp->pix_heights[0] = lm_calculate_row_height(lmp, 0);
lmp->rrr_offset -= lmp->pix_heights[0];
calculate_pix_offsets(lmp, do_redraw);
}
else
{
calculate_pix_offsets(lmp, do_redraw);
nbr_rows = lmp->first_fully_vis;
}
}
}
}
else
{
BOOLEAN get_next_accepted = TRUE;
int pixels;
pixels = lmp->pix_offsets[lmp->first_fully_vis + nbr_rows] -
lmp->pix_offsets[lmp->first_fully_vis];
while (TRUE)
{
int delta_avail;
if (! nbr_rows)
{
*rows = 0;
return 0;
}
/*
if get_all_records is true, then we never need to get more records
if there is a row beyond the last partially visible row, then we
don't need to get more records
if a get next has been refused, then we have all the records that
we are going to get
*/
if (lmp->get_all_records ||
lmp->last_fully_vis + 1 + nbr_rows < lmp->nbr_realized_rows ||
! get_next_accepted)
{
delta_avail = lmp->pix_offsets[lmp->nbr_realized_rows - 1] +
lmp->pix_heights[lmp->nbr_realized_rows - 1] +
lmp->rrr_offset - lmp->mlr_height;
if (lmp->get_all_records || pixels <= delta_avail || ! get_next_accepted)
{
int nrows, cnt, pcnt;
for (nrows = 0, cnt = lmp->last_fully_vis + 1, pcnt = 0;
pcnt < pixels && cnt < lmp->nbr_realized_rows;
++nrows, ++cnt, pcnt += lmp->pix_heights[cnt])
;
lmp->update_rows_at_bottom = nrows;
*rows = nbr_rows;
return pixels;
}
}
if (!lmp->get_all_records
&& (get_next_accepted = get_next_rec(lmp, FALSE)) != 0)
calculate_pix_offsets(lmp, do_redraw);
else
{
calculate_pix_offsets(lmp, do_redraw);
nbr_rows = lmp->nbr_realized_rows - 1 - lmp->last_fully_vis;
}
}
}
}
static int make_room_rows( LM_DATA* lm_data, int rows, BOOLEAN do_draw )
{
return make_rrr_room_rows( lm_data, &rows, do_draw );
}
/*-------------------------------------------------------------------------
function: do_scroll_bar
itf: current itf
listdata: list_data
list: list
-------------------------------------------------------------------------*/
void
do_scroll_bar(XI_LIST_DATA *listdata)
{
LM_DATA *lmp;
if (listdata->scroll_bar)
{
lmp = (LM_DATA *)listdata->lm;
if (lmp->get_all_records)
{
int top, prop;
if (lmp->rrr_offset == 0 && lmp->rrr_bottom < lmp->mlr_height)
{
top = 0;
prop = 100;
} else
{
top = (int)(-lmp->rrr_offset * 100L / lmp->rrr_bottom);
if (lmp->mlr_height - lmp->rrr_offset >= lmp->rrr_bottom - 1)
prop = 100 - top;
else
prop = (int)(lmp->mlr_height * 100L / lmp->rrr_bottom);
}
xvt_sbar_set_proportion(listdata->sb_win, HVSCROLL, prop);
xvt_sbar_set_pos(listdata->sb_win, HVSCROLL, top);
} else
{
int percent1 = 0;
int percent2 = 100;
if (lmp->nbr_realized_rows > 1)
{
do_lm_cb(listdata->lm, LM_CB_GET_PERCENT, lmp->first_fully_vis,
0, NULL, &percent1, 0);
do_lm_cb(listdata->lm, LM_CB_GET_PERCENT, lmp->last_fully_vis,
0, NULL, &percent2, 0);
}
xvt_sbar_set_proportion(listdata->sb_win, HVSCROLL, percent2 - percent1);
xvt_sbar_set_pos(listdata->sb_win, HVSCROLL, percent1);
#if XI_IS_CH
CTOS_IS_CH;
xvt_sbar_set_range(listdata->sb_win, HVSCROLL, 0, 100 - (percent2 - percent1));
CTOS_END;
#endif
}
}
}
/*-------------------------------------------------------------------------
function: lm_remove_all_rows
lm: current lm
-------------------------------------------------------------------------*/
void lm_remove_all_rows( LM_DATA* lmp, BOOLEAN delete_focus )
{
int i;
LM_CB_DATA lm_cb_data;
if (lmp->focus_rec && delete_focus )
{
int idx;
BOOLEAN found = FALSE;
for (idx = 0; idx < lmp->nbr_realized_rows; ++idx)
{
if (lmp->focus_rec == lmp->recs[idx])
{
found = TRUE;
break;
}
}
if (! found)
{
lm_cb_data.lm = (LM)lmp;
lm_cb_data.cb_type = LM_CB_REC_FREE;
lm_cb_data.cid = lmp->cid;
lm_cb_data.win = lmp->win;
lm_cb_data.v.rec_free.record = lmp->focus_rec;
(*lmp->lm_cb)(&lm_cb_data);
}
}
for (i = 0; i < lmp->nbr_realized_rows; ++i)
do_rec_event(lmp, i, XIE_REC_FREE);
lmp->nbr_realized_rows = 0;
lmp->rrr_bottom = 0;
lmp->rrr_offset = 0;
}
BOOLEAN
lm_list_has_focus(LM_DATA *lmp)
{
XI_ITF_DATA *itf;
BOOLEAN retval;
itf = lmp->itf_obj->v.itf;
retval = (itf->focus_obj != NULL && itf->focus_obj->parent == lmp->list_obj);
return retval;
}
BOOLEAN
lm_cell_has_focus( LM_DATA *lmp, int row, int column,
BOOLEAN is_vert_scrolled)
{
XI_ITF_DATA *itf;
XI_OBJ *focus_obj;
XI_CELL_DATA *cd;
if (lmp->txt_is_invisible)
return FALSE;
itf = lmp->itf_obj->v.itf;
focus_obj = itf->focus_obj;
if (focus_obj != NULL && focus_obj->parent == lmp->list_obj &&
focus_obj->type == XIT_CELL)
{
cd = &focus_obj->v.cell;
return (cd->row == row && cd->column == column
&& cd->is_vert_scrolled == is_vert_scrolled);
}
return FALSE;
}
BOOLEAN
lm_row_has_focus( LM_DATA *lmp, int row, BOOLEAN is_vert_scrolled)
{
XI_ITF_DATA *itf;
XI_OBJ *focus_obj;
XI_CELL_DATA *cd;
#if 0
if (lmp->txt_is_invisible && ! lmp->horizontally_scrolling_list)
return FALSE;
#endif
itf = lmp->itf_obj->v.itf;
focus_obj = itf->focus_obj;
if (focus_obj != NULL && focus_obj->parent == lmp->list_obj &&
focus_obj->type == XIT_CELL)
{
cd = &focus_obj->v.cell;
return (cd->row == row && cd->is_vert_scrolled == is_vert_scrolled);
}
return FALSE;
}
void
lm_get_focus_cell(LM_DATA *lmp, int *rowp, int *columnp, BOOLEAN* is_vert_scrolled)
{
XI_ITF_DATA *itf;
XI_OBJ *focus_obj;
XI_CELL_DATA *cd;
itf = lmp->itf_obj->v.itf;
focus_obj = itf->focus_obj;
if (focus_obj != NULL && focus_obj->parent == lmp->list_obj &&
focus_obj->type == XIT_CELL)
{
cd = &focus_obj->v.cell;
*rowp = cd->row;
*columnp = cd->column;
*is_vert_scrolled = cd->is_vert_scrolled;
return;
}
*rowp = 0;
*columnp = 0;
*is_vert_scrolled = FALSE;
return;
}
void lm_set_focus_cell(LM_DATA *lmp, int row, int column, BOOLEAN is_vert_scrolled)
{
XI_ITF_DATA *itf;
XI_OBJ *focus_obj;
XI_CELL_DATA *cd;
itf = lmp->itf_obj->v.itf;
focus_obj = itf->focus_obj;
if (focus_obj != NULL && focus_obj->parent == lmp->list_obj &&
focus_obj->type == XIT_CELL)
{
cd = &focus_obj->v.cell;
cd->row = row;
cd->column = column;
cd->is_vert_scrolled = (unsigned char)is_vert_scrolled;
return;
}
xvt_errmsg_sig_if(!(xi_false), NULL_WIN, SEV_FATAL,
ERR_ASSERT_4, "20921", 20921,
"lm_set_focus_cell called when list does not have focus");
}
/* -------------------------------------------------------------------------- */
/* lm_set_focus_text */
/* -------------------------------------------------------------------------- */
void lm_set_focus_text( LM_DATA* lmp, const char* new_text )
{
int len = strlen(new_text) + 1;
if (lmp->focus_cell_text)
lmp->focus_cell_text = (char *)xi_tree_realloc(lmp->focus_cell_text, len);
else
lmp->focus_cell_text = (char *)xi_tree_malloc(len, lmp);
strcpy(lmp->focus_cell_text, new_text);
}
void
lm_make_invis(LM_DATA *lmp)
{
TXT_DATA *txt;
if (! lm_list_has_focus(lmp))
return;
if (lmp->txt_is_invisible)
return;
if (lmp->txt)
{
int focus_row, focus_column;
BOOLEAN v_scrolled;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
lmp->txt_is_invisible = TRUE;
lmp->focus_rec = lmp->recs[focus_row];
lmp->focus_rec_color = lmp->row_colors[focus_row];
lmp->focus_rec_attrib = lmp->row_attribs[focus_row];
lmp->focus_rec_height = lmp->pix_heights[focus_row];
txt = lmp->txt;
lm_set_focus_text( lmp, txt->text );
lmp->focus_cell_ip1 = txt->selstart;
lmp->focus_cell_ip2 = txt->selstop;
txt_hide_caret(lmp->txt);
txt_caret(lmp->txt, FALSE);
if (lmp->focus_cell_ip1 != lmp->focus_cell_ip2)
redraw_cell((LM)lmp, focus_row, focus_column, FALSE );
xi_tree_free((char *)lmp->txt);
lmp->txt = NULL;
}
else
{
lmp->txt_is_invisible = FALSE;
}
}
/*-------------------------------------------------------------------------
function: fill_previous
returns: # of records read
-------------------------------------------------------------------------*/
static int fill_previous( LM_DATA* lmp )
{
int *pix_heights, *pix_offsets;
int offset, height;
int i;
int result = 0;
while (TRUE)
{
if (! get_previous_rec(lmp))
break;
result++;
/* recalculate the heights and offsets of every row */
lmp->pix_heights[0] = lm_calculate_row_height(lmp, 0);
offset = 0;
for (i = 0, pix_heights = &lmp->pix_heights[0],
pix_offsets = &lmp->pix_offsets[0];
i < lmp->nbr_realized_rows;
++i, ++pix_heights, ++pix_offsets)
{
*pix_offsets = offset;
offset += *pix_heights;
}
calculate_visibles(lmp);
/*
if we finally have enough rows to display the entire list
note: we subtract 1 from the space necessary because it is not
necessary to create space for the pixel at the bottom of the
last row.
*/
height = lmp->pix_heights[lmp->nbr_realized_rows - 1];
if (! height)
height = lmp->pix_row_spacing;
if (! lmp->get_all_records &&
(lmp->pix_offsets[lmp->nbr_realized_rows - 1] +
height - 1
>= lmp->mlr_height))
break;
}
calculate_pix_offsets(lmp, FALSE);
lmp->rrr_bottom = lmp->pix_offsets[lmp->nbr_realized_rows - 1]
+ lmp->pix_heights[lmp->nbr_realized_rows - 1];
/*
subtract 1 from rrr_bottom because of the pixel at the bottom of the
last row.
*/
lmp->rrr_offset = lmp->mlr_height - (lmp->rrr_bottom - 1);
lmp->rrr_offset = min(0, lmp->rrr_offset);
/*
although we have adjusted pix_offsets, and pix_heights, it is still necessary to calculate
the first and last fully visible rows
*/
calculate_visibles(lmp);
/*
if the page down does not make the first row editable, then
scroll the exact amount to make it editable
*/
if (-lmp->rrr_offset !=
lmp->pix_offsets[lmp->first_fully_vis])
{
lmp->rrr_offset = -lmp->pix_offsets[lmp->first_fully_vis];
calculate_visibles(lmp);
}
return result;
}
/*-------------------------------------------------------------------------*/
/* data structure for passing around lm_scroll functions */
/*-------------------------------------------------------------------------*/
typedef struct {
int nbr_lines;
int percent;
long rec;
BOOLEAN have_rec;
COLOR color;
unsigned long attrib;
int row_height_arg;
int scroll_type;
int pix_overlap;
int nbr_pixels;
RCT focus_cell_rct;
BOOLEAN have_pixels;
BOOLEAN list_had_focus;
BOOLEAN is_first_or_last;
int focus_row;
int focus_column;
BOOLEAN v_scrolled;
int pixels_scrolled;
} lm_scroll_data;
/*-------------------------------------------------------------------------*/
/* lm_scroll_data_construct */
/*-------------------------------------------------------------------------*/
static void lm_scroll_data_construct( LM_DATA* lmp, lm_scroll_data* data,
LM_SCROLL_ARG* arg )
{
int pref_overlap;
data->nbr_lines = arg->nbr_lines;
data->percent = arg->percent;
data->rec = arg->rec;
data->have_rec = arg->have_rec;
data->color = arg->color;
data->attrib = arg->attrib;
data->row_height_arg = arg->row_height;
data->have_pixels = FALSE;
data->list_had_focus = FALSE;
data->is_first_or_last = FALSE;
if (arg->nbr_lines == XI_SCROLL_FIRST && arg->percent == 100)
data->nbr_lines = XI_SCROLL_LAST;
if (! lmp->nbr_realized_rows)
data->nbr_lines = XI_SCROLL_FIRST;
if (arg->have_rec)
{
if (arg->rec_at_top)
data->nbr_lines = XI_SCROLL_FIRST;
else
data->nbr_lines = XI_SCROLL_LAST;
}
data->scroll_type = data->nbr_lines;
pref_overlap = (int)xi_get_pref(XI_PREF_OVERLAP);
data->pix_overlap = pref_overlap * lmp->pix_row_spacing;
data->pixels_scrolled = 0;
}
/*-------------------------------------------------------------------------*/
/* lm_scroll_remove focus */
/*-------------------------------------------------------------------------*/
static BOOLEAN lm_scroll_remove_focus( LM_DATA* lmp, lm_scroll_data* data,
XI_OBJ* old_focus_obj )
{
/* remove the focus from the list being scrolled */
if (lm_list_has_focus(lmp))
{
data->list_had_focus = TRUE;
lm_get_focus_cell( lmp, &data->focus_row, &data->focus_column,
&data->v_scrolled );
if (xi_get_pref(XI_PREF_UNUSED_PREFERENCE))
{
if (lmp->focus_rec == 0)
{
lm_make_invis(lmp);
switch (data->nbr_lines)
{
case XI_SCROLL_FIRST:
{
int current_percent;
do_lm_cb( (LM)lmp, LM_CB_GET_PERCENT,
lmp->first_fully_vis, 0, NULL,&current_percent, 0);
lmp->focus_rec_is_above = (data->percent > current_percent);
break;
}
case XI_SCROLL_LAST:
lmp->focus_rec_is_above = TRUE;
break;
case XI_SCROLL_PGUP:
lmp->focus_rec_is_above = FALSE;
break;
case XI_SCROLL_PGDOWN:
lmp->focus_rec_is_above = TRUE;
break;
default:
lmp->focus_rec_is_above = (data->nbr_lines > 0);
break;
}
}
}
else
{
xi_get_rect(old_focus_obj, &data->focus_cell_rct);
if (! xi_move_focus(lmp->itf_obj))
return FALSE;
}
}
return TRUE;
}
/*------------------------------------------------------------------------- */
/* lm_scroll_calc_lines */
/* if nbr_lines is not an integral, and instead is one of XI_SCROLL_FIRST, */
/* XI_SCROLL_LAST, XI_SCROLL_PGUP, or XI_SCROLL_PGDOWN, then calculate */
/* the number of lines. */
/*------------------------------------------------------------------------- */
static void lm_scroll_calc_lines( LM_DATA* lmp, lm_scroll_data* data )
{
switch (data->nbr_lines)
{
case XI_SCROLL_FIRST:
case XI_SCROLL_LAST:
data->is_first_or_last = TRUE;
break;
case XI_SCROLL_PGUP:
#if XI_IS_CH
CTOS_IS_CH;
data->nbr_pixels = -(lmp->mlr_height - data->pix_overlap);
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
data->nbr_pixels = -(lmp->mlr_height - data->pix_overlap + 1);
CTOS_END;
#endif
data->have_pixels = TRUE;
break;
case XI_SCROLL_PGDOWN:
#if XI_IS_CH
CTOS_IS_CH;
data->nbr_pixels = lmp->mlr_height - data->pix_overlap;
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
data->nbr_pixels = lmp->mlr_height - data->pix_overlap + 1;
CTOS_END;
#endif
data->have_pixels = TRUE;
break;
}
}
/*------------------------------------------------------------------------- */
/* lm_scroll_get_initial_rec */
/*------------------------------------------------------------------------- */
static BOOLEAN lm_scroll_get_initial_rec( LM_DATA* lmp, lm_scroll_data* data,
int record_location, int event_type )
{
int row_height;
BOOLEAN refused;
/* first, get rid of all rows */
lm_remove_all_rows( lmp, FALSE );
make_rec_available(lmp, (BOOLEAN)record_location, (BOOLEAN)!data->have_rec, TRUE);
if (data->have_rec)
{
lmp->recs[0] = data->rec;
lmp->row_colors[0] = data->color;
lmp->row_attribs[0] = data->attrib;
row_height = data->row_height_arg;
refused = FALSE;
}
else
{
refused = do_lm_cb_get( (LM)lmp, event_type, &lmp->recs[0], &lmp->recs[0],
data->percent, &lmp->row_colors[0],
&lmp->row_attribs[0], &row_height);
if (refused)
{
do_rec_event(lmp, lmp->nbr_realized_rows - 1, XIE_REC_FREE);
--lmp->nbr_realized_rows;
calculate_visibles(lmp);
}
}
if (! refused)
{
if (row_height)
{
lmp->pix_heights[0] = row_height;
lmp->set_heights[0] = TRUE;
}
else
{
lmp->pix_heights[0] = 0;
lmp->set_heights[0] = FALSE;
}
lmp->pix_offsets[0] = 0;
lmp->pix_heights[0] = lm_calculate_row_height(lmp, 0);
lm_invalidate_rows_internal((LM)lmp, 0, 0, FALSE, -1, TRUE );
}
return !refused;
}
/*------------------------------------------------------------------------- */
/* lm_scroll_fill_forward */
/* returns # of records read if fill previous called, otherwise 0 */
/*------------------------------------------------------------------------- */
static int lm_scroll_fill_forward( LM_DATA* lmp, BOOLEAN have_rec )
{
BOOLEAN refused;
while (TRUE)
{
int idx;
refused = !get_next_rec(lmp, TRUE);
if ( refused )
break;
idx = lmp->nbr_realized_rows - 1;
lmp->pix_heights[idx] = lm_calculate_row_height(lmp, idx);
if (idx > 0)
lmp->pix_offsets[idx] = lmp->pix_offsets[idx - 1]
+ lmp->pix_heights[idx - 1];
else
lmp->pix_offsets[idx] = 0;
/* if we finally have enough rows to display the entire list */
if (!lmp->get_all_records && ( lmp->pix_offsets[idx] + lmp->pix_heights[idx]
>= lmp->mlr_height))
break;
}
/*
although we have adjusted pix_offsets, and pix_heights, it is still
necessary to calculate the first and last fully visible rows
*/
calculate_visibles(lmp);
/*
If we have the first record and the list is not full, try getting
previous records.
*/
if ( have_rec && refused )
return fill_previous( lmp );
return 0;
}
/*------------------------------------------------------------------------- */
/* lm_scroll_first */
/* returns row # of first record requested - i.e. for xi_scroll_rec, the */
/* row # of the new record. for scroll first with a percentage, the */
/* row # of that percentage. Normally 0, but with back-fill, can be */
/* a positive number. */
/*------------------------------------------------------------------------- */
static int lm_scroll_first( LM_DATA* lmp, lm_scroll_data* data )
{
int result = 0;
if ( (lmp->get_all_records || lmp->keep_all_records)
&& lmp->nbr_realized_rows > 0)
{
/* have_rec */
lmp->rrr_offset = -(int)((long)lmp->rrr_bottom * data->percent / 100);
calculate_visibles(lmp);
lmp->rrr_offset = -lmp->pix_offsets[lmp->first_fully_vis];
} else
{
if (lm_scroll_get_initial_rec( lmp, data, REC_AT_BOTTOM, LM_CB_GET_FIRST ))
result = lm_scroll_fill_forward( lmp, data->have_rec );
if (! lmp->get_all_records && ! lmp->keep_all_records)
{
int nbr_to_free, cnt, idx;
nbr_to_free = lmp->first_fully_vis - 1;
if ( nbr_to_free > 0 )
{
for (cnt = 0; cnt < nbr_to_free; cnt++)
{
lmp->rrr_offset += lmp->pix_heights[cnt];
do_rec_event(lmp, cnt, XIE_REC_FREE);
}
for (idx = nbr_to_free; idx < lmp->nbr_realized_rows; ++idx)
row_copy(lmp, idx, idx - nbr_to_free);
result -= nbr_to_free;
adjust_rows(lmp, -nbr_to_free);
lmp->nbr_realized_rows -= nbr_to_free;
}
/* free any unnecessary records at the end of the list */
nbr_to_free = lmp->nbr_realized_rows - (lmp->last_fully_vis + 2);
for (idx = lmp->nbr_realized_rows - nbr_to_free, cnt = 0;
cnt < nbr_to_free; idx++, cnt++)
do_rec_event(lmp, idx, XIE_REC_FREE);
lmp->nbr_realized_rows -= cnt;
calculate_pix_offsets(lmp, FALSE);
}
}
return result;
}
/*------------------------------------------------------------------------- */
/* lm_scroll_last */
/* returns row # of requested row */
/*------------------------------------------------------------------------- */
static int lm_scroll_last( LM_DATA* lmp, lm_scroll_data* data )
{ /* scroll last */
int result = 0;
if (lmp->get_all_records)
{
if (lmp->rrr_bottom < lmp->mlr_height)
lmp->rrr_offset = 0;
else
#if XI_IS_CH
CTOS_IS_CH;
lmp->rrr_offset = lmp->mlr_height - lmp->rrr_bottom;
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
lmp->rrr_offset = lmp->mlr_height - lmp->rrr_bottom + 1;
CTOS_END;
#endif
calculate_visibles(lmp);
/*
if the page up does not make the first row editable, then
scroll the exact amount to make it editable
*/
if (-lmp->rrr_offset !=
lmp->pix_offsets[lmp->first_fully_vis])
{
int p;
p = lmp->pix_offsets[lmp->first_fully_vis] +
lmp->rrr_offset;
data->nbr_pixels += p;
lmp->rrr_offset -= p;
calculate_visibles(lmp);
}
} else
{
data->percent = 0;
if (lm_scroll_get_initial_rec( lmp, data, REC_AT_TOP, LM_CB_GET_LAST ))
{
result = fill_previous( lmp );
/*
get one record after the last record, so that there will not be a
gray space below the last record, unless there are no more records.
*/
get_next_rec(lmp, FALSE);
calculate_pix_offsets(lmp, FALSE);
}
}
return result;
}
/*------------------------------------------------------------------------- */
/* lm_scroll_calc_pixels */
/*------------------------------------------------------------------------- */
static void lm_scroll_calc_pixels( LM_DATA* lmp, lm_scroll_data* data )
{
/* calculate the max number of pixels that we should scroll */
if (data->nbr_pixels < 0)
{
int p;
data->nbr_pixels = max(data->nbr_pixels, lmp->rrr_offset);
lmp->rrr_offset -= data->nbr_pixels;
calculate_visibles(lmp);
/*
if the page up does not make the first row editable, then
scroll the exact amount to make it editable
*/
if (-lmp->rrr_offset !=
lmp->pix_offsets[lmp->first_fully_vis])
{
p = lmp->pix_offsets[lmp->first_fully_vis - 1] +
lmp->rrr_offset;
data->nbr_pixels += p;
lmp->rrr_offset -= p;
calculate_visibles(lmp);
}
} else
{
int p;
calculate_pix_offsets(lmp, FALSE);
/*
following line puts row coming onto the list at the bottom of the list
completly on the list. new behavior is to have the row at the top of
the list to always be completely on the list.
nbr_pixels = min(nbr_pixels, lmp->rrr_bottom - lmp->mlr_height + lmp->rrr_offset);
*/
data->nbr_pixels = max(data->nbr_pixels, 0);
lmp->rrr_offset -= data->nbr_pixels;
calculate_visibles(lmp);
/*
if the page down does not make the first row editable, then
scroll the exact amount to make it editable
*/
if (-lmp->rrr_offset !=
lmp->pix_offsets[lmp->first_fully_vis])
{
p = lmp->pix_offsets[lmp->first_fully_vis - 1] +
lmp->rrr_offset;
data->nbr_pixels += p;
lmp->rrr_offset -= p;
calculate_visibles(lmp);
}
/*
if the page down leaves too much room at the bottom, then make more
rows visible.
*/
while (TRUE)
{
int h, pix_left;
if (lmp->first_fully_vis == 0)
break;
h = lmp->pix_heights[lmp->first_fully_vis - 1];
/*
Add 1 to pix_left (pixels left in mlr), because it is ok for the pixel
required for the rule at the bottom of the row to fall below the
visible portion of the list.
*/
pix_left = -(lmp->pix_offsets[lmp->nbr_realized_rows - 1] +
lmp->pix_heights[lmp->nbr_realized_rows - 1] +
lmp->rrr_offset - lmp->mlr_height) + 1;
if (pix_left < h)
break;
data->nbr_pixels -= h;
lmp->rrr_offset += h;
calculate_visibles(lmp);
}
}
}
/*-------------------------------------------------------------------------
function: lm_get_scroll_rct
lmp: current lmp
r: pointer to rectangle to be filled in
returns: r
-------------------------------------------------------------------------*/
static RCT* lm_get_scroll_rct(LM_DATA *lmp, RCT *r)
{
*r = lmp->mlr;
if (lmp->pixel_width)
r->right = r->left + lmp->pixel_width + 2 * BORDER_WIDTH;
return r;
}
/*------------------------------------------------------------------------- */
/* lm_scroll_middle */
/*------------------------------------------------------------------------- */
static int lm_scroll_middle( LM_DATA* lmp, lm_scroll_data* data,
BOOLEAN invalidate )
{
int recs_read;
recs_read = 0;
if (data->have_pixels)
recs_read = lm_make_rrr_room_pix(lmp, data->nbr_pixels, FALSE);
else if (data->nbr_lines)
{
recs_read = data->nbr_lines;
data->nbr_pixels = make_rrr_room_rows(lmp, &recs_read, FALSE);
}
lm_scroll_calc_pixels( lmp, data );
if (! lmp->get_all_records && ! lmp->keep_all_records)
{
int nbr_to_free, cnt, idx;
nbr_to_free = lmp->first_fully_vis;
if (nbr_to_free)
{
for (cnt = 0; cnt < nbr_to_free; cnt++)
{
lmp->rrr_offset += lmp->pix_heights[cnt];
do_rec_event(lmp, cnt, XIE_REC_FREE);
}
for (cnt = nbr_to_free; cnt < lmp->nbr_realized_rows; ++cnt)
row_copy(lmp, cnt, cnt - nbr_to_free);
adjust_rows(lmp, -nbr_to_free);
lmp->nbr_realized_rows -= nbr_to_free;
}
/* free any unnecessary records at the end of the list */
nbr_to_free = lmp->nbr_realized_rows - (lmp->last_fully_vis + 2);
for (idx = lmp->nbr_realized_rows - nbr_to_free, cnt = 0;
cnt < nbr_to_free;
idx++, cnt++)
do_rec_event(lmp, idx, XIE_REC_FREE);
lmp->nbr_realized_rows -= cnt;
for (idx = lmp->nbr_realized_rows;
idx < lmp->realized_rows_array_len;
++idx)
init_row(lmp, idx);
calculate_pix_offsets(lmp, FALSE);
}
if (invalidate)
{
RCT r;
lm_get_scroll_rct(lmp, &r);
xi_set_clip(lmp->win, NULL);
if (data->nbr_pixels)
{
xvt_dwin_update(lmp->win);
xi_set_update_obj(lmp->list_obj);
lmp->update_cells_only = TRUE;
xi_scroll_rect(lmp->win, &r, 0, -data->nbr_pixels);
data->pixels_scrolled = data->nbr_pixels;
}
}
return recs_read;
}
/*------------------------------------------------------------------------- */
/* lm_scroll_replace_focus */
/*------------------------------------------------------------------------- */
static void lm_scroll_replace_focus( LM_DATA* lmp, lm_scroll_data* data,
XI_OBJ* old_focus_obj, BOOLEAN same_cell )
{
/* put the focus back */
if (data->list_had_focus)
{
if (old_focus_obj->type == XIT_CELL)
{
if (xi_get_pref(XI_PREF_UNUSED_PREFERENCE))
lm_make_vis(lmp);
else
{
if (same_cell)
{
int col = old_focus_obj->v.cell.column;
int row, t, b;
int max_intersect, intersect_row;
XI_OBJ cell;
RCT cell_rct;
int tr;
max_intersect = 0;
intersect_row = -1;
tr = min(lmp->nbr_realized_rows, lmp->last_fully_vis + 1);
for (row = lmp->first_fully_vis; row < tr; ++row)
{
XI_MAKE_CELL(&cell, lmp->list_obj, (unsigned char)row,
(unsigned char)col);
xi_get_rect(&cell, &cell_rct);
t = max(cell_rct.top, data->focus_cell_rct.top);
b = min(cell_rct.bottom, data->focus_cell_rct.bottom);
if ((b - t) > max_intersect)
{
max_intersect = b - t;
intersect_row = row;
}
}
if (intersect_row != -1)
{
XI_MAKE_CELL(&cell, lmp->list_obj, (unsigned char)intersect_row,
(unsigned char)col);
xi_move_focus(&cell);
}
}
else
{
switch (data->scroll_type)
{
case XI_SCROLL_FIRST:
case XI_SCROLL_PGUP:
data->focus_row = lmp->first_fully_vis;
break;
case XI_SCROLL_LAST:
case XI_SCROLL_PGDOWN:
data->focus_row = lmp->last_fully_vis;
break;
default:
data->focus_row = clip( data->focus_row, lmp->first_fully_vis,
lmp->last_fully_vis);
break;
}
}
}
}
else
xi_move_focus(old_focus_obj);
}
}
/*-------------------------------------------------------------------------
function: lm_scroll
lm: current lm
nbr_lines: nbr of lines to scroll, may be positive or negative, may be set
to XI_SCROLL_FIRST, XI_SCROLL_LAST, XI_SCROLL_PGUP, or XI_SCROLL_PGDN
percent: passed with XI_SCROLL_FIRST event
same_cell: sometimes the focus goes back onto the same cell. In other cases,
for instance, XI_SCROLL_FIRST, XI_SCROLL_LAST, XI_SCROLL_PGUP, and
XI_SCROLL_PGDN, we don't want to put the focus back on the same cell,
but instead, want to put the focus on the first or last fully visible
row.
invalidate: indicates whether to invalidate the list. This is only set to FALSE when
xi_scroll_internal is called when the interface is created.
rec: if have_rec is TRUE, then use rec for the first record, and don't do get first
-------------------------------------------------------------------------*/
int lm_scroll(LM_SCROLL_ARG *arg)
{
lm_scroll_data data;
int result = 0;
XI_OBJ* old_focus_obj;
LM_DATA* lmp = (LM_DATA*)arg->lm;
XI_OBJ* itf = lmp->itf_obj;
BOOLEAN invalidate = !itf->v.itf->half_baked;
if ((xi_get_attrib(lmp->list_obj) & XI_ATR_VISIBLE) == 0)
invalidate = FALSE;
lm_scroll_data_construct( lmp, &data, arg );
/*
If the focus is on the first row, and scrolling up, or the focus is on the
last row and scrolling down, return 0.
*/
if (lmp->get_all_records)
{
if (lmp->first_fully_vis == 0 && data.nbr_lines < 0)
return 0;
if (lmp->last_fully_vis == lmp->nbr_realized_rows &&
data.nbr_lines > 0 && data.nbr_lines < XI_SCROLL_PGUP)
return 0;
}
if (! lmp->itf_obj->v.itf->half_baked && invalidate)
xvt_dwin_update(lmp->win);
old_focus_obj = itf->v.itf->focus_obj;
if (!lm_scroll_remove_focus( lmp, &data, old_focus_obj ))
return 0;
lm_scroll_calc_lines( lmp, &data );
if (data.is_first_or_last)
{
if (data.nbr_lines == XI_SCROLL_FIRST)
result = lm_scroll_first( lmp, &data );
else
result = lm_scroll_last( lmp, &data );
if (invalidate)
{
RCT r;
xi_invalidate_rect(lmp->win, lm_get_scroll_rct(lmp, &r));
}
} else
{
result = lm_scroll_middle( lmp, &data, invalidate );
arg->pixels_scrolled = data.pixels_scrolled;
}
lm_scroll_replace_focus( lmp, &data, old_focus_obj, arg->same_cell );
if (lmp->row_focus_border && lmp->nbr_realized_rows > 0)
{
int focus_row, focus_column;
BOOLEAN is_vert_scrolled;
BOOLEAN is_hscrolled;
BOOLEAN is_vis;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &is_vert_scrolled);
is_vis = lm_is_cell_visible( lmp, focus_row, focus_column, TRUE,
&is_hscrolled);
if ((is_vis || is_hscrolled) && !is_vert_scrolled )
{
lm_redraw_row(lmp, focus_row, FALSE);
if ( lmp->txt != NULL )
txt_redraw(lmp->txt, FALSE);
}
}
do_scroll_bar( lmp->list_obj->v.list );
if (invalidate)
xvt_dwin_update( lmp->win );
return result;
}
/*-------------------------------------------------------------------------
function: lm_set_text
lm: current lm
s: string to set
row:
column:
-------------------------------------------------------------------------*/
void lm_set_text(LM lm, char *s, int row, int column, BOOLEAN v_scrolled )
{
BOOLEAN was_suspended = FALSE;
LM_COLUMN_DATA *lmcd;
RCT rct;
LM_DATA *lmp = LMP(lm);
lmcd = lmp->lm_column_data[column];
if (row == LM_HEADING_TEXT)
{
lmcd->heading_text = (char *)xi_tree_realloc(lmcd->heading_text,
strlen(s) + 1);
strcpy(lmcd->heading_text, s);
lm_get_cell_rect(&rct, lm, 1, column, FALSE, TRUE);
rct.top = lmp->pix_hdr_bottom -
max(lmp->pix_cell_height, lmp->min_heading_height +
2 * BORDER_WIDTH);
rct.bottom = lmp->pix_hdr_bottom;
if ( (lmp->attrib & LM_ATR_VISIBLE) != 0)
xi_invalidate_rect(lmp->win, &rct);
} else
{
int new_row_height;
int focus_row, focus_column;
BOOLEAN v_scroll;
if (lm_cell_has_focus(lmp, row, column, v_scrolled))
{
was_suspended = TRUE;
lm_make_invis(lmp);
}
if (!v_scrolled)
tgstrncpy( lmp->buffer[row] + lmcd->text_offset, s, lmcd->text_size);
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scroll);
if (lmp->txt_is_invisible && row == focus_row && column == focus_column)
{
int len;
len = strlen(s) + 1;
if (lmp->focus_cell_text)
lmp->focus_cell_text = (char *)xi_tree_realloc(lmp->focus_cell_text, len);
else
lmp->focus_cell_text = (char *)xi_tree_malloc(len, lmp);
strcpy(lmp->focus_cell_text, s);
if (lmp->lm_column_data[column]->attrib | XI_ATR_AUTOSELECT)
{
lmp->focus_cell_ip1 = 0;
lmp->focus_cell_ip2 = strlen(s);
}
else
{
lmp->focus_cell_ip1 = 0;
lmp->focus_cell_ip2 = 0;
}
}
if (!v_scrolled)
{
new_row_height = lm_calculate_row_height(lmp, row);
if (new_row_height != lmp->pix_heights[row])
lm_set_row_height(lm, row, new_row_height, FALSE, 0, FALSE);
if (LMP(lm)->attrib & XI_ATR_VISIBLE)
redraw_cell(lm, row, column, FALSE );
}
if (was_suspended)
lm_make_vis(lmp);
}
}
/*-------------------------------------------------------------------------
function: next cell
lm: current lm
c: character causing the focus to change
next_row: int pointer to be filled in with next row
next_col: int pointer to be filled in with next column
-------------------------------------------------------------------------*/
static void
next_cell(LM lm, int c, int *next_row, int *next_col)
{
LM_DATA *lmp = LMP(lm);
switch (c)
{
case K_BTAB:
--*next_col;
if (*next_col < 0)
{
*next_col = lmp->nbr_columns - 1;
if ((lmp->attrib & LM_ATR_TABWRAP))
--*next_row;
}
break;
case '\t':
++*next_col;
if (*next_col >= lmp->nbr_columns)
{
*next_col = 0;
if ((lmp->attrib & LM_ATR_TABWRAP))
++*next_row;
}
break;
case K_UP:
--*next_row;
break;
case K_DOWN:
++*next_row;
break;
case K_WLEFT:
case K_LEFT:
--*next_col;
if (*next_col < 0)
*next_col = lmp->nbr_columns - 1;
break;
case K_WRIGHT:
case K_RIGHT:
++*next_col;
if (*next_col >= lmp->nbr_columns)
*next_col = 0;
break;
}
}
/*-------------------------------------------------------------------------
function: do_lm_cb
lm: current lm
cb_reason: one of LM_CB_CHAR, LM_CB_CHANGE, LM_CB_FOCUS, LM_CB_REC_ALLOCATE,
LM_CB_REC_FREE
row: relevent row
column: relevent column
ep: xvt event that caused the LM event, used to pass on shift and control
-------------------------------------------------------------------------*/
BOOLEAN
do_lm_cb(LM lm, LM_CB_TYPE cb_reason, int row, int column, EVENT *ep, int *percent, int pixels)
{
LM_CB_DATA lm_cb_data;
LM_DATA *lmp = LMP(lm);
lm_cb_data.lm = lm;
lm_cb_data.cb_type = cb_reason;
lm_cb_data.cid = lmp->cid;
lm_cb_data.win = lmp->win;
lm_cb_data.row = (unsigned char)row;
lm_cb_data.column = (unsigned char)column;
switch (cb_reason)
{
case LM_CB_REC_ALLOCATE:
lm_cb_data.v.rec_allocate.record = lmp->recs[row];
if (lm_cb_data.v.rec_allocate.record)
return FALSE;
break;
case LM_CB_REC_FREE:
lm_cb_data.v.rec_free.record = lmp->recs[row];
if (! lm_cb_data.v.rec_allocate.record)
return FALSE;
break;
case LM_CB_CHAR:
lm_cb_data.v.chr.ch = ep->v.chr.ch;
lm_cb_data.v.chr.shift = ep->v.chr.shift;
lm_cb_data.v.chr.control = ep->v.chr.control;
lm_cb_data.v.chr.is_paste = FALSE;
lm_cb_data.v.chr.refused = FALSE;
break;
case LM_CB_CELL_BTN:
lm_cb_data.v.cell_btn.shift = ep->v.chr.shift;
lm_cb_data.v.cell_btn.control = ep->v.chr.control;
break;
case LM_CB_GET_PERCENT:
lm_cb_data.v.get_percent.record = lmp->recs[row];
break;
case LM_CB_ROW_SIZE:
lm_cb_data.v.row_size.new_row_height = pixels;
break;
default:
lm_cb_data.v.refused = FALSE;
break;
}
(*lmp->lm_cb)(&lm_cb_data);
/* retval = FALSE if event refused */
switch (cb_reason)
{
case LM_CB_REC_ALLOCATE:
lmp->recs[row] = lm_cb_data.v.rec_allocate.record;
return FALSE;
case LM_CB_REC_FREE:
lmp->recs[row] = 0L;
return FALSE;
case LM_CB_CHAR:
if (! lm_cb_data.v.chr.refused)
ep->v.chr.ch = lm_cb_data.v.chr.ch;
return (! lm_cb_data.v.chr.refused);
case LM_CB_GET_PERCENT:
*percent = lm_cb_data.v.get_percent.percent;
return FALSE;
case LM_CB_ROW_SIZE:
return (! lm_cb_data.v.row_size.refused);
default:
return (! lm_cb_data.v.refused);
}
}
/*-------------------------------------------------------------------------
function: do_lm_cb_get
lm: current lm
cb_reason: one of LM_CB_GET_FIRST, LM_CB_GET_LAST, LM_CB_GET_NEXT,
LM_CB_GET_PREV
spec_rec:
data_rec:
percent:
returns: TRUE if event refused
-------------------------------------------------------------------------*/
BOOLEAN
do_lm_cb_get(LM lm, LM_CB_TYPE cb_reason, long *spec_rec,
long *data_rec, int percent, COLOR *color, unsigned long *attrib, int *row_height)
{
LM_CB_DATA lm_cb_data;
LM_DATA *lmp = LMP(lm);
lm_cb_data.lm = lm;
lm_cb_data.cb_type = cb_reason;
lm_cb_data.cid = lmp->cid;
lm_cb_data.win = lmp->win;
lm_cb_data.v.rec_request.spec_rec = *spec_rec;
lm_cb_data.v.rec_request.data_rec = *data_rec;
lm_cb_data.v.rec_request.percent = percent;
lm_cb_data.v.rec_request.color = *color;
lm_cb_data.v.rec_request.attrib = *attrib;
lm_cb_data.v.rec_request.refused = FALSE;
(*lmp->lm_cb)(&lm_cb_data);
/* retval = FALSE if event refused */
if (! lm_cb_data.v.rec_request.refused)
{
*data_rec = lm_cb_data.v.rec_request.data_rec;
*color = lm_cb_data.v.rec_request.color;
*attrib = lm_cb_data.v.rec_request.attrib;
#if XI_IS_NOT_CH
CTOS_IS_PM;
*row_height = lm_cb_data.v.rec_request.row_height;
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
*row_height = 0;
CTOS_END;
#endif
if ( lm_cb_data.v.rec_request.has_focus
&& xi_get_pref(XI_PREF_UNUSED_PREFERENCE) )
{
if ( lmp->focus_rec )
{
lm_cb_data.lm = (LM)lmp;
lm_cb_data.cb_type = LM_CB_REC_FREE;
lm_cb_data.cid = lmp->cid;
lm_cb_data.win = lmp->win;
lm_cb_data.v.rec_free.record = lmp->focus_rec;
(*lmp->lm_cb)(&lm_cb_data);
}
lmp->focus_rec = *data_rec;
}
}
return lm_cb_data.v.rec_request.refused;
}
static void calculate_next_cell( LM_DATA *lmp, int *next_row, int *next_col,
BOOLEAN *use_key, EVENT *ep, BOOLEAN *off_top,
BOOLEAN *off_bottom)
{
BOOLEAN keep_looking;
int focus_row, focus_column;
BOOLEAN v_scrolled;
keep_looking = *use_key;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
*next_row = focus_row;
*next_col = focus_column;
while (keep_looking)
{
next_cell((LM)lmp, ep->v.chr.ch, next_row, next_col);
if (*next_row < 0)
{
/* off top logic */
if (lmp->get_all_records)
{
*use_key = FALSE;
break;
}
else
{
keep_looking = FALSE;
*off_top = TRUE;
}
}
else
if (*next_row >= lmp->nbr_realized_rows)
{
/* off bottom logic */
if (lmp->get_all_records)
{
*use_key = FALSE;
break;
}
else
{
keep_looking = FALSE;
*off_bottom = TRUE;
}
}
else
if ( CELL_IS_ENABLED(lmp, *next_row, *next_col)
&& !CELL_IS_SELECTABLE(lmp, *next_row, *next_col)
&& lmp->cell_data[*next_row][*next_col].icon_rid
== 0 )
{
/* found a valid cell */
keep_looking = FALSE;
}
}
}
static void adjust_rows(LM_DATA *lmp, int delta)
{
XI_OBJ *focus_obj;
focus_obj = lmp->itf_obj->v.itf->focus_obj;
if (focus_obj && focus_obj->cid == lmp->cid)
{
if (focus_obj && focus_obj->type == XIT_CELL)
{
focus_obj->v.cell.row += delta;
if ( !focus_obj->v.cell.is_vert_scrolled
&& (long)focus_obj->v.cell.row >= (long)lmp->nbr_realized_rows )
focus_obj->v.cell.is_vert_scrolled = TRUE;
}
if (focus_obj && focus_obj->type == XIT_ROW)
focus_obj->v.row += delta;
}
}
/*-------------------------------------------------------------------------
function: navigate_char_event
lm: current lm
ep: xvt event
returns: TRUE if key was used.
-------------------------------------------------------------------------*/
BOOLEAN
navigate_char_event(LM lm, EVENT *ep)
{
BOOLEAN use_key = FALSE;
BOOLEAN off_top = FALSE;
BOOLEAN off_bottom = FALSE;
BOOLEAN should_redraw = TRUE;
int next_row, next_col, row_inc, col_inc;
LM_DATA *lmp = LMP(lm);
if (!lm_list_has_focus(lmp))
return FALSE;
switch (ep->v.chr.ch) {
case '\t':
case K_BTAB:
case K_UP:
case K_DOWN:
use_key = TRUE;
break;
case K_WRIGHT:
case K_WLEFT:
case K_LEFT:
case K_RIGHT:
if ((lmp->attrib & LM_ATR_NAVIGATE) || ep->v.chr.control)
use_key = TRUE;
break;
}
calculate_next_cell(lmp, &next_row, &next_col,
&use_key, ep, &off_top, &off_bottom);
if (use_key)
{
XI_LIST_DATA *list_data;
list_data = lmp->list_obj->v.list;
if (off_top || off_bottom)
{
int old_row_height, focus_row, focus_column;
BOOLEAN v_scrolled;
BOOLEAN do_redraw;
lm_make_invis(lmp);
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
old_row_height = lmp->pix_heights[focus_row];
do_redraw = (lm_calculate_row_height(lmp, focus_row) != old_row_height);
if (off_top)
make_room_rows(lmp, -1, do_redraw);
else
make_room_rows(lmp, 1, do_redraw);
/*
calculate next cell again, because the desired next cell
may have changed.
*/
calculate_next_cell( lmp, &next_row, &next_col, &use_key, ep, &off_top,
&off_bottom);
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
row_inc = next_row - focus_row;
col_inc = next_col - focus_column;
next_row = focus_row + row_inc;
if (next_row >= lmp->nbr_realized_rows)
next_row = lmp->nbr_realized_rows - 1;
if (next_row < 0)
next_row = 0;
next_col = focus_column + col_inc;
while (TRUE)
{
if (CELL_IS_ENABLED(lm, next_row, next_col) &&
! CELL_IS_SELECTABLE(lm, next_row, next_col))
break;
next_cell(lm, off_bottom ? '\t' :
K_BTAB, &next_row, &next_col);
}
if (list_data->vert_sync_list &&
! list_data->scrolling_in_progress)
{
XI_OBJ *other_list;
list_data->scrolling_in_progress = TRUE;
other_list = xi_get_obj(lmp->itf_obj,
list_data->vert_sync_list);
if (other_list)
xi_scroll(other_list, off_top ? -1 : 1);
xvt_dwin_update(lmp->win);
list_data->scrolling_in_progress = FALSE;
}
xvt_dwin_update(lmp->win);
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
if (focus_row > lmp->last_fully_vis)
{
lm_force_vis(lmp);
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
next_row = focus_row;
calculate_pix_offsets( lmp, FALSE );
}
lm_make_vis(lmp);
}
else if (next_row < lmp->first_fully_vis || next_row > lmp->last_fully_vis)
{
if (list_data->vert_sync_list &&
! list_data->scrolling_in_progress)
{
XI_OBJ *other_list;
list_data->scrolling_in_progress = TRUE;
other_list = xi_get_obj(lmp->itf_obj,
list_data->vert_sync_list);
if (other_list)
xi_scroll(other_list,
next_row < lmp->first_fully_vis ? -1 : 1);
xvt_dwin_update(lmp->win);
list_data->scrolling_in_progress = FALSE;
}
}
if (next_row < lmp->first_fully_vis)
{
int delta, idx2, pix2, old_pix, cnt, height;
RCT tmp_rct;
if (lmp->first_fully_vis == 0)
return use_key;
lm_make_invis(lmp);
idx2 = lmp->first_fully_vis - 1;
pix2 = lmp->pix_offsets[idx2];
old_pix = -lmp->rrr_offset;
delta = old_pix - pix2;
lmp->rrr_offset += delta;
calculate_pix_offsets(lmp, FALSE );
if (! lmp->itf_obj->v.itf->half_baked)
xvt_dwin_update(lmp->win);
xi_set_update_obj(lmp->list_obj);
lm_get_scroll_rct(lmp, &tmp_rct);
/*
calculate lmp->update_rows_at_top to speed up scrolling the list
*/
height = delta;
for (cnt = 0; cnt < lmp->nbr_realized_rows && height > 0; ++cnt)
height -= lmp->pix_heights[cnt];
lmp->update_rows_at_top = cnt;
xi_scroll_rect(lmp->win, &tmp_rct, 0, delta);
do_scroll_bar(lmp->list_obj->v.list);
lm_make_vis(lmp);
should_redraw = FALSE;
}
if (next_row > lmp->last_fully_vis)
{
int delta, delta2, diff, cnt, height, first, old_row_height, focus_row;
int focus_column, new_row_height;
BOOLEAN v_scrolled;
RCT tmp_rct;
if (lmp->last_fully_vis >= lmp->nbr_realized_rows)
return use_key;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
old_row_height = lmp->pix_heights[focus_row];
lm_make_invis(lmp);
delta = lmp->pix_heights[lmp->first_fully_vis];
lm_make_rrr_room_pix(lmp, delta, TRUE);
if (lmp->last_fully_vis + 1 < lmp->nbr_realized_rows)
delta = max(delta, lmp->pix_heights[lmp->last_fully_vis + 1]);
lmp->rrr_offset -= delta;
calculate_pix_offsets(lmp, TRUE);
calculate_visibles(lmp);
if (-lmp->rrr_offset != lmp->pix_offsets[lmp->first_fully_vis])
{
delta2 = lmp->pix_offsets[lmp->first_fully_vis] +
lmp->rrr_offset;
lmp->rrr_offset -= delta2;
calculate_pix_offsets(lmp, FALSE);
calculate_visibles(lmp);
delta += delta2;
}
diff = lmp->pix_offsets[lmp->nbr_realized_rows - 1] +
lmp->pix_heights[lmp->nbr_realized_rows - 1] -
lmp->mlr_height + lmp->rrr_offset;
if (! lmp->itf_obj->v.itf->half_baked)
xvt_dwin_update(lmp->win);
if (diff < 0)
lm_make_rrr_room_pix(lmp, -diff, FALSE);
xi_set_update_obj(lmp->list_obj);
lm_get_scroll_rct(lmp, &tmp_rct);
/*
calculate lmp->update_rows_at_bottom to speed up scrolling the list
*/
height = lmp->mlr.bottom - lmp->mlr.top - delta;
for (cnt = 0; cnt < lmp->nbr_realized_rows && height > 0; ++cnt)
height -= lmp->pix_heights[cnt];
first = cnt - 1;
height += delta;
for (;height > 0; ++cnt)
height -= lmp->pix_heights[cnt];
lmp->update_rows_at_bottom = cnt - first;
/*
scroll the list
*/
xi_scroll_rect(lmp->win, &tmp_rct, 0, -delta);
do_scroll_bar(lmp->list_obj->v.list);
/*
if the row height changed, then we need to redraw the row
*/
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
new_row_height = lmp->pix_heights[focus_row];
if (new_row_height != old_row_height)
{
lm_redraw_row(lmp, focus_row, FALSE );
calculate_pix_offsets(lmp, TRUE );
}
should_redraw = FALSE;
}
if (! lmp->get_all_records && ! lmp->keep_all_records)
{
int nbr_to_free, cnt, i, idx;
nbr_to_free = lmp->first_fully_vis;
if (nbr_to_free > 0)
{
for (cnt = 0; cnt < nbr_to_free; cnt++)
{
lmp->rrr_offset += lmp->pix_heights[cnt];
do_rec_event(lmp, cnt, XIE_REC_FREE);
}
for (idx = nbr_to_free; idx < lmp->nbr_realized_rows; ++idx)
row_copy(lmp, idx, idx - nbr_to_free);
adjust_rows(lmp, -nbr_to_free);
/*
calculate next cell again, because the desired next cell
may have changed.
*/
calculate_next_cell(lmp, &next_row, &next_col,
&use_key, ep, &off_top, &off_bottom);
lmp->nbr_realized_rows -= cnt;
calculate_pix_offsets(lmp, should_redraw );
calculate_visibles(lmp);
}
/* free any unnecessary records at the end of the list */
nbr_to_free = lmp->nbr_realized_rows - (lmp->last_fully_vis + 2);
if (nbr_to_free > 0)
{
for (i = lmp->nbr_realized_rows - nbr_to_free, cnt = 0; cnt < nbr_to_free;
i++, cnt++)
do_rec_event(lmp, i, XIE_REC_FREE);
lmp->nbr_realized_rows -= cnt;
}
calculate_pix_offsets(lmp, should_redraw );
lm_make_rrr_room_pix(lmp, 0, FALSE );
}
do_lm_cb(lm, LM_CB_FOCUS, next_row, next_col, NULL, NULL, 0);
}
return use_key;
}
/*-------------------------------------------------------------------------
function: lm_insert_row
lm: current lm
row: row to insert
-------------------------------------------------------------------------*/
BOOLEAN
lm_insert_row(LM lm, int row)
{
LM_DATA *lmp = LMP(lm);
xvt_errmsg_sig_if(!(! lmp->get_all_records), NULL_WIN, SEV_FATAL,
ERR_ASSERT_4, "20919", 20919,
"xi_insert_row called with get_all_records set to TRUE");
if (xi_move_focus(lmp->itf_obj))
{
if (row > 0 && lmp->nbr_realized_rows)
{
int idx, row_height, pix;
RCT r, row_rect;
BOOLEAN is_visible;
row = min(row, lmp->nbr_realized_rows);
pix = lmp->pix_offsets[row - 1] + lmp->pix_heights[row - 1]
+ 1;
is_visible = (pix <= lmp->mlr_height - lmp->rrr_offset);
if (is_visible || lmp->get_all_records)
{
LM_CELL_DATA *lmcdp;
int i;
make_rec_available(lmp, REC_AT_BOTTOM, FALSE, FALSE);
for (i = lmp->nbr_realized_rows - 2; i >= row; i--)
row_copy(lmp, i, i + 1);
idx = row;
lmcdp = lmp->cell_data[idx];
for (i = 0; i < lmp->nbr_columns; ++i, ++lmcdp)
memset((char *)lmcdp, '\0', sizeof(LM_CELL_DATA));
lmp->recs[idx] = 0L;
do_rec_event(lmp, idx, XIE_REC_ALLOCATE);
if (do_lm_cb_get((LM)lmp, LM_CB_GET_NEXT,
&lmp->recs[idx - 1], &lmp->recs[idx], 0, &lmp->row_colors[idx],
&lmp->row_attribs[idx], &row_height))
{
do_rec_event(lmp, lmp->nbr_realized_rows - 1, XIE_REC_FREE);
for (i = row; i < lmp->nbr_realized_rows - 2; ++i)
row_copy(lmp, i + 1, i);
--lmp->nbr_realized_rows;
return FALSE;
}
if (row_height)
{
lmp->pix_heights[idx] = row_height;
lmp->set_heights[idx] = TRUE;
}
else
{
lmp->pix_heights[idx] = lm_calculate_row_height(lmp, idx);
lmp->set_heights[idx] = FALSE;
}
lm_invalidate_rows_internal((LM)lmp, idx, idx, FALSE, -1, TRUE);
}
if (is_visible)
{
lm_get_scroll_rct(lmp, &r);
row_height = lm_calculate_row_height(lmp, idx);
calculate_pix_offsets(lmp, FALSE );
lm_get_rect(lm, LM_ROW, idx, &row_rect);
r.top = row_rect.top;
xi_scroll_rect(lmp->win, &r, 0, row_height);
}
do_scroll_bar(lmp->list_obj->v.list);
return TRUE;
}
else
{
int idx, row_height, cnt;
RCT r;
BOOLEAN need_first = ! lmp->nbr_realized_rows;
make_rec_available(lmp, REC_AT_TOP, TRUE, FALSE);
idx = 0;
if (do_lm_cb_get((LM)lmp, need_first ? LM_CB_GET_FIRST : LM_CB_GET_PREV,
&lmp->recs[idx + 1], &lmp->recs[idx], 0, &lmp->row_colors[idx],
&lmp->row_attribs[idx], &row_height))
{
do_rec_event(lmp, 0, XIE_REC_FREE);
for (cnt = 1; cnt < lmp->nbr_realized_rows; ++cnt)
row_copy(lmp, cnt, cnt - 1);
--lmp->nbr_realized_rows;
return FALSE;
}
if (row_height)
{
lmp->pix_heights[idx] = row_height;
lmp->set_heights[idx] = TRUE;
}
else
{
lmp->pix_heights[idx] = lm_calculate_row_height(lmp, idx);
lmp->set_heights[idx] = FALSE;
}
lm_invalidate_rows_internal((LM)lmp, idx, idx, FALSE, -1, TRUE );
lm_get_scroll_rct(lmp, &r);
row_height = lm_calculate_row_height(lmp, idx);
calculate_pix_offsets(lmp, FALSE );
xi_scroll_rect(lmp->win, &r, 0, row_height);
do_scroll_bar(lmp->list_obj->v.list);
return TRUE;
}
}
return FALSE;
}
/*-------------------------------------------------------------------------
function: lm_delete_row
lm: current lm
row: row to delete
-------------------------------------------------------------------------*/
BOOLEAN
lm_delete_row(LM lm, int row)
{
LM_DATA *lmp = LMP(lm);
xvt_errmsg_sig_if(!(! lmp->get_all_records), NULL_WIN, SEV_FATAL,
ERR_ASSERT_4, "20920", 20920,
"xi_delete_row called with get_all_records set to TRUE");
if (xi_move_focus(lmp->itf_obj))
{
int pix_height, i;
int recs_read;
RCT r, row_rct;
pix_height = lmp->pix_heights[row];
lm_get_rect(lm, LM_ROW, row, &row_rct);
do_rec_event(lmp, row, XIE_REC_FREE);
for (i = row + 1; i < lmp->nbr_realized_rows; i++)
row_copy(lmp, i, i - 1);
lmp->recs[--lmp->nbr_realized_rows] = 0;
calculate_pix_offsets(lmp, FALSE );
recs_read = lm_make_rrr_room_pix(lmp, pix_height, FALSE);
pix_height = max(pix_height, 0);
lm_get_scroll_rct(lmp, &r);
r.top = max(r.top, row_rct.top);
if (recs_read)
xi_invalidate_rect( lmp->win, &r );
else
xi_scroll_rect(lmp->win, &r, 0, -pix_height);
do_scroll_bar(lmp->list_obj->v.list);
}
return TRUE;
}
/*-------------------------------------------------------------------------
function: lm_set_row_height
lm: current lm
row: row to set
height: height
-------------------------------------------------------------------------*/
void
lm_set_row_height(LM lm, int row, int height, BOOLEAN set_height,
int old_height, BOOLEAN only_update)
{
LM_DATA *lmp = (LM_DATA *)lm;
int idx = row;
int old_row_height, delta;
RCT r, r2;
if (! lmp->itf_obj->v.itf->half_baked)
xvt_dwin_update(lmp->win);
if (only_update)
old_row_height = old_height;
else
{
old_row_height = lmp->pix_heights[idx];
lmp->pix_heights[idx] = height;
lmp->set_heights[idx] = set_height;
}
calculate_pix_offsets(lmp, FALSE );
/* Adjust row information */
if (! lmp->get_all_records && ! lmp->keep_all_records)
{
if (height < old_row_height)
lm_make_rrr_room_pix(lmp, 0, FALSE);
else
{ /* Free rows at bottom */
int i, cnt;
int nbr_to_free = lmp->nbr_realized_rows - (lmp->last_fully_vis + 2);
for (i = lmp->nbr_realized_rows - nbr_to_free,
cnt = 0; cnt < nbr_to_free; i++, cnt++)
do_rec_event(lmp, i, XIE_REC_FREE);
if (nbr_to_free > 0)
lmp->nbr_realized_rows -= nbr_to_free;
}
}
lm_get_scroll_rct(lmp, &r);
if (row < lmp->nbr_realized_rows - 1)
{
r.top = lmp->pix_offsets[idx + 1] + lmp->rrr_offset + lmp->mlr.top;
delta = height - old_row_height;
xi_scroll_rect(lmp->win, &r, 0, delta);
}
lm_get_rect(lm, LM_ROW, row, &r);
if (row == lmp->nbr_realized_rows - 1)
{
r2 = r;
r2.top = r2.bottom;
r2.bottom = lmp->mlr.bottom;
if (r2.top < r2.bottom)
xi_invalidate_rect(lmp->win, &r2);
}
xi_invalidate_rect(lmp->win, &r);
}
/*-------------------------------------------------------------------------
function: lm_set_list_size
lm: current lm
height: new height
width: new width
-------------------------------------------------------------------------*/
void
lm_set_list_size(LM lm, int height, int width)
{
LM_DATA* lmp = (LM_DATA *)lm;
RCT vert_scrollbar_rect;
RCT horz_scrollbar_rect;
RCT ir, old_rct;
int old_height;
int col_offset;
int max_row_height;
int row_height;
int heading_height;
int i;
XI_LIST_DATA* list_data;
int nbr_to_free, cnt;
list_data = lmp->list_obj->v.list;
xi_get_rect(lmp->list_obj, &old_rct);
col_offset = (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
xi_get_hsb_rect(lmp->list_obj, &horz_scrollbar_rect);
xi_get_sb_rect(lmp->list_obj, &vert_scrollbar_rect);
/* calculate minumum height */
{
int leading;
int ascent;
int descent;
int char_width;
int font_height;
xi_get_font_metrics_font(lmp->font, &leading, &ascent, &descent,
&char_width);
font_height = leading + ascent + descent;
max_row_height = lmp->max_lines_in_cell * font_height + RULE_Y_OFFSET_TOP
+ RULE_Y_OFFSET_BOTTOM + RULE_WIDTH_H;
}
for (i = 0; i < lmp->nbr_realized_rows; ++i)
{
row_height = lmp->pix_heights[i];
max_row_height = max(row_height, max_row_height);
}
heading_height = (lmp->pix_row1_top - lmp->rct.top) + BORDER_WIDTH;
i = max_row_height + heading_height + (horz_scrollbar_rect.bottom
- horz_scrollbar_rect.top);
height = max(height, i);
/* calculate new list metrics */
lmp->rct.bottom = lmp->rct.top + height
- ((list_data->hsb_win) ? (horz_scrollbar_rect.bottom
- horz_scrollbar_rect.top - 1)
: 0);
#if XI_IS_CH
CTOS_IS_CH;
lmp->mlr.bottom = lmp->rct.bottom;
CTOS_END;
#else
CTOS_IS_PM;
lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH;
CTOS_END;
#endif
old_height = lmp->mlr_height;
lmp->mlr_height = lmp->mlr.bottom - lmp->mlr.top;
calculate_pix_offsets( lmp, FALSE );
if (! lmp->get_all_records)
{
/* fill in with more records */
if (old_height < lmp->mlr_height)
lm_make_rrr_room_pix(lmp, lmp->mlr_height - old_height, FALSE);
}
calculate_visibles(lmp);
if (width && lmp->pixel_width)
{
int i, min_width, max_col_width;
max_col_width = 0;
for (i = lmp->fixed_columns; i < lmp->nbr_columns; ++i)
max_col_width = max(lmp->lm_column_data[i]->pix_width, max_col_width);
max_col_width += BORDER_WIDTH;
min_width = (lmp->vir_left - lmp->rct.left) + max_col_width
+ (vert_scrollbar_rect.right - vert_scrollbar_rect.left)
+ BORDER_WIDTH + 2 * col_offset;
if ( list_data->sb_win )
min_width += ( vert_scrollbar_rect.right
- vert_scrollbar_rect.left );
width = max(min_width, width);
lmp->pixel_width = width - (2 * BORDER_WIDTH);
if ( list_data->sb_win )
lmp->pixel_width -= ( vert_scrollbar_rect.right
- vert_scrollbar_rect.left - 1 );
lmp->vir_right = lmp->rct.left + lmp->pixel_width + BORDER_WIDTH;
}
/* move scroll bars */
list_data->have_sb_rct = FALSE;
list_data->have_hsb_rct = FALSE;
xi_move_list_scroll_bar(lmp->list_obj);
xi_move_list_hscroll_bar(lmp->list_obj);
lm_set_hscroll_range(lm);
ir = lmp->rct;
xi_get_hsb_rect(lmp->list_obj, &horz_scrollbar_rect);
ir.bottom = horz_scrollbar_rect.bottom + BORDER_WIDTH;
xi_get_sb_rect(lmp->list_obj, &vert_scrollbar_rect);
ir.right = vert_scrollbar_rect.right + BORDER_WIDTH;
ir.right = max(ir.right, old_rct.right);
ir.bottom = max(ir.bottom, old_rct.bottom);
xi_invalidate_rect(lmp->win, &ir);
do_scroll_bar(lmp->list_obj->v.list);
if (width && lmp->pixel_width)
{
/* calculate visible columns */
i = lm_get_left_most_far_right_col(lmp, lmp->nbr_columns);
if (i < lmp->first_vis)
{
xvt_dwin_update(lmp->win);
lm_hscroll(lm, lmp->first_vis - i, 0);
} else
{
lm_calc_last_vis(lmp);
lm_set_hscroll_bar((LM)lmp);
}
}
if (! lmp->get_all_records)
{
/* free any unnecessary records at the end of the list */
nbr_to_free = lmp->nbr_realized_rows - (lmp->last_fully_vis + 2);
for (i = lmp->nbr_realized_rows - nbr_to_free, cnt = 0; cnt < nbr_to_free;
i++, cnt++)
do_rec_event(lmp, i, XIE_REC_FREE);
lmp->nbr_realized_rows -= cnt;
calculate_visibles(lmp);
}
}
void
lm_recalc_metrics(LM lm)
{
LM_DATA *lmp = (LM_DATA *)lm;
int leading, ascent, descent, font_height, mch, i;
WINDOW win;
LM_COLUMN_DATA * * lmcdp;
int old_char_width;
XI_LIST_DATA *list_data;
PNT pnt;
RCT rct;
list_data = lmp->list_obj->v.list;
pnt = list_data->xi_pnt;
xi_fu_to_pu(lmp->itf_obj, &pnt, 1);
lmp->rct.top = pnt.v;
lmp->rct.left = pnt.h;
if (! lmp->resize_with_window)
{
lmp->pixel_width = list_data->width *
xi_get_fu_width(lmp->itf_obj) / XI_FU_MULTIPLE;
}
*lmp->font = *lmp->itf_obj->v.itf->font;
win = lmp->win;
xi_set_xvt_font(win, lmp->font, FALSE);
xi_get_font_metrics(win, &leading, &ascent, &descent);
lmp->leading = leading;
lmp->ascent = ascent;
lmp->descent = descent;
font_height = lmp->ascent + lmp->leading + lmp->descent;
lmp->pix_cell_height = font_height + (RULE_Y_OFFSET_TOP +
RULE_Y_OFFSET_BOTTOM);
#if XI_IS_CH
CTOS_IS_CH;
mch = 8;
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
mch = lmp->min_cell_height;
CTOS_END;
#endif
lmp->pix_cell_height = max(lmp->pix_cell_height, mch);
lmp->pix_row_spacing = lmp->pix_cell_height + RULE_WIDTH_H;
lmp->pix_top = lmp->rct.top;
lmp->pix_hdr_bottom = lmp->rct.top + lmp->leading + lmp->ascent +
lmp->descent + BORDER_WIDTH +
RULE_Y_OFFSET_BOTTOM + RULE_Y_OFFSET_TOP;
lmp->pix_hdr_bottom = max(lmp->pix_hdr_bottom,
(lmp->rct.top + lmp->min_heading_height + 2 * BORDER_WIDTH));
if (lmp->no_heading)
lmp->pix_row1_top = lmp->rct.top + BORDER_WIDTH;
else
lmp->pix_row1_top = lmp->pix_hdr_bottom + BORDER_WIDTH;
old_char_width = lmp->pix_char_width;
lmp->pix_char_width = xi_get_fu_width(lmp->itf_obj);
calculate_pix_offsets(lmp, FALSE);
for (i = 0, lmcdp = lmp->lm_column_data; i < lmp->nbr_columns; ++i, ++lmcdp)
(*lmcdp)->pix_width = (*lmcdp)->pix_width * lmp->pix_char_width /
old_char_width;
for (i = 0; i < lmp->nbr_columns; ++i)
calc_x_pix_pos(lm, lmp->lm_column_data[i], i);
lmp->rct.right = lmp->rct.left +
lmp->lm_column_data[lmp->nbr_columns - 1]->x_pix_pos +
lmp->lm_column_data[lmp->nbr_columns - 1]->pix_width +
2 * BORDER_WIDTH;
if (! lmp->resize_with_window)
{
#if XI_IS_NOT_CH
CTOS_IS_PM;
lmp->rct.bottom = lmp->pix_row1_top + lmp->nbr_rows * lmp->pix_row_spacing +
(BORDER_WIDTH - RULE_WIDTH_H);
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
lmp->rct.bottom = lmp->pix_row1_top + lmp->nbr_rows * lmp->pix_row_spacing
+ BORDER_WIDTH;
CTOS_END;
#endif
}
if (lmp->fixed_columns >= lmp->nbr_columns)
lmp->delta_x = 0;
else
lmp->delta_x = lmp->lm_column_data[lmp->first_vis]->x_pix_pos -
lmp->lm_column_data[lmp->fixed_columns]->x_pix_pos;
lmp->mlr.top = lmp->pix_row1_top;
#if XI_IS_NOT_CH
CTOS_IS_PM;
lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH;
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
if (lmp->pixel_width)
lmp->mlr.bottom = lmp->rct.bottom;
else
lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH;
CTOS_END;
#endif
lmp->mlr_height = lmp->mlr.bottom - lmp->mlr.top;
if (lmp->rrr_bottom < lmp->mlr_height)
lm_make_rrr_room_pix(lmp, lmp->mlr_height - lmp->rrr_bottom, FALSE);
list_data->have_sb_rct = FALSE;
list_data->have_hsb_rct = FALSE;
xi_get_sb_rect(lmp->list_obj, &rct);
xvt_vobj_move(list_data->sb_win, &rct);
xi_get_hsb_rect(lmp->list_obj, &rct);
xvt_vobj_move(list_data->hsb_win, &rct);
lm_calc_last_vis(lmp);
}
void
lm_text_scrolling(XI_OBJ *xi_obj)
{
LM_DATA *lmp = (LM_DATA *)xi_obj->v.list->lm;
lmp->text_scrolling = TRUE;
}
void
lm_set_hscroll_range(LM lm)
{
LM_DATA *lmp = (LM_DATA *)lm;
int hscroll_width, fixed_width, cnt;
RCT mlr;
XI_LIST_DATA *listdata;
if (lmp->list_obj->nbr_children <= 0) return;
listdata = lmp->list_obj->v.list;
lm_get_scroll_rct(lmp, &mlr);
if (lmp->pixel_width)
{
int prop;
hscroll_width = 0;
fixed_width = 0;
for (cnt = lmp->fixed_columns; cnt < lmp->nbr_columns; ++cnt)
hscroll_width += lmp->lm_column_data[cnt]->pix_width + lm_get_col_spacing();
for (cnt = 0; cnt < lmp->fixed_columns; ++cnt)
fixed_width += lmp->lm_column_data[cnt]->pix_width + lm_get_col_spacing();
#if XIWS == MTFWS
if ( hscroll_width != 0 )
{
#endif
xvt_sbar_set_range(listdata->hsb_win, HVSCROLL, 0, hscroll_width);
prop = mlr.right - mlr.left - fixed_width - BORDER_WIDTH;
prop = min(prop, hscroll_width);
prop = max(prop, 0);
xvt_sbar_set_proportion(listdata->hsb_win, HVSCROLL, prop);
#if XIWS == MTFWS
}
#endif
}
}
/*-------------------------------------------------------------------------
function: lm_column_set_pixel_width
lm: current lm
idx: column number
width: in pixels
-------------------------------------------------------------------------*/
void lm_column_set_pixel_width(LM lm, int idx, int width)
{
LM_DATA *lmp = (LM_DATA *) lm;
LM_COLUMN_DATA * column;
RCT invalid_rct, old_rct;
int i, old_width, new_row_height, cnt;
old_rct = lmp->rct;
column = lmp->lm_column_data[idx];
old_width = column->pix_width;
column->width = width / lmp->pix_char_width;
column->pix_width = width;
for (i = idx + 1; i < lmp->nbr_columns; ++i)
calc_x_pix_pos(lm, lmp->lm_column_data[i], i);
/* adjust bounding rectangle */
lmp->rct.right += column->pix_width - old_width;
lmp->mlr.right += column->pix_width - old_width;
if (idx < lmp->fixed_columns)
lmp->vir_left += column->pix_width - old_width;
/* The x_pix_pos of the first visible column may have changed so
recalculate delta_x */
if (lmp->fixed_columns >= lmp->nbr_columns)
lmp->delta_x = 0;
else
lmp->delta_x = lmp->lm_column_data[lmp->first_vis]->x_pix_pos -
lmp->lm_column_data[lmp->fixed_columns]->x_pix_pos;
invalid_rct = lmp->rct;
invalid_rct.left = column->x_pix_pos;
invalid_rct.right = max(invalid_rct.right, old_rct.right);
if (lmp->pixel_width)
invalid_rct.right = lmp->rct.left + lmp->pixel_width + 2 * BORDER_WIDTH;
lmp->list_obj->v.list->have_sb_rct = FALSE;
lmp->list_obj->v.list->have_hsb_rct = FALSE;
lm_set_hscroll_range((LM)lmp);
lm_calc_last_vis(lmp);
if (column->wrap_text)
{
int first_fully_vis = lmp->first_fully_vis;
int last_row = lmp->nbr_realized_rows - 1;
int height;
for (cnt = 0; cnt < lmp->nbr_realized_rows; ++cnt)
{
int old_row_height;
old_row_height = lmp->pix_heights[cnt];
new_row_height = lm_calculate_row_height(lmp, cnt);
lmp->pix_heights[cnt] = new_row_height;
if (old_row_height != new_row_height)
invalid_rct.left = lmp->rct.left;
}
calculate_pix_offsets(lmp, FALSE);
height = lmp->pix_offsets[last_row] + lmp->pix_heights[last_row] -
lmp->pix_offsets[first_fully_vis];
if (height < lmp->mlr_height)
lm_make_rrr_room_pix(lmp, lmp->mlr_height - height, FALSE);
if (! lmp->get_all_records)
{
int nbr_to_free;
/* free any unnecessary records at the end of the list */
nbr_to_free = lmp->nbr_realized_rows - (lmp->last_fully_vis + 2);
for (i = lmp->nbr_realized_rows - nbr_to_free, cnt = 0;
cnt < nbr_to_free;
i++, cnt++)
do_rec_event(lmp, i, XIE_REC_FREE);
lmp->nbr_realized_rows -= cnt;
calculate_visibles(lmp);
}
}
lm_invalidate_rect2(lmp, &invalid_rct, TRUE);
}
/*-------------------------------------------------------------------------
function: lm_set_column_width
lm: current lm
idx: column number
width: in characters
-------------------------------------------------------------------------*/
void lm_set_column_width(LM lm, int idx, int width)
{
lm_column_set_pixel_width( lm, idx,
width * ((LM_DATA *)lm)->pix_char_width );
}
/* ------------------------------------------------------------------- */
/* lm_cell_is_visible */
/* ------------------------------------------------------------------- */
BOOLEAN
lm_is_cell_visible( LM_DATA *lmp, int row, int column,
BOOLEAN use_txt_is_visible,
BOOLEAN *is_hscrolled)
{
if (is_hscrolled)
*is_hscrolled = FALSE;
if (use_txt_is_visible && lmp->txt_is_invisible)
{
int r;
if (lmp->focus_rec == 0L)
{
if (column < lmp->fixed_columns || (column >= lmp->first_vis && column <= lmp->last_vis))
return TRUE;
*is_hscrolled = TRUE;
return FALSE;
}
for (r = 0; r < lmp->nbr_realized_rows; ++r)
{
if (lmp->recs[r] == lmp->focus_rec)
{
if (r >= lmp->first_fully_vis && r <= lmp->last_fully_vis)
{
if (column < lmp->fixed_columns || (column >= lmp->first_vis && column <= lmp->last_vis))
{
return TRUE;
}
else
{
if (is_hscrolled)
*is_hscrolled = TRUE;
return FALSE;
}
}
else
return FALSE;
}
}
return FALSE;
}
else
{
if (row >= lmp->first_fully_vis && row <= lmp->last_fully_vis + 1)
{
if (column < lmp->fixed_columns || (column >= lmp->first_vis && column <= lmp->last_vis))
{
return TRUE;
}
else
{
if (is_hscrolled)
*is_hscrolled = TRUE;
return FALSE;
}
}
else
return FALSE;
}
}
void lm_force_vis(LM_DATA *lmp)
{
LM_COLUMN_DATA* lmcdp;
unsigned long attrib, cell_attrib;
int c;
RCT mr;
int focus_row, focus_column;
BOOLEAN v_scrolled;
mr = lmp->mlr;
if (lmp->pixel_width)
mr.right = mr.left + lmp->pixel_width + BORDER_WIDTH;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
lmcdp = lmp->lm_column_data[focus_column];
attrib = lmcdp->attrib;
cell_attrib = lm_get_attrib( (LM) lmp, LM_CELL, focus_row, focus_column,
v_scrolled ) & (XI_ATR_HCENTER | XI_ATR_RJUST);
if (cell_attrib)
{
attrib &= ~(XI_ATR_HCENTER | XI_ATR_RJUST);
attrib |= cell_attrib;
}
/* force cell to be visible */
c = min(focus_column, lmp->nbr_columns - 1);
if (c >= lmp->fixed_columns && c < lmp->first_vis)
lm_local_hscroll((LM)lmp, c - lmp->first_vis);
else
{
if (c > lmp->last_vis)
{
int first_col;
c++;
c = min(c, lmp->nbr_columns);
first_col = lm_get_left_most_far_right_col(lmp, c);
lm_local_hscroll((LM)lmp, first_col - lmp->first_vis);
}
}
if (focus_row < lmp->first_fully_vis)
{
int delta, idx2, pix2, old_pix;
RCT tmp_rct;
make_room_rows(lmp, focus_row - lmp->first_fully_vis, FALSE);
idx2 = focus_row;
pix2 = lmp->pix_offsets[idx2];
old_pix = -lmp->rrr_offset;
delta = old_pix - pix2;
lmp->rrr_offset += delta;
calculate_pix_offsets(lmp, FALSE);
if (! lmp->itf_obj->v.itf->half_baked)
xvt_dwin_update(lmp->win);
xi_set_update_obj(lmp->list_obj);
lm_get_scroll_rct(lmp, &tmp_rct);
xi_scroll_rect(lmp->win, &tmp_rct, 0, delta);
do_scroll_bar(lmp->list_obj->v.list);
}
if (focus_row > lmp->last_fully_vis)
{
int pix, delta;
RCT tmp_rct;
delta = 0;
while (TRUE)
{
if (focus_row <= lmp->last_fully_vis)
break;
pix = lmp->pix_heights[0];
delta += pix;
lm_make_rrr_room_pix(lmp, pix, FALSE);
lmp->rrr_offset -= pix;
calculate_pix_offsets(lmp, FALSE);
calculate_visibles(lmp);
}
if (! lmp->itf_obj->v.itf->half_baked)
xvt_dwin_update(lmp->win);
xi_set_update_obj(lmp->list_obj);
lm_get_scroll_rct(lmp, &tmp_rct);
xi_scroll_rect(lmp->win, &tmp_rct, 0, -delta);
do_scroll_bar(lmp->list_obj->v.list);
if (! lmp->get_all_records && ! lmp->keep_all_records)
{
int nbr_to_free, cnt, i, idx;
nbr_to_free = lmp->first_fully_vis;
if (nbr_to_free > 0)
{
for (cnt = 0; cnt < nbr_to_free; cnt++)
{
lmp->rrr_offset += lmp->pix_heights[cnt];
do_rec_event(lmp, cnt, XIE_REC_FREE);
}
for (idx = nbr_to_free; idx < lmp->nbr_realized_rows; ++idx)
row_copy(lmp, idx, idx - nbr_to_free);
adjust_rows(lmp, -nbr_to_free);
lmp->nbr_realized_rows -= cnt;
}
/* free any unnecessary records at the end of the list */
nbr_to_free = lmp->nbr_realized_rows - (lmp->last_fully_vis + 2);
if (nbr_to_free > 0)
{
for (i = lmp->nbr_realized_rows - nbr_to_free, cnt = 0; cnt < nbr_to_free;
i++, cnt++)
do_rec_event(lmp, i, XIE_REC_FREE);
lmp->nbr_realized_rows -= cnt;
}
calculate_pix_offsets(lmp, TRUE );
}
}
lm_make_vis(lmp);
}
/*-------------------------------------------------------------------------
function: lm_get_visible_columns
lm: current lm
first_vis:
last_vis:
-------------------------------------------------------------------------*/
void
lm_get_visible_columns(LM lm, int *first_vis, int *last_vis)
{
LM_DATA *lmp = (LM_DATA *)lm;
*first_vis = lmp->first_vis;
*last_vis = lmp->last_vis;
}
/*-------------------------------------------------------------------------
function: lm_get_list_info
lm: current lm
nbr_recs: number of records
returns: array of record handles
-------------------------------------------------------------------------*/
long *
lm_get_list_info(LM lm, int *nbr_recs)
{
LM_DATA *lmp = (LM_DATA *)lm;
*nbr_recs = lmp->nbr_realized_rows;
return &lmp->recs[0];
}
/*-------------------------------------------------------------------------
function: lm_cell_request
lm: current lm
lm_part: may be LM_LIST, LM_ROW, LM_COLUMN, or LM_CELL ??
-------------------------------------------------------------------------*/
void
lm_cell_request( LM lm, LM_PART lm_part, int idx1, int idx2 )
{
LM_DATA *lmp = LMP(lm);
BOOLEAN redraw;
redraw = (BOOLEAN)(lmp->attrib & (LM_ATR_VISIBLE));
lm_make_invis(lmp);
switch (lm_part)
{
case LM_LIST:
lm_invalidate_rows_internal( lm, 0, lmp->nbr_realized_rows - 1, redraw, -1,
FALSE );
lm_make_vis(lmp);
return;
case LM_ROW:
lm_invalidate_rows_internal(lm, idx1, idx1, redraw, -1, FALSE);
lm_make_vis(lmp);
return;
case LM_COLUMN:
lm_invalidate_rows_internal(lm, 0, lmp->nbr_realized_rows - 1, redraw, idx1,
FALSE );
lm_make_vis(lmp);
return;
case LM_CELL:
lm_invalidate_rows_internal(lm, idx1, idx1, redraw, idx2, FALSE);
lm_make_vis(lmp);
return;
}
xvt_errmsg_sig_if(!(xi_false), NULL_WIN, SEV_FATAL,
ERR_ASSERT_4, "20918", 20918, "lm_cell_request: Invalid LM part");
}
/*-------------------------------------------------------------------------
function: lm_get_visible_rows
------------------------------------------------------------------------- */
int
lm_get_visible_rows(LM lm, int *first_vis, int *last_vis)
{
LM_DATA *lmp = (LM_DATA *)lm;
if (first_vis)
*first_vis = lmp->first_fully_vis;
if (last_vis)
*last_vis = lmp->last_fully_vis;
if (! lmp->nbr_realized_rows)
return 0;
else
return lmp->last_fully_vis - lmp->first_fully_vis + 1;
}
/*-------------------------------------------------------------------------
function: lm_get_list_obj
lm: current lm
returns: XI_OBJ * for list
-------------------------------------------------------------------------*/
XI_OBJ *
lm_get_list_obj(LM lm)
{
LM_DATA *lmp = LMP(lm);
return(lmp->list_obj);
}
/*-------------------------------------------------------------------------
function: lm_set_buf_size_internal
lm: current lm
part: must be LM_COLUMN
idx: column number
size: the new buffer size
redraw: if TRUE, then redraw the cell
-------------------------------------------------------------------------*/
static void near
lm_set_buf_size_internal(LM lm, LM_PART part, int idx, int size, BOOLEAN redraw)
{
int i, toff;
int oldlen, diff;
int oldbufsize;
char *p;
LM_COLUMN_DATA *lmcd, *lmcdm1;
LM_DATA *lmp = LMP(lm);
xvt_errmsg_sig_if(!(part == LM_COLUMN), NULL_WIN, SEV_FATAL,
ERR_ASSERT_4,"20917",
20917, "lm_set_buf_size: Invalid LM part");
lmcd = lmp->lm_column_data[idx];
oldlen = lmcd->text_size;
oldbufsize = lmp->text_size;
lmcd->text_size = size;
diff = size - oldlen;
lmp->text_size += diff;
toff = lmcd->text_offset;
for (i = 0; i < lmp->realized_rows_array_len; i++)
{
p = lmp->buffer[i];
if (diff < 0) {
p[toff + size - 1] = '\0';
gmemmove(p + toff + size, p + toff + oldlen,
(long)(oldbufsize - toff - oldlen));
lmp->buffer[i] = (char *)xi_tree_realloc(p, oldbufsize + diff);
/* redraw cause might obliterate some text */
if (redraw)
redraw_cell(lm, i, idx, FALSE );
}
else
{
p = lmp->buffer[i] = (char *)xi_tree_realloc(p, oldbufsize + diff);
gmemmove(p + toff + size, p + toff + oldlen,
(long)(oldbufsize - toff - oldlen));
}
}
for (i = 0; i < lmp->nbr_columns; ++i)
{
lmcd = lmp->lm_column_data[i];
if (i)
lmcdm1 = lmp->lm_column_data[i - 1];
lmcd->text_offset = (i == 0) ? 0 :
lmcdm1->text_offset + lmcdm1->text_size;
}
}
/*-------------------------------------------------------------------------
function: lm_set_buf_size
lm: current lm
part: must be LM_COLUMN
idx: column number
size: the new buffer size
-------------------------------------------------------------------------*/
void
lm_set_buf_size(LM lm, LM_PART part, int idx, int size)
{
lm_set_buf_size_internal(lm, part, idx, size, TRUE);
}
/* ------------------------------------------------------------------------ */
/* adjust_focus_for_column_delete */
/* if the focus is on a column after the deleted column, adjust the focus */
/* objects. */
/* if the focus is on the deleted column, move the focus to the interface */
/* ------------------------------------------------------------------------ */
static void adjust_focus_for_column_delete( LM_DATA* lmp, int column_nbr )
{
XI_OBJ* focus_obj;
focus_obj = lmp->itf_obj->v.itf->focus_obj;
if (focus_obj == NULL || focus_obj->parent != lmp->list_obj
|| focus_obj->type != XIT_CELL)
return;
if ( focus_obj->v.cell.column == column_nbr )
{
xi_set_focus( lmp->itf_obj );
return;
}
if ( (int)focus_obj->v.cell.column > (int)column_nbr )
focus_obj->v.cell.column--;
}
/*-------------------------------------------------------------------------
function: lm_delete_column
lm: current lm
column_nbr: column to delete
adjust_hscrolling: if TRUE, then make more horizontal columns visible
-------------------------------------------------------------------------*/
void
lm_delete_column(LM lm, int column_nbr, BOOLEAN adjust_hscrolling)
{
LM_DATA *lmp = LMP(lm);
LM_COLUMN_DATA *lmcd;
RCT invalid_rct, old_rct;
int i, old_width, old_left, col_spacing;
int old_x_pix_pos;
LM_CELL_DATA *cell_data;
adjust_focus_for_column_delete( lmp, column_nbr );
col_spacing = lm_get_col_spacing();
xvt_errmsg_sig_if(!(column_nbr < lmp->nbr_columns), NULL_WIN, SEV_FATAL,
ERR_ASSERT_4, "20915", 20915,
"Invalid column number passed to lm_delete_column");
old_rct = lmp->rct;
lmcd = lmp->lm_column_data[column_nbr];
old_left = lmcd->x_pix_pos - lmp->delta_x;
old_x_pix_pos = lmcd->x_pix_pos;
old_width = lmcd->pix_width;
lm_set_buf_size_internal(lm, LM_COLUMN, column_nbr, 0, FALSE);
xi_tree_free(lmp->lm_column_data[column_nbr]);
for (i = 0; i < lmp->nbr_realized_rows; ++i)
{
cell_data = &(lmp->cell_data[i][column_nbr]);
if (cell_data->font)
{
xi_free_font_id(lmp->itf_obj, *cell_data->font);
xi_tree_free(cell_data->font);
}
if (cell_data->string)
xi_tree_free(cell_data->string);
if (cell_data->line_breaks)
xi_tree_free(cell_data->line_breaks);
}
for (i = 0; i < lmp->realized_rows_array_len; ++i)
{
int j;
for (j = column_nbr; j < lmp->nbr_columns - 1; ++j)
lmp->cell_data[i][j] = lmp->cell_data[i][j + 1];
lmp->cell_data[i] = (LM_CELL_DATA *)xi_tree_realloc(lmp->cell_data[i],
(lmp->nbr_columns - 1) * sizeof(LM_CELL_DATA));
}
for (i = column_nbr; i < lmp->nbr_columns - 1; ++i)
lmp->lm_column_data[i] = lmp->lm_column_data[i + 1];
--lmp->nbr_columns;
for (i = column_nbr; i < lmp->nbr_columns; ++i)
calc_x_pix_pos(lm, lmp->lm_column_data[i], i);
/*
adjust bounding rectangle
*/
lmp->rct.right = lmp->rct.right - old_width - lm_get_col_spacing();
/* single-column lists do not have a vertical rule seperating columns */
if (lmp->nbr_columns == 0)
lmp->rct.right += RULE_WIDTH_V;
/* adjust left border of horizontal virtual space */
if (column_nbr < lmp->fixed_columns)
lmp->vir_left -= (old_width + col_spacing);
/*
if the column is invisible
*/
calculate_pix_offsets( lmp, TRUE );
if (column_nbr >= lmp->fixed_columns && old_x_pix_pos < lmp->delta_x)
{
lmp->delta_x -= (old_width + lm_get_col_spacing());
--lmp->first_vis;
lm_set_hscroll_range((LM)lmp);
}
else
{
if (column_nbr < lmp->fixed_columns)
{
--lmp->first_vis;
--lmp->fixed_columns;
lm_set_hscroll_range((LM)lmp);
}
invalid_rct = lmp->rct;
invalid_rct.left = old_left;
invalid_rct.right = max(invalid_rct.right, old_rct.right);
if (lmp->pixel_width)
invalid_rct.right = lmp->rct.left + lmp->pixel_width + BORDER_WIDTH;
/*
if we add the following two lines in, it prevents flashing of the top and bottom borders when
moving columns, however, the top and bottom borders need to get invalidated
invalid_rct.top += BORDER_WIDTH;
invalid_rct.bottom -= BORDER_WIDTH;
*/
lm_invalidate_rect2(lmp, &invalid_rct, FALSE);
lmp->list_obj->v.list->have_sb_rct = FALSE;
lmp->list_obj->v.list->have_hsb_rct = FALSE;
i = lm_get_left_most_far_right_col(lmp, lmp->nbr_columns);
if (lmp->first_vis >= lmp->nbr_columns)
{
RCT r;
xvt_dwin_update(lmp->win);
lmp->delta_x = lmp->lm_column_data[i]->x_pix_pos - lmp->vir_left;
xi_set_update_obj(lmp->list_obj);
lmp->last_vis = lmp->first_vis = i;
lm_calc_last_vis(lmp);
r.left = lmp->vir_left;
r.right = lmp->vir_right;
#if XI_IS_NOT_CH
CTOS_IS_PM;
r.top = lmp->rct.top + BORDER_WIDTH;
r.bottom = lmp->rct.bottom - BORDER_WIDTH;
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
r.top = lmp->rct.top;
r.bottom = lmp->rct.bottom;
CTOS_END;
#endif
xi_invalidate_rect(lmp->win, &r);
xvt_dwin_update(lmp->win);
lm_set_hscroll_bar((LM)lmp);
}
else
{
if (i < lmp->first_vis && adjust_hscrolling)
{
xvt_dwin_update(lmp->win);
lm_hscroll(lm, i - lmp->first_vis, 0);
}
else
{
lm_calc_last_vis(lmp);
lm_set_hscroll_range((LM)lmp);
}
}
}
}
/*
TODO this function will change. pix_row_spacing will no longer be used.
instead, min_row_height, and absolute_height will be used.
*/
/*-------------------------------------------------------------------------
lm_get_vertical_metrics
-------------------------------------------------------------------------*/
void lm_get_vertical_metrics( XI_OBJ_DEF* obj_def, int* first_row_y,
int* row_spacing, int *client_height,
int* title_height )
{
XI_LIST_DEF* list_def;
XI_OBJ_DEF* itf_def;
int leading, ascent, descent, char_width, font_height, pix_cell_height,
pix_hdr_bottom, min_cell_height;
PNT p;
FONT_OBJ *fontp = NULL;
list_def = obj_def->v.list;
#if XI_IS_CH
NOREF(char_width);
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
itf_def = obj_def->parent;
if (itf_def && itf_def->v.itf->font_id)
fontp = &itf_def->v.itf->font_id;
if (list_def->font_id)
xi_get_font_metrics_font( &list_def->font_id, &leading, &ascent, &descent,
&char_width);
else if (fontp)
xi_get_font_metrics_font(fontp, &leading, &ascent, &descent, &char_width);
else
xi_get_font_metrics_font( &xi_sysfont, &leading, &ascent, &descent,
&char_width);
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
leading = 0;
ascent = 8;
descent = 0;
CTOS_END;
#endif
font_height = ascent + leading + descent;
#if XI_IS_CH
CTOS_IS_CH;
min_cell_height = 8;
pix_cell_height = font_height;
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
min_cell_height = list_def->min_cell_height;
pix_cell_height = font_height + CELL_VERTICAL_MARGIN;
CTOS_END;
#endif
pix_cell_height = max(pix_cell_height, min_cell_height);
#if XVTWS == WMWS
*row_spacing = pix_cell_height;
#else
*row_spacing = pix_cell_height + RULE_WIDTH_H;
#endif
itf_def = obj_def->parent;
if (itf_def && itf_def->v.itf->font_id)
fontp = &itf_def->v.itf->font_id;
if (xi_get_xil_pref((XI_OBJ *)itf_def))
{
p = list_def->xi_pnt;
}
else
{
p = list_def->pixel_origin;
if (!p.v && !p.h)
{
p = list_def->xi_pnt;
if (list_def->font_id)
xi_fu_to_pu_font(&list_def->font_id, &p, 1);
else if (fontp)
xi_fu_to_pu_font(fontp, &p, 1);
else
xi_fu_to_pu_font(&xi_sysfont, &p, 1);
}
}
#if XVTWS != WMWS
pix_hdr_bottom = p.v + leading + ascent + descent + BORDER_WIDTH
+ RULE_Y_OFFSET_BOTTOM + RULE_Y_OFFSET_TOP;
pix_hdr_bottom = max( pix_hdr_bottom, p.v + list_def->min_heading_height
+ BORDER_WIDTH);
#else
pix_hdr_bottom = p.v + leading + ascent + descent + BORDER_WIDTH;
pix_hdr_bottom = max( pix_hdr_bottom, p.v + list_def->min_heading_height);
#endif
if (list_def->no_heading)
{
int first_row_y_pos = p.v + BORDER_WIDTH;
*first_row_y = first_row_y_pos;
}
else
{
*first_row_y = pix_hdr_bottom + BORDER_WIDTH;
}
if (xi_get_xil_pref((XI_OBJ *)itf_def))
{
*client_height = list_def->height;
}
else
{
if (list_def->pixel_height)
*client_height = list_def->pixel_height;
else
{
int height;
if (list_def->font_id)
height = xi_get_fu_height_font(&list_def->font_id);
else if (fontp)
height = xi_get_fu_height_font(fontp);
else
height = xi_get_fu_height_font(&xi_sysfont);
*client_height = list_def->height * height / XI_FU_MULTIPLE;
}
}
*title_height = *first_row_y - p.v;
*client_height -= *title_height + BORDER_WIDTH;
}
/*-------------------------------------------------------------------------
function: lm_get_metrics
lm_def: definition of a list
hborder: to be filled in with the horizontal border width
column_div: to be filled in with the column spacing in pixels
list_button: bottom of the list, in pixels
-------------------------------------------------------------------------*/
void lm_get_metrics(XI_OBJ_DEF *obj_def, int *hborder, int *column_div,
int *list_bottom)
{
if (hborder != NULL)
*hborder = BORDER_WIDTH;
if (column_div != NULL)
*column_div = lm_get_col_spacing();
if (obj_def->v.list)
{
int pix_row_spacing, nbr_rows, height, pix_row1_top, title_height;
lm_get_vertical_metrics( obj_def, &pix_row1_top, &pix_row_spacing,
&height, &title_height );
if (obj_def->v.list->one_row_list)
nbr_rows = 1;
else
nbr_rows = height / pix_row_spacing;
#if XVTWS == WMWS
*list_bottom = pix_row1_top + nbr_rows * pix_row_spacing + BORDER_WIDTH;
#else
*list_bottom = pix_row1_top + nbr_rows * pix_row_spacing
+ (BORDER_WIDTH - RULE_WIDTH_H);
#endif
}
}
/*-------------------------------------------------------------------------
function: lm_start_edit
lm: current lm
row: relevant row
column: relevant column
notes: create a text core edit field in the position of the
cell of interest, and copy in the necessary attributes
and text from the list
-------------------------------------------------------------------------*/
static void lm_start_edit(LM lm, int row, int column)
{
LM_DATA* lmp = LMP(lm);
int focus_row, focus_column;
BOOLEAN v_scrolled;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled );
xvt_errmsg_sig_if(!( focus_row == row && focus_column == column), NULL_WIN,
SEV_FATAL, ERR_ASSERT_4, "20919", 20919,
"lm_start_edit: Internal error, called with focus not poperly set");
lm_force_vis(lmp);
}
/*-------------------------------------------------------------------------
function: lm_set_focus
lm: current lm
row: row
column: column
-------------------------------------------------------------------------*/
void lm_set_focus(LM lm, int row, int column)
{
LM_DATA *lmp = LMP(lm);
if (lm_list_has_focus(lmp))
{
int focus_row, focus_column;
BOOLEAN v_scrolled;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled );
if (row != focus_row || column != focus_column)
{
lm_make_invis(lmp);
lm_make_vis(lmp);
}
}
else
lm_start_edit(lm, row, column);
}
/*-------------------------------------------------------------------------
function: lm_set_hscroll_bar
lm: current lm
notes: Calculate the percentage for the horizontal scroll bar, and set the
thumb position on the horizontal scroll bar.
-------------------------------------------------------------------------*/
void
lm_set_hscroll_bar(LM lm)
{
XI_OBJ *list_obj;
int i, first_vis, p;
LM_DATA *lmp;
int rng1, rng2;
int prop;
lmp = (LM_DATA *)lm;
list_obj = lmp->list_obj;
if (list_obj->v.list->hsb_win)
{
xvt_sbar_get_range(list_obj->v.list->hsb_win, HVSCROLL,
&rng1, &rng2);
prop = xvt_sbar_get_proportion(list_obj->v.list->hsb_win, HVSCROLL);
rng2 -= prop;
i = lm_get_left_most_far_right_col(lmp, lmp->nbr_columns);
if (i == 0)
p = 0;
else
{
i = i - lmp->fixed_columns;
first_vis = lmp->first_vis - lmp->fixed_columns;
if (i)
p = (int)(((long)rng2 * (long)first_vis) / i);
else
p = 0;
}
if (p < 0)
p = 0;
if (p > rng2)
p = rng2;
xvt_sbar_set_pos(list_obj->v.list->hsb_win, HVSCROLL,
p);
}
}
/*-------------------------------------------------------------------------
function: lm_create_column
lcdef: column definition
not_creating_list: if TRUE, do all of the cell requests for the column
in_hscrolling: if TRUE, and if on border between fixed and scrolling columns
-------------------------------------------------------------------------*/
void
lm_create_column(LM lm, LM_COLUMN_DEF *lcdef, BOOLEAN not_creating_list,
BOOLEAN in_hscrolling)
{
LM_COLUMN_DATA *lcdata, *lcdatam1;
LM_COLUMN_DATA * *column_data;
LM_DATA *lmp = LMP(lm);
RCT rct_to_invalidate;
int new_textlen;
int text_copyidx;
int i;
char *src;
char *dst;
char *target;
char *buf;
int position, col_spacing;
int focus_row, focus_column;
BOOLEAN made_invis = FALSE;
col_spacing = lm_get_col_spacing();
position = min(lcdef->position, lmp->nbr_columns);
if (lm_list_has_focus(lmp))
{
BOOLEAN vert_scrolled;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &vert_scrolled);
if (focus_column >= position)
++focus_column;
lm_set_focus_cell(lmp, focus_row, focus_column, vert_scrolled );
if (! lmp->txt_is_invisible)
{
lm_make_invis(lmp);
made_invis = TRUE;
}
}
lcdata = (LM_COLUMN_DATA *)xi_tree_malloc(sizeof(LM_COLUMN_DATA),
(char *)lm);
lcdata->attrib = lcdef->attrib;
/*
lcdata->pix_width = lcdef->width * lmp->pix_char_width;
lcdata->width = lcdef->width;
*/
lcdata->pix_width = lcdef->pix_width;
lcdata->width = lcdef->pix_width / lmp->pix_char_width;
calc_x_pix_pos(lm, lcdata, position);
if (position)
lcdatam1 = lmp->lm_column_data[position - 1];
text_copyidx = (position == 0) ? 0 : lcdatam1->text_offset +
lcdatam1->text_size;
lcdata->text_offset = text_copyidx;
lcdata->text_size = lcdef->text_size;
lcdata->center_heading = lcdef->center_heading;
lcdata->heading_well = lcdef->heading_well;
lcdata->heading_platform = lcdef->heading_platform;
lcdata->column_well = lcdef->column_well;
lcdata->column_platform = lcdef->column_platform;
lcdata->heading_text = (char *)xi_tree_malloc(
strlen(lcdef->heading_text) + 1, (char *)lm);
strcpy(lcdata->heading_text, lcdef->heading_text);
if (lcdef->font)
{
#if 0
/* reparenting font object, not reallocating */
lcdata->font = (FONT_OBJ *)xi_tree_malloc(sizeof(FONT_OBJ),
(void *)lm);
#endif
lcdata->font = lcdef->font;
xi_tree_reparent(lcdata->font, lcdata);
}
lcdata->icon_rid = lcdef->icon_rid;
lcdata->icon_x = lcdef->icon_x;
lcdata->icon_y = lcdef->icon_y;
lcdata->size_rows = lcdef->size_rows;
lcdata->suppress_update_heading = lcdef->suppress_update_heading;
lcdata->suppress_update_cells = lcdef->suppress_update_cells;
lcdata->vertical_align_center = lcdef->vertical_align_center;
lcdata->vertical_align_bottom = lcdef->vertical_align_bottom;
lcdata->wrap_text = lcdef->wrap_text;
lcdata->auto_tab = lcdef->auto_tab;
new_textlen = lmp->text_size + lcdata->text_size;
/* allocate new text for each row and move text if necessary */
for (i = 0; i < lmp->realized_rows_array_len; i++)
{
buf = lmp->buffer[i] = (char *)xi_tree_realloc2(lmp->buffer[i],
new_textlen, (char *)lm);
/* zero out new text */
memset(buf + lmp->text_size, '\0', (size_t)lcdata->text_size);
/* copy text for old columns that were moved */
/* degenerate zero-column case is handled correctly */
dst = buf + new_textlen;
src = buf + lmp->text_size;
target = buf + text_copyidx;
while (src > target)
*--dst = *--src;
}
/* allocate new columns */
column_data = lmp->lm_column_data =
(LM_COLUMN_DATA * *)xi_tree_realloc2(
(char *)lmp->lm_column_data,
sizeof(LM_COLUMN_DATA *) * (lmp->nbr_columns + 1),
(char *)lm);
/* create space for cell data */
for (i = 0; i < lmp->realized_rows_array_len; i++)
{
int j;
lmp->cell_data[i] = (LM_CELL_DATA *)xi_tree_realloc(lmp->cell_data[i],
(lmp->nbr_columns + 1) * sizeof(LM_CELL_DATA));
for (j = lmp->nbr_columns; j > position; j--)
lmp->cell_data[i][j] = lmp->cell_data[i][j - 1];
memset((char *)&lmp->cell_data[i][position], '\0',
sizeof(LM_CELL_DATA));
}
/* move column pointers around in the column list */
for (i = lmp->nbr_columns; i > position; i--)
{
column_data[i] = column_data[i - 1];
column_data[i]->x_pix_pos += lcdata->pix_width + col_spacing;
column_data[i]->text_offset += lcdata->text_size;
}
column_data[position] = lcdata;
lmp->nbr_columns++;
if ((not_creating_list) && (position < lmp->fixed_columns))
{
lmp->first_vis++;
lmp->fixed_columns++;
}
if (not_creating_list && (! in_hscrolling) && position == lmp->fixed_columns)
{
lmp->first_vis++;
lmp->fixed_columns++;
}
if (lmp->first_vis < lmp->fixed_columns &&
lmp->nbr_columns > lmp->fixed_columns)
lmp->first_vis = lmp->fixed_columns;
lmp->text_size = new_textlen;
/* adjust bounding rectangle */
lmp->rct.right += lcdata->pix_width + col_spacing;
if (lmp->nbr_columns == 1)
lmp->rct.right -= RULE_WIDTH_V; /* did not add divider rule */
#if XI_IS_CH
CTOS_IS_CH;
lmp->mlr.right = lmp->rct.right;
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
lmp->mlr.right = lmp->rct.right - BORDER_WIDTH;
CTOS_END;
#endif
/* calculate the left boundary of the virtual space for the list */
lmp->vir_left = lmp->rct.left + BORDER_WIDTH;
for (i = 0; i < min(lmp->nbr_columns, lmp->fixed_columns); ++i)
{
lmp->vir_left += lmp->lm_column_data[i]->pix_width;
lmp->vir_left += col_spacing;
}
if (not_creating_list)
{
lm_invalidate_rows_internal(lm, 0, INT_MAX, FALSE, position, TRUE);
calculate_pix_offsets( lmp, TRUE );
}
if (position >= lmp->fixed_columns && column_data[position]->x_pix_pos < lmp->delta_x)
{
lmp->delta_x += (column_data[position]->pix_width + lm_get_col_spacing());
++lmp->first_vis;
lm_set_hscroll_range((LM)lmp);
}
else
{
/* invalidate changed rectangle */
lm_get_list_rct(lmp, &rct_to_invalidate);
/*
if we add the following two lines in, it prevents flashing of the top and bottom borders when
moving columns, however, the top and bottom borders need to get invalidated
rct_to_invalidate.top += BORDER_WIDTH;
rct_to_invalidate.bottom -= BORDER_WIDTH;
*/
rct_to_invalidate.left = lcdata->x_pix_pos;
lm_adj_h(lmp, &rct_to_invalidate.left);
if (rct_to_invalidate.bottom > rct_to_invalidate.top &&
rct_to_invalidate.right > rct_to_invalidate.left)
lm_invalidate_rect2(lmp, &rct_to_invalidate, FALSE);
}
lm_calc_last_vis(lmp);
lmp->list_obj->v.list->have_sb_rct = FALSE;
if (not_creating_list && lmp->list_obj->v.list->hsb_win)
{
RCT rct;
lmp->list_obj->v.list->have_hsb_rct = FALSE;
lm_set_hscroll_range((LM)lmp);
lm_set_hscroll_bar((LM) lmp);
xi_get_hsb_rect(lmp->list_obj, &rct);
xvt_vobj_move(lmp->list_obj->v.list->hsb_win, &rct);
}
if (xi_get_pref(XI_PREF_UNUSED_PREFERENCE))
{
if (not_creating_list && made_invis)
lm_make_vis(lmp);
}
}
/*-------------------------------------------------------------------------
function: do_lm_cb_column
lm: current lm
cb_reason: one of LM_CB_COL_DELETE, LM_CB_COL_MOVE, LM_CB_COL_SIZE
col_nbr: column being deleted, moved, or re-sized
new_col_nbr: new column number on LM_CB_COL_MOVE
new_col_width: new column width on LM_CB_COL_SIZE
new_col_pixel_width: new column pixel width on LM_CB_COL_SIZE
in_fixed: if TRUE, then column is being moved to fixed portion of list
returns: TRUE if event refused
-------------------------------------------------------------------------*/
static BOOLEAN
near do_lm_cb_column(LM lm, LM_CB_TYPE cb_reason, int col_nbr,
int new_col_nbr, int new_col_width, int new_col_pixel_width,
BOOLEAN in_fixed)
{
LM_CB_DATA lm_cb_data;
lm_cb_data.lm = lm;
lm_cb_data.cb_type = cb_reason;
lm_cb_data.cid = LMP(lm)->cid;
lm_cb_data.win = LMP(lm)->win;
lm_cb_data.column = (unsigned char)col_nbr;
lm_cb_data.v.column.new_col_nbr = new_col_nbr;
lm_cb_data.v.column.in_fixed = in_fixed;
lm_cb_data.v.column.new_col_width = new_col_width;
lm_cb_data.v.column.new_col_pixel_width = new_col_pixel_width;
lm_cb_data.v.column.refused = FALSE;
(*LMP(lm)->lm_cb)(&lm_cb_data);
return (lm_cb_data.v.column.refused);
}
/*-------------------------------------------------------------------------
function: get_rubber_rect
lmp: current lmp
rctp: rectangle to be filled in
x: current mouse x position
y: current mouse y position
-------------------------------------------------------------------------*/
static void
get_rubber_rect(LM_DATA *lmp, RCT *rctp, int x, int y,
BOOLEAN last_in_hscrolling)
{
RCT rct;
int col, delta_x, delta_y;
col = lmp->column_being_moved;
/*
lm_get_cell_rect returns the exact physical rectangle of the cell - not
shifted to the right or to the left.
*/
lm_get_cell_rect(&rct, (LM)lmp, 1, col, FALSE, TRUE);
rct.top = lmp->pix_top + BORDER_WIDTH;
rct.bottom = lmp->pix_hdr_bottom;
delta_x = x - lmp->org_x;
if (lmp->down_in_hscrolling && ! last_in_hscrolling)
delta_x += lmp->delta_x;
if (! lmp->down_in_hscrolling && last_in_hscrolling)
delta_x -= lmp->delta_x;
delta_y = y - lmp->org_y;
rct.left += delta_x;
rct.right += delta_x;
rct.top += delta_y;
rct.bottom += delta_y;
*rctp = rct;
}
/*-------------------------------------------------------------------------
function: rubber_rect
lmp: current lmp
-------------------------------------------------------------------------*/
static void
rubber_rect(LM_DATA *lmp)
{
#if XI_IS_NOT_CH
RCT rct;
DRAW_CTOOLS new_ctools;
WINDOW win = lmp->win;
CTOS_IS_PM;
xvt_app_get_default_ctools(&new_ctools);
xi_set_draw_ctools(win, &new_ctools);
xi_set_cpen(win, &rubber_cpen);
xi_set_cbrush(win, &hollow_cbrush);
xi_set_draw_mode(win, M_XOR);
xi_set_clip(win, NULL);
get_rubber_rect(lmp, &rct, lmp->last_x, lmp->last_y, lmp->last_in_hscrolling);
xi_draw_rect(win, &rct);
CTOS_END;
#endif
NOREF(lmp);
}
/*-------------------------------------------------------------------------
function: lm_move_event
lmp: current lmp
ep: xvt event
-------------------------------------------------------------------------*/
void
lm_move_event(LM_DATA *lmp, EVENT *ep)
{
PNT where;
int col_offset;
col_offset = (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
where = ep->v.mouse.where;
switch (ep->type)
{
case E_MOUSE_DOWN:
case E_MOUSE_DBL:
lmp->last_x = where.h;
lmp->org_x = lmp->last_x;
lmp->last_y = where.v;
lmp->org_y = lmp->last_y;
lmp->last_in_hscrolling = lmp->in_hscrolling;
rubber_rect(lmp);
break;
case E_MOUSE_MOVE:
if (where.h != lmp->last_x || where.v != lmp->last_y)
{
rubber_rect(lmp);
lmp->last_x = where.h;
lmp->last_y = where.v;
lmp->last_in_hscrolling = lmp->in_hscrolling;
rubber_rect(lmp);
}
break;
case E_MOUSE_UP:
{
int column;
XI_OBJ *list_obj, * *members;
int nbr_members, col_cnt, temp1, temp2, dist1, dist2, min_dist,
position;
RCT rct;
PNT where;
where = ep->v.mouse.where;
rubber_rect(lmp);
column = lmp->column_being_moved;
list_obj = lmp->list_obj;
if (list_obj)
get_rubber_rect(lmp, &rct, where.h, where.v, lmp->in_hscrolling);
if (lmp->drop_and_delete &&
(rct.bottom < (lmp->pix_top - 8) ||
rct.top > (lmp->pix_row1_top + 8)))
{
if (do_lm_cb_column((long)lmp, LM_CB_COL_DELETE, column,
0, 0, 0, FALSE) == FALSE)
{
members = xi_get_member_list(list_obj, &nbr_members);
xi_delete(members[column]);
lm_set_hscroll_range((LM)lmp);
}
}
if (where.v > lmp->pix_top && where.v < lmp->pix_row1_top &&
where.h >= lmp->rct.left)
{
BOOLEAN in_hscrolling, old_in_hscrolling;
/*
determine where to move the column, if anywhere
*/
in_hscrolling = FALSE;
old_in_hscrolling = (column >= lmp->fixed_columns);
min_dist = INT_MAX;
position = 0;
for (col_cnt = 0; col_cnt < lmp->nbr_columns; col_cnt++)
{
LM_COLUMN_DATA *column_data;
if (col_cnt >= lmp->fixed_columns &&
col_cnt < lmp->first_vis)
continue;
column_data = lmp->lm_column_data[col_cnt];
temp1 = column_data->x_pix_pos;
temp2 = temp1 + 2 * col_offset + column_data->pix_width;
dist1 = abs(temp1 - where.h);
dist2 = abs(temp2 - where.h);
if (dist1 < min_dist)
{
position = col_cnt;
min_dist = dist1;
}
if (dist2 < min_dist)
{
position = col_cnt + 1;
min_dist = dist2;
}
if (col_cnt == lmp->fixed_columns)
{
if (where.h < column_data->x_pix_pos)
in_hscrolling = FALSE;
else
in_hscrolling = TRUE;
}
}
/*
if we need to move the column, then move it
*/
if (position < column || position > column + 1 ||
position == lmp->fixed_columns)
{
if (column == position && position == lmp->fixed_columns &&
in_hscrolling && (! old_in_hscrolling))
position -= 1;
else if (position > column)
position -= 1;
/*
if there is only one fixed column left, then don't move it
*/
if (column != 0 || lmp->fixed_columns != 1)
{
int widest_remaining, col_width, width_remaining,
new_fixed_width, cnt;
BOOLEAN do_move = TRUE;
LM_COLUMN_DATA *column_data, *lmcdp2;
RCT r;
if (lmp->fixed_columns < lmp->nbr_columns)
{
/*
if there is not room in the horizontal scrolling portion of the
list for the widest column remaining in the horizontal scrolling
portion of the list, then don't move the column
*/
widest_remaining = 0;
for (cnt = lmp->fixed_columns; cnt < lmp->nbr_columns;
++cnt)
{
if (cnt == column)
continue;
column_data = lmp->lm_column_data[cnt];
col_width = column_data->pix_width + 2 * col_offset;
if (col_width > widest_remaining)
widest_remaining = col_width;
}
column_data = lmp->lm_column_data[lmp->fixed_columns];
lmcdp2 = lmp->lm_column_data[column];
new_fixed_width = column_data->x_pix_pos;
if (position < lmp->fixed_columns || ! in_hscrolling)
new_fixed_width += lmcdp2->pix_width + 2 * col_offset;
if (column < lmp->fixed_columns)
new_fixed_width -= lmcdp2->pix_width + 2 * col_offset;
lm_get_list_rct(lmp, &r);
width_remaining = r.right - r.left - new_fixed_width;
if (widest_remaining > width_remaining)
do_move = FALSE;
}
if (do_move)
{
BOOLEAN in_fixed = ! in_hscrolling;
if (position > lmp->fixed_columns)
in_fixed = FALSE;
if (do_lm_cb_column((long)lmp, LM_CB_COL_MOVE, column,
position, 0, 0, in_fixed) == FALSE)
{
members = xi_get_member_list(list_obj, &nbr_members);
xi_move_column_internal(members[column], position,
in_hscrolling);
lm_calc_last_vis(lmp);
lm_set_hscroll_bar((LM)lmp);
}
}
}
}
}
lm_make_vis(lmp);
break;
}
}
}
/*-------------------------------------------------------------------------
function: calc_x
lmp: current lmp
ep: xvt event
returns: Calculates and returns the X pixel position of the rubber band line.
Used only when sizing columns.
-------------------------------------------------------------------------*/
static int
calc_x(LM_DATA *lmp, EVENT *ep)
{
int column = lmp->column_being_sized;
int temp, temp2, widest_remaining;
int min_width_in_pix = 16;
int col_offset;
col_offset = (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
/*
temp is the min width position of the column, relative to the
left edge of the list.
*/
temp = lmp->lm_column_data[column]->x_pix_pos + col_offset +
min_width_in_pix;
temp = max(ep->v.mouse.where.h, temp);
widest_remaining = 0;
if (lmp->pixel_width)
{
int col_offset, col_width, cnt;
LM_COLUMN_DATA *column_data;
col_offset = (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
if (column < lmp->fixed_columns)
{
/*
figure out the widest column in the horizontal scrolling
portion of the list
*/
for (cnt = lmp->fixed_columns; cnt < lmp->nbr_columns; ++cnt)
{
column_data = lmp->lm_column_data[cnt];
col_width = column_data->pix_width + 2 * col_offset;
if (col_width > widest_remaining)
widest_remaining = col_width;
}
/*
add the widths of all of the columns to the right of this column
in the fixed portion of the list
*/
temp2 = 0;
for (cnt = column + 1; cnt < lmp->fixed_columns; ++cnt)
{
column_data = lmp->lm_column_data[cnt];
col_width = column_data->pix_width + 2 * col_offset;
temp2 += col_width;
}
temp = min((lmp->pixel_width - widest_remaining - temp2) - BORDER_WIDTH,
temp);
}
else
temp = min((lmp->pixel_width + lmp->delta_x) - BORDER_WIDTH, temp);
}
return temp;
}
/*-------------------------------------------------------------------------
function: rubber_x
lmp: current lmp
x: draw a rubber line at position x
-------------------------------------------------------------------------*/
static void
rubber_x(LM_DATA *lmp, int x)
{
#if XI_IS_NOT_CH
int top, bottom;
DRAW_CTOOLS new_ctools;
PNT pnt;
WINDOW win = lmp->win;
CTOS_IS_PM;
top = lmp->pix_top;
bottom = lmp->mlr.bottom;
xvt_app_get_default_ctools(&new_ctools);
xi_set_draw_ctools(win, &new_ctools);
xi_set_cpen(win, &rubber_cpen);
xi_set_draw_mode(win, M_XOR);
xi_set_clip(win, NULL);
pnt.h = x;
pnt.v = top;
if (! lmp->down_in_hscrolling)
pnt.h += lmp->rct.left;
lm_move_to(lmp, pnt, FALSE, lmp->down_in_hscrolling);
pnt.v = bottom;
lm_draw_line(lmp, pnt, FALSE, lmp->down_in_hscrolling);
CTOS_END;
#endif
NOREF(lmp);
NOREF(x);
}
/*-------------------------------------------------------------------------
function: lm_size_event
lmp: current lmp
ep: xvt event
-------------------------------------------------------------------------*/
void
lm_size_event(LM_DATA *lmp, EVENT *ep)
{
int x;
switch (ep->type)
{
case E_MOUSE_DOWN:
case E_MOUSE_DBL:
x = calc_x(lmp, ep);
lmp->last_x = x;
rubber_x(lmp, x);
break;
case E_MOUSE_MOVE:
x = calc_x(lmp, ep);
rubber_x(lmp, lmp->last_x);
lmp->last_x = x;
rubber_x(lmp, x);
break;
case E_MOUSE_UP:
{
int col_offset;
int column;
int temp;
int width_in_chars;
int pixel_width;
XI_OBJ * list_obj, * *members;
int nbr_members;
int char_width;
col_offset = (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
x = calc_x(lmp, ep);
rubber_x(lmp, lmp->last_x);
column = lmp->column_being_sized;
temp = lmp->lm_column_data[column]->x_pix_pos + col_offset;
pixel_width = (x - temp) - col_offset;
width_in_chars = (int)(pixel_width / (long)xi_get_fu_width(lmp->itf_obj));
list_obj = lmp->list_obj;
char_width = width_in_chars * XI_FU_MULTIPLE;
if (xi_get_xil_pref(list_obj->itf))
char_width = width_in_chars;
if (do_lm_cb_column((long)lmp, LM_CB_COL_SIZE, column,
0, char_width, pixel_width, FALSE) == FALSE)
{
int i;
members = xi_get_member_list(list_obj, &nbr_members);
xi_column_set_pixel_width( members[column], pixel_width );
i = lm_get_left_most_far_right_col(lmp, lmp->nbr_columns);
if (i < lmp->first_vis)
{
xvt_dwin_update(lmp->win);
lm_hscroll((LM)lmp, lmp->first_vis - i, 0);
}
else
{
lm_calc_last_vis(lmp);
lm_set_hscroll_bar((LM)lmp);
}
}
lm_make_vis(lmp);
break;
}
}
}
/*-------------------------------------------------------------------------
function: lm_set_icon
lm: current lm
icon_rid: icon resource id
row:
column:
-------------------------------------------------------------------------*/
void
lm_set_icon(LM lm, int icon_rid, int row, int column)
{
LM_DATA *lmp = LMP(lm);
lmp->cell_data[row][column].icon_rid = icon_rid;
if (LMP(lm)->attrib & XI_ATR_VISIBLE)
redraw_cell(lm, row, column, FALSE );
}
/*-------------------------------------------------------------------------
function: lm_set_sel
lm: current lm
row: row
column: column
c1: starting position in selection
c2: ending position
-------------------------------------------------------------------------*/
void lm_set_sel(LM lm, int row, int column, BOOLEAN v_scrolled, int c1, int c2)
{
LM_DATA *lmp = LMP(lm);
if (!lm_list_has_focus(lmp))
{
lm_set_focus(lm, row, column);
} else
{
int focus_row, focus_column;
BOOLEAN is_v_scrolled;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &is_v_scrolled);
if (focus_row != row || focus_column != column || v_scrolled != is_v_scrolled)
lm_set_focus(lm, row, column);
}
if (v_scrolled)
{
lmp->focus_cell_ip1 = c1;
lmp->focus_cell_ip2 = c2;
} else
txt_set_sel(lmp->txt, c1, c2);
}
/*-------------------------------------------------------------------------
function: scroll_list
lmp: current lmp
left_col:
right_col:
-------------------------------------------------------------------------*/
static void
scroll_list(LM_DATA *lmp, int left_col, int right_col)
{
RCT r;
int l1, l2, dist;
if (left_col == right_col)
{
if (lmp->nbr_columns == lmp->fixed_columns)
lmp->delta_x = 0;
return;
}
l1 = lmp->rct.left + lmp->lm_column_data[left_col]->x_pix_pos;
l2 = lmp->rct.left + lmp->lm_column_data[right_col]->x_pix_pos;
dist = l2 - l1;
lmp->delta_x += dist;
r.left = lmp->vir_left;
r.right = lmp->vir_right;
#if XI_IS_NOT_CH
CTOS_IS_PM;
r.top = lmp->rct.top + BORDER_WIDTH;
r.bottom = lmp->rct.bottom - BORDER_WIDTH;
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
r.top = lmp->rct.top;
r.bottom = lmp->rct.bottom;
CTOS_END;
#endif
if (! lmp->itf_obj->v.itf->half_baked)
xvt_dwin_update(lmp->win);
xi_set_update_obj(lmp->list_obj);
lmp->last_vis = lmp->first_vis;
lm_calc_last_vis(lmp);
#if XI_IS_CH
CTOS_IS_CH;
xi_invalidate_rect(lmp->win, &r);
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
xi_scroll_rect(lmp->win, &r, -dist, 0);
CTOS_END;
#endif
if (! lmp->itf_obj->v.itf->half_baked)
xvt_dwin_update(lmp->win);
lm_set_hscroll_bar((LM)lmp);
}
/*-------------------------------------------------------------------------
function: lm_hscroll
lm: current lm
nbr_columns: number of columns to scroll
pos: if set, pos is a percentage based on where the thumb was dropped.
-------------------------------------------------------------------------*/
void
lm_hscroll(LM lm, int nbr_columns, int pos)
{
LM_DATA *lmp = LMP(lm);
int first_vis, last_vis, lmfrc, starting_column;
xvt_dwin_update(lmp->win);
lmfrc = lm_get_left_most_far_right_col(LMP(lm), lmp->nbr_columns);
first_vis = min(lmp->first_vis, lmp->nbr_columns - 1);
last_vis = min(lmp->last_vis, lmp->nbr_columns - 1);
if (xi_get_pref(XI_PREF_UNUSED_PREFERENCE))
lm_make_invis(lmp);
else
{
if (! lmp->itf_obj->v.itf->moving_focus)
if (! xi_move_focus(lmp->itf_obj))
return;
}
if (nbr_columns == XI_SCROLL_FIRST)
{
starting_column = lmfrc;
if (starting_column)
{
starting_column = starting_column - lmp->fixed_columns;
starting_column = (int)(((long)pos * (long)starting_column) /
(long)100);
}
starting_column += lmp->fixed_columns;
lmp->first_vis = starting_column;
lmp->first_vis = min(lmp->first_vis, lmp->nbr_columns - 1);
scroll_list(lmp, first_vis, lmp->first_vis);
lm_make_vis(lmp);
return;
}
if (nbr_columns == XI_SCROLL_PGDOWN)
{
starting_column = min(last_vis + 1, lmfrc);
starting_column = min(starting_column, lmp->nbr_columns - 1);
lmp->first_vis = starting_column;
lmp->first_vis = min(lmp->first_vis, lmp->nbr_columns - 1);
scroll_list(lmp, first_vis, lmp->first_vis);
lm_make_vis(lmp);
return;
}
if (nbr_columns == XI_SCROLL_PGUP)
{
starting_column = lm_get_left_most_far_right_col(lmp, first_vis);
starting_column = min(starting_column, lmp->nbr_columns - 1);
lmp->first_vis = starting_column;
lmp->first_vis = min(lmp->first_vis, lmp->nbr_columns - 1);
scroll_list(lmp, first_vis, lmp->first_vis);
lm_make_vis(lmp);
return;
}
lmp->first_vis += nbr_columns;
if (nbr_columns > 0)
{
lmp->first_vis = min(lmp->first_vis, lm_get_left_most_far_right_col(lmp, lmp->nbr_columns));
lmp->first_vis = min(lmp->first_vis, lmp->nbr_columns - 1);
}
else
{
lmp->first_vis = max(lmp->first_vis, lmp->fixed_columns);
lmp->first_vis = min(lmp->first_vis, lmp->nbr_columns - 1);
}
scroll_list(lmp, first_vis, lmp->first_vis);
lm_make_vis(lmp);
}