campo-sirio/src/xi/xilm2.c
mtollari 1b14ec9415 Spostamento cartella sorgenti
git-svn-id: svn://10.65.10.50/branches/R_10_00@23236 c028cbd2-c16b-5b4b-a496-9718f37d4682
2016-09-09 13:59:02 +00:00

5291 lines
161 KiB
C
Executable File

/*******************************************************************************
* Copyright 1991-1996 by ORCA Software, Inc. *
* *
* All rights reserved. May not be reproduced or distributed, 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 "xilmst.h"
#include "xiutils.h"
#include "xidisply.h"
#include "xi_int.h"
#include <limits.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)
/*-------------------------------------------------------------------------
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 );
/* 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 = ( XinColor * ) xi_tree_realloc( lmp->row_colors,
sizeof( XinColor ) * realized_rows_array_len );
for ( i = old_len; i < realized_rows_array_len; ++i )
lmp->row_colors[i] = 0L;
}
else
lmp->row_colors = ( XinColor * ) xi_tree_malloc( sizeof( XinColor ) * realized_rows_array_len,
lmp );
/* cell_data */
if ( lmp->cell_data )
{
/* cell data destructor */
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( XinWindow 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->focus_state = ( LM_FOCUS_STATE * ) xi_tree_malloc( sizeof( LM_FOCUS_STATE ), lmp );
lmp->focus_state->where = LM_FOCUS_NOWHERE;
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->is_list_font = lm_def->is_list_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 XIWS == XIWS_WM
lmp->min_cell_height = 0;
lmp->min_heading_height = lm_def->min_heading_height;
#else
lmp->min_cell_height = lm_def->min_cell_height;
lmp->min_heading_height = lm_def->min_heading_height;
#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->retain_back_color_on_select = lm_def->retain_back_color_on_select;
lmp->drag_and_drop_rows = lm_def->drag_and_drop_rows;
lmp->drag_rows_autoscroll = lm_def->drag_rows_autoscroll;
lmp->button_on_cell_focus = lm_def->button_on_cell_focus;
lmp->position_by_typing_cid = lm_def->position_by_typing_cid;
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 );
XinWindowFontMap( win, lm_def->font );
XinFontMetricsGet( lm_def->font, &leading, &ascent, &descent );
lmp->cur_font = lm_def->font;
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 XIWS == XIWS_WM
lmp->pix_cell_height = font_height;
#else
lmp->pix_cell_height = font_height + CELL_VERTICAL_MARGIN;
#endif
#if XIWS == XIWS_WM
mch = 8;
#else
mch = lm_def->min_cell_height;
#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 XIWS == XIWS_WM
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 + 1;
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;
lm_def->resize_with_window = FALSE;
}
lmp->rct.left = lm_def->pnt.h;
lmp->rct.top = lm_def->pnt.v;
#if XIWS != XIWS_WM
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 );
#else
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;
#endif
lmp->vir_left = lmp->rct.left + BORDER_WIDTH;
lmp->vir_right = lmp->vir_left + lmp->pixel_width;
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 XIWS != XIWS_WM
lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH;
lmp->mlr.left = lmp->rct.left + BORDER_WIDTH;
lmp->mlr.right = lmp->rct.right - BORDER_WIDTH;
#else
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;
#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 ) ( long ) lmp );
}
/*-------------------------------------------------------------------------
function: lm_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.
-------------------------------------------------------------------------*/
void
lm_do_rec_event( LM_DATA * lmp, int row, XI_EVENT_TYPE type )
{
LM_CELL_DATA *cell_data;
int i;
if ( type == XIE_REC_FREE )
{
if ( lmp->recs[row] != lm_focus_rec_get( lmp ) )
do_lm_cb( ( LM ) lmp, LM_CB_REC_FREE, row, 0, NULL, NULL, 0 );
cell_data = lmp->cell_data[row];
/* cell_data_destruct */
for ( i = 0; i < lmp->nbr_columns; ++i, ++cell_data )
{
if ( cell_data->font )
XinFontDestroy( cell_data->font );
xi_bitmap_destroy( cell_data->bitmap );
xi_bitmap_destroy( cell_data->button_bitmap );
if ( cell_data->xi_text )
xi_text_destruct( cell_data->xi_text );
memset( ( char * ) cell_data, '\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;
lmp->row_attribs[row] = 0L;
lmp->row_colors[row] = 0L;
}
/* cell_data_construct */
if ( type == XIE_REC_ALLOCATE )
{
do_lm_cb( ( LM ) lmp, LM_CB_REC_ALLOCATE, row, 0, NULL, NULL, 0 );
cell_data = lmp->cell_data[row];
for ( i = 0; i < lmp->nbr_columns; ++i, ++cell_data )
{
memset( ( char * ) cell_data, '\0', sizeof( LM_CELL_DATA ) );
lm_xi_text_construct( lmp, row, i );
}
}
}
/*-------------------------------------------------------------------------
function: lm_row_copy
lmp: current lmp
source_row: row from which to copy
dest_row: destination row
-------------------------------------------------------------------------*/
void
lm_row_copy( LM_DATA * lmp, int source_row, int dest_row )
{
int idx;
LM_CELL_DATA *dest_cell_data,
*source_cell_data;
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];
lmp->row_attribs[dest_row] = lmp->row_attribs[source_row];
lmp->row_colors[dest_row] = lmp->row_colors[source_row];
for ( idx = 0,
dest_cell_data = lmp->cell_data[dest_row],
source_cell_data = lmp->cell_data[source_row];
idx < lmp->nbr_columns;
++idx,
++dest_cell_data,
++source_cell_data )
{
*dest_cell_data = *source_cell_data;
}
}
/*-------------------------------------------------------------------------
function: init_row
lmp: current lmp
row: row to init
-------------------------------------------------------------------------*/
static void
init_row( LM_DATA * lmp, int row )
{
int idx;
LM_CELL_DATA *cell_data;
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,
cell_data = lmp->cell_data[row];
idx < lmp->nbr_columns;
++idx,
++cell_data )
{
memset( ( char * ) cell_data, '\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 )
lm_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 )
lm_row_copy( lmp, idx - 1, idx );
lm_adjust_rows( lmp, 1 );
init_row( lmp, 0 );
if ( allocate_rec )
lm_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];
lm_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 )
lm_row_copy( lmp, idx, idx - cnt );
lm_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 )
lm_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 ) )
{
lm_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 ) )
{
lm_do_rec_event( lmp, 0, XIE_REC_FREE );
for ( cnt = 0; cnt < lmp->nbr_realized_rows - 1; ++cnt )
lm_row_copy( lmp, cnt + 1, cnt );
lm_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.
-------------------------------------------------------------------------*/
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;
LM_COLUMN_DATA *lm_column_data;
cell_data = &lmp->cell_data[row][column];
lm_column_data = lmp->lm_column_data[column];
if ( !cell_data->font_height )
{
XinFont *font;
int leading,
ascent,
descent,
char_width;
if ( lm_column_data->wrap_text && !cell_data->valid_data )
do_lm_cb_text( lmp, row, column, TRUE );
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 ( lm_column_data->wrap_text )
{
int pix_spacing;
BOOLEAN is_editing;
int ip1,
ip2,
start_ip;
if ( !cell_data->valid_data )
do_lm_cb_text( lmp, row, column, TRUE );
is_editing = xi_text_editing_is( cell_data->xi_text );
if ( is_editing )
xi_text_selection_get_internal( cell_data->xi_text, &ip1, &ip2, &start_ip );
xi_text_initialized_set( cell_data->xi_text, FALSE );
pix_spacing = lm_column_data->pix_width -
( cell_data->button ? lmp->pix_row_spacing : 0 );
xi_text_pix_width_set( cell_data->xi_text, pix_spacing );
if ( is_editing )
xi_text_selection_set_internal( cell_data->xi_text, ip1, ip2, start_ip, FALSE, FALSE );
nbr_lines = min( xi_text_nbr_lines_get( cell_data->xi_text ), lmp->max_lines_in_cell );
}
else
nbr_lines = 1;
#if XIWS != XIWS_WM
pix_height = nbr_lines * cell_data->font_height + CELL_VERTICAL_MARGIN
+ RULE_WIDTH_H;
#else
pix_height = nbr_lines * cell_data->font_height;
#endif
if ( lm_focus_state_get( lmp ) == LM_FOCUS_VERTICALLY_SCROLLED )
{
int focus_row,
focus_column;
BOOLEAN v_scrolled;
lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled );
if ( focus_column == column && lmp->recs[row] == lmp->focus_state->focus_rec )
pix_height = lmp->focus_state->focus_rec_height;
}
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 XIWS == XIWS_WM
if ( *pix_offsetsp + *pix_heightsp + lmp->rrr_offset <= lmp->mlr_height )
lmp->last_fully_vis = i;
#else
if ( *pix_offsetsp + *pix_heightsp - 1 + lmp->rrr_offset <= lmp->mlr_height )
lmp->last_fully_vis = i;
#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 ) )
{
XinRect 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 XIWS == XIWS_WM
if ( cur_pix + lmp->rrr_offset <= lmp->mlr_height )
lmp->last_fully_vis = i;
#else
if ( cur_pix - 1 + lmp->rrr_offset <= lmp->mlr_height )
lmp->last_fully_vis = i;
#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->nbr_columns == 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 )
return recs_read;
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 );
}
prop = max( 0, min( 100, prop ) );
XinScrollBarSet( listdata->sb_win, XinScrollBarTypeEither, 0, 100,
prop, top );
}
else
{
int percent1 = 0;
int percent2 = 100;
int prop = 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 );
prop = min(100, max( 1, ( percent2 - percent1 ) ) );
#if XIWS == XIWS_WXGTK
const int act_pos = XinScrollBarPositionGet( listdata->sb_win, XinScrollBarTypeEither );
if (act_pos >= percent1 && act_pos <= percent2)
percent1 = -1;
#endif
}
#if XIWS != XIWS_WXGTK
else
prop = min(100, max( 1, ( percent2 - percent1 ) ) );
#endif
XinScrollBarSet( listdata->sb_win, XinScrollBarTypeEither, 0,
100, prop, percent1 );
}
}
}
/*-------------------------------------------------------------------------
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 ( lm_focus_rec_get( lmp ) && delete_focus )
{
int idx;
BOOLEAN found = FALSE;
for ( idx = 0; idx < lmp->nbr_realized_rows; ++idx )
{
if ( lm_focus_rec_get( lmp ) == 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 = lm_focus_rec_get( lmp );
( *lmp->lm_cb ) ( &lm_cb_data );
}
}
for ( i = 0; i < lmp->nbr_realized_rows; ++i )
lm_do_rec_event( lmp, i, XIE_REC_FREE );
lmp->nbr_realized_rows = 0;
lmp->rrr_bottom = 0;
lmp->rrr_offset = 0;
}
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;
}
/*-------------------------------------------------------------------------
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;
XinColor color;
unsigned long attrib;
int row_height_arg;
int scroll_type;
int pix_overlap;
int nbr_pixels;
XinRect 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_focus_list_has( lmp ) )
{
data->list_had_focus = TRUE;
lm_focus_cell_get( lmp, &data->focus_row, &data->focus_column,
&data->v_scrolled );
if ( xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) )
{
if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE )
{
lm_focus_cell_invis_make( lmp );
switch ( data->nbr_lines )
{
case XI_SCROLL_FIRST:
lm_focus_rec_is_above_set( lmp, FALSE );
case XI_SCROLL_LAST:
lm_focus_rec_is_above_set( lmp, TRUE );
break;
case XI_SCROLL_PGUP:
lm_focus_rec_is_above_set( lmp, FALSE );
break;
case XI_SCROLL_PGDOWN:
lm_focus_rec_is_above_set( lmp, TRUE );
break;
default:
lm_focus_rec_is_above_set( lmp, ( BOOLEAN ) ( 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;
if (data->nbr_lines == XI_SCROLL_FIRST || data->nbr_lines == XI_SCROLL_LAST)
{ /* The old data went away, so the old focus location is no longer valid. */
lmp->list_obj->v.list->focus_cell->v.cell.row = 0;
lmp->list_obj->v.list->focus_cell->v.cell.column = 0;
lmp->list_obj->v.list->focus_cell->v.cell.is_vert_scrolled = 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 XIWS == XIWS_WM
data->nbr_pixels = -( lmp->mlr_height - data->pix_overlap );
#else
data->nbr_pixels = -( lmp->mlr_height - data->pix_overlap + 1 );
#endif
data->have_pixels = TRUE;
break;
case XI_SCROLL_PGDOWN:
#if XIWS == XIWS_WM
data->nbr_pixels = lmp->mlr_height - data->pix_overlap;
#else
data->nbr_pixels = lmp->mlr_height - data->pix_overlap + 1;
#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, LM_CB_TYPE event_type )
{
int row_height;
BOOLEAN refused;
/* first, get rid of all rows, except the focus row */
lm_remove_all_rows( lmp, FALSE );
make_rec_available( lmp, ( BOOLEAN ) record_location, ( BOOLEAN ) ! data->have_rec, TRUE );
if ( data->have_rec )
{
LM_CELL_DATA *cell_data;
int i;
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;
/* cell_data_construct */
cell_data = lmp->cell_data[0];
for ( i = 0; i < lmp->nbr_columns; ++i, ++cell_data )
{
memset( ( char * ) cell_data, '\0', sizeof( LM_CELL_DATA ) );
lm_xi_text_construct( lmp, 0, i );
}
}
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 )
{
lm_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->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 )
{
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];
lm_do_rec_event( lmp, cnt, XIE_REC_FREE );
}
for ( idx = nbr_to_free; idx < lmp->nbr_realized_rows; ++idx )
lm_row_copy( lmp, idx, idx - nbr_to_free );
result -= nbr_to_free;
lm_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++ )
lm_do_rec_event( lmp, idx, XIE_REC_FREE );
lmp->nbr_realized_rows -= cnt;
calculate_pix_offsets( lmp, FALSE );
{
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.is_vert_scrolled = TRUE;
}
}
}
}
}
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 XIWS == XIWS_WM
lmp->rrr_offset = lmp->mlr_height - lmp->rrr_bottom;
#else
lmp->rrr_offset = lmp->mlr_height - lmp->rrr_bottom + 1;
#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
-------------------------------------------------------------------------*/
XinRect *
lm_get_scroll_rct( LM_DATA * lmp, XinRect * r )
{
*r = lmp->mlr;
if ( lmp->pixel_width )
r->right = r->left + lmp->pixel_width + BORDER_WIDTH - 1;
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 )
{
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];
lm_do_rec_event( lmp, cnt, XIE_REC_FREE );
}
for ( cnt = nbr_to_free; cnt < lmp->nbr_realized_rows; ++cnt )
lm_row_copy( lmp, cnt, cnt - nbr_to_free );
lm_adjust_rows( lmp, -nbr_to_free );
lmp->nbr_realized_rows -= nbr_to_free;
}
calculate_pix_offsets( lmp, FALSE );
/* 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++ )
lm_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 )
{
XinRect r;
lm_get_scroll_rct( lmp, &r );
xi_set_clip( lmp->win, NULL );
if ( data->nbr_pixels )
{
XinWindowPaintForce( 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_KEEP_FOCUS_FIXED ) )
lm_focus_cell_visible_attempt( 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;
XinRect 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;
BOOLEAN v_scrolled,
focus;
int new_row_height;
int row,
column;
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 )
XinWindowPaintForce( lmp->win );
old_focus_obj = itf->v.itf->focus_obj;
if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE )
{
focus = lm_focus_cell_get( lmp, &row, &column, &v_scrolled );
if ( focus && !v_scrolled )
{
new_row_height = lm_calculate_row_height( lmp, row );
if ( new_row_height != lmp->pix_heights[row] )
lm_set_row_height( ( LM ) lmp, row, new_row_height, FALSE, 0, FALSE );
}
}
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 )
{
XinRect 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_focus_cell_get( lmp, &focus_row, &focus_column, &is_vert_scrolled );
is_vis = lm_focus_cell_is_visible( lmp, &is_hscrolled );
if ( ( is_vis || is_hscrolled ) && !is_vert_scrolled )
{
lm_redraw_row( lmp, focus_row, FALSE );
if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE )
set_focus_cell_rct( lmp, focus_row, focus_column, FALSE );
} /* is vis */
} /* focus border */
do_scroll_bar( lmp->list_obj->v.list );
if ( invalidate )
XinWindowPaintForce( lmp->win );
return result;
}
/*-------------------------------------------------------------------------
function: lm_set_text
lm: current lm
s: string to set
row:
column:
-------------------------------------------------------------------------*/
void
lm_set_text( LM lm, const char *s, int row, int column, BOOLEAN v_scrolled )
{
BOOLEAN was_suspended = FALSE;
BOOLEAN preserve_focus_text;
LM_COLUMN_DATA *lmcd;
XinRect 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;
LM_CELL_DATA *cell_data;
cell_data = &lmp->cell_data[row][column];
preserve_focus_text = FALSE;
if ( lm_focus_cell_has( lmp, row, column, v_scrolled ) && lmp->itf_obj->v.itf->chg_flag )
{
was_suspended = TRUE;
lm_focus_cell_invis_make( lmp );
preserve_focus_text = TRUE;
}
/* If the cell has focus the XI_TEXT string needs updated */
if ( lm_focus_cell_has( lmp, row, column, v_scrolled ) )
{
xi_text_set( cell_data->xi_text, s );
}
else if ( !v_scrolled )
xi_text_set( cell_data->xi_text, s );
if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE )
lm_focus_cell_text_set( lmp, preserve_focus_text, s, row, column, v_scrolled );
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 && LMP( lm )->cell_data[row][column].valid_data )
redraw_cell( lm, row, column, FALSE );
}
if ( was_suspended )
lm_focus_cell_visible_attempt( 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, BOOLEAN v_scrolled )
{
LM_DATA *lmp = LMP( lm );
switch ( c )
{
case XI_KEY_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 ) )
{
if ( *next_row == 255 && v_scrolled )
*next_row = 0;
else
++* next_row;
}
}
break;
case XI_KEY_UP:
--*next_row;
break;
case XI_KEY_DOWN:
if ( *next_row == 255 && v_scrolled )
*next_row = 0;
else
++* next_row;
break;
case XI_KEY_WLEFT:
case XI_KEY_LEFT:
--*next_col;
if ( *next_col < 0 )
*next_col = lmp->nbr_columns - 1;
break;
case XI_KEY_WRIGHT:
case XI_KEY_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, XinEvent * 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 ( lmp->have_last_rec && lm_cb_data.v.rec_free.record == lmp->last_rec )
lmp->have_last_rec = FALSE;
if ( !lm_cb_data.v.rec_allocate.record )
return FALSE;
break;
case LM_CB_CHAR:
lm_cb_data.v.chr.ch = ep->v.character.ch;
lm_cb_data.v.chr.shift = ep->v.character.shift;
lm_cb_data.v.chr.control = ep->v.character.control;
lm_cb_data.v.chr.alt = ep->v.character.alt;
lm_cb_data.v.chr.is_paste = FALSE;
lm_cb_data.v.chr.refused = FALSE;
break;
case LM_CB_CELL_BTN:
if ( ep->type == XinEventCharacter )
{
lm_cb_data.v.cell_btn.shift = ep->v.character.shift;
lm_cb_data.v.cell_btn.control = ep->v.character.control;
}
else
{
lm_cb_data.v.cell_btn.shift = ep->v.mouse.shift;
lm_cb_data.v.cell_btn.control = ep->v.mouse.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.character.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, XinColor * 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 );
if ( cb_reason == LM_CB_GET_NEXT && lm_cb_data.v.rec_request.refused )
{
lmp->have_last_rec = TRUE;
lmp->last_rec = lm_cb_data.v.rec_request.spec_rec;
}
if ( !lm_cb_data.v.rec_request.refused )
{
if ( cb_reason == LM_CB_GET_LAST )
{
lmp->have_last_rec = TRUE;
lmp->last_rec = lm_cb_data.v.rec_request.data_rec;
}
*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 XIWS != XIWS_WM
*row_height = lm_cb_data.v.rec_request.row_height;
#else
*row_height = 0;
#endif
if ( lm_cb_data.v.rec_request.has_focus
&& xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) )
{
if ( lm_focus_rec_get( lmp ) )
{
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 = lm_focus_rec_get( lmp );
( *lmp->lm_cb ) ( &lm_cb_data );
}
lm_focus_rec_set( lmp, *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, int ch, BOOLEAN * off_top,
BOOLEAN * off_bottom )
{
BOOLEAN keep_looking;
int focus_row,
focus_column;
BOOLEAN v_scrolled;
keep_looking = *use_key;
lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled );
*next_row = focus_row;
*next_col = focus_column;
while ( keep_looking )
{
next_cell( ( LM ) lmp, ch, next_row, next_col, v_scrolled );
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
{
LM_CELL_DATA *cell_data;
cell_data = &lmp->cell_data[*next_row][*next_col];
if ( !cell_data->valid_data )
do_lm_cb_text( lmp, *next_row, *next_col, TRUE );
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
&& lmp->cell_data[*next_row][*next_col].bitmap == NULL )
/* found a valid cell */
keep_looking = FALSE;
}
}
}
void
lm_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 )
{
if ( (int)focus_obj->v.cell.row + delta < 0 )
{
focus_obj->v.cell.is_vert_scrolled = TRUE;
focus_obj->v.cell.row += delta;
return;
}
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, XinEvent * 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 );
short c = ep->v.character.ch;
if ( !lm_focus_list_has( lmp ) )
return FALSE;
if ( ( c == '\r' || c == '\n' ) && lmp->itf_obj->v.itf->tab_on_enter)
{
int row, col;
BOOLEAN is_vert_scrolled;
lm_focus_cell_get( lmp, &row, &col, &is_vert_scrolled );
if (!lmp->lm_column_data[col]->cr_ok)
{
c = (short)xi_get_pref( XI_PREF_FORM_TAB_CHAR );
ep->v.character.ch = c;
}
}
switch ( c )
{
case '\t':
case XI_KEY_BTAB:
case XI_KEY_UP:
case XI_KEY_DOWN:
case XI_KEY_PREV:
case XI_KEY_NEXT:
use_key = TRUE;
break;
case XI_KEY_WRIGHT:
case XI_KEY_WLEFT:
case XI_KEY_LEFT:
case XI_KEY_RIGHT:
if ( ( lmp->attrib & LM_ATR_NAVIGATE ) || ep->v.character.control )
use_key = TRUE;
break;
}
switch ( c )
{
case XI_KEY_UP:
case XI_KEY_DOWN:
case XI_KEY_PREV:
case XI_KEY_NEXT:
{
if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE )
{
XI_TEXT *text = xi_text_focus_get( lmp->win );
if ( text != 0 && text->multi_line && !ep->v.character.control
&& !( lmp->attrib & LM_ATR_NAVIGATE ) )
return FALSE;
}
switch ( c )
{
case XI_KEY_PREV:
xi_control_event_scroll( lmp->list_obj, XI_SCROLL_PGUP, 0, TRUE );
return TRUE;
case XI_KEY_NEXT:
xi_control_event_scroll( lmp->list_obj, XI_SCROLL_PGDOWN, 0, TRUE );
return TRUE;
}
break;
}
case XI_KEY_WRIGHT:
case XI_KEY_WLEFT:
case XI_KEY_LEFT:
case XI_KEY_RIGHT:
if ( !use_key )
return FALSE;
}
calculate_next_cell( lmp, &next_row, &next_col,
&use_key, c, &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_focus_cell_invis_make( lmp );
lm_focus_cell_get( 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, c,
&off_top, &off_bottom );
lm_focus_cell_get( 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 )
{
LM_CELL_DATA *cell_data;
cell_data = &lmp->cell_data[next_row][next_col];
if ( !cell_data->valid_data )
do_lm_cb_text( lmp, next_row, next_col, TRUE );
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
&& lmp->cell_data[next_row][next_col].bitmap == NULL )
break;
next_cell( lm, off_bottom ? '\t' :
XI_KEY_BTAB, &next_row, &next_col, v_scrolled );
}
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 );
XinWindowPaintForce( lmp->win );
list_data->scrolling_in_progress = FALSE;
}
XinWindowPaintForce( lmp->win );
lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled );
if ( focus_row > lmp->last_fully_vis )
{
LM_FOCUS_CELL_VISIBLE_FORCE_ARGS args;
MEMCLEAR( args );
args.lmp = lmp;
args.row = focus_row;
args.column = focus_column;
args.vert_scrolled = v_scrolled;
lm_focus_cell_visible_force( &args );
lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled );
next_row = focus_row;
calculate_pix_offsets( lmp, FALSE );
}
lm_focus_cell_visible_attempt( 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 );
XinWindowPaintForce( lmp->win );
list_data->scrolling_in_progress = FALSE;
}
}
if ( next_row < lmp->first_fully_vis )
{
int delta,
idx2,
pix2,
old_pix,
cnt,
height;
XinRect tmp_rct;
if ( lmp->first_fully_vis == 0 )
return use_key;
lm_focus_cell_invis_make( 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 )
XinWindowPaintForce( 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_focus_cell_visible_attempt( lmp );
should_redraw = FALSE;
}
if ( next_row > lmp->last_fully_vis )
{
int delta,
delta2,
diff,
cnt,
height,
first,
old_row_height,
focus_row;
int idx,
missing;
int focus_column,
new_row_height;
BOOLEAN v_scrolled;
XinRect tmp_rct;
if ( lmp->last_fully_vis >= lmp->nbr_realized_rows )
return use_key;
lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled );
old_row_height = lmp->pix_heights[focus_row];
lm_focus_cell_invis_make( lmp );
delta = lmp->pix_heights[lmp->first_fully_vis];
lm_make_rrr_room_pix( lmp, delta, TRUE );
idx = lmp->last_fully_vis + 1;
missing = lmp->mlr_height - ( lmp->pix_offsets[idx] + lmp->pix_heights[idx] );
if ( lmp->last_fully_vis + 1 < lmp->nbr_realized_rows )
delta = max( delta, missing );
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 )
XinWindowPaintForce( 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_focus_cell_get( 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 )
{
int nbr_to_free,
cnt,
i,
idx;
nbr_to_free = lmp->first_fully_vis;
if ( nbr_to_free > 0 )
{
int rheight;
rheight = 0;
for ( cnt = 0; cnt < nbr_to_free; cnt++ )
{
lmp->rrr_offset += lmp->pix_heights[cnt];
rheight += lmp->pix_heights[cnt];
lm_do_rec_event( lmp, cnt, XIE_REC_FREE );
}
for ( idx = nbr_to_free; idx < lmp->nbr_realized_rows; ++idx )
lm_row_copy( lmp, idx, idx - nbr_to_free );
lm_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, c, &off_top, &off_bottom );
lmp->nbr_realized_rows -= cnt;
calculate_pix_offsets( lmp, should_redraw );
calculate_visibles( lmp );
lm_make_rrr_room_pix( lmp, rheight, TRUE );
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++ )
lm_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 );
lm_focus_cell_visible_attempt( lmp );
}
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 );
if ( lmp->get_all_records )
XinError( 20919, XinSeverityFatal, 0L );
if ( xi_move_focus( lmp->itf_obj ) )
{
if ( row > 0 && lmp->nbr_realized_rows )
{
int idx = 0,
row_height,
pix;
XinRect 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 *cell_data;
int i;
make_rec_available( lmp, REC_AT_BOTTOM, FALSE, FALSE );
for ( i = lmp->nbr_realized_rows - 2; i >= row; i-- )
lm_row_copy( lmp, i, i + 1 );
idx = row;
/* cell_data_construct */
cell_data = lmp->cell_data[idx];
for ( i = 0; i < lmp->nbr_columns; ++i, ++cell_data )
{
memset( ( char * ) cell_data, '\0', sizeof( LM_CELL_DATA ) );
lm_xi_text_construct( lmp, idx, i );
}
lmp->recs[idx] = 0L;
lm_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 ) )
{
lm_do_rec_event( lmp, lmp->nbr_realized_rows - 1, XIE_REC_FREE );
for ( i = row; i < lmp->nbr_realized_rows - 2; ++i )
lm_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;
XinRect 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 ) )
{
lm_do_rec_event( lmp, 0, XIE_REC_FREE );
for ( cnt = 1; cnt < lmp->nbr_realized_rows; ++cnt )
lm_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 );
if ( lmp->get_all_records )
XinError( 20920, XinSeverityFatal, 0L );
if ( xi_move_focus( lmp->itf_obj ) )
{
int pix_height,
i;
int recs_read;
XinRect r,
row_rct;
pix_height = lmp->pix_heights[row];
lm_get_rect( lm, LM_ROW, row, &row_rct );
lm_do_rec_event( lmp, row, XIE_REC_FREE );
for ( i = row + 1; i < lmp->nbr_realized_rows; i++ )
lm_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 );
XinWindowPaintForce( lmp->win );
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;
XinRect r,
r2;
if ( !lmp->itf_obj->v.itf->half_baked )
XinWindowPaintForce( 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 )
{
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++ )
lm_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;
if ( r.top < r.bottom )
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;
XinRect vert_scrollbar_rect;
XinRect horz_scrollbar_rect;
XinRect ir,
old_rct;
int old_height;
int col_offset;
int max_row_height;
int row_height;
int heading_height;
int i;
int row,
col;
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 */
if ( !list_data->one_row_list )
{
{
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->pixel_height = height;
lmp->rct.bottom = lmp->rct.top + height
- ( ( list_data->hsb_win ) ? ( horz_scrollbar_rect.bottom
- horz_scrollbar_rect.top - 1 )
: 0 );
#if XIWS == XIWS_WM
lmp->mlr.bottom = lmp->rct.bottom;
#else
lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH;
#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 );
lm_set_hscroll_bar( 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 )
{
XinWindowPaintForce( 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++ )
lm_do_rec_event( lmp, i, XIE_REC_FREE );
lmp->nbr_realized_rows -= cnt;
calculate_visibles( lmp );
}
for ( col = 0; col < lmp->nbr_columns; ++col )
{
for ( row = 0; row < lmp->nbr_realized_rows; ++row )
{
LM_CELL_DATA *cell_data;
cell_data = &lmp->cell_data[row][col];
if ( cell_data->xi_text )
{
XinRect r;
r = lmp->mlr;
if ( lmp->pixel_width )
r.right = r.left + lmp->pixel_width;
xi_text_clip_set( cell_data->xi_text, &r );
}
}
}
}
static void
calc_lmp_rct_right( LM_DATA * lmp )
{
/* TODO for XINCH mode, need to duplicate algorythm in lm_create */
/* single-column lists do not have a vertical rule seperating columns */
if ( lmp->nbr_columns == 0 )
lmp->rct.right = lmp->rct.left + 2 * BORDER_WIDTH;
else
{
LM_COLUMN_DATA *cell_data = lmp->lm_column_data[lmp->nbr_columns - 1];
lmp->rct.right = lmp->rct.left + cell_data->x_pix_pos + cell_data->pix_width + 2 * BORDER_WIDTH +
( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET );
}
lmp->mlr.right = lmp->rct.right - BORDER_WIDTH;
}
void
lm_recalc_metrics( LM lm )
{
LM_DATA *lmp = ( LM_DATA * ) lm;
int leading,
ascent,
descent,
font_height,
mch,
i;
XinWindow win;
LM_COLUMN_DATA **cell_data;
int old_char_width;
XI_LIST_DATA *list_data;
XinPoint pnt;
XinRect 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;
}
if ( !lmp->is_list_font )
lmp->font = lmp->itf_obj->v.itf->font;
if (!lmp->font)
lmp->font = xi_get_system_font();
win = lmp->win;
XinWindowFontMap( win, lmp->font );
XinFontMetricsGet( lmp->font, &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 XIWS == XIWS_WM
mch = 8;
#else
mch = lmp->min_cell_height;
#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 + 1;
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, cell_data = lmp->lm_column_data; i < lmp->nbr_columns; ++i, ++cell_data )
( *cell_data )->pix_width = ( *cell_data )->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 );
calc_lmp_rct_right( lmp );
if ( !lmp->resize_with_window )
{
#if XIWS != XIWS_WM
lmp->rct.bottom = lmp->pix_row1_top + lmp->nbr_rows * lmp->pix_row_spacing +
( BORDER_WIDTH - RULE_WIDTH_H );
#else
lmp->rct.bottom = lmp->pix_row1_top + lmp->nbr_rows * lmp->pix_row_spacing
+ BORDER_WIDTH;
#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 XIWS != XIWS_WM
lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH;
#else
if ( lmp->pixel_width )
lmp->mlr.bottom = lmp->rct.bottom;
else
lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH;
#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 );
{
XinRect vert_scrollbar_rect;
xi_get_sb_rect( lmp->list_obj, &vert_scrollbar_rect );
if ( list_data->sb_win )
lmp->pixel_width -= ( vert_scrollbar_rect.right
- vert_scrollbar_rect.left - 1 );
lmp->pixel_width = max( lmp->pixel_width, 0 );
lmp->vir_right = lmp->rct.left + lmp->pixel_width + BORDER_WIDTH;
}
list_data->have_sb_rct = FALSE;
list_data->have_hsb_rct = FALSE;
xi_get_sb_rect( lmp->list_obj, &rct );
xi_offset_rect( &rct, -lmp->list_obj->itf->v.itf->delta_x,
-lmp->list_obj->itf->v.itf->delta_y );
if ( list_data->sb_win )
XinWindowRectSet( list_data->sb_win, &rct );
xi_get_hsb_rect( lmp->list_obj, &rct );
xi_offset_rect( &rct, -lmp->list_obj->itf->v.itf->delta_x,
-lmp->list_obj->itf->v.itf->delta_y );
if ( list_data->hsb_win )
XinWindowRectSet( 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;
XinRect 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( );
prop = mlr.right - mlr.left - fixed_width - BORDER_WIDTH;
prop = min( prop, hscroll_width );
prop = max( prop, 0 );
XinScrollBarSet( listdata->hsb_win, XinScrollBarTypeEither, 0,
hscroll_width, prop, 0 );
}
}
/*-------------------------------------------------------------------------
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;
XinRect 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 */
calc_lmp_rct_right( lmp );
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_set_hscroll_bar( ( 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++ )
lm_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 );
}
/*-------------------------------------------------------------------------
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_focus_cell_invis_make( lmp );
switch ( lm_part )
{
case LM_LIST:
lm_invalidate_rows_internal( lm, 0, lmp->nbr_realized_rows - 1, redraw, -1,
FALSE );
lm_focus_cell_visible_attempt( lmp );
return;
case LM_ROW:
lm_invalidate_rows_internal( lm, idx1, idx1, redraw, -1, FALSE );
lm_focus_cell_visible_attempt( lmp );
return;
case LM_COLUMN:
lm_invalidate_rows_internal( lm, 0, lmp->nbr_realized_rows - 1, redraw, idx1,
FALSE );
lm_focus_cell_visible_attempt( lmp );
return;
case LM_CELL:
lm_invalidate_rows_internal( lm, idx1, idx1, redraw, idx2, FALSE );
lm_focus_cell_visible_attempt( lmp );
return;
}
XinError( 20918, XinSeverityFatal, 0L );
}
/*-------------------------------------------------------------------------
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
lm_set_buf_size_internal( LM lm, LM_PART part, int idx, int size, BOOLEAN redraw )
{
int i;
LM_COLUMN_DATA *lmcd;
LM_DATA *lmp = LMP( lm );
if ( part != LM_COLUMN )
XinError( 20917, XinSeverityFatal, 0L );
lmcd = lmp->lm_column_data[idx];
lmcd->text_size = size;
if ( ! lmcd->var_len_text )
{
for ( i = 0; i < lmp->nbr_realized_rows; i++ )
{
LM_CELL_DATA *cell_data = &lmp->cell_data[i][idx];
xi_text_buffer_size_set( cell_data->xi_text, size );
if ( redraw && i < lmp->nbr_realized_rows )
redraw_cell( lm, i, idx, FALSE );
}
}
}
/*-------------------------------------------------------------------------
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 next */
/* column, previous column, or interface. */
/* ------------------------------------------------------------------------ */
static BOOLEAN
adjust_focus_for_column_delete( LM_DATA * lmp, int column_nbr,
BOOLEAN adjust_focus_column )
{
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 TRUE;
if ( focus_obj->v.cell.column == column_nbr )
{
XI_OBJ new_cell;
int row, col;
BOOLEAN temp;
temp = TRUE;
calculate_next_cell( lmp, &row, &col, &temp, '\t', &temp, &temp );
if ( row != focus_obj->v.cell.row )
{
temp = TRUE;
calculate_next_cell( lmp, &row, &col, &temp, XI_KEY_BTAB, &temp, &temp );
}
if ( row == focus_obj->v.cell.row )
{
XI_MAKE_CELL( &new_cell, lmp->list_obj, row, col );
if ( !xi_move_focus( &new_cell ) )
return FALSE;
if ( adjust_focus_column &&
( int ) focus_obj->v.cell.column > ( int ) column_nbr )
{
focus_obj = lmp->itf_obj->v.itf->focus_obj;
focus_obj->v.cell.column--;
}
return TRUE;
}
return xi_move_focus( lmp->itf_obj );
}
if ( adjust_focus_column &&
( int ) focus_obj->v.cell.column > ( int ) column_nbr )
focus_obj->v.cell.column--;
return TRUE;
}
/*-------------------------------------------------------------------------
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;
XinRect invalid_rct,
old_rct;
int i,
old_width,
old_left,
col_spacing;
int old_x_pix_pos;
LM_CELL_DATA *cell_data;
if ( !adjust_focus_for_column_delete( lmp, column_nbr, TRUE ) )
return;
col_spacing = lm_get_col_spacing( );
if ( column_nbr >= lmp->nbr_columns )
XinError( 20915, XinSeverityFatal, 0L );
old_rct = lmp->rct;
lmcd = lmp->lm_column_data[column_nbr];
if ( lmcd->font )
XinFontDestroy( lmcd->font );
xi_bitmap_destroy( lmcd->bitmap );
old_left = lmcd->x_pix_pos - lmp->delta_x;
old_x_pix_pos = lmcd->x_pix_pos;
old_width = lmcd->pix_width;
xi_tree_free( lmp->lm_column_data[column_nbr] );
/* cell_data_destruct */
for ( i = 0; i < lmp->nbr_realized_rows; ++i )
{
cell_data = &( lmp->cell_data[i][column_nbr] );
if ( cell_data->font )
XinFontDestroy( cell_data->font );
xi_bitmap_destroy( cell_data->bitmap );
xi_bitmap_destroy( cell_data->button_bitmap );
if ( cell_data->xi_text )
xi_text_destruct( cell_data->xi_text );
}
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;
{ /* Check focus cell, to see if it is now out of range */
XI_OBJ* focus_cell;
focus_cell = lmp->list_obj->v.list->focus_cell;
if ( (int)focus_cell->v.cell.column >= lmp->nbr_columns )
focus_cell->v.cell.column = lmp->nbr_columns - 1;
}
for ( i = column_nbr; i < lmp->nbr_columns; ++i )
calc_x_pix_pos( lm, lmp->lm_column_data[i], i );
calc_lmp_rct_right( lmp );
/* 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 );
lm_set_hscroll_bar( ( LM ) lmp );
}
else
{
if ( column_nbr < lmp->fixed_columns )
{
--lmp->first_vis;
--lmp->fixed_columns;
lm_set_hscroll_range( ( LM ) lmp );
lm_set_hscroll_bar( ( 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 );
/* All columns have been deleted */
if ( i == 0 )
{
lmp->delta_x = 0;
lmp->last_vis = lmp->first_vis = i;
lm_calc_last_vis( lmp );
lm_set_hscroll_bar( ( LM ) lmp );
return;
}
if ( lmp->first_vis >= lmp->nbr_columns )
{
XinRect r;
XinWindowPaintForce( lmp->win );
if ( i < lmp->nbr_columns )
lmp->delta_x = lmp->lm_column_data[i]->x_pix_pos - lmp->vir_left;
else
lmp->delta_x = 0;
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 XIWS != XIWS_WM
r.top = lmp->rct.top + BORDER_WIDTH;
r.bottom = lmp->rct.bottom - BORDER_WIDTH;
#else
r.top = lmp->rct.top;
r.bottom = lmp->rct.bottom;
#endif
xi_invalidate_rect( lmp->win, &r );
XinWindowPaintForce( lmp->win );
lm_set_hscroll_bar( ( LM ) lmp );
}
else
{
if ( i < lmp->first_vis && adjust_hscrolling )
{
XinWindowPaintForce( lmp->win );
lm_hscroll( lm, i - lmp->first_vis, 0 );
lm_set_hscroll_range( ( LM ) lmp );
lm_set_hscroll_bar( ( LM ) lmp );
}
else
{
lm_calc_last_vis( lmp );
lm_set_hscroll_range( ( LM ) lmp );
lm_set_hscroll_bar( ( 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;
XinPoint p;
XinFont *fontp = NULL;
list_def = obj_def->v.list;
#if XIWS != XIWS_WM
itf_def = obj_def->parent;
if ( itf_def && itf_def->v.itf->font )
fontp = itf_def->v.itf->font;
if ( list_def->font )
xi_get_font_metrics_font( list_def->font, &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_get_system_font( ), &leading,
&ascent, &descent, &char_width );
#else
leading = 0;
ascent = 8;
descent = 0;
#endif
font_height = ascent + leading + descent;
#if XIWS == XIWS_WM
min_cell_height = 8;
pix_cell_height = font_height;
#else
min_cell_height = list_def->min_cell_height;
pix_cell_height = font_height + CELL_VERTICAL_MARGIN;
#endif
pix_cell_height = max( pix_cell_height, min_cell_height );
#if XIWS == XIWS_WM
*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 )
fontp = itf_def->v.itf->font;
if ( xi_def_get_xil_pref( 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 )
xi_fu_to_pu_font( list_def->font, &p, 1 );
else if ( fontp )
xi_fu_to_pu_font( fontp, &p, 1 );
else
xi_fu_to_pu_font( xi_get_system_font( ), &p, 1 );
}
}
#if XIWS != XIWS_WM
pix_hdr_bottom = p.v + leading + ascent + descent + BORDER_WIDTH
+ RULE_Y_OFFSET_BOTTOM + RULE_Y_OFFSET_TOP + 1;
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_def_get_xil_pref( 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 )
height = xi_get_fu_height_font( list_def->font );
else if ( fontp )
height = xi_get_fu_height_font( fontp );
else
height = xi_get_fu_height_font( xi_get_system_font( ) );
*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_bottom: 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 XIWS == XIWS_WM
*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_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 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 )
{
XinScrollBarRangeGet( list_obj->v.list->hsb_win, XinScrollBarTypeEither,
&rng1, &rng2 );
prop = XinScrollBarProportionGet( list_obj->v.list->hsb_win, XinScrollBarTypeEither );
p = lmp->delta_x;
if ( p > rng2 - prop )
p = rng2 - prop;
XinScrollBarPositionSet( list_obj->v.list->hsb_win, XinScrollBarTypeEither,
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;
LM_COLUMN_DATA **column_data;
LM_DATA *lmp = LMP( lm );
XinRect rct_to_invalidate;
int i;
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_focus_list_has( lmp ) )
{
BOOLEAN v_scrolled;
lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled );
if ( focus_column >= position )
++focus_column;
lm_focus_cell_set( lmp, focus_row, focus_column, v_scrolled );
if ( lm_focus_state_get( lmp ) != LM_FOCUS_VISIBLE )
{
lm_focus_cell_invis_make( 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 );
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 )
lcdata->font = lcdef->font;
lcdata->icon_rid = lcdef->icon_rid;
lcdata->icon_x = lcdef->icon_x;
lcdata->icon_y = lcdef->icon_y;
lcdata->bitmap = lcdef->bitmap;
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->wrap_text_scrollbar = lcdef->wrap_text_scrollbar;
lcdata->cr_ok = lcdef->cr_ok;
lcdata->var_len_text = lcdef->var_len_text;
lcdata->auto_tab = lcdef->auto_tab;
lcdata->icon_mode = lcdef->icon_mode;
/* 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 );
/* 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[position] = lcdata;
lmp->nbr_columns++;
/* create space for cell data */
/* cell_data_construct */
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 ) );
}
if ( not_creating_list )
{
for ( i = 0; i < lmp->nbr_realized_rows; ++i )
lm_xi_text_construct( lmp, i, position );
}
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;
/* adjust bounding rectangle */
calc_lmp_rct_right( lmp );
/* 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 );
lm_set_hscroll_bar( ( 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 )
{
XinRect 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 );
xi_offset_rect( &rct, -lmp->list_obj->itf->v.itf->delta_x,
-lmp->list_obj->itf->v.itf->delta_y );
XinWindowRectSet( lmp->list_obj->v.list->hsb_win, &rct );
}
if ( xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) )
{
if ( not_creating_list && made_invis )
lm_focus_cell_visible_attempt( 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
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, XinRect * rctp, int x, int y,
BOOLEAN last_in_hscrolling )
{
XinRect rct;
if ( lmp->moving_column )
{
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;
}
else
{
lm_get_rect( ( LM ) lmp, LM_LIST, 0, &rct );
rct.top = y;
rct.bottom = rct.top + lmp->drag_row_height;
rct.right += x - rct.left;
rct.left = x;
}
*rctp = rct;
}
/*-------------------------------------------------------------------------
function: rubber_rect
lmp: current lmp
-------------------------------------------------------------------------*/
static void
rubber_rect( LM_DATA * lmp )
{
#if XIWS != XIWS_WM
XinRect rct;
XinDrawTools new_ctools;
XinWindow win = lmp->win;
if ( lmp->last_itf )
win = xi_get_window( lmp->last_itf );
XinWindowDrawToolsNormalGet( &new_ctools );
XinWindowDrawToolsSet( win, &new_ctools );
XinWindowPenSet( win, &rubber_cpen );
XinWindowBrushSet( win, &hollow_cbrush );
XinWindowDrawModeSet( win, XinDrawModeXor );
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 );
#else
NOREF( lmp );
#endif
}
/*-------------------------------------------------------------------------
function: lm_move_event
lmp: current lmp
ep: xvt event
-------------------------------------------------------------------------*/
#define XI_AUTOSCROLL_COUNT 8 /* Number of move events before autoscroll
* occurs */
#define XI_AUTOSCROLL_FAST 50 /* Number of pixels to get to fast autoscroll */
void
lm_move_event( LM_DATA * lmp, XinEvent * ep )
{
XinPoint where;
int col_offset;
col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET );
where = ep->v.mouse.where;
switch ( ep->type )
{
case XinEventMouseDown:
case XinEventMouseDouble:
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 XinEventMouseMove:
{
static int autoscroll_count = 0;
BOOLEAN scrolled = FALSE;
if ( lmp->pixel_width != 0 )
{ /* Check for autoscroll */
if ( where.h - lmp->delta_x > lmp->vir_right )
{
if ( where.h - lmp->delta_x > lmp->vir_right + XI_AUTOSCROLL_FAST
|| ++autoscroll_count >= XI_AUTOSCROLL_COUNT )
{
autoscroll_count = 0;
rubber_rect( lmp );
lm_hscroll( ( LM ) lmp, 1, 0 );
scrolled = TRUE;
}
}
else if ( where.h < lmp->vir_left )
{
if ( where.h < lmp->vir_left - XI_AUTOSCROLL_FAST
|| ++autoscroll_count >= XI_AUTOSCROLL_COUNT )
{
autoscroll_count = 0;
rubber_rect( lmp );
lm_hscroll( ( LM ) lmp, -1, 0 );
scrolled = TRUE;
}
}
}
else
autoscroll_count = 0;
if ( scrolled || where.h != lmp->last_x || where.v != lmp->last_y )
{
if ( !scrolled )
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 XinEventMouseUp:
{
int column;
XI_OBJ *list_obj,
**members;
int nbr_members,
col_cnt,
temp1,
temp2,
dist1,
dist2,
min_dist,
position;
XinRect rct;
XinPoint 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 the focus is in the column to be deleted, we will move focus as if
the tab key had been pressed before deleting the col. This is so the
Bridge doesn't try to reference a deleted column object in the
OFF_CELL event. */
XI_OBJ *old_focus;
BOOLEAN deleteable = TRUE;
BOOLEAN return_focus = FALSE;
old_focus = lmp->itf_obj->v.itf->focus_obj;
if (old_focus->type == XIT_CELL && old_focus->parent == lmp->list_obj
&& old_focus->v.cell.column == column)
{
if (adjust_focus_for_column_delete( lmp, column, FALSE ))
return_focus = TRUE;
else
deleteable = FALSE;
}
if (deleteable && 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 );
lm_set_hscroll_bar( ( LM ) lmp );
} else if (return_focus)
xi_move_focus( old_focus );
}
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,
*cell_data2;
XinRect 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];
cell_data2 = lmp->lm_column_data[column];
new_fixed_width = column_data->x_pix_pos;
if ( position < lmp->fixed_columns || !in_hscrolling )
new_fixed_width += cell_data2->pix_width + 2 * col_offset;
if ( column < lmp->fixed_columns )
new_fixed_width -= cell_data2->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_focus_cell_visible_attempt( lmp );
break;
}
default:
break;
}
}
/*-------------------------------------------------------------------------
function: lm_get_drag_rect
lmp: current lmp
prct: returns rectangle where row or "after-all" events will be
generated
-------------------------------------------------------------------------*/
#define DROP_AFTER_MARGIN 10
static void
lm_get_drag_rect( LM_DATA * lmp, XinRect * prct )
{
lm_get_rect( ( LM ) lmp, LM_LIST, 0, prct );
if ( lmp->nbr_rows == 0 || ( lmp->have_last_rec
&& lmp->recs[lmp->last_fully_vis] == lmp->last_rec ) )
{
if ( lmp->pixel_width != 0 )
{
XinRect hsb_rct;
xi_get_hsb_rect( lmp->list_obj, &hsb_rct );
prct->bottom = hsb_rct.bottom;
}
else
prct->bottom += DROP_AFTER_MARGIN;
}
}
/*-------------------------------------------------------------------------
function: lm_get_no_event_rect
lmp: current lmp
prct: returns rectangle where no drag event will be generated
-------------------------------------------------------------------------*/
static void
lm_get_no_event_rect( LM_DATA * lmp, XinRect * prct )
{
lm_get_rect( ( LM ) lmp, LM_LIST, 0, prct );
if ( lmp->list_obj->v.list->sb_win )
{
XinRect rct;
xi_get_sb_rect( lmp->list_obj, &rct );
prct->right = rct.right;
}
if ( lmp->pixel_width != 0 && ( !lmp->have_last_rec
|| lmp->recs[lmp->last_fully_vis] != lmp->last_rec ) )
{
XinRect rct;
xi_get_hsb_rect( lmp->list_obj, &rct );
prct->bottom = rct.bottom;
}
}
/*-------------------------------------------------------------------------
function: lm_check_interface
itf: current interface
where: current mouse position, will be translated if new interface
is returned
returns: new interface, or NULL if no change
-------------------------------------------------------------------------*/
static XI_OBJ *
lm_check_interface( XI_OBJ * itf, XinPoint * where )
{
XinRect rct;
XinWindow win;
win = xi_get_window( itf );
XinWindowRectGet( win, &rct );
if ( !XinRectPointContained( &rct, where ) )
{
XinRect temp;
XinPoint pt;
XI_OBJ *new_itf;
temp.top = temp.bottom = where->v;
temp.left = temp.right = where->h;
XinWindowRectTranslate( win, XinWindowTaskGet( ), &temp );
pt.v = temp.top;
pt.h = temp.left;
new_itf = xi_get_itf_containing( &pt );
if ( new_itf == itf )
itf = NULL;
else
itf = new_itf;
if ( itf != NULL )
{
win = xi_get_window( itf );
XinWindowRectTranslate( XinWindowTaskGet( ), win, &temp );
where->v = temp.top;
where->h = temp.left;
XinWindowMouseRelease( );
XinWindowFrontSet( win );
XinWindowPaintForce( win );
XinWindowMouseTrap( win, TRUE );
}
return itf;
}
return NULL;
}
/*-------------------------------------------------------------------------
function: lm_drag_row_hit_test
lmp: current lmp
itf: current interface
where: current mouse position, will be translated if new interface
is returned
returns: new interface, or NULL if no change
-------------------------------------------------------------------------*/
static BOOLEAN
lm_drag_row_hit_test( LM_DATA * lmp, XinPoint * where, int *rowp )
{
int tmp_v,
i,
first,
last;
int *pix_offsetsp;
int *pix_heightsp;
/* figure out what row the mouse is in */
tmp_v = where->v - lmp->mlr.top - lmp->rrr_offset;
first = max( lmp->first_fully_vis - 1, 0 );
last = min( lmp->last_fully_vis + 1, lmp->nbr_realized_rows - 1 );
for ( i = first,
pix_offsetsp = &lmp->pix_offsets[i],
pix_heightsp = &lmp->pix_heights[i];
i <= last; ++i, ++pix_offsetsp, ++pix_heightsp )
{
if ( tmp_v >= *pix_offsetsp && tmp_v < ( *pix_offsetsp + *pix_heightsp ) )
{
*rowp = i;
break;
}
}
return ( i <= last );
}
/*-------------------------------------------------------------------------
function: lm_drag_row_event
itf: interface where event actually occured
lmp: current lmp
ep: xin event
oevp: orginal xin event
-------------------------------------------------------------------------*/
void
lm_drag_row_event( XI_OBJ * itf, LM_DATA * lmp, XinEvent * ep, XinEvent * oevp )
{
XinPoint where;
where = oevp->v.mouse.where;
switch ( ep->type )
{
case XinEventMouseMove:
{
static int autoscroll_count = 0;
BOOLEAN scrolled = FALSE;
XI_OBJ *new_itf;
if ( !lmp->dragging_row )
{
lmp->dragging_row = TRUE;
lmp->last_itf = itf;
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;
xi_set_drag_list_obj( lmp->list_obj );
rubber_rect( lmp );
break;
}
new_itf = lm_check_interface( itf, &where );
if ( new_itf == NULL && lmp->itf_obj == itf && lmp->drag_rows_autoscroll )
{ /* Test for autoscroll */
XinRect list_rct;
lm_get_rect( ( LM ) lmp, LM_LIST, 0, &list_rct );
list_rct.top = lmp->pix_row1_top;
if ( where.v > list_rct.bottom )
{
if ( where.v > list_rct.bottom + XI_AUTOSCROLL_FAST
|| ++autoscroll_count >= XI_AUTOSCROLL_COUNT )
{
LM_SCROLL_ARG arg;
autoscroll_count = 0;
rubber_rect( lmp );
MEMCLEAR( arg );
arg.lm = ( LM ) lmp;
arg.nbr_lines = 1;
arg.percent = 0;
arg.same_cell = TRUE;
arg.rec_at_top = TRUE;
lm_scroll( &arg );
scrolled = TRUE;
}
}
else if ( where.v < list_rct.top )
{
if ( where.v < list_rct.top - XI_AUTOSCROLL_FAST
|| ++autoscroll_count >= XI_AUTOSCROLL_COUNT )
{
LM_SCROLL_ARG arg;
autoscroll_count = 0;
rubber_rect( lmp );
MEMCLEAR( arg );
arg.lm = ( LM ) lmp;
arg.nbr_lines = -1;
arg.percent = 0;
arg.same_cell = TRUE;
arg.rec_at_top = TRUE;
lm_scroll( &arg );
scrolled = TRUE;
}
}
else
autoscroll_count = 0;
}
if ( scrolled || where.h != lmp->last_x || where.v != lmp->last_y )
{
if ( !scrolled )
rubber_rect( lmp );
if ( new_itf != NULL )
lmp->last_itf = new_itf;
lmp->last_x = where.h;
lmp->last_y = where.v;
lmp->last_in_hscrolling = lmp->in_hscrolling;
rubber_rect( lmp );
}
break;
}
case XinEventMouseUp:
{
int obj_num;
XI_OBJ **objlist;
XI_OBJ *dest_list;
LM_DATA *dest_lmp;
rubber_rect( lmp );
lmp->last_itf = NULL;
lmp->dragging_row = FALSE;
xi_set_drag_list_obj( NULL );
/* Check to see if window changed */
{
XI_OBJ *new_itf;
new_itf = lm_check_interface( itf, &where );
if ( new_itf != NULL )
itf = new_itf;
}
/* Find list object in current position */
dest_list = lmp->list_obj;
objlist = xi_get_member_list( itf, &obj_num );
for ( ; obj_num > 0; obj_num--, objlist++ )
if ( ( *objlist )->type == XIT_LIST )
{
XinRect rct;
lm_get_drag_rect( ( LM_DATA * ) ( *objlist )->v.list->lm, &rct );
if ( XinRectPointContained( &rct, &where ) )
{
dest_list = *objlist;
break;
}
}
dest_lmp = ( LM_DATA * ) dest_list->v.list->lm;
/* Match coordinates to window */
if ( dest_lmp->itf_obj != itf )
{
XinRect temp;
temp.top = temp.bottom = where.v;
temp.left = temp.right = where.h;
XinWindowRectTranslate( xi_get_window( itf ), xi_get_window( lmp->itf_obj ), &temp );
where.v = temp.top;
where.h = temp.left;
}
{ /* Generate drop rows event */
int row;
int column = 0;
LM_CB_DATA lm_cb_data;
XinRect list_rct;
lm_cb_data.v.drop_row.src_rec = lmp->rec_being_moved;
lm_cb_data.v.drop_row.after_all_rows = FALSE;
lm_cb_data.v.drop_row.delete_row = FALSE;
lm_cb_data.rec = 0;
lm_get_drag_rect( dest_lmp, &list_rct );
if ( !XinRectPointContained( &list_rct, &where ) )
{
lm_get_no_event_rect( dest_lmp, &list_rct );
if ( XinRectPointContained( &list_rct, &where ) )
break;
row = column = 0;
lm_cb_data.v.drop_row.delete_row = TRUE;
}
else
{
if ( where.v < dest_lmp->pix_row1_top )
break;
if ( lm_drag_row_hit_test( dest_lmp, &where, &row ) )
lm_cb_data.rec = dest_lmp->recs[row];
else
lm_cb_data.v.drop_row.after_all_rows = TRUE;
}
lm_cb_data.lm = ( LM ) dest_lmp;
lm_cb_data.cb_type = LM_CB_DROP_ROW;
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;
lm_cb_data.v.drop_row.shift = ep->v.mouse.shift;
lm_cb_data.v.drop_row.control = ep->v.mouse.control;
lm_cb_data.v.drop_row.src_list = lmp->list_obj;
( *lmp->lm_cb ) ( &lm_cb_data );
}
break;
}
default:
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, XinEvent * 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;
if ( lmp->lm_column_data[column]->wrap_text_scrollbar )
temp += (int)XinMetricGet( XinMetricVerticalScrollBarWidth );
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 XIWS != XIWS_WM
int top,
bottom;
XinDrawTools new_ctools;
XinPoint pnt;
XinWindow win = lmp->win;
top = lmp->pix_top;
bottom = lmp->mlr.bottom;
XinWindowDrawToolsNormalGet( &new_ctools );
XinWindowDrawToolsSet( win, &new_ctools );
XinWindowPenSet( win, &rubber_cpen );
XinWindowDrawModeSet( win, XinDrawModeXor );
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 );
#else
NOREF( lmp );
NOREF( x );
#endif
}
/*-------------------------------------------------------------------------
function: lm_size_event
lmp: current lmp
ep: xvt event
-------------------------------------------------------------------------*/
void
lm_size_event( LM_DATA * lmp, XinEvent * ep )
{
int x;
switch ( ep->type )
{
case XinEventMouseDown:
case XinEventMouseDouble:
x = calc_x( lmp, ep );
lmp->last_x = x;
rubber_x( lmp, x );
break;
case XinEventMouseMove:
x = calc_x( lmp, ep );
rubber_x( lmp, lmp->last_x );
lmp->last_x = x;
rubber_x( lmp, x );
break;
case XinEventMouseUp:
{
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;
LM_COLUMN_DATA *lm_column_data;
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;
lm_column_data = lmp->lm_column_data[column];
temp = lm_column_data->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 )
{
XinWindowPaintForce( lmp->win );
lm_hscroll( ( LM ) lmp, lmp->first_vis - i, 0 );
}
else
{
lm_calc_last_vis( lmp );
lm_set_hscroll_bar( ( LM ) lmp );
}
}
lm_focus_cell_visible_attempt( lmp );
break;
}
default:
break;
}
}
/*-------------------------------------------------------------------------
function: lm_set_bitmap
lm: current lm
bitmap: bitmap object
row:
column:
-------------------------------------------------------------------------*/
void
lm_set_bitmap( LM lm, XI_BITMAP* bitmap, int row, int column )
{
LM_DATA *lmp = LMP( lm );
lmp->cell_data[row][column].bitmap = xi_bitmap_copy( bitmap );
if ( LMP( lm )->attrib & XI_ATR_VISIBLE )
redraw_cell( lm, row, column, FALSE );
}
/*-------------------------------------------------------------------------
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_column_bitmap
lm: current lm
bitmap: bitmap object
cid: cid of the column to set
-------------------------------------------------------------------------*/
void
lm_set_column_bitmap( LM lm, XI_BITMAP* bitmap, int cid )
{
LM_DATA *lmp = LMP( lm );
XI_OBJ *list = lmp->list_obj;
int column;
for ( column = 0; column < list->nbr_children; column++ )
{
if ( list->children[column]->cid == cid )
{
XinRect rect;
lmp->lm_column_data[column]->bitmap = xi_bitmap_copy( bitmap );
lm_get_rect( lm, LM_COLUMN, column, &rect );
xi_invalidate_rect( lmp->win, &rect );
break;
}
}
}
/*-------------------------------------------------------------------------
function: lm_set_column_icon
lm: current lm
icon_rid: icon resource id
cid: cid of the column to set
-------------------------------------------------------------------------*/
void
lm_set_column_icon( LM lm, int icon_rid, int cid )
{
LM_DATA *lmp = LMP( lm );
XI_OBJ *list = lmp->list_obj;
int column;
for ( column = 0; column < list->nbr_children; column++ )
{
if ( list->children[column]->cid == cid )
{
XinRect rect;
lmp->lm_column_data[column]->icon_rid = icon_rid;
lm_get_rect( lm, LM_COLUMN, column, &rect );
xi_invalidate_rect( lmp->win, &rect );
break;
}
}
}
/*-------------------------------------------------------------------------
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_focus_list_has( lmp ) )
{
lm_focus_cell_set( lmp, row, column, FALSE );
}
else
{
int focus_row,
focus_column;
BOOLEAN is_v_scrolled;
lm_focus_cell_get( lmp, &focus_row, &focus_column, &is_v_scrolled );
if ( focus_row != row || focus_column != column || v_scrolled != is_v_scrolled )
lm_focus_cell_set( lmp, row, column, FALSE );
}
if ( v_scrolled )
{
lm_focus_cell_selection_set( lmp, c1, c2 );
}
else
{
XI_TEXT *text;
text = xi_text_focus_get( lmp->win );
if ( text )
xi_text_selection_set( text, c1, c2 );
}
}
/*-------------------------------------------------------------------------
function: scroll_list
lmp: current lmp
left_col:
right_col:
-------------------------------------------------------------------------*/
static void
scroll_list( LM_DATA * lmp, int new_first_col )
{
XinRect r;
int new_pos;
int dist;
new_pos = lmp->lm_column_data[new_first_col]->x_pix_pos
- lmp->lm_column_data[lmp->fixed_columns]->x_pix_pos;
if ( new_pos == lmp->delta_x )
{
if ( lmp->nbr_columns == lmp->fixed_columns )
lmp->delta_x = 0;
return;
}
dist = new_pos - lmp->delta_x;
lmp->delta_x += dist;
r.left = lmp->vir_left;
r.right = lmp->vir_right;
#if XIWS != XIWS_WM
r.top = lmp->rct.top + BORDER_WIDTH;
r.bottom = lmp->rct.bottom - BORDER_WIDTH;
#else
r.top = lmp->rct.top;
r.bottom = lmp->rct.bottom;
#endif
if ( !lmp->itf_obj->v.itf->half_baked )
XinWindowPaintForce( lmp->win );
xi_set_update_obj( lmp->list_obj );
lmp->last_vis = lmp->first_vis;
lm_calc_last_vis( lmp );
xi_scroll_rect( lmp->win, &r, -dist, 0 );
if ( !lmp->itf_obj->v.itf->half_baked )
XinWindowPaintForce( 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 last_vis,
lmfrc,
starting_column;
XinWindowPaintForce( lmp->win );
if ( lmp->nbr_columns == 0 )
return;
lmfrc = lm_get_left_most_far_right_col( LMP( lm ), lmp->nbr_columns );
last_vis = min( lmp->last_vis, lmp->nbr_columns - 1 );
if ( xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) )
lm_focus_cell_invis_make( 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, lmp->first_vis );
lm_focus_cell_visible_attempt( 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, lmp->first_vis );
lm_focus_cell_visible_attempt( lmp );
return;
}
if ( nbr_columns == XI_SCROLL_PGUP )
{
starting_column = lm_get_left_most_far_right_col( lmp, 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, lmp->first_vis );
lm_focus_cell_visible_attempt( 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, lmp->first_vis );
lm_focus_cell_visible_attempt( lmp );
}
void
lm_calculate_pix_offsets( LM lm )
{
LM_DATA *lmp = LMP( lm );
calculate_pix_offsets( lmp, TRUE );
lm_make_rrr_room_pix( lmp, 0, FALSE );
}
BOOLEAN
lm_cr_is_ok( LM lm, int row, int col, BOOLEAN v_scrolled )
{
LM_DATA *lmp = LMP( lm );
LM_COLUMN_DATA *lm_column_data;
LM_CELL_DATA *cell_data;
lm_column_data = lmp->lm_column_data[col];
if ( lm_column_data->cr_ok )
return TRUE;
if ( v_scrolled )
{
if ( lm_focus_cell_is_button_full_cell( lmp ) )
return TRUE;
else
return FALSE;
}
cell_data = &lmp->cell_data[row][col];
if ( cell_data->button_full_cell )
return TRUE;
else
return FALSE;
}
BOOLEAN
lm_is_button_full_cell( LM lm, int row, int col )
{
LM_DATA *lmp = LMP( lm );
LM_CELL_DATA *cell_data = &lmp->cell_data[row][col];
return cell_data->button_full_cell;
}
void
lm_set_rect( LM lm, XinRect *rect )
{
LM_DATA *lmp;
XinRect fu_rect;
lmp = (LM_DATA*)lm;
fu_rect = *rect;
fu_rect.right -= 2 * BORDER_WIDTH;
if (lmp->list_obj->v.list->hsb_win)
{
XinRect hsb_rect;
xi_get_hsb_rect( lmp->list_obj, & hsb_rect );
fu_rect.bottom += hsb_rect.bottom - hsb_rect.top;
}
xi_pu_to_fu( lmp->itf_obj, (XinPoint*)&fu_rect, 2 );
lmp->list_obj->v.list->xi_pnt = *(XinPoint*)&fu_rect;
if (lmp->list_obj->v.list->height != 0)
lmp->list_obj->v.list->height = fu_rect.bottom - fu_rect.top;
if (lmp->list_obj->v.list->width != 0 )
lmp->list_obj->v.list->width = fu_rect.right - fu_rect.left;
/* TODO - lm_recalc_metrics gets the proper height for the list not including
the hsb, then puts the hsb inside that rect instead of below it. Therefore,
the first time you resize, the list gets shorter by a scrollbar height, and
thereafter it doesn't change. */
lm_recalc_metrics( lm );
}