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

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

5807 lines
158 KiB
C
Executable File

/*******************************************************************************
* Copyright 1991-1995 by ORCA Software, Inc. *
* *
* All rights reserved. May not be reproduced or distribfuted, in printed or *
* electronic form, without permission of ORCA Software, Inc. May not be *
* distributed as object code, separately or linked with other object modules, *
* without permission. *
*******************************************************************************/
#define XI_INTERNAL
#include "xi.h"
#include "xitext.h"
#include "xilm.h"
#include "xiutils.h"
#include "xidisply.h"
/*-------------------------------------------------------------------------
Metrics Documentation
lmp->rct.top and lmp->rct.bottom are the top and bottom of the list, excluding the
horizontal scroll bar.
lmp->rct.left is the physical left position of the list
lmp->rct.right is the position of the physical right position of the list. However, if the
list is a horizontal scrolling list, then lmp->rct.right will be beyond lmp->width.
It is useful for drawing using the virtual functions, but it is necessary to subtract
lmp->rct.left before calling the drawing functions, because the drawing functions will
add lmp->rct.left to the h values before drawing.
-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------
ROWS: REALIZED, and ALLOCATED-USED, and ALLOCATED-NOT USED.
In the realized rows array, there are three types of rows.
First, there are rows that are not being used at all. These are the rows
after lmp->nbr_realized_rows. The record handles for these rows are 0L.
Second, there are rows that are allocated, and used. These are the rows
after 0, and before lmp->nbr_realized_rows.
The record handles for these rows are not 0L.
Third, there are rows that are allocated, and not used. These are the rows
after 0, and less than lmp->nbr_realized_rows.
The record handles for these rows are not 0L. If one of these rows is requested
to be allocated, and the handle is not 0L, then then allocation event is not
done. If one of these rows is requested to be freed, and the handle is 0L,
then the free event is not done.
-------------------------------------------------------------------------*/
/* Error codes: 20900 - 20918 */
#define SELECT_CELLS_OFFSET 1
#define LM_COL_ATTR(lm, col) (LMP(lm)->lm_column_data[col]->attrib)
#define LM_CELL_TEXT(lm, row, col) (LMP(lm)->buffer[row] + LMP(lm)->lm_column_data[col]->text_offset)
#define LM_REDRAW_ATR (LM_ATR_VISIBLE | LM_ATR_ENABLED)
#define LM_REDRAW_COL_ATR (LM_COL_ATR_ENABLED | LM_COL_ATR_RJUST | LM_COL_ATR_PASSWORD | LM_COL_ATR_SELECTED)
#define LM_REDRAW_ROW_ATR (LM_ROW_ATR_ENABLED | LM_ROW_ATR_SELECTED)
#define LM_REDRAW_CELL_ATR (LM_CELL_ATR_SELECTED | LM_CELL_ATR_RJUST | LM_CELL_ATR_HCENTER)
#define BUFLEN 256
/*-------------------------------------------------------------------------
function: lm_adj_v
lmp: current lmp
v: to vertical coord to convert
-------------------------------------------------------------------------*/
#define lm_adj_v(lmp, v) (v = v + lmp->mlr.top + lmp->rrr_offset)
static CBRUSH lm_white_cbrush;
static CPEN lm_black_cpen;
static DRAW_CTOOLS lm_normal_ctools;
static BOOLEAN lm_tools_inited = FALSE;
typedef struct {
BOOLEAN needs_update;
RCT rct;
RCT prct;
} ROW_INFO;
/*-------------------------------------------------------------------------
function: calc_last_vis
lmp: current lmp
process: calculates the last fully visible column in the list
-------------------------------------------------------------------------*/
void
lm_calc_last_vis(LM_DATA *lmp)
{
LM_COLUMN_DATA *column_data;
int l1;
if (! lmp->pixel_width)
lmp->last_vis = lmp->nbr_columns - 1;
else
{
lmp->last_vis = lmp->first_vis;
for (l1 = lmp->first_vis + 1; l1 < lmp->nbr_columns; ++l1)
{
column_data = lmp->lm_column_data[l1];
if ((column_data->x_pix_pos - lmp->delta_x + column_data->pix_width)
>= lmp->pixel_width)
{
lmp->last_vis = l1 - 1;
return;
}
lmp->last_vis = l1;
}
if (l1 == lmp->nbr_columns)
lmp->last_vis = l1 - 1;
}
}
/*-------------------------------------------------------------------------
function: lm_get_col_spacing
returns: column spacing
-------------------------------------------------------------------------*/
int
lm_get_col_spacing(void)
{
return (2 * (int)xi_get_pref(XI_PREF_COLUMN_OFFSET) + RULE_WIDTH_V);
}
/*-------------------------------------------------------------------------
function: lm_get_left_most_far_right_column
lmp: current lmp
nbr_columns: column, from which we will count back
notes: This function is also used when the users presses page up on the
horizontal scroll bar, to determine the new left most column.
Get the column number for the column that would be visible if the
list is scrolled entirely over to the right. This is necessary
to compute the position of the horizontal thumb, and other reasons.
-------------------------------------------------------------------------*/
int
lm_get_left_most_far_right_col(LM_DATA *lmp, int nbr_columns)
{
int width, i;
#if XVTWS == WMWS
width = lmp->pixel_width;
#else
width = lmp->pixel_width + (int)xi_get_pref(XI_PREF_COLUMN_OFFSET)
+ RULE_WIDTH_V;
#endif
for (i = 0; i < min(lmp->fixed_columns, lmp->nbr_columns); ++i)
width -= lmp->lm_column_data[i]->pix_width + lm_get_col_spacing();
for (i = nbr_columns - 1; i >= lmp->fixed_columns; --i)
{
width -= lmp->lm_column_data[i]->pix_width + lm_get_col_spacing();
if (width <= 0)
break;
}
return (i + 1);
}
/*-------------------------------------------------------------------------
function: lm_get_cell_rect
rctp: pointer to rectangle to be filled in
lm: current lm
row: relevant row
col: relevant column
inner: if TRUE, get the inner rectangle of the cell, else get the outer
rectangle of the cell
physical_rct: if TRUE, get the physical rectangle, else get the virtual
rectangle
notes: This function is called before starting the text edit object for the cell.
returns: rctp
-------------------------------------------------------------------------*/
RCT *
lm_get_cell_rect(RCT *rctp, LM lm, int row, int col, BOOLEAN inner, BOOLEAN physical_rct)
{
LM_COLUMN_DATA *temp_lmcd;
int col_offset;
LM_DATA *lmp = LMP(lm);
col_offset = (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
temp_lmcd = lmp->lm_column_data[col];
rctp->top = lmp->pix_offsets[row];
#if XI_IS_NOT_CH
CTOS_IS_PM;
rctp->bottom = rctp->top + lmp->pix_heights[row] - RULE_WIDTH_V;
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
rctp->bottom = rctp->top + lmp->pix_heights[row];
CTOS_END;
#endif
rctp->left = temp_lmcd->x_pix_pos;
rctp->right = rctp->left + temp_lmcd->pix_width + 2 *
(int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
if (inner)
{
rctp->left += col_offset;
rctp->right -= col_offset;
#if XI_IS_NOT_CH
CTOS_IS_PM;
rctp->top += RULE_Y_OFFSET_TOP;
rctp->bottom -= RULE_Y_OFFSET_BOTTOM;
CTOS_END;
#endif
}
if (physical_rct)
{
rctp->left += lmp->rct.left;
rctp->right += lmp->rct.left;
if (rctp->left >= lmp->vir_left)
{
rctp->left -= lmp->delta_x;
rctp->right -= lmp->delta_x;
}
rctp->top = rctp->top + lmp->rrr_offset + lmp->mlr.top;
rctp->bottom = rctp->bottom + lmp->rrr_offset + lmp->mlr.top;
}
return(rctp);
}
/*-------------------------------------------------------------------------
function: get_row_rect
rctp: pointer to rectangle to be filled in
lm: current lm
row: relevant row
returns: rctp
-------------------------------------------------------------------------*/
RCT*
lm_get_row_rect(RCT *rctp, LM lm, int row)
{
LM_DATA *lmp = LMP(lm);
rctp->top = lmp->pix_offsets[row];
rctp->bottom = rctp->top + lmp->pix_heights[row];
rctp->left = lmp->rct.left + BORDER_WIDTH;
#if XI_IS_NOT_CH
CTOS_IS_PM;
rctp->right = lmp->rct.right - BORDER_WIDTH;
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
rctp->right = lmp->rct.right;
CTOS_END;
#endif
if (lmp->pixel_width)
rctp->right = rctp->left + lmp->pixel_width;
return(rctp);
}
/*-------------------------------------------------------------------------
function: lm_adj_h
lmp: current lmp
h: pointer to horizontal coord to convert
returns: TRUE if position is visible
-------------------------------------------------------------------------*/
BOOLEAN
lm_adj_h(LM_DATA *lmp, short *h)
{
if (*h >= lmp->vir_left)
{
RCT r;
*h -= lmp->delta_x;
if (*h < lmp->vir_left)
return FALSE;
r = lmp->rct;
if (lmp->pixel_width)
r.right = r.left + lmp->pixel_width + 2 * BORDER_WIDTH;
return (*h <= r.right);
}
return TRUE;
}
/*-------------------------------------------------------------------------
function: lm_get_list_rct
lmp: current lmp
r: pointer to rectangle to be filled in
returns: r
-------------------------------------------------------------------------*/
RCT*
lm_get_list_rct(LM_DATA *lmp, RCT *r)
{
*r = lmp->rct;
if (lmp->pixel_width)
r->right = r->left + lmp->pixel_width + 2 * BORDER_WIDTH;
return r;
}
/*-------------------------------------------------------------------------
function: lm_set_fixed_columns
-------------------------------------------------------------------------*/
void
lm_set_fixed_columns( LM lm, int new_fixed_count )
{
LM_DATA *lmp = (LM_DATA *)lm;
int col_spacing, i;
RCT rct_to_invalidate, rct;
if (new_fixed_count > lmp->nbr_columns)
new_fixed_count = lmp->nbr_columns;
col_spacing = lm_get_col_spacing();
lmp->fixed_columns = new_fixed_count;
lmp->first_vis = lmp->fixed_columns;
lmp->delta_x = 0;
/* 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;
}
lmp->list_obj->v.list->have_hsb_rct = FALSE;
lm_get_list_rct(lmp, &rct_to_invalidate);
xi_invalidate_rect(lmp->win, &rct_to_invalidate);
lm_set_hscroll_range((LM)lmp);
lm_set_hscroll_bar((LM) lmp);
xi_get_hsb_rect(lmp->list_obj, &rct);
xvt_vobj_move(lmp->list_obj->v.list->hsb_win, &rct);
}
/*-------------------------------------------------------------------------
function: lm_stop_edit
lm: current lm
-------------------------------------------------------------------------*/
static void
lm_stop_edit(LM lm, BOOLEAN do_update, int row, int column)
{
LM_DATA *lmp = LMP(lm);
int new_row_height;
if (lmp->txt)
{
txt_hide_caret(lmp->txt);
txt_caret(lmp->txt, FALSE);
xi_tree_free((char *)lmp->txt);
lmp->txt = NULL;
new_row_height = lm_calculate_row_height(lmp, row);
if (new_row_height != lmp->old_row_height)
{
xvt_dwin_update(lmp->win);
lm_set_row_height(lm, row, new_row_height,
FALSE, lmp->old_row_height, TRUE);
xvt_dwin_update(lmp->win);
}
}
/*
if lmp->row_focus_border is TRUE, don't redraw, because old
focus row will be invalidated
*/
if (do_update && !lmp->txt_is_invisible)
redraw_cell(lm, row, column, FALSE );
lmp->txt_is_invisible = FALSE;
}
/*-------------------------------------------------------------------------
function: lm_focus_cb
lm: current lm
row: relevant row
column: relevant column
set: if TRUE, start editing on specified cell
if FALSE, stop editing altogether
-------------------------------------------------------------------------*/
void lm_focus_cb( long lm, int row, int column, BOOLEAN vert_scrolled,
BOOLEAN set)
{
LM_DATA *lmp = (LM_DATA *)lm;
if (set)
{
if (lm_list_has_focus(lmp))
{
int focus_row, focus_column;
BOOLEAN is_vert_scrolled;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &is_vert_scrolled);
if ( lmp->txt == NULL || row != focus_row || column != focus_column
|| vert_scrolled != is_vert_scrolled )
{
BOOLEAN remake_vis = FALSE;
if (! lmp->focus_rec)
{
lm_make_invis(lmp);
remake_vis = TRUE;
}
lm_set_focus_cell(lmp, row, column, vert_scrolled );
if (remake_vis)
lm_force_vis(lmp);
}
}
else
{
xvt_errmsg_sig_if(!(xi_false), NULL_WIN, SEV_FATAL,
ERR_ASSERT_4, "20930",
20930, "lm_focus_cb: Internal Error");
#if 0
/*
the following line was never executed when doing coverage. If the
above assert gets triggered, research, and uncomment the following line.
Remove after 7/31/95.
*/
lm_start_edit(lm, row, column);
#endif
}
}
else
{
int idx;
BOOLEAN found = FALSE;
lm_stop_edit(lm, TRUE, row, column);
if (lmp->focus_rec)
{
lmp->txt_is_invisible = FALSE;
for (idx = 0; idx < lmp->nbr_realized_rows; ++idx)
{
if (lmp->recs[idx] == lmp->focus_rec)
{
found = TRUE;
break;
}
}
if (found)
{
lmp->focus_rec = 0L;
lmp->txt_is_invisible = FALSE;
}
else
{
LM_CB_DATA lm_cb_data;
lm_cb_data.lm = (LM)lmp;
lm_cb_data.cb_type = LM_CB_REC_FREE;
lm_cb_data.cid = lmp->cid;
lm_cb_data.win = lmp->win;
lm_cb_data.v.rec_free.record = lmp->focus_rec;
(*lmp->lm_cb)(&lm_cb_data);
lm_allocate_rec_info(lmp, lmp->nbr_realized_rows - 1);
--lmp->nbr_realized_rows;
lmp->focus_rec = 0L;
lmp->txt_is_invisible = FALSE;
}
}
}
}
/*-------------------------------------------------------------------------
function: lm_delete
lm: current lm
notes: do not call this function in response to E_KILL_WINDOW.
-------------------------------------------------------------------------*/
void
lm_delete(LM lm)
{
RCT r;
LM_DATA *lmp = LMP(lm);
int focus_row, focus_column;
BOOLEAN v_scrolled;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled );
lm_stop_edit(lm, TRUE, focus_row, focus_column);
lm_remove_all_rows( lmp, TRUE );
lm_get_list_rct(lmp, &r);
xi_invalidate_rect(lmp->win, &r);
xi_tree_free((char *)lm);
}
/*-------------------------------------------------------------------------
function: calc_x_pix_pos
lm: current lm
lcdata: column data pointer
position: position of column
-------------------------------------------------------------------------*/
void
calc_x_pix_pos(LM lm, LM_COLUMN_DATA *lcdata, int position)
{
LM_DATA *lmp = LMP(lm);
LM_COLUMN_DATA *lmcd;
if (position)
lmcd = lmp->lm_column_data[position - 1];
lcdata->x_pix_pos = (! position) ? BORDER_WIDTH :
lmcd->x_pix_pos + lmcd->pix_width + lm_get_col_spacing();
}
/*-------------------------------------------------------------------------
function: lm_invalidate_rect
lmp: current lmp
rctp: rectangle to invalidate
adj_h: adjust the horizontal coords
-------------------------------------------------------------------------*/
void
lm_invalidate_rect(LM_DATA *lmp, RCT *rctp, BOOLEAN adj_h)
{
RCT r;
r = *rctp;
if (adj_h)
{
lm_adj_h(lmp, &r.left);
lm_adj_h(lmp, &r.right);
}
lm_adj_v(lmp, r.top);
lm_adj_v(lmp, r.bottom);
xi_invalidate_rect(lmp->win, &r);
}
/*-------------------------------------------------------------------------
function: lm_invalidate_rect2
lmp: current lmp
rctp: rectangle to invalidate
adj_left: if TRUE, adjust left of rctp
-------------------------------------------------------------------------*/
void
lm_invalidate_rect2(LM_DATA *lmp, RCT *rctp, BOOLEAN adj_left)
{
RCT r;
r = *rctp;
if (adj_left)
lm_adj_h(lmp, &r.left);
xi_invalidate_rect(lmp->win, &r);
}
/*-------------------------------------------------------------------------
function: lm_get_fixed_columns
-------------------------------------------------------------------------*/
int lm_get_fixed_columns( LM lm )
{
return ((LM_DATA*)lm)->fixed_columns;
}
void
lm_local_hscroll(LM lm, int nbr_columns)
{
LM_DATA *lmp;
XI_LIST_DATA *list_data;
XI_OBJ *other_list;
lmp = (LM_DATA *)lm;
list_data = lmp->list_obj->v.list;
lm_hscroll(lm, nbr_columns, 0);
if (list_data->horz_sync_list &&
! list_data->scrolling_in_progress)
{
list_data->scrolling_in_progress = TRUE;
other_list = xi_get_obj(lmp->itf_obj,
list_data->horz_sync_list);
if (other_list)
lm_hscroll(other_list->v.list->lm, nbr_columns, 0);
list_data->scrolling_in_progress = FALSE;
}
}
void lm_make_vis(LM_DATA *lmp)
{
int focus_row, focus_column;
BOOLEAN v_scrolled;
BOOLEAN is_hscrolled;
if (! lm_list_has_focus(lmp))
return;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
if (v_scrolled)
return;
if (lm_is_cell_visible(lmp, focus_row, focus_column, TRUE, &is_hscrolled))
{
TXT_DATA *txt;
LM_COLUMN_DATA *column_data;
DRAW_CTOOLS ct;
RCT cell_r;
unsigned long attrib, cell_attrib;
LM_CELL_DATA *cell_data;
BOOLEAN button;
BOOLEAN button_on_left;
RCT mr;
COLOR color;
int leading, ascent, descent, char_width;
BOOLEAN text_was_invisible;
if (lmp->focus_rec && lmp->txt_is_invisible && ! is_hscrolled)
{
int cnt;
/*
the following loop should *always* find a row, because
lmp->txt_is_invisible is TRUE, and the cell is now visible.
*/
for (cnt = 0; cnt < lmp->nbr_realized_rows; ++cnt)
{
if (lmp->recs[cnt] == lmp->focus_rec)
{
lm_set_focus_cell(lmp, cnt, focus_column, FALSE );
focus_row = cnt;
break;
}
}
}
mr = lmp->mlr;
if (lmp->pixel_width)
mr.right = mr.left + lmp->pixel_width + BORDER_WIDTH;
column_data = lmp->lm_column_data[focus_column];
attrib = column_data->attrib;
cell_data = &lmp->cell_data[focus_row][focus_column];
button = cell_data->button;
button_on_left = cell_data->button_on_left;
cell_attrib = cell_data->attrib &
(XI_ATR_HCENTER | XI_ATR_RJUST);
if (cell_attrib)
{
attrib &= ~(XI_ATR_HCENTER | XI_ATR_RJUST);
attrib |= cell_attrib;
}
txt = lmp->txt = (TXT_DATA *)xi_tree_malloc(sizeof(TXT_DATA), lmp);
lm_get_cell_rect(&cell_r, (LM)lmp, focus_row, focus_column, FALSE, TRUE);
if (button)
{
RCT r2;
r2 = cell_r;
xi_inflate_rect(&r2, 1);
if (button_on_left)
cell_r.left = r2.left + lmp->pix_row_spacing;
else
cell_r.right = r2.right - lmp->pix_row_spacing;
}
txt->parent_obj = lmp->list_obj;
txt->attrib = attrib | (TXT_ATR_ENABLED | TXT_ATR_VISIBLE);
txt->attrib &= ~XI_ATR_VCENTER;
txt->inside_only = TRUE;
txt->attrib &= ~TXT_ATR_BORDER;
if (lmp->min_cell_height && (! column_data->wrap_text))
txt->attrib |= XI_ATR_VCENTER;
txt->text = lmp->buffer[focus_row] + column_data->text_offset;
txt->text_size = column_data->text_size;
txt->auto_tab = column_data->auto_tab;
cell_data = &(lmp->cell_data[focus_row][focus_column]);
if (cell_data->font)
txt->font = cell_data->font;
else
txt->font = lmp->font;
xi_get_font_metrics_font(txt->font, &leading, &ascent, &descent, &char_width);
if (column_data->vertical_align_center)
{
int height, delta, new_top, new_bottom;
height = leading + ascent + descent;
delta = (cell_r.bottom - cell_r.top - height) / 2;
new_top = cell_r.top + delta;
new_bottom = cell_r.bottom - delta;
cell_r.top = max(cell_r.top, new_top);
cell_r.bottom = min(cell_r.bottom, new_bottom);
}
else if (column_data->vertical_align_bottom)
{
int new_top;
new_top = cell_r.bottom - (leading + ascent + descent) - 3;
cell_r.top = max(cell_r.top, new_top);
}
else
{
int new_bottom;
#if XVTWS != WMWS
new_bottom = cell_r.top + leading + ascent + descent + 4;
#else
new_bottom = cell_r.top + leading + ascent + descent;
#endif
cell_r.bottom = min(cell_r.bottom, new_bottom);
}
txt->rct = cell_r;
#if XVTWS != WMWS
txt->rct.top++;
txt->rct.bottom--;
#endif
txt->back_color = lmp->active_back_color;
txt->fore_color = lmp->active_color;
txt->win = lmp->win;
xvt_app_get_default_ctools(&ct);
ct.pen = hollow_cpen;
ct.fore_color = lmp->enabled_color;
ct.brush.color = lmp->back_color;
xi_set_draw_ctools(lmp->win, &ct);
xi_set_xvt_font(lmp->win, lmp->font, FALSE);
text_was_invisible = lmp->txt_is_invisible;
lmp->old_row_height = lmp->pix_heights[focus_row];
lmp->txt_is_invisible = FALSE;
lmp->focus_rec = 0L;
redraw_cell((LM)lmp, focus_row, focus_column, FALSE );
color = lmp->cell_data[focus_row][focus_column].back_color;
if (color)
txt->back_color = color;
txt_reset(txt);
if (text_was_invisible)
{
txt_set_text(txt, lmp->focus_cell_text);
txt_set_sel(txt, lmp->focus_cell_ip1, lmp->focus_cell_ip2);
}
else
{
if (lmp->have_mouse)
{
if ((column_data->attrib & (LM_COL_ATR_AUTOSELECT | LM_COL_ATR_READONLY)) ==
(LM_COL_ATR_AUTOSELECT | LM_COL_ATR_READONLY))
txt_set_sel(txt, 0, SHRT_MAX);
if ((column_data->attrib & LM_COL_ATR_AUTOSELECT) && xi_get_pref(XI_PREF_AUTOSEL_ON_MOUSE))
txt_set_sel(txt, 0, SHRT_MAX);
}
else
{
if (column_data->attrib & LM_COL_ATR_AUTOSELECT)
txt_set_sel(txt, 0, SHRT_MAX);
else
txt_set_sel(txt, 0, 0);
}
}
txt_caret(txt, TRUE);
}
else
{
if (lmp->focus_rec && is_hscrolled && lmp->txt_is_invisible)
{
int cnt;
/*
the following loop should *always* find a row, because
the only reason the cell is not visible is because the
list is horizontally scrolled.
*/
for (cnt = 0; cnt < lmp->nbr_realized_rows; ++cnt)
{
if (lmp->recs[cnt] == lmp->focus_rec)
{
lm_set_focus_cell(lmp, cnt, focus_column, FALSE );
break;
}
}
}
}
}
/*-------------------------------------------------------------------------
function: do_lm_cb_text
lm: current lm
row: row
col: column
-------------------------------------------------------------------------*/
void
do_lm_cb_text(LM_DATA *lmp, int row, int col, BOOLEAN preserve_focus )
{
LM_CELL_DATA *cell_data;
LM_CB_DATA lm_cb_data;
LM_COLUMN_DATA *lm_column_data;
lm_cb_data.lm = (LM)lmp;
lm_cb_data.cb_type = LM_CB_TEXT;
lm_cb_data.cid = lmp->cid;
lm_cb_data.win = lmp->win;
lm_cb_data.row = (unsigned char)row;
lm_cb_data.rec = lmp->recs[row];
lm_cb_data.column = (unsigned char)col;
lm_column_data = lmp->lm_column_data[col];
lm_cb_data.v.text.text = lmp->buffer[row] + lm_column_data->text_offset;
lm_cb_data.v.text.len = lm_column_data->text_size;
lm_cb_data.v.text.text[0] = '\0';
lm_cb_data.v.text.font = NULL;
lm_cb_data.v.text.font_id = 0L;
cell_data = &(lmp->cell_data[row][col]);
lm_cb_data.v.text.icon_rid = cell_data->icon_rid;
lm_cb_data.v.text.attrib = cell_data->attrib;
lm_cb_data.v.text.color = 0;
lm_cb_data.v.text.back_color = 0;
(*lmp->lm_cb)(&lm_cb_data);
cell_data->valid_data = TRUE;
cell_data->icon_rid = lm_cb_data.v.text.icon_rid;
cell_data->attrib = lm_cb_data.v.text.attrib;
cell_data->color = lm_cb_data.v.text.color;
cell_data->back_color = lm_cb_data.v.text.back_color;
if (lmp->txt_is_invisible) /* update the focus_cell_text */
{
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)
{
XI_CELL_DATA* focus_cell;
focus_cell = &focus_obj->v.cell;
if ( focus_cell->row == row && focus_cell->column == col )
{
if (preserve_focus && lmp->focus_cell_text != NULL)
strncpy( lm_cb_data.v.text.text, lmp->focus_cell_text,
lm_column_data->text_size - 1 );
else
{
lm_set_focus_text( lmp, lm_cb_data.v.text.text );
lmp->focus_cell_ip1 = 0;
lmp->focus_cell_ip2 = strlen( lmp->focus_cell_text );
}
}
}
}
else
{
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)
{
XI_CELL_DATA* focus_cell;
focus_cell = &focus_obj->v.cell;
if ( focus_cell->row == row && focus_cell->column == col )
{
if (lmp->txt)
{
lm_set_focus_text( lmp, lm_cb_data.v.text.text );
lmp->focus_cell_ip1 = 0;
lmp->focus_cell_ip2 = strlen( lmp->focus_cell_text );
txt_set_text(lmp->txt, lm_cb_data.v.text.text);
}
}
}
}
#if XI_IS_NOT_CH
CTOS_IS_PM;
/* cell buttons not supported for XVT/CH */
cell_data->button = lm_cb_data.v.text.button;
cell_data->button_on_left = lm_cb_data.v.text.button_on_left;
cell_data->button_on_focus = lm_cb_data.v.text.button_on_focus;
cell_data->button_icon_rid = lm_cb_data.v.text.button_icon_rid;
CTOS_END;
#endif
if (lm_cb_data.v.text.font_id)
{
XVT_FNTID old_font_id;
if (! cell_data->font)
cell_data->font = (FONT_OBJ *)
xi_tree_malloc(sizeof(FONT_OBJ), lmp);
old_font_id = *cell_data->font;
*cell_data->font = xi_create_copy_font_id(lmp->itf_obj,
lm_cb_data.v.text.font_id, old_font_id);
}
else
{
if (cell_data->font)
{
xi_free_font_id(lmp->itf_obj, *cell_data->font);
xi_tree_free(cell_data->font);
cell_data->font = NULL;
}
}
}
/*-------------------------------------------------------------------------
function: lm_get_attrib
lm: current lm
lm_part: may be LM_LIST, LM_ROW, LM_COLUMN, or LM_CELL
returns: attribute
notes: all rows are
-------------------------------------------------------------------------*/
unsigned long lm_get_attrib( LM lm, LM_PART lm_part, int idx, int idx2,
BOOLEAN v_scrolled)
{
LM_DATA *lmp = LMP(lm);
switch (lm_part)
{
case LM_LIST:
return(lmp->attrib);
case LM_ROW:
return(lmp->row_attribs[idx]);
case LM_COLUMN:
return(lmp->lm_column_data[idx]->attrib);
case LM_CELL:
{
LM_CELL_DATA *cell_data;
cell_data = &lmp->cell_data[idx][idx2];
if (! cell_data->valid_data)
{
do_lm_cb_text(lmp, idx, idx2, TRUE );
}
if (v_scrolled)
return lmp->focus_rec_attrib;
return(cell_data->attrib);
}
}
xvt_errmsg_sig_if(!(xi_false), NULL_WIN, SEV_FATAL,
ERR_ASSERT_4, "20907",
20907, "lm_get_attrib: Invalid LM part");
return 0L;
}
/*-------------------------------------------------------------------------
function: lm_get_buf_size
lm: current lm
part: must be LM_COLUMN
idx: column number
-------------------------------------------------------------------------*/
int
lm_get_buf_size(LM lm, LM_PART part, int idx)
{
LM_DATA *lmp = LMP(lm);
NOREF(part);
return(lmp->lm_column_data[idx]->text_size);
}
/*-------------------------------------------------------------------------
function: lm_get_cid
lm: current lm
returns: control id of list
-------------------------------------------------------------------------*/
int
lm_get_cid(LM lm)
{
LM_DATA *lmp = LMP(lm);
return lmp->cid;
}
/*-------------------------------------------------------------------------
function: lm_get_rect
lm: current lm
part: may be LM_LIST, LM_COLUMN, or LM_ROW
idx: if LM_LIST, not used
if LM_COLUMN, column number
if LM_ROW, row number
rct: rectangle to be filled in
returns: rct
-------------------------------------------------------------------------*/
RCT *
lm_get_rect(LM lm, LM_PART part, int idx, RCT *rct)
{
LM_DATA *lmp = LMP(lm);
switch (part)
{
case LM_LIST:
*rct = lmp->rct;
if (lmp->pixel_width)
rct->right = rct->left + lmp->pixel_width + 2 * BORDER_WIDTH;
break;
case LM_COLUMN:
{
LM_COLUMN_DATA *column_data;
column_data = lmp->lm_column_data[idx];
if (idx >= lmp->fixed_columns)
rct->left = lmp->rct.left + column_data->x_pix_pos - lmp->delta_x;
else
rct->left = lmp->rct.left + column_data->x_pix_pos;
rct->right = rct->left + column_data->pix_width +
2 * (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
rct->top = lmp->rct.top;
rct->bottom = lmp->rct.bottom;
break;
}
case LM_ROW:
{
int con;
con = lmp->rrr_offset + lmp->mlr.top;
rct->top = lmp->pix_offsets[idx] + con;
rct->bottom = rct->top + lmp->pix_heights[idx];
rct->left = lmp->rct.left;
rct->right = lmp->rct.right;
break;
}
}
return rct;
}
/*-------------------------------------------------------------------------
function: lm_get_text
lm: current lm
s: string to be filled in
NULL is valid
len: size of string to be filled in
if the length of the text is longer than the size of the buffer s,
then len-1 characters will be copied, and s[len-1] will be set
to '\0'
row: row number of cell
column: column number of cell
returns: s
-------------------------------------------------------------------------*/
char* lm_get_text( LM lm, char *s, int len, int row, int column,
BOOLEAN v_scrolled )
{
LM_DATA *lmp = LMP(lm);
char *b;
if (row == LM_HEADING_TEXT)
b = lmp->lm_column_data[column]->heading_text;
else if (v_scrolled)
b = lmp->focus_cell_text;
else
{
LM_CELL_DATA *cell_data;
cell_data = &lmp->cell_data[row][column];
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, column, TRUE );
b = LM_CELL_TEXT(lm, row, column);
}
if (s)
{
tgstrncpy(s, b, len);
return s;
}
else
return b;
}
/*-------------------------------------------------------------------------
function: lm_get_sel
lm: current lm
c1: pointer to integer to contain selection start
c2: pointer to integer to contain selection stop
-------------------------------------------------------------------------*/
void
lm_get_sel(LM lm, int *c1, int *c2)
{
LM_DATA *lmp = LMP(lm);
if (lm_list_has_focus(lmp) && lmp->txt)
{
*c1 = lmp->txt->selstart;
*c2 = lmp->txt->selstop;
}
else
*c1 = *c2 = 0;
}
/*-------------------------------------------------------------------------
function: lm_invalidate_rows_internal
lm: current lm
row_start: starting row
row_end: ending row
redraw: if TRUE, then redraw the rows
column: if -1, then do for all columns
if set, then do for a specific column
-------------------------------------------------------------------------*/
void
lm_invalidate_rows_internal( LM lm, int row_start, int row_end,
BOOLEAN redraw, int column,
BOOLEAN preserve_focus_text )
{
int row, col;
RCT rct1, rct2;
LM_DATA *lmp = LMP(lm);
row_end = min(row_end, lmp->nbr_realized_rows - 1);
if (row_start > row_end || row_start < 0)
return;
for (row = row_start; row <= row_end; row++)
{
for (col = (column == -1) ? 0 : column;
col < ((column == -1) ? (lmp->nbr_columns) : (column + 1));
col++)
{
if (xi_get_pref(XI_PREF_OPTIMIZE_CELL_REQUESTS))
{
LM_CELL_DATA *cell_data;
cell_data = &(lmp->cell_data[row][col]);
cell_data->valid_data = FALSE;
}
else
{
do_lm_cb_text(lmp, row, col, preserve_focus_text );
}
}
}
if (redraw)
{
if( (column == -1) && (row_start == 0) &&
(row_end == lmp->nbr_realized_rows - 1) ){
lm_get_row_rect(&rct1, lm, row_start);
lm_get_row_rect(&rct2, lm, row_end);
rct1.bottom = rct2.bottom;
lm_invalidate_rect(lmp, &rct1, FALSE);
}else{
int col_start, col_end;
if( column == -1 ){
col_start = 0;
col_end = lmp->nbr_columns - 1;
}else
col_start = col_end = column;
draw_cell_range( lmp, row_start, row_end, col_start,
col_end, FALSE);
}
}
}
/*-------------------------------------------------------------------------
function: lm_invalidate_rows
lm: current lm
row_start: starting row
row_end: ending row
redraw: if TRUE, then redraw the rows
-------------------------------------------------------------------------*/
void
lm_invalidate_rows(LM lm, int row_start, int row_end, BOOLEAN redraw)
{
lm_invalidate_rows_internal(lm, row_start, row_end, redraw, -1, TRUE );
}
/*-------------------------------------------------------------------------
function: find_selection
-------------------------------------------------------------------------*/
static int find_selection( LM_DATA* lmp )
{
int row_num;
for ( row_num = 0; row_num < lmp->nbr_realized_rows; row_num++ )
if ( lm_get_attrib( (LM)lmp, LM_ROW, row_num, 0, FALSE )
& LM_ROW_ATR_SELECTED )
return row_num;
return -1;
}
/*-------------------------------------------------------------------------
function: lm_set_attrib
lm: current lm
lm_part: must be LM_LIST, LM_COLUMN, LM_ROW, or LM_CELL
idx: if LM_LIST, not used
if LM_COLUMN, column number
if LM_ROW, row number
if LM_CELL, row number
idx2: if LM_LIST, not used
if LM_COLUMN, not used
if LM_ROW, not used
if LM_CELL, column number
attrib: attribute to set
half_baked: if set, don't redraw
-------------------------------------------------------------------------*/
void lm_set_attrib( LM lm, LM_PART lm_part, int idx, int idx2,
BOOLEAN v_scrolled, unsigned long attrib, int half_baked)
{
unsigned long do_redraw;
LM_DATA *lmp = LMP(lm);
switch (lm_part)
{
case LM_LIST:
{
RCT r;
lmp->attrib = attrib;
xi_get_rect(lmp->list_obj, &r);
r.right += 10;
r.bottom += 4;
xi_invalidate_rect(lmp->win, &r);
break;
}
case LM_COLUMN:
{
LM_COLUMN_DATA *column_data;
RCT rct;
column_data = lmp->lm_column_data[idx];
do_redraw = ((column_data->attrib ^ attrib) & LM_REDRAW_COL_ATR);
column_data->attrib = attrib;
if (do_redraw)
{
int focus_row, focus_column;
BOOLEAN is_vert_scrolled;
lm_get_rect(lm, LM_COLUMN, idx, &rct);
xi_invalidate_rect(lmp->win, &rct);
lm_get_focus_cell(lmp, &focus_row, &focus_column, &is_vert_scrolled);
if ((! is_vert_scrolled) && (focus_column == idx) && (lmp->txt))
txt_redraw(lmp->txt, FALSE);
}
break;
}
case LM_ROW:
{
unsigned long old_attrib;
do_redraw = ((lmp->row_attribs[idx] ^ attrib) & LM_REDRAW_ROW_ATR);
old_attrib = lmp->row_attribs[idx];
if ( lmp->single_select && (attrib & XI_ATR_SELECTED))
{
int old_row;
old_row = find_selection( lmp );
if (old_row != -1 && old_row != idx)
lm_set_attrib( lm, LM_ROW, old_row, 0, FALSE,
lmp->row_attribs[old_row] & ~XI_ATR_SELECTED,
half_baked );
}
lmp->row_attribs[idx] = attrib;
if (! half_baked && do_redraw)
{
if ((old_attrib & XI_ATR_SELECTED) != (attrib & XI_ATR_SELECTED))
{
int focus_row, focus_column;
BOOLEAN is_vert_scrolled;
lm_redraw_row(lmp, idx, FALSE );
lm_get_focus_cell(lmp, &focus_row, &focus_column, &is_vert_scrolled);
if ((! is_vert_scrolled) && (focus_row == idx) && (lmp->txt))
txt_redraw(lmp->txt, FALSE);
}
else
{
RCT r;
lm_get_row_rect(&r, lm, idx);
xi_set_clip(lmp->win, NULL);
lm_invalidate_rect(lmp, &r, FALSE);
}
}
break;
}
case LM_CELL:
{
unsigned long old_attrib;
LM_CELL_DATA *cell_data;
cell_data = &lmp->cell_data[idx][idx2];
if (! cell_data->valid_data)
return;
if (v_scrolled)
lmp->focus_rec_attrib = attrib;
else
{
old_attrib = lmp->cell_data[idx][idx2].attrib;
do_redraw = ((old_attrib ^ attrib) & LM_REDRAW_CELL_ATR);
cell_data->attrib = attrib;
if (! half_baked && do_redraw)
{
int focus_row, focus_column;
BOOLEAN is_vert_scrolled;
redraw_cell(lm, idx, idx2, FALSE );
lm_get_focus_cell(lmp, &focus_row, &focus_column, &is_vert_scrolled);
if ((! is_vert_scrolled) && (focus_row == idx) && (focus_column == idx2) && (lmp->txt))
txt_redraw(lmp->txt, FALSE);
}
}
}
}
}
/*-------------------------------------------------------------------------
function: lm_set_color
lm: current lm
part: must be LM_ROW, or LM_CELL
idx: if LM_ROW, row number
if LM_CELL, row number
idx2: if LM_ROW, not used
if LM_CELL, column number
color: color to set
half_baked: if set, don't redraw
-------------------------------------------------------------------------*/
void lm_set_color( LM lm, LM_PART part, int idx, int idx2, BOOLEAN v_scrolled,
COLOR color, BOOLEAN half_baked)
{
BOOLEAN do_redraw;
LM_DATA *lmp = LMP(lm);
switch (part)
{
case LM_ROW:
do_redraw = (color != lmp->row_colors[idx]);
lmp->row_colors[idx] = color;
if (! half_baked && do_redraw)
{
RCT r;
lm_get_row_rect(&r, lm, idx);
lm_invalidate_rect(lmp, &r, FALSE);
}
break;
case LM_CELL:
{
LM_CELL_DATA *cell_data;
cell_data = &lmp->cell_data[idx][idx2];
if (! cell_data->valid_data)
return;
if (v_scrolled)
lmp->focus_rec_color = color;
else
cell_data->color = color;
break;
}
}
}
/*-------------------------------------------------------------------------
function: lm_draw_rect
lmp: current lmp
rctp: rectangle to draw
-------------------------------------------------------------------------*/
static void
lm_draw_rect(LM_DATA *lmp, RCT *rctp, BOOLEAN adj_v)
{
RCT r;
BOOLEAN leftb, rightb;
r = *rctp;
r.left += lmp->rct.left;
r.right += lmp->rct.left;
if (adj_v)
{
lm_adj_v(lmp, r.top);
lm_adj_v(lmp, r.bottom);
}
leftb = lm_adj_h(lmp, &r.left);
rightb = lm_adj_h(lmp, &r.right);
if ( ! leftb && ! rightb )
return;
xi_draw_rect(lmp->win, &r);
}
/*-------------------------------------------------------------------------
function: lm_draw_3d_rect
lmp: current lmp
rctp: rectangle
well: or platform
depth: in pixels
-------------------------------------------------------------------------*/
static void
lm_draw_3d_rect(LM_DATA *lmp, RCT *rctp, BOOLEAN well, int depth, BOOLEAN adj_v)
{
RCT r;
BOOLEAN left, right;
r = *rctp;
r.left += lmp->rct.left;
r.right += lmp->rct.left;
if (adj_v)
{
lm_adj_v(lmp, r.top);
lm_adj_v(lmp, r.bottom);
}
left = lm_adj_h(lmp, &r.left);
right = lm_adj_h(lmp, &r.right);
if (! left && ! right)
return;
xi_draw_3d_rect(lmp->win, &r, well, depth, 0L, 0L, 0L);
}
/*-------------------------------------------------------------------------
function: lm_draw_icon
lmp: current lmp
left: h position
top: v position
icon_rid: resource id
vir_clip: virtual clip rectangle
phys_rct:
fore_color: desired colors if icons
back_color:
-------------------------------------------------------------------------*/
static void
lm_draw_icon(LM_DATA *lmp, int left, int top, int icon_rid, RCT *vir_clip,
RCT *phys_rct, BOOLEAN adj_v, COLOR fore_color, COLOR back_color)
{
RCT crct, r;
short sleft;
BOOLEAN leftb, rightb;
left += lmp->rct.left;
r = *vir_clip;
r.left += lmp->rct.left;
r.right += lmp->rct.left;
if (adj_v)
{
lm_adj_v(lmp, r.top);
lm_adj_v(lmp, r.bottom);
}
leftb = lm_adj_h(lmp, &r.left);
rightb = lm_adj_h(lmp, &r.right);
if ( ! leftb && ! rightb )
return;
if (adj_v)
lm_adj_v(lmp, top);
xi_rect_intersect(&crct, &r, phys_rct);
xi_set_clip(lmp->win, &crct);
sleft = left;
if (lm_adj_h(lmp, &sleft))
xi_draw_icon(lmp->win, sleft, top, icon_rid, fore_color, back_color);
}
/*-------------------------------------------------------------------------
function: lm_move_to
lmp: current lmp
p: point
-------------------------------------------------------------------------*/
void
lm_move_to(LM_DATA *lmp, PNT p, BOOLEAN adj_v, BOOLEAN adj_h)
{
if (adj_h)
{
p.h += lmp->rct.left;
lm_adj_h(lmp, &p.h);
}
if (adj_v)
lm_adj_v(lmp, p.v);
xi_move_to(lmp->win, p);
}
/*-------------------------------------------------------------------------
function: lm_draw_line
lmp: current lmp
p: point
-------------------------------------------------------------------------*/
void
lm_draw_line(LM_DATA *lmp, PNT p, BOOLEAN adj_v, BOOLEAN adj_h)
{
if (adj_h)
{
p.h += lmp->rct.left;
if (lm_adj_h(lmp, &p.h))
{
if (adj_v)
lm_adj_v(lmp, p.v);
xi_draw_line(lmp->win, p);
}
}
else
{
if (adj_v)
lm_adj_v(lmp, p.v);
xi_draw_line(lmp->win, p);
}
}
/*-------------------------------------------------------------------------
function: redraw_cell_button
lmp: current lmp
row:
col: 0
clip_rct: clip rectangle
down: if TRUE, then button is depressed
-------------------------------------------------------------------------*/
static void near
redraw_cell_button(LM_DATA *lmp, int row, int col, RCT *clip_rct,
BOOLEAN down, BOOLEAN clear_button)
{
RCT r, outer_rct, col_rct, clip_rect;
int cell_btn_icon_x, cell_btn_icon_y;
LM_CELL_DATA *cell_data;
BOOLEAN button_on_left;
int button_icon_rid;
LM_COLUMN_DATA *column_data;
PNT p;
DRAW_CTOOLS ct;
RCT actual_rct;
int actual_r;
actual_rct = lmp->rct;
#if XI_IS_NOT_CH
CTOS_IS_PM;
if (lmp->pixel_width)
actual_r = lmp->rct.left + lmp->pixel_width + 2 * BORDER_WIDTH;
else
actual_r = lmp->rct.right;
actual_rct.right = actual_r - BORDER_WIDTH;
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
if (lmp->pixel_width)
actual_r = lmp->rct.left + lmp->pixel_width;
else
actual_r = lmp->rct.right;
actual_rct.right = actual_r;
CTOS_END;
#endif
column_data = lmp->lm_column_data[col];
col_rct.left = column_data->x_pix_pos;
col_rct.right = col_rct.left + column_data->pix_width +
2 * (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
col_rct.top = clip_rct->top;
col_rct.bottom = clip_rct->bottom;
cell_data = &lmp->cell_data[row][col];
button_on_left = cell_data->button_on_left;
button_icon_rid = cell_data->button_icon_rid;
lm_get_cell_rect(&outer_rct, (LM)lmp, row, col, FALSE, FALSE);
r = outer_rct;
xi_inflate_rect(&r, 1);
if (button_on_left)
{
r.right = r.left + lmp->pix_row_spacing;
p.h = r.right - 1;
}
else
{
r.left = r.right - lmp->pix_row_spacing;
p.h = r.left;
}
xi_set_cpen(lmp->win, &black_cpen);
xi_set_draw_mode(lmp->win, M_COPY);
clip_rect = col_rct;
clip_rect.left += lmp->rct.left;
clip_rect.right += lmp->rct.left;
lm_adj_h(lmp, &clip_rect.left);
lm_adj_h(lmp, &clip_rect.right);
xi_rect_intersect(&clip_rect, &clip_rect, &lmp->mlr);
xi_rect_intersect(&clip_rect, &clip_rect, &actual_rct);
xi_set_clip(lmp->win, &clip_rect);
if (clear_button)
{
if (lmp->no_horz_lines)
{
/* if there is a button below, then decrement r.bottom */
int nr;
LM_CELL_DATA *cd;
nr = row;
cd = &lmp->cell_data[nr + 1][col];
if (row < lmp->nbr_realized_rows - 1 &&
cd->button &&
cd->button_on_left == lmp->cell_data[nr][col].button_on_left &&
(! cd->button_on_focus))
r.bottom--;
xi_set_cpen(lmp->win, &hollow_cpen);
xi_set_cbrush(lmp->win, &white_cbrush);
lm_draw_rect(lmp, &r, TRUE);
}
return;
}
if (lmp->no_horz_lines || lmp->no_vert_lines)
lm_draw_rect(lmp, &r, TRUE);
else
{
p.v = r.top;
lm_move_to(lmp, p, TRUE, TRUE);
p.v = r.bottom;
lm_draw_line(lmp, p, TRUE, TRUE);
}
xi_inflate_rect(&r, -1);
lm_draw_3d_rect(lmp, &r, down, 2, TRUE);
xi_inflate_rect(&r, -2);
cell_btn_icon_x = (int)xi_get_pref(XI_PREF_CELL_BTN_ICON_X);
cell_btn_icon_y = (int)xi_get_pref(XI_PREF_CELL_BTN_ICON_Y);
r.left = max(r.left, col_rct.left);
r.right = min(r.right, col_rct.right);
xi_get_draw_ctools(lmp->win, &ct);
ct.fore_color = lmp->enabled_color;
ct.back_color = xi_get_pref(XI_PREF_COLOR_CTRL);
ct.opaque_text = TRUE;
if (lmp->row_colors[row])
ct.fore_color = lmp->row_colors[row];
if (cell_data->color)
ct.fore_color = cell_data->color;
xi_set_draw_ctools(lmp->win, &ct);
lm_draw_icon(lmp, r.left + cell_btn_icon_x, r.top + cell_btn_icon_y + down,
button_icon_rid ? button_icon_rid : (int)xi_get_pref(XI_PREF_COMBO_ICON),
&r, clip_rct, TRUE, COLOR_BLACK, xi_get_pref(XI_PREF_COLOR_CTRL));
}
/*-------------------------------------------------------------------------
function: xvtch_draw_line
lmp: current lm pointer
from: from point
to: to point
-------------------------------------------------------------------------*/
#if XI_IS_CH
static void
xvtch_draw_line(LM_DATA *lmp, PNT *from, PNT *to, BOOLEAN adj_h)
{
int i, len;
#if XVT_OS != XVT_OS_CTOS
char c_v = (char)C_V;
#else
char c_v = 225;
#endif
char *s, *s2;
if (from->h == to->h)
{
/* draw vertical line */
if (adj_h)
{
from->h += lmp->rct.left;
if (lm_adj_h(lmp, &from->h))
{
for (i = from->v + VPIX_PER_CH; i <= to->v; i += VPIX_PER_CH)
xi_draw_text(lmp->win, from->h, i, &c_v, 1);
}
}
else
{
for (i = from->v + VPIX_PER_CH; i <= to->v; i += VPIX_PER_CH)
xi_draw_text(lmp->win, from->h, i, &c_v, 1);
}
}
else
{
len = (to->h - from->h) / VPIX_PER_CH;
s = xi_tree_malloc(len + 4, NULL);
s2 = s;
for (i = 0; i < len; ++i)
{
#if XVT_OS != XVT_OS_CTOS
*s2 = C_H;
#else
*s2 = 218;
#endif
++s2;
}
xi_draw_text(lmp->win, from->h, from->v + VPIX_PER_CH, s, len);
xi_tree_free(s);
}
}
#endif
#if XI_IS_CH
static char c_xd, c_xu, c_v, c_xx;
#endif
/*********** draw border around entire list ***********/
static void
draw_list_rect(LM_DATA *lmp, RCT *vr, RCT *hr)
{
RCT r;
XI_OBJ *list_obj = lmp->list_obj;
XI_LIST_DATA *list_data = list_obj->v.list;
r = lmp->rct;
if (list_data->sb_win)
r.right = vr->right;
else
r.right += BORDER_WIDTH;
if (list_data->hsb_win)
r.bottom = hr->bottom;
xi_draw_rect(lmp->win, &r);
}
/*********** draw heading rules ***********/
static void
draw_heading_rules(LM_DATA *lmp, int hrule_h)
{
if (! (lmp->update_rows_at_top + lmp->update_rows_at_bottom))
{
if (! lmp->no_heading)
{
int r2, i;
PNT p;
WINDOW win = lmp->win;
#if XI_IS_CH
NOREF(r2);
NOREF(win);
#endif
#if XI_IS_CH
CTOS_IS_CH;
/* heading rule, Release 3.0 */
p.h = lmp->rct.left;
p.v = lmp->pix_hdr_bottom;
xi_move_to(lmp->win, p);
p.h = hrule_h - VPIX_PER_CH;
xi_draw_line(lmp->win, p);
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
r2 = lmp->rct.right - lmp->delta_x;
r2 = min(r2, hrule_h);
WIDTHLOOP(i, BORDER_WIDTH)
{
p.h = lmp->rct.left;
p.v = lmp->pix_row1_top - BORDER_WIDTH + i;
xi_move_to(win, p);
p.h = r2;
xi_draw_line(win, p);
}
CTOS_END;
#endif
}
}
}
/*********** draw column rules ***********/
static void
draw_column_rules(LM_DATA *lmp)
{
LM_COLUMN_DATA * *lmcd;
int col;
PNT p;
#if XI_IS_CH
PNT from_p;
#endif
if (lmp->no_vert_lines)
{
CPEN back_cpen;
back_cpen = black_cpen;
back_cpen.color = lmp->back_color;
xi_set_cpen(lmp->win, &back_cpen);
}
else
{
CPEN back_cpen;
back_cpen = black_cpen;
back_cpen.color = lmp->rule_color;
xi_set_cpen(lmp->win, &back_cpen);
}
for (col = 1, lmcd = &lmp->lm_column_data[1]; col < lmp->nbr_columns; col++, ++lmcd)
{
p.h = (*lmcd)->x_pix_pos - RULE_WIDTH_V;
#if XI_IS_CH
CTOS_IS_CH;
p.v = lmp->pix_top;
lm_move_to(lmp, p, FALSE, TRUE);
p.v = lmp->mlr.bottom - VPIX_PER_CH;
lm_draw_line(lmp, p, FALSE, TRUE);
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
/* if RULE_WIDTH_V were used, this is where it would be used */
p.v = lmp->rct.top;
lm_move_to(lmp, p, FALSE, TRUE);
p.v = min(lmp->rct.bottom, lmp->rrr_bottom + lmp->rrr_offset + lmp->mlr.top);
lm_draw_line(lmp, p, FALSE, TRUE);
CTOS_END;
#endif
}
}
/*-------------------------------------------------------------------------
function: lm_needs_update
lmp: current lmp
rctp: rectangle to test
adj_h: adjust h
adj_v: adjust v
returns: TRUE if rectangle needs update
-------------------------------------------------------------------------*/
static BOOLEAN
lm_needs_update(LM_DATA *lmp, RCT *rctp, BOOLEAN adj_h, BOOLEAN adj_v)
{
RCT r;
r = *rctp;
if (adj_h)
{
r.left += lmp->rct.left;
r.right += lmp->rct.left;
}
if (adj_v)
{
lm_adj_v(lmp, r.top);
lm_adj_v(lmp, r.bottom);
}
if (adj_h)
{
BOOLEAN leftb, rightb;
leftb = lm_adj_h(lmp, &r.left);
rightb = lm_adj_h(lmp, &r.right);
if ( ! leftb && ! rightb )
return FALSE;
else
return xi_needs_update(lmp->win, &r);
}
else
{
return xi_needs_update(lmp->win, &r);
}
}
/*********** draw row rules ***********/
static void
draw_row_rules(LM_DATA *lmp, int first_row_to_draw, int last_row_to_draw, BOOLEAN update)
{
int r2, first_row, last_row;
int row, actual_r, hrule_h, col;
PNT p;
RCT r;
RCT actual_rct = lmp->mlr;
#if XI_IS_NOT_CH
CTOS_IS_PM;
if (lmp->pixel_width)
actual_r = lmp->rct.left + lmp->pixel_width + 2 * BORDER_WIDTH;
else
actual_r = lmp->rct.right;
actual_rct.right = actual_r;
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
if (lmp->pixel_width)
actual_r = lmp->rct.left + lmp->pixel_width;
else
actual_r = lmp->rct.right;
actual_rct.right = actual_r;
CTOS_END;
#endif
hrule_h = actual_r;
xi_set_clip(lmp->win, &actual_rct);
if (lmp->no_horz_lines)
{
CPEN back_cpen;
back_cpen = black_cpen;
back_cpen.color = lmp->back_color;
xi_set_cpen(lmp->win, &back_cpen);
}
else
{
#if XIWS != WMWS
CPEN back_cpen;
back_cpen = black_cpen;
back_cpen.color = lmp->rule_color;
xi_set_cpen(lmp->win, &back_cpen);
#else
xi_set_cpen(lmp->win, &black_cpen);
#endif
}
r2 = lmp->rct.right - lmp->delta_x;
r2 = min(r2, hrule_h);
first_row = max(0, lmp->first_fully_vis - 1);
last_row = min(lmp->nbr_realized_rows, lmp->last_fully_vis + 1);
if (lmp->update_rows_at_top)
{
RCT row_rct;
int old_last_row = last_row;
last_row = min(last_row, first_row + lmp->update_rows_at_top + 1);
lm_get_row_rect(&row_rct, (LM)lmp, last_row);
row_rct.bottom = lmp->mlr.bottom - lmp->mlr.top;
if (update && lm_needs_update(lmp, &row_rct, FALSE, TRUE))
last_row = old_last_row;
}
if (lmp->update_rows_at_bottom)
{
RCT row_rct;
int old_first_row = first_row;
first_row = max(first_row, lmp->last_fully_vis - lmp->update_rows_at_bottom);
lm_get_row_rect(&row_rct, (LM)lmp, first_row);
row_rct.top = 0;
if (update && lm_needs_update(lmp, &row_rct, FALSE, TRUE))
first_row = old_first_row;
}
if (first_row_to_draw != -1)
{
first_row = max(first_row_to_draw - 1, first_row);
last_row = min(last_row_to_draw + 1, last_row);
}
r = lmp->rct;
for (col = 0; col < lmp->nbr_columns; ++col)
if (! lmp->lm_column_data[col]->suppress_update_cells)
break;
if (col)
r.left = lmp->lm_column_data[col]->x_pix_pos;
for (row = first_row; row < last_row; ++row)
{
p.h = r.left;
p.v = lmp->pix_offsets[row] + lmp->pix_heights[row] - 1;
lm_move_to(lmp, p, TRUE, FALSE);
p.h = r2;
lm_draw_line(lmp, p, TRUE, FALSE);
}
}
/*-------------------------------------------------------------------------
function: lm_draw_clipped_text
lmp: current lmp
s: string
bound_rctp:
clip_rctp:
attrib:
set_the_cpen:
rule_and_space:
-------------------------------------------------------------------------*/
static void
lm_draw_clipped_text(LM_DATA *lmp, char *s, RCT *bound_rctp,
RCT *clip_rctp, unsigned long attrib, BOOLEAN set_the_cpen,
int rule_and_space, BOOLEAN adj_v)
{
RCT br, cr;
BOOLEAN left, right;
br = *bound_rctp;
br.left += lmp->rct.left;
br.right += lmp->rct.left;
if (adj_v)
{
lm_adj_v(lmp, br.top);
lm_adj_v(lmp, br.bottom);
}
left = lm_adj_h(lmp, &br.left);
right = lm_adj_h(lmp, &br.right);
if ( ! left && ! right )
return;
xi_rect_intersect(&cr, &br, clip_rctp);
xi_draw_clipped_text(lmp->win, s, &br, &cr, attrib, set_the_cpen,
rule_and_space, -1);
}
/*********** draw column headings ***********/
static void
draw_column_headings(LM_DATA *lmp, RCT *actual_rct)
{
WINDOW win = lmp->win;
LM lm = (LM)lmp;
if (! lmp->update_cells_only)
{
if (! (lmp->update_rows_at_top + lmp->update_rows_at_bottom))
{
if ( !lmp->no_heading)
{
int col;
for (col = 0; col < lmp->nbr_columns; col++)
{
RCT heading_rct, cell_rct;
LM_COLUMN_DATA *col_data;
unsigned long attrib;
col_data = lmp->lm_column_data[col];
if (col_data->suppress_update_heading)
continue;
lm_get_cell_rect(&heading_rct, lm, 1, col, FALSE, FALSE);
heading_rct.top = lmp->pix_top + BORDER_WIDTH;
#if XI_IS_CH
CTOS_IS_CH;
heading_rct.bottom = lmp->pix_hdr_bottom - VPIX_PER_CH;
lm_get_cell_rect(&cell_rct, lm, 1, col, TRUE, FALSE);
cell_rct.top = lmp->rct.top + VPIX_PER_CH;
CTOS_END;
#endif
#if XI_IS_NOT_CH
CTOS_IS_PM;
heading_rct.bottom = lmp->pix_hdr_bottom;
lm_get_cell_rect(&cell_rct, lm, 1, col, TRUE, FALSE);
cell_rct.top = lmp->rct.top + 2 * BORDER_WIDTH;
CTOS_END;
#endif
cell_rct.bottom = lmp->pix_hdr_bottom;
xi_set_cpen(win, &hollow_cpen);
xi_set_cbrush(win, &white_cbrush);
xi_set_draw_mode(win, M_COPY);
xi_set_clip(win, actual_rct);
if (col_data->font)
xi_set_xvt_font(win, col_data->font, FALSE);
else
xi_set_xvt_font(win, lmp->font, FALSE);
if (col_data->heading_well || col_data->heading_platform)
{
COLOR fore_color, back_color;
lm_draw_3d_rect(lmp, &heading_rct,
(BOOLEAN)(COLUMN_IS_SELECTED(lm, col) ?
!col_data->heading_well :
col_data->heading_well),
2, FALSE);
if (COLUMN_IS_ENABLED(lm, col))
{
if (LIST_IS_ENABLED(lmp))
fore_color = lmp->enabled_color;
else
fore_color = lmp->disabled_color;
back_color = lmp->back_color;
}
else
{
fore_color = lmp->disabled_color;
back_color = lmp->disabled_back_color;
}
if (col_data->heading_well || col_data->heading_platform)
back_color = xi_get_pref(XI_PREF_COLOR_CTRL);
xi_set_xvt_fore_color(win, fore_color);
xi_set_xvt_back_color(win, back_color);
}
else
{
COLOR fore_color;
if (COLUMN_IS_ENABLED(lm, col))
{
if (LIST_IS_ENABLED(lmp))
fore_color = lmp->enabled_color;
else
fore_color = lmp->disabled_color;
xi_set_xvt_fore_color(win, fore_color);
xi_set_xvt_back_color(win, lmp->back_color);
}
else
{
fore_color = lmp->disabled_color;
xi_set_xvt_fore_color(win, fore_color);
xi_set_xvt_back_color(win, lmp->disabled_back_color);
}
if (COLUMN_IS_SELECTED(lm, col))
{
CBRUSH cb;
cb = white_cbrush;
cb.color = fore_color;
xi_set_cbrush(win, &cb);
xi_set_xvt_fore_color(win, COLOR_WHITE);
}
lm_draw_rect(lmp, &heading_rct, FALSE);
}
if (col_data->heading_well || col_data->heading_platform)
{
cell_rct.left++;
cell_rct.right--;
}
attrib = ((LM_COL_ATTR(lm, col) | XI_ATR_VISIBLE) &
~XI_ATR_PASSWORD) |
(lmp->min_heading_height ? XI_ATR_VCENTER : 0);
if (col_data->center_heading)
{
attrib |= XI_ATR_HCENTER;
attrib &= ~XI_ATR_RJUST;
}
if (col_data->icon_rid)
{
COLOR fore_color, back_color;
if (COLUMN_IS_ENABLED(lm, col))
{
if (LIST_IS_ENABLED(lmp))
fore_color = lmp->enabled_color;
else
fore_color = lmp->disabled_color;
back_color = lmp->back_color;
}
else
{
fore_color = lmp->disabled_color;
back_color = lmp->disabled_back_color;
}
if (col_data->heading_well || col_data->heading_platform)
back_color = xi_get_pref(XI_PREF_COLOR_CTRL);
lm_draw_icon(lmp, cell_rct.left + col_data->icon_x,
cell_rct.top + col_data->icon_y, col_data->icon_rid,
&cell_rct, actual_rct, FALSE, fore_color, back_color);
}
else
{
char *ch;
int lines;
#if 0
#if XI_IS_CH
char buf[BUFLEN];
int i;
CTOS_IS_CH;
for (i = 0; i < BUFLEN; ++i)
buf[i] = ' ';
buf[BUFLEN - 1] = '\0';
lm_draw_clipped_text(lmp, buf, &cell_rct, &actual_rct,
((LM_COL_ATTR(lm, col) | XI_ATR_VISIBLE) & ~XI_ATR_PASSWORD) |
(col_data->center_heading ? XI_ATR_HCENTER : 0),
TRUE, 0, FALSE);
CTOS_END;
#endif
#endif
ch = col_data->heading_text;
lines = 1;
while (*ch != '\0')
{
if (*ch == '\n')
++lines;
++ch;
}
if (lines == 1)
{
lm_draw_clipped_text(lmp, col_data->heading_text, &cell_rct,
actual_rct,
attrib, TRUE, 0, FALSE);
}
else
{
char *s;
char *first_char;
char *ch;
BOOLEAN bk = FALSE;
int leading, ascent, descent;
s = xvt_mem_alloc(strlen(col_data->heading_text) + 1);
strcpy(s, col_data->heading_text);
ch = s;
first_char = ch;
xi_get_font_metrics(win, &leading, &ascent, &descent);
cell_rct.top +=
(cell_rct.bottom - cell_rct.top -
(leading + ascent + descent) * lines) / 2;
cell_rct.bottom = cell_rct.top + leading + ascent + descent;
while (TRUE)
{
while (*ch != '\n' && *ch != '\0')
++ch;
if (*ch == '\0')
bk = TRUE;
*ch = 0;
lm_draw_clipped_text(lmp, first_char, &cell_rct,
actual_rct,
attrib & ~XI_ATR_VCENTER, TRUE, 0, FALSE);
if (bk)
break;
cell_rct.top += (leading + ascent + descent);
cell_rct.bottom += (leading + ascent + descent);
++ch;
first_char = ch;
}
xvt_mem_free(s);
}
}
}
}
}
}
}
/* ------------------------------------------------------------------------- */
/* fast_calc_col_needs_update */
/* ------------------------------------------------------------------------- */
static void
fast_calc_col_needs_update(LM_DATA *lmp, int first_col, int last_col,
BOOLEAN update)
{
int col;
LM_COLUMN_DATA *column_data;
#if XVTWS == WMWS
NOREF(update);
#endif
for (col = 0; col < lmp->nbr_columns; ++col)
lmp->lm_column_data[col]->needs_update = FALSE;
for (col = first_col; col <= last_col; ++col)
{
RCT rct;
BOOLEAN rightb, leftb;
column_data = lmp->lm_column_data[col];
if (column_data->suppress_update_cells)
continue;
rct.left = lmp->rct.left + column_data->x_pix_pos;
rct.right = rct.left + column_data->pix_width +
2 * (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
rct.top = lmp->rct.top;
rct.bottom = lmp->rct.bottom;
column_data->column_rct = rct;
#if XIWS != WMWS
leftb = lm_adj_h(lmp, &rct.left);
rightb = lm_adj_h(lmp, &rct.right);
column_data->prct = rct;
if (! leftb && !rightb)
column_data->needs_update = FALSE;
else
{
if (update)
{
if (xi_needs_update(lmp->win, &column_data->prct))
column_data->needs_update = TRUE;
else
column_data->needs_update = FALSE;
}
else
column_data->needs_update = TRUE;
}
#else
leftb = lm_adj_h(lmp, &rct.left);
rightb = lm_adj_h(lmp, &rct.right);
column_data->prct = rct;
if (! leftb && !rightb)
column_data->needs_update = FALSE;
else
column_data->needs_update = TRUE;
#endif
}
}
static void
fast_draw_exception_rects(LM_DATA *lmp, WINDOW win, ROW_INFO *row_info, int first_row, int last_row)
{
COLOR last_brush_color;
int col, row;
LM_COLUMN_DATA *column_data;
ROW_INFO *ri;
extern CPEN hollow_cpen;
/* draw exception rectangles - draw enabled, not selected cells */
last_brush_color = 0L;
xi_set_cpen(win, &hollow_cpen);
for (col = 0; col < lmp->nbr_columns; ++col)
{
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
COLOR brush_color;
LM_CELL_DATA *cell_data = &lmp->cell_data[row][col];
BOOLEAN do_draw;
if (! ri->needs_update)
continue;
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
do_draw = lm_cell_has_focus( lmp, row, col, FALSE );
if ((CELL_IS_ENABLED(lmp, row, col)) && ! (CELL_IS_SELECTED(lmp, row, col)))
do_draw = TRUE;
if (do_draw)
{
RCT rct;
brush_color = lmp->back_color;
if (cell_data->back_color)
brush_color = cell_data->back_color;
/*
TO OPTIMIZE BACKGROUND DRAWING, USE NEXT TWO LINES
if (brush_color == lmp->back_color)
continue;
*/
if (brush_color != last_brush_color)
{
CBRUSH cbrush;
cbrush.color = brush_color;
cbrush.pat = PAT_SOLID;
xi_set_cbrush(win, &cbrush);
}
rct = column_data->prct;
rct.top = ri->prct.top;
rct.bottom = ri->prct.bottom;
xi_draw_rect(win, &rct);
}
}
}
/* draw exception rectangles - draw disabled, not selected cells */
for (col = 0; col < lmp->nbr_columns; ++col)
{
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
COLOR brush_color;
LM_CELL_DATA *cell_data = &lmp->cell_data[row][col];
if (! ri->needs_update)
continue;
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
if (! (CELL_IS_ENABLED(lmp, row, col)) && ! (CELL_IS_SELECTED(lmp, row, col)))
{
RCT rct;
brush_color = lmp->disabled_back_color;
/*
TO OPTIMIZE BACKGROUND DRAWING, USE NEXT TWO LINES
if (brush_color == lmp->back_color)
continue;
*/
if (brush_color != last_brush_color)
{
CBRUSH cbrush;
cbrush.color = brush_color;
cbrush.pat = PAT_SOLID;
xi_set_cbrush(win, &cbrush);
}
rct = column_data->prct;
rct.top = ri->prct.top;
rct.bottom = ri->prct.bottom;
xi_draw_rect(win, &rct);
}
}
}
/* draw exception rectangles - draw selected cells */
for (col = 0; col < lmp->nbr_columns; ++col)
{
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
COLOR brush_color;
LM_CELL_DATA *cell_data = &lmp->cell_data[row][col];
if (! ri->needs_update)
continue;
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
if (CELL_IS_SELECTED(lmp, row, col) && ! lm_cell_has_focus(lmp, row, col, FALSE))
{
RCT rct;
if (CELL_IS_ENABLED(lmp, row, col))
{
brush_color = lmp->enabled_color;
if (lmp->row_colors[row])
brush_color = lmp->row_colors[row];
if (cell_data->color)
brush_color = cell_data->color;
}
else
brush_color = lmp->disabled_color;
if (cell_data->back_color && lmp->retain_back_color_on_select)
brush_color = cell_data->back_color;
/*
TO OPTIMIZE BACKGROUND DRAWING, USE NEXT TWO LINES
if (brush_color == lmp->back_color)
continue;
*/
if (brush_color != last_brush_color)
{
CBRUSH cbrush;
cbrush.color = brush_color;
cbrush.pat = PAT_SOLID;
xi_set_cbrush(win, &cbrush);
}
rct = column_data->prct;
rct.top = ri->prct.top;
rct.bottom = ri->prct.bottom;
xi_draw_rect(win, &rct);
}
}
}
#if XVTWS != WMWS
/* draw 3d rectangles */
for (col = 0; col < lmp->nbr_columns; ++col)
{
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
RCT rct;
LM_CELL_DATA *cell_data = &lmp->cell_data[row][col];
if (! ri->needs_update)
continue;
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
rct = column_data->prct;
rct.top = ri->prct.top;
rct.bottom = ri->prct.bottom;
if (column_data->column_well || column_data->column_platform)
xi_draw_3d_rect(win, &rct, (BOOLEAN)(CELL_IS_SELECTED(lmp, row, col) ? ! column_data->column_well :
column_data->column_well), 2, 0L, 0L, 0L);
}
}
#else
for (col = 0; col < lmp->nbr_columns; ++col)
{
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
COLOR brush_color;
LM_CELL_DATA *cell_data = &lmp->cell_data[row][col];
BOOLEAN do_draw;
if (! ri->needs_update)
continue;
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col);
do_draw = lm_cell_has_focus( lmp, row, col, FALSE );
if ((CELL_IS_ENABLED(lmp, row, col)) && ! (CELL_IS_SELECTED(lmp, row, col)))
do_draw = TRUE;
if (do_draw)
{
if (column_data->column_well || column_data->column_platform)
{
RCT rct;
brush_color = lmp->back_color;
if (cell_data->back_color)
brush_color = cell_data->back_color;
if (brush_color != last_brush_color)
{
CBRUSH cbrush;
cbrush.color = brush_color;
cbrush.pat = PAT_SOLID;
xi_set_cbrush(win, &cbrush);
}
rct = column_data->prct;
rct.top = ri->prct.top;
rct.bottom = ri->prct.bottom;
xi_draw_rect(win, &rct);
}
}
}
}
#endif
}
static void
fast_draw_cell_icons(LM_DATA *lmp, WINDOW win, ROW_INFO *row_info, int first_row, int last_row)
{
int col, row;
LM_COLUMN_DATA *column_data;
ROW_INFO *ri;
DRAW_CTOOLS ct;
#if XIWS != PMWS
COLOR last_fore_color, last_back_color;
#endif
xi_get_draw_ctools(win, &ct);
ct.fore_color = lmp->enabled_color;
ct.back_color = lmp->back_color;
ct.opaque_text = TRUE;
xi_set_draw_ctools(win, &ct);
#if XIWS != PMWS
last_back_color = 0L;
last_fore_color = 0L;
#endif
/* draw cell icons */
for (col = 0; col < lmp->nbr_columns; ++col)
{
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
RCT rct;
LM_CELL_DATA *cell_data = &lmp->cell_data[row][col];
COLOR fore_color, back_color;
if (! ri->needs_update)
continue;
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
rct = column_data->prct;
rct.top = ri->rct.top;
rct.bottom = ri->rct.bottom;
lm_adj_v(lmp, rct.top);
lm_adj_v(lmp, rct.bottom);
{
RCT mlr = lmp->mlr;
if (lmp->pixel_width)
mlr.right = mlr.left + lmp->pixel_width + BORDER_WIDTH;
xi_rect_intersect(&mlr, &mlr, &rct);
xi_set_clip(win, &mlr);
}
fore_color = ct.fore_color;
back_color = ct.back_color;
if (lmp->row_colors[row])
fore_color = lmp->row_colors[row];
if (cell_data->color)
fore_color = cell_data->color;
if (cell_data->back_color)
{
back_color = cell_data->back_color;
}
if (! cell_data->icon_rid)
continue;
#if XIWS == PMWS
xi_draw_icon(win, rct.left, rct.top, cell_data->icon_rid, fore_color, back_color);
#else
if (fore_color != last_fore_color || back_color != last_back_color)
xi_draw_icon(win, rct.left, rct.top, cell_data->icon_rid, fore_color, back_color);
else
xi_draw_icon(win, rct.left, rct.top, cell_data->icon_rid, 0L, 0L);
#endif
}
}
}
static void
fast_draw_cell_buttons(LM_DATA *lmp, ROW_INFO *row_info, int first_row, int last_row)
{
int col, row;
LM_COLUMN_DATA *column_data;
ROW_INFO *ri;
/* draw exception rectangles - draw enabled, not selected cells */
for (col = 0; col < lmp->nbr_columns; ++col)
{
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
RCT mr;
BOOLEAN button;
BOOLEAN button_on_focus;
LM_CELL_DATA *cell_data;
if (! ri->needs_update)
continue;
mr = lmp->mlr;
if (lmp->pixel_width)
mr.right = lmp->rct.left + lmp->pixel_width + BORDER_WIDTH;
cell_data = &lmp->cell_data[row][col];
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
button = cell_data->button;
button_on_focus = cell_data->button_on_focus;
if ((button && ! button_on_focus) ||
(button && button_on_focus &&
lm_row_has_focus(lmp, row, FALSE)))
redraw_cell_button(lmp, row, col, &mr, FALSE, FALSE);
}
}
}
static void
fast_draw_cell_text(LM_DATA *lmp, LM_CELL_DATA *cell_data, LM_COLUMN_DATA *column_data,
int row, int col, ROW_INFO *ri, int col_offset, int leading, int ascent,
int descent, BOOLEAN xvt_dwin_set_clip)
{
RCT rct;
unsigned long attrib, cell_attrib;
char *s;
int len, rule_and_space, baseline, wid;
char buf[256];
WINDOW win = lmp->win;
BOOLEAN button, button_on_left;
#if XVTWS == WMWS
NOREF(rule_and_space);
#endif
if (lm_cell_has_focus( lmp, row, col, FALSE ))
return;
button = cell_data->button;
button_on_left = cell_data->button_on_left;
cell_attrib = cell_data->attrib &
(XI_ATR_HCENTER | XI_ATR_RJUST);
attrib = LM_COL_ATTR(lmp, col) | XI_ATR_VISIBLE |
(lmp->min_cell_height ? XI_ATR_VCENTER : 0);
if (cell_attrib)
{
attrib &= ~(XI_ATR_HCENTER | XI_ATR_RJUST);
attrib |= cell_attrib;
}
rct = column_data->prct;
rct.top = ri->prct.top;
rct.bottom = ri->prct.bottom;
rct.left += col_offset;
rct.right -= col_offset;
if (! column_data->wrap_text)
{
if (column_data->vertical_align_bottom)
{
int new_top;
#if XVTWS == WMWS
new_top = rct.bottom - (leading + ascent + descent);
#else
new_top = rct.bottom - (leading + ascent + descent) - 3;
#endif
rct.top = max(rct.top, new_top);
}
else if (! column_data->vertical_align_center)
{
int new_bottom;
#if XVTWS == WMWS
new_bottom = rct.top + leading + ascent + descent;
#else
new_bottom = rct.top + leading + ascent + descent + 4;
#endif
rct.bottom = min(rct.bottom, new_bottom);
}
}
if (button)
{
RCT r;
r = rct;
xi_inflate_rect(&r, 1);
if (button_on_left)
{
r.right = r.left + lmp->pix_row_spacing;
rct.left = r.right;
}
else
{
r.left = r.right - lmp->pix_row_spacing;
rct.right = r.left - (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
}
}
#if XI_IS_NOT_CH
CTOS_IS_PM;
rct.top += RULE_Y_OFFSET_TOP;
rct.bottom -= RULE_Y_OFFSET_BOTTOM;
CTOS_END;
#endif
if (column_data->column_well || column_data->column_platform)
{
rct.left++;
rct.right--;
}
if (xvt_dwin_set_clip)
{
RCT mlr = lmp->mlr;
if (lmp->pixel_width)
mlr.right = mlr.left + lmp->pixel_width + BORDER_WIDTH;
xi_rect_intersect(&mlr, &mlr, &rct);
xi_set_clip(win, &mlr);
}
if (column_data->wrap_text)
{
int nbr_lines, cnt;
char* s;
lm_wrap_text(lmp, row, col, FALSE);
nbr_lines = min(cell_data->nbr_lines, lmp->max_lines_in_cell);
s = LM_CELL_TEXT(lmp, row, col);
for (cnt = 0; cnt < nbr_lines; ++cnt)
{
int len = -1;
if (cnt < nbr_lines - 1)
len = cell_data->line_breaks[cnt + 1] - cell_data->line_breaks[cnt];
#if XIWS == WMWS
baseline = rct.top + 8;
#else
baseline = rct.top + leading + ascent;
#endif
if ((&s[cell_data->line_breaks[cnt]])[len - 1] == '\n')
len--;
xi_draw_text(win, rct.left, baseline, &s[cell_data->line_breaks[cnt]], len);
#if XVTWS == WMWS
rct.top += cell_data->font_height;
#else
rct.top += cell_data->font_height - 1;
#endif
}
}
else
{
s = lmp->buffer[row] + column_data->text_offset;
len = strlen(s);
len = min(len, sizeof(buf) - 1);
if (attrib & XI_ATR_PASSWORD)
memset(buf, XI_PASSWORD_CHAR, len);
else
gstrncpy(buf, s, len);
buf[len] = '\0';
rule_and_space = lmp->min_cell_height ? RULE_Y_OFFSET_TOP : 0;
#if XIWS == WMWS
baseline = rct.top + 8;
#else
if (attrib & XI_ATR_VCENTER)
baseline = rct.top + leading + ascent + rule_and_space +
(rct.bottom - rct.top - leading - ascent - descent) / 2 - 1;
else
baseline = rct.top + leading + ascent + rule_and_space;
#endif
if (attrib & XI_ATR_RJUST)
{
wid = xi_xvt_get_text_width(win, buf, -1);
xi_draw_text(win, rct.right - wid, baseline, buf, len);
}
else
{
if (attrib & XI_ATR_HCENTER)
{
int x;
wid = xi_xvt_get_text_width(win, buf, len);
x = (rct.left + rct.right) / 2 - wid / 2;
if (x < rct.left)
x = rct.left;
xi_draw_text(win, x, baseline, buf, len);
}
else
xi_draw_text(win, rct.left, baseline, buf, len);
}
}
}
static void
fast_draw_all_cell_text(LM_DATA *lmp, WINDOW win, ROW_INFO *row_info,
int col_offset, int first_row, int last_row, RCT* list_rect)
{
DRAW_CTOOLS ctools;
int row, col;
ROW_INFO *ri;
LM_COLUMN_DATA *column_data;
int leading, ascent, descent;
BOOLEAN have_last_font;
XVT_FNTID *last_font;
ctools = lm_normal_ctools;
/* the following two lines must come before the xi_set_xvt_font, because in
R3, setting the draw ctools also sets the font.
*/
if (LIST_IS_ENABLED(lmp))
ctools.fore_color = lmp->enabled_color;
else
ctools.fore_color = lmp->disabled_color;
#if XVTWS == WMWS
ctools.back_color = lmp->back_color;
#endif
xi_set_draw_ctools(win, &ctools);
xi_set_xvt_font(win, lmp->font, FALSE);
xi_get_font_metrics(win, &leading, &ascent, &descent);
/* draw default font, not wrapped text, not selected cells */
for (col = 0; col < lmp->nbr_columns; ++col)
{
RCT clip_rect;
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
if (column_data->wrap_text)
continue;
if ((column_data->attrib & XI_ATR_ENABLED) == 0)
xi_set_xvt_fore_color(win, lmp->disabled_color);
else
xi_set_xvt_fore_color(win, ctools.fore_color);
if (!xi_rect_intersect( &clip_rect, &column_data->prct, list_rect ))
continue;
xi_set_clip(win, &clip_rect);
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
LM_CELL_DATA *cell_data;
if (! ri->needs_update)
continue;
if (lmp->row_colors[row])
continue;
cell_data = &lmp->cell_data[row][col];
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
if (cell_data->color)
continue;
if (cell_data->font)
continue;
if (cell_data->icon_rid)
continue;
if (CELL_IS_SELECTED(lmp, row, col))
continue;
fast_draw_cell_text(lmp, cell_data, column_data,
row, col, ri, col_offset, leading, ascent,
descent, FALSE);
}
}
/*
draw default font, colored text
*/
for (col = 0; col < lmp->nbr_columns; ++col)
{
RCT clip_rect;
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
if (column_data->wrap_text)
continue;
if (!xi_rect_intersect( &clip_rect, &column_data->prct, list_rect ))
continue;
xi_set_clip(win, &clip_rect);
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
LM_CELL_DATA *cell_data;
COLOR color;
if (! ri->needs_update)
continue;
cell_data = &lmp->cell_data[row][col];
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
if (cell_data->font)
continue;
if (cell_data->icon_rid)
continue;
if (CELL_IS_SELECTED(lmp, row, col))
{
color = lmp->back_color;
if (column_data->column_well || column_data->column_platform)
color = lmp->enabled_color;
if (cell_data->back_color)
if (lmp->retain_back_color_on_select)
color = lmp->enabled_color;
else
color = cell_data->back_color;
}
else
{
color = lmp->row_colors[row];
if (cell_data->color)
color = cell_data->color;
if ((column_data->attrib & XI_ATR_ENABLED) == 0)
color = lmp->disabled_color;
}
if (! color)
continue;
xi_set_xvt_fore_color(win, color);
#if XVTWS == WMWS
xi_set_xvt_back_color(win, lmp->enabled_color);
#endif
fast_draw_cell_text(lmp, cell_data, column_data,
row, col, ri, col_offset, leading, ascent,
descent, FALSE);
}
}
/* draw default font, black text, wrapped text */
/*
this needs to be a separate loop from above, because this loop sets the
clipping region for each cell, and the above loop sets the clipping region
for each column.
*/
xi_set_xvt_fore_color(win, COLOR_BLACK);
for (col = 0; col < lmp->nbr_columns; ++col)
{
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
if (! column_data->wrap_text)
continue;
if ((column_data->attrib & XI_ATR_ENABLED) == 0)
xi_set_xvt_fore_color(win, lmp->disabled_color);
else
xi_set_xvt_fore_color(win, COLOR_BLACK);
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
LM_CELL_DATA *cell_data;
if (! ri->needs_update)
continue;
if (lmp->row_colors[row])
continue;
cell_data = &lmp->cell_data[row][col];
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
if (cell_data->color)
continue;
if (cell_data->font)
continue;
if (cell_data->icon_rid)
continue;
if (CELL_IS_SELECTED(lmp, row, col))
continue;
fast_draw_cell_text(lmp, cell_data, column_data,
row, col, ri, col_offset, leading, ascent,
descent, TRUE);
}
}
/* draw default font, colored text, wrapped text */
/*
this needs to be a separate loop from above, because this loop sets the
colors for each cell, and the above loop only draws black.
*/
for (col = 0; col < lmp->nbr_columns; ++col)
{
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
if (! column_data->wrap_text)
continue;
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
LM_CELL_DATA *cell_data;
COLOR color;
if (! ri->needs_update)
continue;
cell_data = &lmp->cell_data[row][col];
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
if (cell_data->font)
continue;
if (cell_data->icon_rid)
continue;
if (CELL_IS_SELECTED(lmp, row, col))
{
color = lmp->back_color;
if (column_data->column_well || column_data->column_platform)
color = lmp->enabled_color;
if (cell_data->back_color)
if (lmp->retain_back_color_on_select)
color = lmp->enabled_color;
else
color = cell_data->back_color;
}
else
{
color = lmp->row_colors[row];
if (cell_data->color)
color = cell_data->color;
if ((column_data->attrib & XI_ATR_ENABLED) == 0)
color = lmp->disabled_color;
}
if (! color)
continue;
xi_set_xvt_fore_color(win, color);
fast_draw_cell_text(lmp, cell_data, column_data,
row, col, ri, col_offset, leading, ascent,
descent, TRUE);
}
}
/* draw all of the rest of the text */
have_last_font = FALSE;
last_font = NULL;
for (col = 0; col < lmp->nbr_columns; ++col)
{
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
LM_CELL_DATA *cell_data;
COLOR color;
BOOLEAN need_to_set;
if (! ri->needs_update)
continue;
cell_data = &lmp->cell_data[row][col];
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
if (! cell_data->font)
continue;
if (cell_data->icon_rid)
continue;
need_to_set = FALSE;
if (! have_last_font)
need_to_set = TRUE;
if (have_last_font && ! font_compare(*last_font, *cell_data->font))
need_to_set = TRUE;
if (need_to_set)
{
int char_width;
xi_set_xvt_font(win, cell_data->font, FALSE);
xi_get_font_metrics_font(cell_data->font, &leading, &ascent,
&descent, &char_width);
last_font = cell_data->font;
have_last_font = TRUE;
}
if (CELL_IS_SELECTED(lmp, row, col))
{
color = lmp->back_color;
if (cell_data->back_color)
if (lmp->retain_back_color_on_select)
color = lmp->enabled_color;
else
color = cell_data->back_color;
}
else
{
color = lmp->row_colors[row];
if (cell_data->color)
color = cell_data->color;
if ((column_data->attrib & XI_ATR_ENABLED) == 0)
color = lmp->disabled_color;
}
xi_set_xvt_fore_color(win, color);
fast_draw_cell_text(lmp, cell_data, column_data,
row, col, ri, col_offset, leading, ascent,
descent, TRUE);
}
}
}
#if XVTWS != WMWS
static void
fast_draw_row_focus_border(LM_DATA *lmp, ROW_INFO *row_info, int first_row, int last_row)
{
int col, row;
LM_COLUMN_DATA *column_data;
ROW_INFO *ri;
CPEN color_cpen;
CPEN rule_cpen;
BOOLEAN last_was_rule = TRUE;
RCT mr;
if (! lmp->row_focus_border)
return;
color_cpen.width = 1;
color_cpen.color = lmp->row_focus_border_color;
color_cpen.pat = PAT_SOLID;
color_cpen.style = P_SOLID;
rule_cpen.width = 1;
rule_cpen.color = lmp->rule_color;
rule_cpen.pat = PAT_SOLID;
rule_cpen.style = P_SOLID;
xi_set_cpen(lmp->win, &rule_cpen);
{
mr = lmp->mlr;
if (lmp->pixel_width)
mr.right = mr.left + lmp->pixel_width + BORDER_WIDTH;
xi_set_clip(lmp->win, &mr);
}
for (row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri)
{
RCT rct;
PNT p;
WINDOW win = lmp->win;
BOOLEAN row_has_focus = lm_row_has_focus(lmp, row, FALSE);
if (! ri->needs_update)
continue;
if (row_has_focus)
{
if (last_was_rule)
{
xi_set_cpen(lmp->win, &color_cpen);
last_was_rule = FALSE;
}
}
else
{
if (! last_was_rule)
{
xi_set_cpen(lmp->win, &rule_cpen);
last_was_rule = TRUE;
}
}
for (col = 0; col < lmp->nbr_columns; ++col)
{
column_data = lmp->lm_column_data[col];
if (! column_data->needs_update)
continue;
rct = column_data->prct;
rct.top = ri->prct.top;
rct.bottom = ri->prct.bottom;
/* draw top line */
p.h = rct.left;
p.v = rct.top - 1;
xi_move_to(win, p);
p.h = rct.right;
xi_draw_line(win, p);
if (row_has_focus)
{
/* draw next line down */
p.v++;
p.h = rct.left;
xi_move_to(win, p);
p.h = rct.right;
xi_draw_line(win, p);
}
/* draw bottom line */
p.h = rct.left;
p.v = rct.bottom;
xi_move_to(win, p);
p.h = rct.right;
xi_draw_line(win, p);
if (row_has_focus)
{
/* draw line above bottom line */
p.v--;
p.h = rct.left;
xi_move_to(win, p);
p.h = rct.right;
xi_draw_line(win, p);
}
}
}
}
#endif
/* ------------------------------------------------------------------------- */
/* draw_cell_block */
/* ------------------------------------------------------------------------- */
static void
draw_cell_block( LM_DATA* lmp, int first_row, int last_row,
ROW_INFO* row_info )
{
WINDOW win = lmp->win;
RCT actual_rct = lmp->mlr;
int actual_r;
int col_offset;
col_offset = (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
#if XI_IS_NOT_CH
CTOS_IS_PM;
if (lmp->pixel_width)
actual_r = lmp->mlr.left + lmp->pixel_width;
else
actual_r = lmp->mlr.right;
actual_rct.right = actual_r;
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
if (lmp->pixel_width)
actual_r = lmp->mlr.left + lmp->pixel_width;
else
actual_r = lmp->mlr.right;
actual_rct.right = actual_r;
CTOS_END;
#endif
xi_set_clip(win, &actual_rct);
/* draw all rectangles that are not white */
fast_draw_exception_rects(lmp, win, row_info, first_row, last_row);
/* draw all of the text in the cells */
fast_draw_all_cell_text(lmp, win, row_info, col_offset, first_row, last_row,
&actual_rct );
/* draw cell buttons */
fast_draw_cell_buttons(lmp, row_info, first_row, last_row);
fast_draw_cell_icons(lmp, win, row_info, first_row, last_row);
#if XVTWS != WMWS
draw_row_rules(lmp, first_row, last_row, FALSE);
fast_draw_row_focus_border(lmp, row_info, first_row, last_row);
#endif
}
/* ------------------------------------------------------------------------- */
/* draw_cell_range */
/* ------------------------------------------------------------------------- */
void
draw_cell_range( LM_DATA* lmp, int first_row, int last_row,
int first_col, int last_col,
BOOLEAN in_event_update )
{
int row, col;
ROW_INFO* row_info;
ROW_INFO* row_ptr;
if (lmp->list_obj->nbr_children <= 0) return;
if (xi_get_attrib(lmp->list_obj) & XI_ATR_VISIBLE)
{
row_info = (ROW_INFO *)xvt_mem_alloc(sizeof(ROW_INFO) * (last_row + 1));
for ( row = first_row, row_ptr = row_info + first_row; row <= last_row;
++row, ++row_ptr)
{
lm_get_row_rect(&row_ptr->rct, (LM)lmp, row);
/* don't need to test for the rule, it is drawn elsewhere */
#if XVTWS != WMWS
row_ptr->rct.bottom--;
if (row_ptr->rct.bottom < row_ptr->rct.top)
row_ptr->rct.bottom = row_ptr->rct.top;
#endif
row_ptr->prct = row_ptr->rct;
lm_adj_v(lmp, row_ptr->prct.top);
lm_adj_v(lmp, row_ptr->prct.bottom);
if (in_event_update)
{
if (lm_needs_update(lmp, &row_ptr->rct, FALSE, TRUE))
row_ptr->needs_update = TRUE;
else
row_ptr->needs_update = FALSE;
}
else
row_ptr->needs_update = TRUE;
}
/*
force cell requests for cells that have suppress_update_cells set to true
*/
for (col = first_col; col <= last_col; ++col)
{
if (lmp->lm_column_data[col]->suppress_update_cells)
{
for (row = first_row; row <= last_row; ++row)
{
LM_CELL_DATA *cell_data;
cell_data = &(lmp->cell_data[row][col]);
if (! cell_data->valid_data)
do_lm_cb_text(lmp, row, col, TRUE );
}
}
}
/*
determine which columns need to be updated
*/
fast_calc_col_needs_update(lmp, first_col, last_col, in_event_update);
/*
at this point, we should never need to call lm_needs_update again in this function
or any called functions.
*/
draw_cell_block( lmp, first_row, last_row, row_info );
xvt_mem_free((char *)row_info);
}
}
/*********** draw cells ***********/
static void
fast_draw_cells(LM_DATA *lmp, BOOLEAN update)
{
int first_row;
int last_row;
first_row = lmp->first_fully_vis;
if (first_row < 0)
first_row = 0;
last_row = min(lmp->last_fully_vis + 1, lmp->nbr_realized_rows - 1);
if (last_row < 0)
return;
draw_cell_range( lmp, first_row, last_row, 0, lmp->nbr_columns - 1, update );
}
/*-------------------------------------------------------------------------
function: redraw_cell
lm: current lm
row:
col:
update: if TRUE, redraw_cell is being called due to an E_UPDATE event.
clip_rct: clip rectangle
-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/* redraw_cell */
/*-------------------------------------------------------------------------*/
void redraw_cell( LM lm, int row, int col, BOOLEAN update )
{
draw_cell_range( (LM_DATA*)lm, row, row, col, col, update );
}
/*-------------------------------------------------------------------------*/
/* lm_redraw_row */
/*-------------------------------------------------------------------------*/
void lm_redraw_row(LM_DATA *lmp, int row, BOOLEAN update )
{
draw_cell_range( lmp, row, row, 0, lmp->nbr_columns - 1, update );
}
/*-------------------------------------------------------------------------*/
/* draw_other_rectangles */
/*-------------------------------------------------------------------------*/
static void
draw_other_rectangles(LM_DATA *lmp, RCT *actual_rct)
{
WINDOW win = lmp->win;
RCT lmp_rct, vr, hr;
int i, actual_r, hrule_h;
CBRUSH cbrush;
XI_LIST_DATA *list_data;
XI_OBJ *list_obj;
#if XVTWS == WMWS
NOREF(lmp_rct);
NOREF(hrule_h);
NOREF(list_data);
#endif
lmp_rct = lmp->rct;
if (lmp->pixel_width)
actual_r = lmp->rct.left + lmp->pixel_width + 2 * BORDER_WIDTH;
else
actual_r = lmp->rct.right;
list_obj = lmp->list_obj;
list_data = list_obj->v.list;
hrule_h = actual_r;
/*********** Graphical: border at right of last column ***********/
/*********** Graphical: rectangle around entire list ***********/
/*********** Graphical: rectangle at bottom of list ***********/
/* NOTE: GRAPHICAL SYSTEMS ONLY, HERE. CH is in beginning of draw_lm */
#if XI_IS_NOT_CH
CTOS_IS_PM;
xi_set_clip(win, actual_rct);
xi_set_cpen(win, &black_cpen);
xi_set_draw_mode(win, M_COPY);
if (lmp->pixel_width)
{
PNT p, p2;
int width;
RCT r;
p.h = lmp->rct.right - 1 - lmp->rct.left;
p.v = lmp_rct.top;
p2 = p;
p2.v = min(lmp_rct.bottom, lmp->rrr_bottom + lmp->rrr_offset + lmp->mlr.top);
width = BORDER_WIDTH;
if (lmp->no_vert_lines)
{
CPEN back_cpen;
back_cpen = black_cpen;
back_cpen.color = lmp->back_color;
xi_set_cpen(win, &back_cpen);
} else
xi_set_cpen(win, &black_cpen);
WIDTHLOOP(i, width)
{
lm_move_to(lmp, p, FALSE, TRUE);
lm_draw_line(lmp, p2, FALSE, TRUE);
--p.h;
--p2.h;
}
r = lmp->rct;
r.left = lmp->rct.right - lmp->rct.left;
if (lmp->list_obj->nbr_children <= 0) r.left -= lmp->pixel_width;
r.right = 9999;
xi_set_cpen(win, &hollow_cpen);
cbrush.pat = PAT_SOLID;
cbrush.color = lmp->white_space_color;
xi_set_cbrush(win, &cbrush);
xi_set_clip(win, actual_rct);
#if XIWS == XOLWS || XIWS == MTFWS
/* X GRAY SCALE HACK */
xi_set_xvt_back_color(win, COLOR_WHITE);
{
DRAW_CTOOLS ct;
xi_get_draw_ctools(win, &ct);
ct.opaque_text = FALSE;
xi_set_draw_ctools(win, &ct);
xi_draw_text(win, r.left, r.top, " ", -1);
}
#endif
lm_draw_rect(lmp, &r, FALSE);
/* draw border around entire list */
lmp_rct.right = actual_r;
{
RCT r;
CBRUSH cb;
r = lmp->rct;
if (list_data->sb_win)
{
xi_get_sb_rect(list_obj, &vr);
/*
add one, so that one pixel of the double border will overlap one pixel of the
scroll bar.
*/
r.right = vr.right + 1;
}
else
if (list_data->hsb_win)
r.right = r.left + lmp->pixel_width + 2 * BORDER_WIDTH;
xi_get_hsb_rect(list_obj, &hr);
r.bottom = hr.bottom + 1;
xi_set_cbrush(win, &hollow_cbrush);
xi_set_cpen(win, &black_cpen);
xi_set_clip(win, NULL);
xi_draw_rect(win, &r);
xi_inflate_rect(&r, -1);
xi_draw_rect(win, &r);
cb = white_cbrush;
cb.color = lmp->white_space_color;
xi_set_cbrush(win, &cb);
xi_set_cpen(win, &hollow_cpen);
r.left += 1;
r.top = lmp->rct.bottom;
r.right -= 1;
r.bottom -= 1;
xi_draw_rect(win, &r);
}
}
{ /* rectangle at bottom of list */
RCT r;
RCT hsb_rect;
xi_get_hsb_rect(lmp->list_obj, &hsb_rect);
cbrush.pat = PAT_SOLID;
cbrush.color = lmp->white_space_color;
xi_set_cbrush(win, &cbrush);
r = lmp->mlr;
r.top = lmp->rrr_bottom + lmp->rrr_offset + lmp->mlr.top;
r.top = min(r.top, hsb_rect.top);
r.bottom = hsb_rect.bottom;
r.right = lmp->rct.right;
if (lmp->pixel_width)
r.right = lmp->rct.left + lmp->pixel_width + 2;
if (r.top < r.bottom)
{
#if XIWS == XOLWS || XIWS == MTFWS
/* X GRAY SCALE HACK */
xi_set_xvt_back_color(win, COLOR_WHITE);
{
DRAW_CTOOLS ct;
xi_get_draw_ctools(win, &ct);
ct.opaque_text = FALSE;
xi_set_draw_ctools(win, &ct);
xi_draw_text(win, r.left, r.top, " ", -1);
}
#endif
}
xi_draw_rect(win, &r);
}
/* border around entire list */
if (! (lmp->update_rows_at_top + lmp->update_rows_at_bottom))
{
xi_set_cpen(win, &black_cpen);
xi_set_cbrush(win, &hollow_cbrush);
xi_set_draw_mode(win, M_COPY);
xi_set_clip(win, NULL);
lmp_rct = lmp->rct;
if (lmp->pixel_width)
lmp_rct.right = hrule_h;
WIDTHLOOP(i, BORDER_WIDTH)
{
xi_draw_rect(win, &lmp_rct);
xi_inflate_rect(&lmp_rct, -1);
}
CTOS_END;
}
#endif
#if XI_IS_CH
CTOS_IS_CH;
xi_set_clip(win, actual_rct);
xi_set_cpen(win, &black_cpen);
xi_set_draw_mode(win, M_COPY);
if (lmp->pixel_width)
{
RCT r;
PNT p1, p2;
r = lmp->rct;
r.left = lmp->rct.right - lmp->rct.left + BORDER_WIDTH;
r.top += BORDER_WIDTH;
r.right = 9999;
xi_set_cpen(win, &hollow_cpen);
cbrush.pat = PAT_SOLID;
cbrush.color = lmp->white_space_color;
xi_set_cbrush(win, &cbrush);
xi_set_clip(win, actual_rct);
lm_draw_rect(lmp, &r, FALSE);
xi_set_cpen(win, &black_cpen);
p1.h = r.left;
p1.v = lmp->rct.top;
p2.h = r.left;
p2.v = r.bottom;
lm_move_to(lmp, p1, FALSE, TRUE);
lm_draw_line(lmp, p2, FALSE, TRUE);
}
{ /* rectangle at bottom of list */
RCT r;
cbrush.pat = PAT_SOLID;
cbrush.color = lmp->white_space_color;
xi_set_cbrush(win, &cbrush);
xi_set_cpen(win, &hollow_cpen);
r = lmp->mlr;
r.left += BORDER_WIDTH;
r.top = lmp->rrr_bottom + lmp->rrr_offset + lmp->mlr.top;
r.right = lmp->rct.right;
if (lmp->pixel_width)
r.right = lmp->rct.left + 2 * lmp->pixel_width;
if (r.top < r.bottom)
xi_draw_rect(win, &r);
}
CTOS_END;
#endif
lmp->update_rows_at_top = 0;
lmp->update_rows_at_bottom = 0;
lmp->update_cells_only = FALSE;
}
/*-------------------------------------------------------------------------
lm: current lm
update: if TRUE, draw_lm is being called due to an E_UPDATE event
-------------------------------------------------------------------------*/
static void near
draw_lm(LM lm, BOOLEAN update)
{
int hrule_h, actual_r, idx;
RCT lmp_rct, actual_rct, clip_rct;
RCT hr, vr, urct;
XI_OBJ *list_obj;
XI_LIST_DATA *list_data;
LM_DATA *lmp = LMP(lm);
WINDOW win = lmp->win;
CBRUSH back_cbrush;
#if XI_IS_CH
CBRUSH lm_cbrush;
PNT from_p;
#if XVTWS == WMWS
NOREF(urct);
#endif
/***********************************************************************/
/* set up variables for drawing */
#if XVT_OS != XVT_OS_CTOS
c_xd = C_XD;
c_xu = C_XU;
c_v = C_V;
c_xx = C_XX;
#else
c_xd = 220;
c_xu = 221;
c_v = 225;
c_xx = 218;
c_xr = 226;
c_xl = 227;
#endif
#endif
if (! (lmp->attrib & LM_ATR_VISIBLE))
{
lmp->update_rows_at_top = 0;
lmp->update_rows_at_bottom = 0;
return;
}
list_obj = lmp->list_obj;
list_data = list_obj->v.list;
lmp_rct = lmp->rct;
actual_rct = lmp_rct;
#if XI_IS_NOT_CH
CTOS_IS_PM;
if (lmp->pixel_width)
actual_r = lmp->rct.left + lmp->pixel_width + 2 * BORDER_WIDTH;
else
actual_r = lmp->rct.right;
actual_rct.right = actual_r - BORDER_WIDTH;
CTOS_END;
#endif
#if XI_IS_CH
CTOS_IS_CH;
if (lmp->pixel_width)
actual_r = lmp->rct.left + lmp->pixel_width;
else
actual_r = lmp->rct.right + 8;
actual_rct.right = actual_r;
CTOS_END;
#endif
hrule_h = actual_r;
if (lmp->pixel_width)
lmp_rct.right = hrule_h;
urct = lmp_rct;
if (list_data->sb_win)
{
if (list_data->have_sb_rct)
vr = list_data->sb_rct;
else
xi_get_sb_rect(list_obj, &vr);
urct.right = vr.right;
}
if (list_data->hsb_win)
{
if (list_data->have_hsb_rct)
hr = list_data->hsb_rct;
else
xi_get_hsb_rect(list_obj, &hr);
urct.bottom = hr.bottom;
}
#if XIWS != WMWS
if (update && !xi_needs_update(win, &urct))
{
lmp->update_rows_at_top = 0;
lmp->update_rows_at_bottom = 0;
return;
}
#endif
lmp_rct = lmp->rct;
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;
if (! lm_tools_inited)
{
lm_white_cbrush.color = COLOR_WHITE;
lm_white_cbrush.pat = PAT_SOLID;
lm_black_cpen.width = 1;
lm_black_cpen.color = COLOR_BLACK;
lm_black_cpen.pat = PAT_SOLID;
lm_black_cpen.style = P_SOLID;
xvt_app_get_default_ctools(&lm_normal_ctools);
}
/***********************************************************************/
/* draw anything other than in the cell region */
/* prior to this, there are no calls to XVT for drawing */
back_cbrush = lm_white_cbrush;
/*
TO OPTIMIZE BACKGROUND DRAWING, USE THE FOLLOWING LINE, AND DON'T SET TO HOLLOW
back_cbrush.color = lmp->back_color;
*/
#if XIWS != WMWS
back_cbrush.pat = PAT_HOLLOW;
#endif
xi_set_cbrush(win, &back_cbrush);
xi_set_cpen(win, &lm_black_cpen);
clip_rct = actual_rct;
#if XVTWS == WMWS
if (list_data->hsb_win)
clip_rct.bottom += 8;
clip_rct.right += 8;
#endif
xi_set_clip(win, &clip_rct);
xi_set_draw_mode(win, M_COPY);
/*
CBRUSH: white_cbrush
CPEN: black_cpen
CLIP: actual_rct
*/
/*********** draw the rectangle around the list ***********/
draw_list_rect(lmp, &vr, &hr);
#if XVTWS == WMWS
xi_set_clip(win, &actual_rct);
#endif
/*********** draw the rules between the heading and the cells ***********/
if (! lmp->update_cells_only)
draw_heading_rules(lmp, hrule_h);
/*********** draw column rules ***********/
draw_column_rules(lmp);
/*
CBRUSH: white_cbrush
CPEN: black_cpen OR back_color cpen
CLIP: actual_rct
*/
#if 0
/*********** draw row rules ***********/
/* this was moved to draw_cell_block */
draw_row_rules(lmp, -1, -1, update);
#endif
/*********** draw column headings ***********/
if (! lmp->update_cells_only)
draw_column_headings(lmp, &actual_rct);
xi_set_clip(win, NULL);
/*********** draw text in cells ***********/
fast_draw_cells(lmp, update);
draw_other_rectangles(lmp, &actual_rct);
/*********** draw column rules ***********/
/* Moved after the draw row rules otherwise
no_horz_lines results in spotted vertical lines */
if (lmp->no_horz_lines && ! lmp->no_vert_lines)
draw_column_rules(lmp);
xi_set_clip(win, NULL);
}
/*-------------------------------------------------------------------------
function: lm_hit_test
lm: current lm
ep: xvt event
oevt: original xvt event, without virtual space coordinate conversions
rowp: if set, to be filled in with the results of the row hit test
columnp: if set, to be filled in with the results of the column hit test
is_vis: row is fully visible
is_part_vis:row is partially visible
returns: 0 - no hit
1 - hit
5 - hit on cell button
-------------------------------------------------------------------------*/
static int near
lm_hit_test(LM lm, EVENT *ep, EVENT *oevt, int *rowp, int *columnp,
BOOLEAN *is_vis, BOOLEAN *is_hit, BOOLEAN *is_part_vis)
{
int row, column, temp, col_offset, tmp_v, i, first, last;
int *pix_offsetsp, *pix_heightsp;
LM_DATA *lmp = LMP(lm);
PNT where;
if (is_vis)
*is_vis = TRUE;
if (is_hit)
*is_hit = FALSE;
if (is_part_vis)
*is_part_vis = FALSE;
col_offset = (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
where = ep->v.mouse.where;
/* if the mouse is to the left or the right of the list, return 0 */
if (oevt->v.mouse.where.h < 0)
return 0;
if (lmp->pixel_width &&
(oevt->v.mouse.where.h > (lmp->rct.left + lmp->pixel_width
+ BORDER_WIDTH)))
return 0;
/* if the mouse is in the column headings */
if (where.v > lmp->pix_top && where.v < lmp->pix_row1_top)
{
for (column = 0; column < lmp->nbr_columns; column++)
{
LM_COLUMN_DATA *column_data;
column_data = lmp->lm_column_data[column];
temp = column_data->x_pix_pos + col_offset;
if (where.h >= temp && where.h < temp + column_data->pix_width)
{
*rowp = -1;
*columnp = column;
return 1;
}
}
return 0;
}
/* if the mouse is above the list, return 0 */
if (where.v < lmp->pix_row1_top)
return 0;
/* 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))
{
row = i;
break;
}
}
if (i > last)
{
if (is_vis)
*is_vis = FALSE;
return 0;
}
if (is_vis)
{
if (i < lmp->first_fully_vis || i > lmp->last_fully_vis)
{
*is_vis = FALSE;
if ((i == lmp->last_fully_vis + 1) && (ep->v.mouse.where.v < lmp->mlr.bottom))
{
if (is_part_vis)
*is_part_vis = TRUE;
}
}
else
*is_vis = TRUE;
}
else
if (i < lmp->first_fully_vis || i > lmp->last_fully_vis)
return 0;
for (column = 0; column < lmp->nbr_columns; column++)
{
LM_COLUMN_DATA *column_data;
column_data = lmp->lm_column_data[column];
temp = column_data->x_pix_pos + col_offset;
if (where.h >= temp && where.h < temp + column_data->pix_width)
{
if (((lmp->attrib & (LM_ATR_ENABLED | LM_ATR_VISIBLE)) == (LM_ATR_ENABLED | LM_ATR_VISIBLE))
&& (lmp->lm_column_data[column]->attrib & (LM_COL_ATR_ENABLED | LM_COL_ATR_SELECTABLE)))
{
LM_CELL_DATA *cell_data;
*rowp = row;
*columnp = column;
if (is_hit)
*is_hit = TRUE;
cell_data = &lmp->cell_data[row][column];
if (cell_data->button)
{
RCT outer_rct;
PNT p;
lm_get_cell_rect(&outer_rct, lm, row, column, FALSE, FALSE);
xi_inflate_rect(&outer_rct, 1);
if (cell_data->button_on_left)
outer_rct.right = outer_rct.left + lmp->pix_row_spacing;
else
outer_rct.left = outer_rct.right - lmp->pix_row_spacing;
p = ep->v.mouse.where;
p.v = tmp_v;
if (xvt_rect_has_point(&outer_rct, p))
{
return 5;
}
}
return 1;
}
else
{
*rowp = row;
*columnp = column;
if (is_hit)
*is_hit = TRUE;
if (is_part_vis)
*is_part_vis = FALSE;
return 0;
}
}
}
if (is_part_vis)
*is_part_vis = FALSE;
return 0;
}
/*-------------------------------------------------------------------------
function: lm_vsize_hit_test
lm: current lm
ep: xvt event
rowp: row, to be filled in
columnp: column, to be filled in
returns: FALSE if hit test did not fall on place where column could be vertically sized.
-------------------------------------------------------------------------*/
static BOOLEAN near
lm_vsize_hit_test(LM_DATA *lmp, EVENT *ep, int *rowp, int *columnp)
{
int i, n, v;
int *pix_offsetsp;
int *pix_heightsp;
if (lmp->lm_column_data[*columnp]->size_rows)
{
v = ep->v.mouse.where.v - lmp->rrr_offset - lmp->mlr.top;
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)
{
n = *pix_offsetsp + *pix_heightsp;
if (v >= n - 3 && v <= n + 1)
{
*rowp = i;
return TRUE;
}
}
return FALSE;
}
else
return FALSE;
}
/*-------------------------------------------------------------------------
function: lm_size_hit_test
lm: current lm
ep: xvt event
columnp: column, to be filled in
returns: FALSE if hit test did not fall on place where column could be sized.
-------------------------------------------------------------------------*/
static BOOLEAN near
lm_size_hit_test(LM lm, EVENT *ep, int *columnp)
{
int column, temp, col_offset;
LM_DATA *lmp = LMP(lm);
PNT where;
col_offset = (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
where = ep->v.mouse.where;
if (where.h < 0)
return FALSE;
if (lmp->pixel_width && (where.h > (lmp->pixel_width + lmp->delta_x)
+ 2 * BORDER_WIDTH))
return FALSE;
if (where.v > lmp->pix_top && where.v < lmp->pix_row1_top)
{
for (column = 0; column < lmp->nbr_columns; column++)
{
LM_COLUMN_DATA *column_data;
if (column >= lmp->fixed_columns && column < lmp->first_vis)
continue;
column_data = lmp->lm_column_data[column];
temp = column_data->x_pix_pos +
col_offset +
column_data->pix_width;
if (where.h >= temp &&
where.h < temp + col_offset * 2 + RULE_WIDTH_V)
{
*columnp = column;
return TRUE;
}
}
return FALSE;
}
return FALSE;
}
/*-------------------------------------------------------------------------
function: calc_y
lmp: current lmp
ep: xvt event
returns: Calculates and returns the Y pixel position of the rubber band line.
Used only when sizing rows.
-------------------------------------------------------------------------*/
static int
calc_y(LM_DATA *lmp, EVENT *ep)
{
int row = lmp->row_being_sized;
int temp;
int min_height_in_pix = 4;
int v;
v = min(lmp->mlr.bottom, ep->v.mouse.where.v) - lmp->rrr_offset - lmp->mlr.top;
temp = lmp->pix_offsets[row] + min_height_in_pix;
temp = max(v, temp);
return temp;
}
/*-------------------------------------------------------------------------
function: rubber_y
lmp: current lmp
y: draw a rubber line at position y
-------------------------------------------------------------------------*/
static void
rubber_y(LM_DATA *lmp, int y)
{
#if XI_IS_NOT_CH
int left, right;
DRAW_CTOOLS new_ctools;
PNT pnt;
WINDOW win = lmp->win;
CTOS_IS_PM;
left = lmp->mlr.left;
right = lmp->mlr.right;
if (lmp->pixel_width)
right = left + lmp->pixel_width + BORDER_WIDTH;
xvt_app_get_default_ctools(&new_ctools);
xi_set_draw_ctools(win, &new_ctools);
xi_set_cpen(win, &rubber_cpen);
xi_set_draw_mode(win, M_XOR);
xi_set_clip(win, NULL);
pnt.h = left;
pnt.v = y;
lm_move_to(lmp, pnt, TRUE, FALSE);
pnt.h = right;
lm_draw_line(lmp, pnt, TRUE, FALSE);
CTOS_END;
#endif
NOREF(lmp);
NOREF(y);
}
/*-------------------------------------------------------------------------
function: lm_vsize_event
lmp: current lmp
ep: xvt event
-------------------------------------------------------------------------*/
static void
lm_vsize_event(LM_DATA *lmp, EVENT *ep)
{
int y;
switch (ep->type)
{
case E_MOUSE_DOWN:
case E_MOUSE_DBL:
y = calc_y(lmp, ep);
lmp->last_y = y;
rubber_y(lmp, y);
break;
case E_MOUSE_MOVE:
y = calc_y(lmp, ep);
rubber_y(lmp, lmp->last_y);
lmp->last_y = y;
rubber_y(lmp, y);
break;
case E_MOUSE_UP:
{
int delta, row;
XI_OBJ row_obj;
row = lmp->row_being_sized;
y = calc_y(lmp, ep);
rubber_y(lmp, lmp->last_y);
delta = y - lmp->pix_offsets[row] + 1;
XI_MAKE_ROW(&row_obj, lmp->list_obj, row);
if (do_lm_cb((LM)lmp, LM_CB_ROW_SIZE, row, 0, NULL, NULL, delta))
{
xi_set_row_height(&row_obj, delta);
calculate_pix_offsets(lmp, FALSE );
}
lm_make_vis(lmp);
break;
}
}
}
/*-------------------------------------------------------------------------
function: send_txt_event
lm: current lm
txt: txt object
ep: xvt event
gaining_focus: if TRUE, the edit control is gaining focus as this function is called
returns: TRUE if the event was used
-------------------------------------------------------------------------*/
static BOOLEAN near
send_txt_event(LM lm, TXT_DATA *txt, EVENT *ep,
BOOLEAN gaining_focus, BOOLEAN send_to_txt)
{
BOOLEAN retval = FALSE;
int ch;
LM_DATA *lmp = LMP(lm);
if (! lmp->txt)
return FALSE;
if (ep->type == E_CHAR)
{
ch = ep->v.chr.ch;
if ( (ch >= ' ' || ch == K_CLEAR || ch == K_DEL || ch == '\b')
&& ch != K_BTAB && ch != K_UP && ch != K_DOWN )
{
int focus_row, focus_column;
BOOLEAN v_scrolled;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
retval = do_lm_cb( lm, LM_CB_CHAR, focus_row, focus_column, ep, NULL, 0);
/* retval = FALSE if event refused */
if (! retval)
return FALSE;
}
}
if (send_to_txt)
{
retval = txt_event(txt, ep, gaining_focus);
/* check flags */
if (txt->flags & TXT_FLAG_TEXT)
{
int focus_row, focus_column;
BOOLEAN v_scrolled;
lmp->itf_obj->v.itf->chg_flag = TRUE;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
do_lm_cb(lm, LM_CB_CHANGE, focus_row, focus_column, NULL, NULL, 0);
}
/* reset flags */
txt->flags = 0;
}
return retval;
}
/*-------------------------------------------------------------------------
function: lm_select_cells_hit_test
lmp: current lmp
ep: xvt event
rowp: row number, to be filled in
columnp: column number, to be filled in
on_disabled: if TRUE, then the hit was on a disabled column
returns: TRUE if there was a hit
-------------------------------------------------------------------------*/
static BOOLEAN
lm_select_cells_hit_test(LM_DATA *lmp, EVENT *ep, int *rowp,
int *columnp, BOOLEAN *on_disabled)
{
int delta_top, column, col_offset, last_vis, row, idx;
LM_COLUMN_DATA *column_data;
BOOLEAN retval;
BOOLEAN inv_v, inv_h; /* if set to TRUE, then invalid v or invalid h */
retval = TRUE;
if (columnp)
*columnp = 0;
if (on_disabled)
*on_disabled = FALSE;
inv_v = FALSE;
inv_h = FALSE;
last_vis = lmp->last_vis;
delta_top = ep->v.mouse.where.v - lmp->mlr.top - lmp->rrr_offset;
/* If list has no columns */
if (lmp->nbr_columns <= 0) return FALSE;
/*
If mouse is above the top of the first row
*/
if (ep->v.mouse.where.v < lmp->pix_row1_top - RULE_WIDTH_V -
RULE_Y_OFFSET_TOP)
{
if (rowp)
*rowp = 0;
retval = FALSE;
inv_v = TRUE;
}
/*
if mouse is below the bottom of the list, or if the mouse is
below the bottom of the last row if there are fewer rows than
can be displayed in the list
*/
idx = lmp->nbr_realized_rows - 1;
if (ep->v.mouse.where.v >= lmp->mlr.bottom ||
delta_top > lmp->pix_offsets[idx] + lmp->pix_heights[idx])
{
if (rowp)
*rowp = lmp->nbr_realized_rows;
retval = FALSE;
inv_v = TRUE;
}
/*
if mouse is to the right of the list, or if the mouse is to the right of the
rightmost column
*/
column_data = lmp->lm_column_data[lmp->nbr_columns - 1];
if ((ep->v.mouse.where.h >= (lmp->rct.right - lmp->rct.left)) ||
(ep->v.mouse.where.h >= (column_data->x_pix_pos + column_data->pix_width)))
{
if (columnp)
*columnp = last_vis + 1;
retval = FALSE;
inv_h = TRUE;
}
/*
if mouse has a valid y coordinate
*/
if (! inv_v)
{
if (rowp)
*rowp = 0;
retval = FALSE;
for (row = 0; row < lmp->nbr_realized_rows; ++row)
{
int pix_offset, pix_height;
pix_offset = lmp->pix_offsets[row];
pix_height = lmp->pix_heights[row];
if (delta_top >= pix_offset - SELECT_CELLS_OFFSET - 2
&& delta_top <= pix_offset + SELECT_CELLS_OFFSET)
{
if (rowp)
*rowp = row;
if (! inv_h)
retval = TRUE;
break;
}
if (delta_top >= (pix_offset + pix_height) - SELECT_CELLS_OFFSET - 2
&& delta_top <= (pix_offset + pix_height) + SELECT_CELLS_OFFSET)
{
if (rowp)
*rowp = row + 1;
if (! inv_h)
retval = TRUE;
break;
}
if (delta_top >= pix_offset &&
delta_top <= pix_offset + pix_height)
{
if (rowp)
*rowp = row;
}
}
if (rowp && ! retval && *rowp < lmp->down_row)
++*rowp;
}
/*
if mouse has a valid x coordinate
*/
if (! inv_h)
{
column_data = lmp->lm_column_data[0];
col_offset = (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
if (((! (column_data->attrib & XI_ATR_ENABLED) || lmp->down_on_disabled) &&
(! (column_data->attrib & XI_ATR_SELECTABLE))) &&
((ep->v.mouse.where.h >= column_data->x_pix_pos) &&
(ep->v.mouse.where.h < (column_data->x_pix_pos + column_data->pix_width))))
{
if (columnp)
*columnp = 0;
if (on_disabled)
*on_disabled = TRUE;
}
else if ((ep->v.mouse.where.h >= column_data->x_pix_pos) &&
(ep->v.mouse.where.h < (column_data->x_pix_pos + col_offset)))
{
if (columnp)
*columnp = 0;
}
else
{
BOOLEAN found = FALSE;
int last_col;
last_col = -1;
for (column = 0; column < lmp->nbr_columns; column++)
{
int temp;
column_data = lmp->lm_column_data[column];
if (((! (column_data->attrib & XI_ATR_ENABLED) || lmp->down_on_disabled) &&
(! (column_data->attrib & XI_ATR_SELECTABLE))) &&
((ep->v.mouse.where.h >= column_data->x_pix_pos) &&
(ep->v.mouse.where.h <
(column_data->x_pix_pos + column_data->pix_width))))
{
if (columnp)
*columnp = column;
if (on_disabled)
*on_disabled = TRUE;
found = TRUE;
break;
}
temp = column_data->x_pix_pos +
col_offset +
column_data->pix_width - SELECT_CELLS_OFFSET;
if (ep->v.mouse.where.h >= temp &&
ep->v.mouse.where.h < (temp + col_offset * 2
+ 2 * SELECT_CELLS_OFFSET
+ RULE_WIDTH_V))
{
if (columnp)
*columnp = column + 1;
found = TRUE;
break;
}
if (ep->v.mouse.where.h >= temp)
last_col = column;
}
if (! found)
{
retval = FALSE;
if (columnp)
{
if ((last_col + 1) < lmp->down_column)
*columnp = last_col + 2;
else
*columnp = last_col + 1;
}
}
}
}
/*
If v is not invalid, and if h is not invalid, and if the column is valid, then
if the column is enabled, then the hit test must be within a range of the rules.
If the column is not enabled, then the hit test may be anywhere within the cell.
*/
if (! inv_v)
{
BOOLEAN enabled_col = FALSE;
if (columnp && ! inv_h)
{
if (*columnp >= lmp->nbr_columns)
enabled_col = FALSE;
else
enabled_col = (lmp->lm_column_data[*columnp]->attrib & XI_ATR_ENABLED &&
! lmp->down_on_disabled);
if (enabled_col)
{
delta_top = ep->v.mouse.where.v - lmp->mlr.top - lmp->rrr_offset;
retval = FALSE;
for (row = 0; row < lmp->nbr_realized_rows; ++row)
{
int pix_offset, pix_height;
pix_offset = lmp->pix_offsets[row];
pix_height = lmp->pix_heights[row];
if (delta_top >= pix_offset - SELECT_CELLS_OFFSET - 2
&& delta_top <= pix_offset + SELECT_CELLS_OFFSET)
{
if (rowp)
*rowp = row;
retval = TRUE;
break;
}
if (delta_top >= (pix_offset + pix_height) - SELECT_CELLS_OFFSET - 2
&& delta_top <= (pix_offset + pix_height) + SELECT_CELLS_OFFSET)
{
if (rowp)
*rowp = row + 1;
retval = TRUE;
break;
}
}
return retval;
}
}
}
return retval;
}
/*-------------------------------------------------------------------------
function: invert_selection
lmp: current lmp
r: row
c: column
-------------------------------------------------------------------------*/
static void invert_selection(LM_DATA *lmp, int r, int c, BOOLEAN v_scrolled)
{
unsigned long attrib;
attrib = lm_get_attrib((LM)lmp, LM_CELL, r, c, v_scrolled);
if (attrib & LM_CELL_ATR_SELECTED)
lm_set_attrib((LM)lmp, LM_CELL, r, c, v_scrolled,
attrib & ~LM_CELL_ATR_SELECTED, FALSE);
else
lm_set_attrib((LM)lmp, LM_CELL, r, c, v_scrolled,
attrib | LM_CELL_ATR_SELECTED, FALSE);
}
/*-------------------------------------------------------------------------
function: in_rct
rct: rectangle
r: row
c: column
returns: TRUE if c and r are in rct
-------------------------------------------------------------------------*/
static BOOLEAN
in_rct(RCT *rct, int r, int c)
{
if (c >= rct->left && c < rct->right && r >= rct->top && r < rct->bottom)
return TRUE;
return FALSE;
}
/*-------------------------------------------------------------------------
function: lm_select_cell_event
lmp: current lmp
ep: xvt event
-------------------------------------------------------------------------*/
static void
lm_select_cell_event(LM_DATA *lmp, EVENT *ep)
{
int row, column;
switch (ep->type)
{
case E_MOUSE_DOWN:
case E_MOUSE_DBL:
if (! ep->v.mouse.shift)
{
int r, c;
for (r = 0; r < lmp->nbr_realized_rows; ++r)
for (c = 0; c < lmp->nbr_columns; ++c)
{
unsigned long attrib;
attrib = lm_get_attrib((LM)lmp, LM_CELL, r, c, FALSE);
if (attrib & LM_CELL_ATR_SELECTED)
lm_set_attrib((LM)lmp, LM_CELL, r, c, FALSE,
attrib & ~LM_CELL_ATR_SELECTED, FALSE);
}
}
break;
case E_MOUSE_MOVE:
case E_MOUSE_UP:
{
int last_cur_row, last_cur_column, r, c, down_row, down_column;
RCT old_rct, new_rct, enclosing_rct;
lm_select_cells_hit_test(lmp, ep, &row, &column, NULL);
last_cur_row = lmp->cur_row;
last_cur_column = lmp->cur_column;
down_row = lmp->down_row;
down_column = lmp->down_column;
if (lmp->down_on_disabled)
{
if (ep->type == E_MOUSE_UP)
lmp->down_on_disabled = FALSE;
if (row >= lmp->down_row)
lmp->cur_row = row + 1;
else
lmp->cur_row = row;
if (column >= lmp->down_column)
lmp->cur_column = column + 1;
else
lmp->cur_column = column;
}
else
{
lmp->cur_row = row;
lmp->cur_column = column;
}
if (lmp->cur_row == last_cur_row && lmp->cur_column == last_cur_column &&
(ep->type == E_MOUSE_MOVE || ep->type == E_MOUSE_UP))
break;
old_rct.left = min(down_column, last_cur_column);
old_rct.right = max(down_column, last_cur_column);
old_rct.top = min(down_row, last_cur_row);
old_rct.bottom = max(down_row, last_cur_row);
new_rct.left = min(down_column, lmp->cur_column);
new_rct.right = max(down_column, lmp->cur_column);
new_rct.top = min(down_row, lmp->cur_row);
new_rct.bottom = max(down_row, lmp->cur_row);
enclosing_rct.top = min(old_rct.top, new_rct.top);
enclosing_rct.bottom = max(old_rct.bottom, new_rct.bottom);
enclosing_rct.left = min(old_rct.left, new_rct.left);
enclosing_rct.right = max(old_rct.right, new_rct.right);
for (c = enclosing_rct.left; c <= enclosing_rct.right; ++c)
{
for (r = enclosing_rct.top; r <= enclosing_rct.bottom; ++r)
{
if ((in_rct(&old_rct, r, c) &&
in_rct(&new_rct, r, c)) ||
(! in_rct(&old_rct, r, c) &&
! in_rct(&new_rct, r, c)))
continue;
if (r >= lmp->nbr_realized_rows || c >= lmp->nbr_columns ||
r < 0 || c < 0)
continue;
invert_selection(lmp, r, c, FALSE);
}
}
}
break;
}
}
/*-------------------------------------------------------------------------
function: lm_cell_btn_event
lmp: current lmp
ep: xvt event
oevp: xvt event, without virtual coordinate conversion
-------------------------------------------------------------------------*/
static void
lm_cell_btn_event(LM_DATA *lmp, EVENT *ep, EVENT *oevp)
{
RCT mr;
int hit_test_value, row, col;
mr = lmp->mlr;
if (lmp->pixel_width)
mr.right = lmp->rct.left + lmp->pixel_width + BORDER_WIDTH;
hit_test_value = lm_hit_test((LM)lmp, ep, oevp, &row, &col, NULL, NULL, NULL);
if (hit_test_value)
{
switch (ep->type)
{
case E_MOUSE_DOWN:
case E_MOUSE_DBL:
lmp->down_in_btn = TRUE;
lmp->btn_down = TRUE;
lmp->btn_down_row = row;
lmp->btn_down_col = col;
xi_trap_mouse(lmp->win);
xi_set_trap_obj(lmp->list_obj);
redraw_cell_button(lmp, row, col, &mr, lmp->btn_down, FALSE);
break;
case E_MOUSE_MOVE:
{
BOOLEAN last = lmp->btn_down;
if (hit_test_value != 5 || row != lmp->btn_down_row || col != lmp->btn_down_col)
lmp->btn_down = FALSE;
else
lmp->btn_down = TRUE;
if (last != lmp->btn_down)
{
redraw_cell_button(lmp, lmp->btn_down_row, lmp->btn_down_col, &mr,
lmp->btn_down, FALSE);
last = lmp->btn_down;
}
break;
}
case E_MOUSE_UP:
if (lmp->btn_down)
redraw_cell_button(lmp, lmp->btn_down_row, lmp->btn_down_col, &mr,
FALSE, FALSE);
lmp->btn_down = FALSE;
lmp->down_in_btn = FALSE;
if (hit_test_value == 5 && row == lmp->btn_down_row && col == lmp->btn_down_col)
do_lm_cb((LM)lmp, LM_CB_CELL_BTN, row, col, ep, NULL, 0);
break;
}
}
}
/*-------------------------------------------------------------------------
function: get_select_column
-------------------------------------------------------------------------*/
static int get_select_column( LM_DATA* lmp )
{
int col;
for ( col = 0; col < lmp->nbr_columns; col++ )
if ( LM_COL_ATTR( (LM)lmp, col ) & XI_ATR_SELECTABLE )
return col;
return 0;
}
/*-------------------------------------------------------------------------
function: select_row
-------------------------------------------------------------------------*/
void select_row( LM lm, int row, int column, BOOLEAN dbl_click )
{
unsigned long attrib;
LM_CB_DATA lm_cb_data;
XI_OBJ *old_itf;
int old_row;
LM_DATA* lmp = LMP(lm);
old_row = find_selection( lmp );
if ( old_row != row && old_row != -1 )
{
attrib = lm_get_attrib( lm, LM_ROW, old_row, 0, FALSE );
attrib &= ~LM_ROW_ATR_SELECTED;
lm_set_attrib( lm, LM_ROW, old_row, 0, FALSE, attrib, FALSE );
}
attrib = lm_get_attrib( lm, LM_ROW, row, 0, FALSE );
attrib |= LM_ROW_ATR_SELECTED;
lm_cb_data.lm = lm;
lm_cb_data.cb_type = LM_CB_SELECT;
lm_cb_data.cid = lmp->cid;
lm_cb_data.win = lmp->win;
lm_cb_data.row = (unsigned char)row;
if ( column == -1 )
column = (unsigned char)get_select_column( lmp );
lm_cb_data.column = column;
lm_cb_data.v.select.selected = TRUE;
lm_cb_data.v.select.dbl_click = dbl_click;
lm_cb_data.v.select.shift = FALSE;
lm_cb_data.v.select.control = FALSE;
old_itf = lmp->itf_obj;
(*lmp->lm_cb)(&lm_cb_data);
if (xi_is_itf(old_itf))
if ( !lm_cb_data.v.select.refused && old_row != row )
lm_set_attrib( lm, LM_ROW, row, 0, FALSE, attrib, FALSE );
}
/*-------------------------------------------------------------------------
function: lm_event
lm: current lm
ep: xvt event
return: TRUE if event is consumed
-------------------------------------------------------------------------*/
int
lm_event(LM lm, EVENT *ep)
{
int row, column;
LM_DATA *lmp = LMP(lm);
BOOLEAN send_event = FALSE;
int retval = 1;
EVENT oevt;
XI_OBJ *itf = lmp->itf_obj;
oevt = *ep;
switch(ep->type)
{
case E_MOUSE_DOWN:
case E_MOUSE_DBL:
case E_MOUSE_MOVE:
case E_MOUSE_UP:
{
RCT rct;
if (lmp->attrib & XI_ATR_VISIBLE)
{
/*
COORDINATE CONVERSION
changes horizontal coordinates - moves mouse to the right -
increases where.h if where.h is > lmp->vir_left, so that where.h
is in the correct virtual horizontal space - also makes where.h
be relative to the list, not the window.
*/
lm_get_rect(lm, LM_LIST, 0, &rct);
if (xvt_rect_has_point(&rct, ep->v.mouse.where) ||
lmp->selecting_cells || lmp->sizing_column || lmp->moving_column ||
lmp->down_in_btn || lmp->selecting_text || lmp->sizing_row)
{
if (ep->type == E_MOUSE_DOWN)
{
if (ep->v.mouse.where.h >= lmp->vir_left)
lmp->down_in_hscrolling = TRUE;
else
lmp->down_in_hscrolling = FALSE;
}
if (! lmp->sizing_column)
{
if ((lmp->pixel_width && (ep->v.mouse.where.h >= lmp->vir_left)))
{
ep->v.mouse.where.h += lmp->delta_x;
lmp->in_hscrolling = TRUE;
}
else
lmp->in_hscrolling = FALSE;
}
else
{
if (lmp->down_in_hscrolling)
ep->v.mouse.where.h += lmp->delta_x;
}
ep->v.mouse.where.h -= lmp->rct.left;
}
else
{
*ep = oevt;
return FALSE;
}
}
else
{
*ep = oevt;
return FALSE;
}
break;
}
}
switch(ep->type)
{
case E_UPDATE:
/* the following code sends the event directly on to redraw_cell
if text is being scrolled in a text object. This speeds horizontal
scrolling. see also lm_text_scrolling.
*/
if (lmp->text_scrolling)
{
int row, col;
BOOLEAN is_vert_scrolled;
lm_get_focus_cell(lmp, &row, &col, &is_vert_scrolled);
draw_cell_range(lmp, row, row, col, col, FALSE);
if ( lmp->txt != NULL )
send_txt_event( lm, lmp->txt, &oevt, FALSE, TRUE );
lmp->text_scrolling = FALSE;
}
else
{
draw_lm(lm, TRUE);
if ( lmp->txt != NULL )
send_txt_event( lm, lmp->txt, &oevt, FALSE, TRUE );
}
retval = 0;
break;
case E_SIZE:
{
int new_height, new_width;
RCT hr, vr, cr;
XI_OBJ *list_obj;
if (lmp->resize_with_window)
{
RCT rct, wrct;
list_obj = lmp->list_obj;
if (xi_get_pref(XI_PREF_UNUSED_PREFERENCE))
lm_make_invis(lmp);
else
{
if (lm_list_has_focus(lmp))
{
if (! xi_move_focus(list_obj->itf))
{
retval = 0;
break;
}
}
}
xi_get_hsb_rect(list_obj, &hr);
xi_get_sb_rect(list_obj, &vr);
xvt_vobj_get_client_rect(lmp->win, &cr);
new_height = cr.bottom - lmp->pix_top;
new_width = cr.right - lmp->rct.left;
xi_set_list_size(list_obj, new_height, new_width);
if ((BOOLEAN)xi_get_pref( XI_PREF_LIMIT_MIN_WIN_SIZE ))
{
xi_get_rect(list_obj, &rct);
if (abs(rct.bottom - cr.bottom) > 4 ||
abs(rct.right - cr.right) > 4)
{
wrct = cr;
wrct.bottom = max(rct.bottom, cr.bottom);
wrct.right = max(rct.right, cr.right);
if ( wrct.bottom != cr.bottom || wrct.right != cr.right )
{
xvt_vobj_translate_points(lmp->win, xvt_vobj_get_parent(lmp->win), (PNT *)&wrct, 2);
xvt_vobj_move(lmp->win, &wrct);
}
}
}
if (xi_get_pref(XI_PREF_UNUSED_PREFERENCE))
lm_make_vis(lmp);
}
retval = 0;
break;
}
case E_MOUSE_DOWN:
case E_MOUSE_DBL:
{
RCT rct;
int last_vis, hit_test_value;
BOOLEAN is_vis, is_hit, is_part_vis;
if (ep->v.mouse.button > 0)
break;
hit_test_value = lm_hit_test(lm, ep, &oevt, &row, &column, &is_vis, &is_hit, &is_part_vis);
if (is_part_vis && ep->type != E_MOUSE_DBL)
{
EVENT lep;
LM_SCROLL_ARG lm_scroll_arg;
static BOOLEAN in_here = FALSE;
if (in_here)
return FALSE;
MEMCLEAR(lm_scroll_arg);
lm_scroll_arg.lm = lm;
lm_scroll_arg.nbr_lines = 1;
/*
lm_scroll_arg.percent = 0;
lm_scroll_arg.same_cell = 0;
lm_scroll_arg.rec = 0L;
lm_scroll_arg.have_rec = FALSE;
lm_scroll_arg.color = 0L;
lm_scroll_arg.attrib = 0L;
lm_scroll_arg.row_height = 0;
lm_scroll_arg.rec_at_top = FALSE;
*/
lm_scroll(&lm_scroll_arg);
lep = oevt;
lep.v.mouse.where.v -= lm_scroll_arg.pixels_scrolled;
in_here = TRUE;
lm_event(lm, &lep);
in_here = FALSE;
return TRUE;
}
if (is_hit)
{
if (lm_vsize_hit_test(lmp, ep, &row, &column))
{
XI_OBJ *itf, *list;
itf = lmp->itf_obj;
list = lmp->list_obj;
if (list && xi_get_pref(XI_PREF_UNUSED_PREFERENCE))
{
lm_make_invis(lmp);
xi_set_trap_obj(list);
lmp->row_being_sized = row;
lmp->sizing_row = TRUE;
xi_trap_mouse(lmp->win);
lm_vsize_event(lmp, ep);
}
else
{
if (list && xi_move_focus(itf))
{
xi_set_trap_obj(list);
lmp->row_being_sized = row;
lmp->sizing_row = TRUE;
xi_trap_mouse(lmp->win);
lm_vsize_event(lmp, ep);
}
}
break;
}
}
if (lmp->select_cells)
{
int row, column;
BOOLEAN on_disabled;
if (lm_select_cells_hit_test(lmp, ep, &row, &column, &on_disabled))
{
XI_OBJ *list;
list = lmp->list_obj;
xi_set_trap_obj(list);
lmp->selecting_cells = TRUE;
lmp->down_row = row;
lmp->cur_row = row;
lmp->down_column = column;
lmp->cur_column = column;
lmp->down_on_disabled = on_disabled;
lm_select_cell_event(lmp, ep);
xi_trap_mouse(lmp->win);
if (on_disabled)
{
invert_selection(lmp, row, column, FALSE );
lmp->cur_row = row + 1;
lmp->cur_column = column + 1;
}
break;
}
}
/* check for cell button hit */
if (hit_test_value == 5)
if (LIST_IS_ENABLED(lm))
lm_cell_btn_event(lmp, ep, &oevt);
/* check for focus acquisition */
if (hit_test_value == 1)
{
if (row == -1)
{
if (LIST_IS_ENABLED(lm) &&
COLUMN_IS_SELECTABLE(lm, column) &&
(ep->type == E_MOUSE_DBL ||
(ep->type == E_MOUSE_DOWN && !
lmp->movable_columns)
))
{
unsigned long attrib;
LM_CB_DATA lm_cb_data;
attrib = lm_get_attrib(lm, LM_COLUMN, column, 0, FALSE);
if (ep->type == E_MOUSE_DBL && !lmp->movable_columns)
attrib |= LM_COL_ATR_SELECTED;
else
{
if (attrib & LM_COL_ATR_SELECTED)
attrib &= ~LM_COL_ATR_SELECTED;
else
attrib |= LM_COL_ATR_SELECTED;
}
lm_cb_data.lm = lm;
lm_cb_data.cb_type = LM_CB_SELECT;
lm_cb_data.cid = lmp->cid;
lm_cb_data.win = lmp->win;
lm_cb_data.row = (unsigned char)255;
lm_cb_data.column = (unsigned char)column;
lm_cb_data.v.select.selected =
((attrib & LM_COL_ATR_SELECTED) != 0);
lm_cb_data.v.select.dbl_click =
(ep->type == E_MOUSE_DBL);
lm_cb_data.v.select.shift = ep->v.mouse.shift;
lm_cb_data.v.select.control = ep->v.mouse.control;
(*lmp->lm_cb)(&lm_cb_data);
if (! lm_cb_data.v.select.refused)
lm_set_attrib( lm, LM_COLUMN, column, 0, FALSE, attrib,
FALSE);
}
if (LIST_IS_ENABLED(lm) &&
(ep->type == E_MOUSE_DOWN ||
(ep->type == E_MOUSE_DBL &&
! COLUMN_IS_SELECTABLE(lm, column))) &&
lmp->movable_columns)
{
XI_OBJ *itf, *list;
itf = lmp->itf_obj;
list = lmp->list_obj;
if (list && xi_get_pref(XI_PREF_UNUSED_PREFERENCE))
{
lm_make_invis(lmp);
xi_set_trap_obj(list);
lmp->column_being_moved = column;
lmp->moving_column = TRUE;
xi_trap_mouse(lmp->win);
lm_move_event(lmp, ep);
}
else
{
if (list && xi_move_focus(itf))
{
xi_set_trap_obj(list);
lmp->column_being_moved = column;
lmp->moving_column = TRUE;
xi_trap_mouse(lmp->win);
lm_move_event(lmp, ep);
}
}
}
break;
}
if (CELL_IS_SELECTABLE(lm, row, column))
{
if ( lmp->single_select )
select_row( lm, row, column, (BOOLEAN)(ep->type == E_MOUSE_DBL) );
else
{
unsigned long attrib;
LM_CB_DATA lm_cb_data;
XI_OBJ *old_itf;
attrib = lm_get_attrib(lm, LM_ROW, row, 0, FALSE);
if (ep->type == E_MOUSE_DBL)
attrib |= LM_ROW_ATR_SELECTED;
else
{
if (attrib & LM_ROW_ATR_SELECTED)
attrib &= ~LM_ROW_ATR_SELECTED;
else
attrib |= LM_ROW_ATR_SELECTED;
}
lm_cb_data.lm = lm;
lm_cb_data.cb_type = LM_CB_SELECT;
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.select.selected =
((attrib & LM_COL_ATR_SELECTED) != 0);
lm_cb_data.v.select.dbl_click = (ep->type == E_MOUSE_DBL);
lm_cb_data.v.select.shift = ep->v.mouse.shift;
lm_cb_data.v.select.control = ep->v.mouse.control;
old_itf = lmp->itf_obj;
(*lmp->lm_cb)(&lm_cb_data);
if (xi_is_itf(old_itf))
if (! lm_cb_data.v.select.refused)
lm_set_attrib(lm, LM_ROW, row, 0, FALSE, attrib, FALSE);
}
}
else
{
BOOLEAN gaining_focus = FALSE;
if (! is_vis)
break;
if (! lmp->cell_data[row][column].icon_rid)
{
/* set this flag here, not later! */
lmp->have_mouse = TRUE;
if (! lm_list_has_focus(lmp))
{
send_event = do_lm_cb(lm, LM_CB_FOCUS, row, column,
NULL, NULL, 0);
gaining_focus = TRUE;
}
else
{
if (! lm_cell_has_focus(lmp, row, column, FALSE))
{
send_event = do_lm_cb(lm, LM_CB_FOCUS, row, column, NULL, NULL, 0);
/* send_event = FALSE if refused */
gaining_focus = send_event;
}
else
send_event = TRUE;
}
if (send_event)
{
int focus_row, focus_column;
BOOLEAN v_scrolled;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
if ( ( lmp->lm_column_data[focus_column]->attrib
& LM_COL_ATR_AUTOSELECT )
&& xi_get_pref(XI_PREF_AUTOSEL_ON_MOUSE)
&& gaining_focus)
;
else
{
xi_trap_mouse(lmp->win);
lmp->selecting_text = TRUE;
send_txt_event( lm, lmp->txt, &oevt, gaining_focus, TRUE);
}
}
else
lmp->have_mouse = FALSE;
if (ep->type == E_MOUSE_DBL)
do_lm_cb(lm, LM_CB_DBL, row, column, NULL, NULL, 0);
}
}
}
else
{
if (LIST_IS_ENABLED(lm) &&
lmp->sizable_columns &&
lm_size_hit_test(lm, ep, &column))
{
XI_OBJ *itf, *list;
itf = lmp->itf_obj;
list = lmp->list_obj;
if (list && xi_get_pref(XI_PREF_UNUSED_PREFERENCE))
{
lm_make_invis(lmp);
xi_set_trap_obj(list);
lmp->column_being_sized = column;
lmp->sizing_column = TRUE;
xi_trap_mouse(lmp->win);
lm_size_event(lmp, ep);
}
else
{
if (list && xi_move_focus(itf))
{
xi_set_trap_obj(list);
lmp->column_being_sized = column;
lmp->sizing_column = TRUE;
xi_trap_mouse(lmp->win);
lm_size_event(lmp, ep);
}
}
}
else
retval = 0;
}
/*
The following code implements the behavor where if the user clicks on a partially
visible column, then the list scrolls to the left.
*/
if (xi_is_itf( itf ))
{
if (! (lmp->attrib & XI_ATR_VISIBLE))
break;
if (lmp->pixel_width)
{
last_vis = lmp->last_vis;
if (last_vis >= lmp->fixed_columns && last_vis < lmp->nbr_columns - 1)
{
lm_get_rect(lm, LM_COLUMN, last_vis + 1, &rct);
rct.left += (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
rct.right = lmp->rct.left + lmp->pixel_width + BORDER_WIDTH;
if (xvt_rect_has_point(&rct, oevt.v.mouse.where))
{
if (xi_get_pref(XI_PREF_UNUSED_PREFERENCE))
{
lm_make_invis(lmp);
lm_local_hscroll(lm, 1);
lm_make_vis(lmp);
}
else
{
if (xi_move_focus(lmp->itf_obj))
{
lm_local_hscroll(lm, 1);
break;
}
}
}
}
}
}
break;
}
case E_MOUSE_UP:
if (lmp->selecting_cells)
{
LM_CB_DATA lm_cb_data;
lm_select_cell_event(lmp, ep);
xi_release_mouse();
lmp->selecting_cells = FALSE;
lmp->down_row = 0;
lmp->down_column = 0;
lm_cb_data.lm = lm;
lm_cb_data.cb_type = LM_CB_SELECT;
lm_cb_data.cid = lmp->cid;
lm_cb_data.win = lmp->win;
lm_cb_data.row = (unsigned char)255;
lm_cb_data.column = (unsigned char)255;
lm_cb_data.v.select.selected = TRUE;
lm_cb_data.v.select.dbl_click = FALSE;
lm_cb_data.v.select.shift = ep->v.mouse.shift;
lm_cb_data.v.select.control = ep->v.mouse.control;
(*lmp->lm_cb)(&lm_cb_data);
}
if (lmp->sizing_column)
{
lm_size_event(lmp, ep);
xi_release_mouse();
lmp->sizing_column = FALSE;
lmp->column_being_sized = 0;
break;
}
if (lmp->sizing_row)
{
lm_vsize_event(lmp, ep);
xi_release_mouse();
lmp->sizing_row = FALSE;
lmp->row_being_sized = 0;
break;
}
if (lmp->moving_column)
{
lm_move_event(lmp, ep);
xi_release_mouse();
lmp->moving_column = FALSE;
lmp->column_being_moved = 0;
break;
}
if (lmp->down_in_btn)
{
lm_cell_btn_event(lmp, ep, &oevt);
xi_release_mouse();
lmp->down_in_btn = FALSE;
lmp->btn_down = FALSE;
break;
}
if (lm_list_has_focus(lmp))
{
send_txt_event(lm, lmp->txt, &oevt, FALSE, TRUE);
lmp->selecting_text = FALSE;
xi_release_mouse();
lmp->have_mouse = FALSE;
break;
}
break;
case E_MOUSE_MOVE:
{
BOOLEAN is_vis, is_hit, is_part_vis;
if (! (lmp->attrib & XI_ATR_VISIBLE))
{
retval = FALSE;
break;
}
if (lmp->selecting_cells)
{
lm_select_cell_event(lmp, ep);
break;
}
if (lmp->sizing_column)
{
lm_size_event(lmp, ep);
break;
}
if (lmp->sizing_row)
{
lm_vsize_event(lmp, ep);
break;
}
if (lmp->moving_column)
{
lm_move_event(lmp, ep);
break;
}
if (lmp->down_in_btn)
{
lm_cell_btn_event(lmp, ep, &oevt);
break;
}
if (lm_list_has_focus(lmp))
send_txt_event(lm, lmp->txt, &oevt, FALSE, TRUE);
retval = lm_hit_test(lm, ep, &oevt, &row, &column, &is_vis, &is_hit, &is_part_vis);
if (is_part_vis)
{
unsigned long attrib;
attrib = lmp->lm_column_data[column]->attrib;
if (attrib & XI_ATR_SELECTABLE)
return 0;
if (! retval)
retval = 1;
return retval;
}
if (is_hit)
{
if (LIST_IS_ENABLED(lm) &&
lm_vsize_hit_test(lmp, ep, &row, &column))
{
*ep = oevt;
return 6;
}
}
if (LIST_IS_ENABLED(lm) &&
lmp->select_cells &&
lm_select_cells_hit_test(lmp, ep, NULL, NULL, NULL))
{
*ep = oevt;
return 4;
}
if (LIST_IS_ENABLED(lm) &&
lmp->sizable_columns &&
lm_size_hit_test(lm, ep, &column))
{
*ep = oevt;
return 2;
}
if (retval)
{
if (! is_vis)
{
*ep = oevt;
return 5;
}
if (CELL_IS_SELECTABLE(lm, row, column))
retval = 5;
if (row == -1)
retval = 5;
if (row >= 0 && lmp->cell_data[row][column].icon_rid)
retval = 5;
if (LIST_IS_ENABLED(lm) &&
lmp->movable_columns &&
lm_hit_test(lm, ep, &oevt, &row, &column, NULL, NULL, NULL))
if (row == -1)
retval = 3;
}
break;
}
case E_CHAR:
if (xi_get_pref(XI_PREF_UNUSED_PREFERENCE))
{
if (lmp->focus_rec)
{
LM_SCROLL_ARG lm_scroll_arg;
int row;
BOOLEAN found = FALSE;
for (row = 0; row < lmp->nbr_realized_rows; ++row)
{
if (lmp->focus_rec == lmp->recs[row])
{
found = TRUE;
break;
}
}
if (! found)
{
MEMCLEAR(lm_scroll_arg);
lm_scroll_arg.lm = lm;
/*
lm_scroll_arg.nbr_lines = 0;
lm_scroll_arg.percent = 0;
lm_scroll_arg.same_cell = 0;
*/
lm_scroll_arg.rec = lmp->focus_rec;
lm_scroll_arg.have_rec = TRUE;
lm_scroll_arg.color = lmp->focus_rec_color;
lm_scroll_arg.attrib = lmp->focus_rec_attrib;
lm_scroll_arg.row_height = lmp->focus_rec_height;
lm_scroll_arg.rec_at_top = lmp->focus_rec_is_above;
lm_scroll(&lm_scroll_arg);
lmp->focus_rec = 0L;
xvt_dwin_update(lmp->win);
}
}
if (lmp->txt_is_invisible)
{
int focus_row, focus_column;
BOOLEAN v_scrolled;
lm_get_focus_cell(lmp, &focus_row, &focus_column, &v_scrolled);
if (focus_column >= lmp->fixed_columns)
{
if (focus_column < lmp->first_vis)
{
lm_local_hscroll((LM)lmp, focus_column - lmp->first_vis);
}
else if (focus_column > lmp->last_vis)
{
int first_col, c;
c = focus_column;
c++;
c = min(c, lmp->nbr_columns);
first_col = lm_get_left_most_far_right_col(lmp, c);
lm_local_hscroll((LM)lmp, first_col - lmp->first_vis);
}
}
}
}
{
long button_key;
BOOLEAN shift, control;
int focus_row, focus_column;
BOOLEAN h_scrolled;
button_key = xi_get_pref(XI_PREF_BUTTON_KEY);
shift = (BOOLEAN)((button_key & XI_MOD_SHIFT) != 0);
control = (BOOLEAN)((button_key & XI_MOD_CONTROL) != 0);
button_key &= 0xffffffL;
if ( button_key == ep->v.chr.ch &&
shift == ep->v.chr.shift &&
control == ep->v.chr.control )
{
lm_get_focus_cell(lmp, &focus_row, &focus_column, &h_scrolled );
do_lm_cb((LM)lmp, LM_CB_CELL_BTN, focus_row, focus_column, ep, NULL, 0);
return FALSE;
}
}
if ( lmp->single_select )
{
switch ( ep->v.chr.ch )
{
case K_UP:
{
int cur_row = find_selection( lmp );
if ( cur_row == -1 )
cur_row = 0;
else
{
if ( cur_row == 0 )
xi_scroll( lmp->list_obj, -1 );
else
cur_row--;
}
select_row( lm, cur_row, -1, FALSE );
break;
}
case K_DOWN:
{
int cur_row = find_selection( lmp );
if ( cur_row == -1 )
cur_row = 0;
else
{
if ( cur_row == lmp->last_fully_vis )
xi_scroll( lmp->list_obj, 1 );
else
cur_row++;
}
select_row( lm, cur_row, -1, FALSE );
break;
}
case K_PREV:
xi_scroll( lmp->list_obj, XI_SCROLL_PGUP );
select_row( lm, lmp->last_fully_vis, -1, FALSE );
break;
case K_NEXT:
xi_scroll( lmp->list_obj, XI_SCROLL_PGDOWN );
select_row( lm, 0, -1, FALSE );
break;
case K_HOME:
case K_LHOME:
xi_scroll( lmp->list_obj, XI_SCROLL_FIRST );
select_row( lm, 0, -1, FALSE );
break;
case K_END:
case K_LEND:
xi_scroll( lmp->list_obj, XI_SCROLL_LAST );
select_row( lm, lmp->last_fully_vis, -1, FALSE );
break;
case '\r':
case ' ':
row = find_selection( lmp );
select_row( lm, row, -1, TRUE );
#if 0
if ( row != -1 )
{
LM_CB_DATA lm_cb_data;
lm_cb_data.lm = lm;
lm_cb_data.cb_type = LM_CB_SELECT;
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)get_select_column( lmp );
lm_cb_data.v.select.selected = TRUE;
lm_cb_data.v.select.dbl_click = TRUE;
lm_cb_data.v.select.shift = FALSE;
lm_cb_data.v.select.control = FALSE;
(*lmp->lm_cb)(&lm_cb_data);
}
#endif
break;
default:
return FALSE;
}
return TRUE;
}
if ( !lmp->sizing_row )
{
BOOLEAN nav_ret = FALSE;
if (! lmp->itf_obj->v.itf->pasting)
nav_ret = (BOOLEAN)navigate_char_event(lm, ep);
retval = send_txt_event(lm, lmp->txt, ep, FALSE, (BOOLEAN)(!nav_ret));
}
break;
case E_KILL_WINDOW:
/* xi_tree_free((char *)lm); */ /* unneeded */
retval = 0;
break;
case E_TIMER:
case E_COMMAND:
if (lmp->txt)
retval = send_txt_event(lm, lmp->txt, ep, FALSE, TRUE);
break;
}
*ep = oevt;
return(retval);
}
/*-------------------------------------------------------------------------
function: lm_set_font
lm: current lm
part: must be LM_COLUMN, or LM_CELL
idx: column number
idx2: if LM_CELL, row number
font: font to set
-------------------------------------------------------------------------*/
void
lm_set_font(LM lm, LM_PART part, int idx, int idx2, FONT_OBJ *font)
{
LM_DATA *lmp = LMP(lm);
LM_CELL_DATA *cell_data;
switch (part)
{
case LM_COLUMN:
{
LM_COLUMN_DATA *lmcd;
RCT rct;
lmcd = lmp->lm_column_data[idx];
if (font)
{
if (! lmcd->font)
lmcd->font = (FONT_OBJ *)xi_tree_malloc(
sizeof(FONT_OBJ), lmp);
*lmcd->font = xi_create_copy_font_id(lmp->itf_obj, *font, 0);
}
lm_get_rect(lm, LM_COLUMN, idx, &rct);
lm_invalidate_rect(lmp, &rct, TRUE);
break;
}
case LM_CELL:
{
cell_data = &lmp->cell_data[idx][idx2];
if (font)
{
XVT_FNTID old_font_id;
if (! cell_data->font)
cell_data->font = (FONT_OBJ *)xi_tree_malloc(
sizeof(FONT_OBJ), lmp);
old_font_id = *cell_data->font;
*cell_data->font = xi_create_copy_font_id(lmp->itf_obj,
*font, old_font_id);
}
break;
}
}
}
/*********************************************************************/
/* LM drawing functions */
#if 0
/*-------------------------------------------------------------------------
function: lm_set_clip
lmp: current lmp
rctp: clipping rectangle
-------------------------------------------------------------------------*/
static void
lm_set_clip(LM_DATA *lmp, RCT *rctp)
{
RCT r;
r = *rctp;
r.left += lmp->rct.left;
r.right += lmp->rct.left;
lm_adj_h(lmp, &r.left);
lm_adj_h(lmp, &r.right);
xi_set_clip(lmp->win, &r);
}
#endif
/*-------------------------------------------------------------------------
function: lm_draw_text
lmp: current lmp
h: h position
v: v position
s: string
len: length of string
-------------------------------------------------------------------------*/
#if XI_IS_CH
static void
lm_draw_text(LM_DATA *lmp, int h, int v, char *s, int len)
{
short sh;
sh = h;
sh += lmp->rct.left;
if (lm_adj_h(lmp, &sh))
{
lm_adj_v(lmp, v);
xi_draw_text(lmp->win, sh, v, s, len);
}
}
#endif
static void
add_seg(void *parent, LM_CELL_DATA *cell_data, int seg_starting_pos)
{
++cell_data->nbr_lines;
if (cell_data->line_breaks)
cell_data->line_breaks = (int*)xi_tree_realloc(cell_data->line_breaks,
sizeof(int) * cell_data->nbr_lines);
else
cell_data->line_breaks = (int*)xi_tree_malloc(
sizeof(int) * cell_data->nbr_lines, parent);
cell_data->line_breaks[cell_data->nbr_lines - 1] = seg_starting_pos;
}
#define is_word_char(ch) (ch != ' ' && ch != '\n')
/*-------------------------------------------------------------------------
lmp: current lmp
row:
col:
-------------------------------------------------------------------------*/
void
lm_wrap_text(LM_DATA *lmp, int row, int col, BOOLEAN set_font)
{
LM_CELL_DATA *cell_data;
LM_COLUMN_DATA *column_data;
int len, pix_width;
char *cell_text;
FONT_OBJ *font;
int leading, ascent, descent, char_width;
int cur_seg, cur_seg_starting_pos, avg_line_len, seg_len;
cell_data = &lmp->cell_data[row][col];
column_data = lmp->lm_column_data[col];
cell_text = lmp->buffer[row] + lmp->lm_column_data[col]->text_offset;
pix_width = column_data->pix_width - lm_get_col_spacing();
if (cell_data->button)
{
pix_width -= lmp->pix_row_spacing;
}
if (cell_data->string)
if (cell_data->pix_width == pix_width &&
strcmp(cell_data->string, cell_text) == 0)
return;
if (cell_data->font)
font = cell_data->font;
else
font = lmp->font;
if (set_font)
xi_set_xvt_font(lmp->win, font, FALSE);
len = strlen(cell_text) + 1;
if (cell_data->string)
cell_data->string = (char*)xi_tree_realloc(cell_data->string, len);
else
cell_data->string = (char*)xi_tree_malloc(len, lmp);
cell_data->pix_width = pix_width;
strcpy(cell_data->string, cell_text);
if (cell_data->line_breaks)
{
xi_tree_free(cell_data->line_breaks);
cell_data->line_breaks = NULL;
}
cell_data->nbr_lines = 0;
xi_get_font_metrics_font(font, &leading, &ascent, &descent, &char_width);
cell_data->font_height = ascent + descent + leading;
avg_line_len = pix_width / char_width;
cur_seg_starting_pos = 0;
cur_seg = 0;
/* find all segments in cell_text */
while (TRUE)
{
int this_seg_len, possible_word_break, cur_seg_len, word_break, cnt;
BOOLEAN continue_loop;
cur_seg_len = strlen(&cell_text[cur_seg_starting_pos]);
/* if there is a new line in the text, will the line fit in the wrap space */
while (TRUE)
{
continue_loop = FALSE;
for (cnt = 0; cnt < cur_seg_len; ++cnt)
{
if (cell_text[cur_seg_starting_pos + cnt] == '\n')
{
seg_len = xi_xvt_get_text_width(lmp->win,
&cell_text[cur_seg_starting_pos], cnt);
if (seg_len <= pix_width)
{
add_seg(lmp, cell_data, cur_seg_starting_pos);
cur_seg_starting_pos += cnt + 1;
cur_seg_len = strlen(&cell_text[cur_seg_starting_pos]);
continue_loop = TRUE;
break;
}
else
{
continue_loop = FALSE;
break;
}
}
}
if (! continue_loop)
break;
}
this_seg_len = min(avg_line_len, cur_seg_len);
/* find character that is beyond pix_width */
while (TRUE)
{
seg_len = xi_xvt_get_text_width(lmp->win,
&cell_text[cur_seg_starting_pos], this_seg_len);
if (seg_len > pix_width)
break;
if (seg_len <= pix_width &&
cell_text[cur_seg_starting_pos + this_seg_len] == '\0')
{
/* this is the last segment of the text */
add_seg(lmp, cell_data, cur_seg_starting_pos);
return;
}
++this_seg_len;
}
/* add the first segment */
add_seg(lmp, cell_data, cur_seg_starting_pos);
/* find character that is just below pix_width */
while (TRUE)
{
--this_seg_len;
seg_len = xi_xvt_get_text_width(lmp->win,
&cell_text[cur_seg_starting_pos], this_seg_len);
if (seg_len <= pix_width)
break;
}
/* find possible word break */
possible_word_break = this_seg_len + 1;
while (possible_word_break > 0)
{
if (! is_word_char(
cell_text[cur_seg_starting_pos + possible_word_break]))
break;
--possible_word_break;
}
/* if there is no possible word break, then break at this_seg_len */
if (possible_word_break == 0)
word_break = this_seg_len;
else
word_break = possible_word_break;
/* move forward so that word break is on a word */
while (! is_word_char(cell_text[cur_seg_starting_pos + word_break]))
++word_break;
++cur_seg;
cur_seg_starting_pos += word_break;
}
}
/*
Make it so a row can have the focus.
Tab will move focus to a cell in the row, if there is a cell in the row
that can take focus.
If XI_ATR_SELECTABLE is set for any columns, space will select the
row.
Up arrow and down arrow work. If the focus is on a cell, the focus stays
on a cell. If the focus is on a row, the focus stays on a row.
Page up and down should work.
If the focus is on the last editable cell, and tab_wrap is set, then the
focus moves to the next row.
If the focus is on the last editable cell, and tab_wrap is not set, then
the focus move to the current row.
Have an option on a list by list basis, enter selects if a row has the
focus. Enter will act like a double click selection.
If the row focus option is set, put up the other hand cursor.
if spreadsheet is resized, then limit size change to max_lines in lmp
have option to have scroll bars on multi-line edit controls in list
possibly revisit how text is stored in cells - may want indefinite buffer
size for a column.
when entering text in a cell, continually evaluate the correct height of
the cell. The function to recalc number of rows and break points should
compare line by line, until there is a difference, then do detailed
comparison after the difference.
it should be possible to scroll the list backwards to gain more room above
if the cell is at the bottom of the list
if the cell is already the maximum possible height, then not necessary to
do any more comparisons
limit text edit to buffer size
make sure that the clipboard works
TODO in the future
------------------
disabled rows should use colors
need option for lm to keep n records - caching
make disabled rows really work
if height is 0, make the list height be the same as the window height
expose lm drawing functions
xi_set_icon for buttons
make an option so that when the user tabs to an edit control that already contains text, the
insertion point is set to the right of the text.
settable background color for text on a 3d radio button or check box, (tab buttons also)
make function xi_is_nav_char
make readonly cells
need colors for static text
want ability on XVT/CH to have single character fields. Eliminate the [ and ].
*/