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