/*
* Copyright(c) 1992 Bell Communications Research, Inc. (Bellcore)
* Copyright(c) 1995-99 Andrew Lister
* All rights reserved
* Permission to use, copy, modify and distribute this material for
* any purpose and without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies, and that the name of Bellcore not be used in advertising
* or publicity pertaining to this material without the specific,
* prior written permission of an authorized representative of
* Bellcore.
*
* BELLCORE MAKES NO REPRESENTATIONS AND EXTENDS NO WARRANTIES, EX-
* PRESS OR IMPLIED, WITH RESPECT TO THE SOFTWARE, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR ANY PARTICULAR PURPOSE, AND THE WARRANTY AGAINST IN-
* FRINGEMENT OF PATENTS OR OTHER INTELLECTUAL PROPERTY RIGHTS. THE
* SOFTWARE IS PROVIDED "AS IS", AND IN NO EVENT SHALL BELLCORE OR
* ANY OF ITS AFFILIATES BE LIABLE FOR ANY DAMAGES, INCLUDING ANY
* LOST PROFITS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES RELAT-
* ING TO THE SOFTWARE.
*
* $Id: Methods.c,v 1.1.2.1 2001-12-26 21:42:27 fnevgeny Exp $
*/
/*
* Methods.c created by Andrew Lister (7 August, 1995)
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <Xm/Xm.h>
#include <X11/Intrinsic.h>
#include <Xbae/MatrixP.h>
#include <Xbae/Methods.h>
#include <Xbae/Actions.h>
#include <Xbae/ScrollMgr.h>
#include <Xbae/Utils.h>
#include <Xbae/Shadow.h>
#include <Xbae/Draw.h>
#include <Xbae/Create.h>
#include <Xbae/ClipP.h>
#include <Xm/XmP.h>
#include <Xm/Text.h>
#include <Xm/TextP.h>
/* For memmove/bcopy */
#include <string.h>
#if !defined(HAVE_MEMMOVE) && !defined(XBAE_NEED_BCOPY)
#define XBAE_NEED_BCOPY
#endif
/* Earl R.
* Added another BCOPY macro for porting purposes. Porting to 15+ UNIX
* platforms. Renamed bcopy to BCOPY and typecast to fix compiler warnings
* on some platforms.
*/
#if !defined(XBAE_NEED_BCOPY) || defined(SVR4) || defined(VMS) || defined(__EMX__)
#define BCOPY(src, dest, n) memmove((void *)(dest), (void *)(src), (n))
#else
#define BCOPY(src, dest, n) bcopy((void *)(src), (void *)(dest), (n))
#endif
static void AddRowsToTable P((XbaeMatrixWidget, int, String *, String *,
Pixel *, Pixel *, int));
static void DeleteRowsFromTable P((XbaeMatrixWidget, int, int));
static void AddColumnsToTable P((XbaeMatrixWidget, int, String *, String *,
short *, int *, unsigned char *,
unsigned char *, Pixel *, Pixel *, int));
static void DeleteColumnsFromTable P((XbaeMatrixWidget, int, int));
static Boolean DoCommitEdit P((XbaeMatrixWidget, XEvent *));
/*
* Add rows to the internal cells data structure.
* If rows or labels is NULL, add empty rows.
*/
static void
AddRowsToTable(mw, position, rows, labels, colors, backgrounds, num_rows)
XbaeMatrixWidget mw;
int position;
String *rows;
String *labels;
Pixel *colors;
Pixel *backgrounds;
int num_rows;
{
int i, j;
/*
* Realloc a larger array of row pointers and a larger label arrays
*/
if (mw->matrix.cells || rows)
mw->matrix.cells = (String **) XtRealloc((char *) mw->matrix.cells,
(mw->matrix.rows + num_rows) *
sizeof(String *));
if (mw->matrix.row_labels || labels)
mw->matrix.row_labels =
(String *) XtRealloc((char *) mw->matrix.row_labels,
(mw->matrix.rows + num_rows) *
sizeof(String));
if (mw->matrix.row_button_labels)
mw->matrix.row_button_labels =
(Boolean *) XtRealloc((char *) mw->matrix.
row_button_labels,
(mw->matrix.rows + num_rows) *
sizeof(Boolean));
if (mw->matrix.colors || colors)
mw->matrix.colors = (Pixel **) XtRealloc((char *) mw->matrix.colors,
(mw->matrix.rows + num_rows) *
sizeof(Pixel *));
if (mw->matrix.cell_background || backgrounds)
mw->matrix.cell_background =
(Pixel **) XtRealloc((char *) mw->matrix.cell_background,
(mw->matrix.rows + num_rows) *
sizeof(Pixel *));
if (mw->matrix.cell_user_data)
mw->matrix.cell_user_data = (XtPointer **)
XtRealloc((char*) mw->matrix.cell_user_data,
(mw->matrix.rows + num_rows) *
sizeof(XtPointer *));
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
mw->matrix.cell_widgets = (Widget **)
XtRealloc((char*) mw->matrix.cell_widgets,
(mw->matrix.rows + num_rows) *
sizeof(Widget *));
#endif
if (mw->matrix.row_user_data)
mw->matrix.row_user_data = (XtPointer*)
XtRealloc((char*) mw->matrix.row_user_data,
(mw->matrix.rows + num_rows) *
sizeof(XtPointer));
if (mw->matrix.cell_shadow_types)
mw->matrix.cell_shadow_types = (unsigned char **)
XtRealloc((char*) mw->matrix.cell_shadow_types,
(mw->matrix.rows + num_rows) *
sizeof(unsigned char *));
if (mw->matrix.row_shadow_types)
mw->matrix.row_shadow_types = (unsigned char *)
XtRealloc((char*) mw->matrix.row_shadow_types,
(mw->matrix.rows + num_rows) *
sizeof(unsigned char));
if (mw->matrix.selected_cells)
mw->matrix.selected_cells =
(Boolean **) XtRealloc((char *) mw->matrix.selected_cells,
(mw->matrix.rows + num_rows) *
sizeof(Boolean *));
#if XmVersion >= 1002
if (mw->matrix.highlighted_cells)
mw->matrix.highlighted_cells =
(unsigned char **) XtRealloc((char *) mw->matrix.highlighted_cells,
(mw->matrix.rows + num_rows) *
sizeof(unsigned char *));
#endif
/*
* If we are inserting rows into the middle, we need to make room.
*/
if (position < mw->matrix.rows)
{
if (mw->matrix.cells)
BCOPY(&mw->matrix.cells[position],
&mw->matrix.cells[position + num_rows],
(mw->matrix.rows - position) * sizeof(String *));
if (mw->matrix.row_labels)
BCOPY(&mw->matrix.row_labels[position],
&mw->matrix.row_labels[position + num_rows],
(mw->matrix.rows - position) * sizeof(String));
if (mw->matrix.row_button_labels)
BCOPY(&mw->matrix.row_button_labels[position],
&mw->matrix.row_button_labels[position + num_rows],
(mw->matrix.rows - position) * sizeof(Boolean));
if (mw->matrix.colors)
BCOPY(&mw->matrix.colors[position],
&mw->matrix.colors[position + num_rows],
(mw->matrix.rows - position) * sizeof(Pixel *));
if (mw->matrix.cell_background)
BCOPY(&mw->matrix.cell_background[position],
&mw->matrix.cell_background[position + num_rows],
(mw->matrix.rows - position) * sizeof(Pixel *));
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
BCOPY(&mw->matrix.cell_widgets[position],
&mw->matrix.cell_widgets[position + num_rows],
(mw->matrix.rows - position) * sizeof(Widget *));
#endif
if (mw->matrix.cell_user_data)
BCOPY(&mw->matrix.cell_user_data[position],
&mw->matrix.cell_user_data[position + num_rows],
(mw->matrix.rows - position) * sizeof(XtPointer *));
if (mw->matrix.row_user_data)
BCOPY(&mw->matrix.row_user_data[position],
&mw->matrix.row_user_data[position + num_rows],
(mw->matrix.rows - position) * sizeof(XtPointer));
if (mw->matrix.cell_shadow_types)
BCOPY(&mw->matrix.cell_shadow_types[position],
&mw->matrix.cell_shadow_types[position + num_rows],
(mw->matrix.rows - position) * sizeof(unsigned char *));
if (mw->matrix.row_shadow_types)
BCOPY(&mw->matrix.row_shadow_types[position],
&mw->matrix.row_shadow_types[position + num_rows],
(mw->matrix.rows - position) * sizeof(unsigned char));
if (mw->matrix.selected_cells)
BCOPY(&mw->matrix.selected_cells[position],
&mw->matrix.selected_cells[position + num_rows],
(mw->matrix.rows - position) * sizeof(Boolean *));
#if XmVersion >= 1002
if (mw->matrix.highlighted_cells)
BCOPY(&mw->matrix.highlighted_cells[position],
&mw->matrix.highlighted_cells[position + num_rows],
(mw->matrix.rows - position) * sizeof(unsigned char *));
#endif
}
/*
* Malloc a new row array for each new row. Copy the label for each row.
* If no label was passed in, use a NULL String. Malloc a new Pixel
* and Boolean row array for each new row.
* Use False for new button label flags.
*/
for (i = 0; i < num_rows; i++)
{
if (mw->matrix.cells)
mw->matrix.cells[i + position] =
(String *) XtMalloc(mw->matrix.columns * sizeof(String));
if (mw->matrix.row_labels)
mw->matrix.row_labels[i + position] =
labels ? XtNewString(labels[i]) : XtNewString("");
if (mw->matrix.row_button_labels)
mw->matrix.row_button_labels[i + position] = False;
if (mw->matrix.colors)
mw->matrix.colors[i + position] =
(Pixel *) XtMalloc(mw->matrix.columns * sizeof(Pixel));
if (mw->matrix.cell_background)
mw->matrix.cell_background[i + position] =
(Pixel *) XtMalloc(mw->matrix.columns * sizeof(Pixel));
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
mw->matrix.cell_widgets[i + position] =
(Widget *) XtMalloc(mw->matrix.columns * sizeof(Widget));
#endif
if (mw->matrix.cell_user_data)
mw->matrix.cell_user_data[i + position] =
(XtPointer *) XtMalloc(mw->matrix.columns * sizeof(XtPointer));
if (mw->matrix.row_user_data)
mw->matrix.row_user_data[i + position] = (XtPointer) NULL;
if (mw->matrix.cell_shadow_types)
mw->matrix.cell_shadow_types[i + position] =
(unsigned char *) XtMalloc(mw->matrix.columns *
sizeof(unsigned char));
if (mw->matrix.row_shadow_types)
mw->matrix.row_shadow_types[i + position] =
mw->matrix.cell_shadow_type;
if (mw->matrix.selected_cells)
mw->matrix.selected_cells[i + position] =
(Boolean *) XtMalloc(mw->matrix.columns * sizeof(Boolean));
#if XmVersion >= 1002
if (mw->matrix.highlighted_cells)
mw->matrix.highlighted_cells[i + position] =
(unsigned char *) XtMalloc(mw->matrix.columns *
sizeof(unsigned char));
#endif
}
/*
* Copy the rows arrays passed in into each new row, or if NULL
* was passed in initialize each row to NULL Strings. Copy the colors
* arrays passed in into each new row, if NULL was passed use foreground.
*/
for (i = 0; i < num_rows; i++)
for (j = 0; j < mw->matrix.columns; j++)
{
if (mw->matrix.cells) /* NULL row[j] is empty string. Earl R. */
mw->matrix.cells[i + position][j] = rows ?
XtNewString((rows[i * mw->matrix.columns + j] ?
rows[i * mw->matrix.columns + j] : "")) :
XtNewString("");
if (mw->matrix.colors)
mw->matrix.colors[i + position][j] =
colors ? colors[i] : mw->manager.foreground;
if (mw->matrix.cell_background)
mw->matrix.cell_background[i + position][j] =
backgrounds ? backgrounds[i] : mw->core.background_pixel;
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
mw->matrix.cell_widgets[i + position][j] = NULL;
#endif
if (mw->matrix.cell_user_data)
mw->matrix.cell_user_data[i + position][j] = (XtPointer) NULL;
if (mw->matrix.cell_shadow_types)
mw->matrix.cell_shadow_types[i + position][j] =
mw->matrix.cell_shadow_type;
if (mw->matrix.selected_cells)
mw->matrix.selected_cells[i + position][j] = False;
#if XmVersion >= 1002
if (mw->matrix.highlighted_cells)
mw->matrix.highlighted_cells[i + position][j] = HighlightNone;
#endif
}
mw->matrix.rows += num_rows;
}
/*
* Delete rows from the internal cells data structure.
*/
static void
DeleteRowsFromTable(mw, position, num_rows)
XbaeMatrixWidget mw;
int position;
int num_rows;
{
int i, j;
/*
* We don't bother to realloc, we will just have some wasted space.
* XXX is this a problem?
*/
/*
* Free all the cells in the rows being deleted and the rows themselves.
* Also free the String row labels and label button flags. Free the color
* arrays for the rows being deleted.
*/
for (i = position; i < position + num_rows; i++)
{
/* Fixed a crash I was getting, Since I allow NULL cells. Earl R. */
if (mw->matrix.cells && mw->matrix.cells[i])
{
for (j = 0; j < mw->matrix.columns; j++)
if (mw->matrix.cells[i][j])
XtFree((XtPointer) mw->matrix.cells[i][j]);
XtFree((XtPointer) mw->matrix.cells[i]);
}
if (mw->matrix.row_labels)
XtFree((XtPointer) mw->matrix.row_labels[i]);
if (mw->matrix.colors)
XtFree((XtPointer) mw->matrix.colors[i]);
if (mw->matrix.cell_background)
XtFree((XtPointer) mw->matrix.cell_background[i]);
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
XtFree((XtPointer) mw->matrix.cell_widgets[i]);
#endif
if (mw->matrix.cell_user_data)
XtFree((XtPointer) mw->matrix.cell_user_data[i]);
if (mw->matrix.cell_shadow_types)
XtFree((XtPointer) mw->matrix.cell_shadow_types[i]);
if (mw->matrix.selected_cells)
{
/*
* Deselect the row so num_selected_cells gets updated
*/
xbaeDeselectRow(mw, i);
XtFree((XtPointer) mw->matrix.selected_cells[i]);
}
#if XmVersion >= 1002
if (mw->matrix.highlighted_cells)
XtFree((XtPointer) mw->matrix.highlighted_cells[i]);
#endif
}
/*
* Copy those rows which are below the ones deleted, up.
* (unless we deleted rows from the bottom).
*/
if (position + num_rows < mw->matrix.rows)
{
if (mw->matrix.cells)
BCOPY(&mw->matrix.cells[position + num_rows],
&mw->matrix.cells[position],
(mw->matrix.rows - position - num_rows) * sizeof(String *));
if (mw->matrix.row_labels)
BCOPY(&mw->matrix.row_labels[position + num_rows],
&mw->matrix.row_labels[position],
(mw->matrix.rows - position - num_rows) * sizeof(String));
if (mw->matrix.row_button_labels)
BCOPY(&mw->matrix.row_button_labels[position + num_rows],
&mw->matrix.row_button_labels[position],
(mw->matrix.rows - position - num_rows) * sizeof(Boolean));
if (mw->matrix.colors)
BCOPY(&mw->matrix.colors[position + num_rows],
&mw->matrix.colors[position],
(mw->matrix.rows - position - num_rows) * sizeof(Pixel *));
if (mw->matrix.cell_background)
BCOPY(&mw->matrix.cell_background[position + num_rows],
&mw->matrix.cell_background[position],
(mw->matrix.rows - position - num_rows) * sizeof(Pixel *));
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
BCOPY(&mw->matrix.cell_widgets[position + num_rows],
&mw->matrix.cell_widgets[position],
(mw->matrix.rows - position - num_rows) * sizeof(Widget *));
#endif
if (mw->matrix.cell_user_data)
BCOPY(&mw->matrix.cell_user_data[position + num_rows],
&mw->matrix.cell_user_data[position],
(mw->matrix.rows - position - num_rows) *
sizeof(XtPointer *));
if (mw->matrix.row_user_data)
BCOPY(&mw->matrix.row_user_data[position + num_rows],
&mw->matrix.row_user_data[position],
(mw->matrix.rows - position - num_rows) * sizeof(XtPointer *));
if (mw->matrix.cell_shadow_types)
BCOPY(&mw->matrix.cell_shadow_types[position + num_rows],
&mw->matrix.cell_shadow_types[position],
(mw->matrix.rows - position - num_rows) *
sizeof(unsigned char *));
if (mw->matrix.row_shadow_types)
BCOPY(&mw->matrix.row_shadow_types[position + num_rows],
&mw->matrix.row_shadow_types[position],
(mw->matrix.rows - position - num_rows) *
sizeof(unsigned char *));
if (mw->matrix.selected_cells)
BCOPY(&mw->matrix.selected_cells[position + num_rows],
&mw->matrix.selected_cells[position],
(mw->matrix.rows - position - num_rows) * sizeof(Boolean *));
#if XmVersion >= 1002
if (mw->matrix.highlighted_cells)
BCOPY(&mw->matrix.highlighted_cells[position + num_rows],
&mw->matrix.highlighted_cells[position],
(mw->matrix.rows - position - num_rows) *
sizeof(unsigned char *));
#endif
}
mw->matrix.rows -= num_rows;
}
/*
* Add columns to the internal cells data structure.
* If columns or labels is NULL, add empty columns.
* If max_lengths is NULL, widths will be used.
* If alignments is NULL, use XmALIGNMENT_BEGINNING.
* If label_alignments is NULL, use alignments, or if it is NULL
* XmALIGNMENT_BEGINNING.
* widths must not be NULL.
*/
static void
AddColumnsToTable(mw, position, columns, labels, widths, max_lengths,
alignments, label_alignments, colors, backgrounds,
num_columns)
XbaeMatrixWidget mw;
int position;
String *columns;
String *labels;
short *widths;
int *max_lengths;
unsigned char *alignments;
unsigned char *label_alignments;
Pixel *colors;
Pixel *backgrounds;
int num_columns;
{
int i, j;
/*
* Realloc larger cells, widths, max_lengths, alignments, colors,
* highlighted_cells, selected_cells, labels and label lines arrays.
*/
if (mw->matrix.rows == 0)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"AddColumns", "noRows", "XbaeMatrix",
"XbaeMatrix: Attempting to add columns with no rows.",
NULL, 0);
return;
}
for (i = 0; i < mw->matrix.rows; i++)
{
if (mw->matrix.cells || columns)
{
if (!mw->matrix.cells)
{
mw->matrix.columns += num_columns;
xbaeCopyCells(mw);
mw->matrix.columns -= num_columns;
}
else
mw->matrix.cells[i] =
(String *) XtRealloc((char *) mw->matrix.cells[i],
(mw->matrix.columns + num_columns) *
sizeof(String));
}
if (mw->matrix.colors || colors)
{
if (!mw->matrix.colors)
{
mw->matrix.columns += num_columns;
xbaeCopyColors(mw);
mw->matrix.columns -= num_columns;
}
else
mw->matrix.colors[i] =
(Pixel *) XtRealloc((char *) mw->matrix.colors[i],
(mw->matrix.columns + num_columns) *
sizeof(Pixel));
}
if (mw->matrix.cell_background || backgrounds)
{
if (!mw->matrix.cell_background)
{
mw->matrix.columns += num_columns;
xbaeCopyBackgrounds(mw);
mw->matrix.columns -= num_columns;
}
else
mw->matrix.cell_background[i] =
(Pixel *) XtRealloc((char *) mw->matrix.cell_background[i],
(mw->matrix.columns + num_columns) *
sizeof(Pixel));
}
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
mw->matrix.cell_widgets[i] =
(Widget *) XtRealloc((char *) mw->matrix.cell_widgets[i],
(mw->matrix.columns + num_columns) *
sizeof(Widget));
#endif
if (mw->matrix.cell_user_data)
mw->matrix.cell_user_data[i] = (XtPointer *)
XtRealloc((char*) mw->matrix.cell_user_data[i],
(mw->matrix.columns + num_columns) *
sizeof(XtPointer));
if (mw->matrix.cell_shadow_types)
mw->matrix.cell_shadow_types[i] = (unsigned char *)
XtRealloc((char*) mw->matrix.cell_shadow_types[i],
(mw->matrix.columns + num_columns) *
sizeof(unsigned char));
if (mw->matrix.selected_cells)
mw->matrix.selected_cells[i] =
(Boolean *) XtRealloc((char *) mw->matrix.selected_cells[i],
(mw->matrix.columns + num_columns) *
sizeof(Boolean));
#if XmVersion >= 1002
if (mw->matrix.highlighted_cells)
mw->matrix.highlighted_cells[i] =
(unsigned char *) XtRealloc(
(char *) mw->matrix.highlighted_cells[i],
(mw->matrix.columns + num_columns) *
sizeof(unsigned char));
#endif
}
mw->matrix.column_widths =
(short *) XtRealloc((char *) mw->matrix.column_widths,
(mw->matrix.columns + num_columns) *
sizeof(short));
if (mw->matrix.column_max_lengths)
mw->matrix.column_max_lengths =
(int *) XtRealloc((char *) mw->matrix.column_max_lengths,
(mw->matrix.columns + num_columns) *
sizeof(int));
if (mw->matrix.column_alignments)
mw->matrix.column_alignments =
(unsigned char *)
XtRealloc((char *) mw->matrix.column_alignments,
(mw->matrix.columns + num_columns) *
sizeof(unsigned char));
if (mw->matrix.column_button_labels)
mw->matrix.column_button_labels =
(Boolean *) XtRealloc((char *) mw->matrix.
column_button_labels,
(mw->matrix.columns + num_columns) *
sizeof(Boolean));
if (mw->matrix.column_label_alignments)
mw->matrix.column_label_alignments =
(unsigned char *) XtRealloc((char *) mw->matrix.
column_label_alignments,
(mw->matrix.columns + num_columns) *
sizeof(unsigned char));
if (mw->matrix.column_user_data)
mw->matrix.column_user_data = (XtPointer*)
XtRealloc((char*) mw->matrix.column_user_data,
(mw->matrix.columns + num_columns) *
sizeof(XtPointer));
if (mw->matrix.column_shadow_types)
mw->matrix.column_shadow_types = (unsigned char *)
XtRealloc((char*) mw->matrix.column_shadow_types,
(mw->matrix.columns + num_columns) *
sizeof(unsigned char));
if (mw->matrix.column_labels)
{
mw->matrix.column_labels =
(String *) XtRealloc((char *) mw->matrix.column_labels,
(mw->matrix.columns + num_columns) *
sizeof(String));
mw->matrix.column_label_lines =
(ColumnLabelLines) XtRealloc(
(char *) mw->matrix.column_label_lines, (mw->matrix.columns +
num_columns) *
sizeof(ColumnLabelLinesRec));
}
/*
* If we are inserting columns into the middle, we need to make room.
*/
if (position < mw->matrix.columns)
{
BCOPY(&mw->matrix.column_widths[position],
&mw->matrix.column_widths[position + num_columns],
(mw->matrix.columns - position) * sizeof(short));
if (mw->matrix.column_max_lengths)
BCOPY(&mw->matrix.column_max_lengths[position],
&mw->matrix.column_max_lengths[position + num_columns],
(mw->matrix.columns - position) * sizeof(int));
if (mw->matrix.column_alignments)
BCOPY(&mw->matrix.column_alignments[position],
&mw->matrix.column_alignments[position + num_columns],
(mw->matrix.columns - position) * sizeof(unsigned char));
if (mw->matrix.column_button_labels)
BCOPY(&mw->matrix.column_button_labels[position],
&mw->matrix.column_button_labels[position + num_columns],
(mw->matrix.columns - position) * sizeof(Boolean));
if (mw->matrix.column_label_alignments)
BCOPY(&mw->matrix.column_label_alignments[position],
&mw->matrix.column_label_alignments[position + num_columns],
(mw->matrix.columns - position) * sizeof(unsigned char));
if (mw->matrix.column_user_data)
BCOPY(&mw->matrix.column_user_data[position],
&mw->matrix.column_user_data[position + num_columns],
(mw->matrix.columns - position) * sizeof(XtPointer));
if (mw->matrix.column_shadow_types)
BCOPY(&mw->matrix.column_shadow_types[position],
&mw->matrix.column_shadow_types[position + num_columns],
(mw->matrix.columns - position) * sizeof(unsigned char));
if (mw->matrix.column_labels)
{
BCOPY(&mw->matrix.column_labels[position],
&mw->matrix.column_labels[position + num_columns],
(mw->matrix.columns - position) * sizeof(String));
BCOPY(&mw->matrix.column_label_lines[position],
&mw->matrix.column_label_lines[position + num_columns],
(mw->matrix.columns - position) *
sizeof(ColumnLabelLinesRec));
}
/*
* Shift the columns in each row.
*/
for (i = 0; i < mw->matrix.rows; i++)
{
if (mw->matrix.cells)
BCOPY(&mw->matrix.cells[i][position],
&mw->matrix.cells[i][position + num_columns],
(mw->matrix.columns - position) * sizeof(String));
if (mw->matrix.colors)
BCOPY(&mw->matrix.colors[i][position],
&mw->matrix.colors[i][position + num_columns],
(mw->matrix.columns - position) * sizeof(Pixel));
if (mw->matrix.cell_background)
BCOPY(&mw->matrix.cell_background[i][position],
&mw->matrix.cell_background[i][position + num_columns],
(mw->matrix.columns - position) * sizeof(Pixel));
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
BCOPY(&mw->matrix.cell_widgets[i][position],
&mw->matrix.cell_widgets[i][position + num_columns],
(mw->matrix.columns - position) * sizeof(Widget));
#endif
if (mw->matrix.cell_user_data)
BCOPY(&mw->matrix.cell_user_data[i][position],
&mw->matrix.cell_user_data[i][position + num_columns],
(mw->matrix.columns - position) * sizeof(XtPointer));
if (mw->matrix.cell_shadow_types)
BCOPY(&mw->matrix.cell_shadow_types[i][position],
&mw->matrix.cell_shadow_types[i][position + num_columns],
(mw->matrix.columns - position) * sizeof(unsigned char));
if (mw->matrix.selected_cells)
BCOPY(&mw->matrix.selected_cells[i][position],
&mw->matrix.selected_cells[i][position + num_columns],
(mw->matrix.columns - position) * sizeof(Boolean));
#if XmVersion >= 1002
if (mw->matrix.highlighted_cells)
BCOPY(&mw->matrix.highlighted_cells[i][position],
&mw->matrix.highlighted_cells[i][position + num_columns],
(mw->matrix.columns - position) * sizeof(unsigned char));
#endif
}
}
/*
* Copy all of the passed in info into each new column
* (except column_positions which will be recalculated below).
* If columns or labels is NULL, add empty columns.
* If max_lengths is NULL, widths will be used.
* If alignments is NULL, use XmALIGNMENT_BEGINNING.
* If label_alignments is NULL, use XmALIGNMENT_BEGINNING
* If labels is NULL, use NULL strings.
* If colors is NULL, use foreground.
* Use False for new button label flags.
*/
for (j = 0; j < num_columns; j++)
{
mw->matrix.column_widths[j + position] = widths[j];
if (mw->matrix.column_max_lengths)
mw->matrix.column_max_lengths[j + position] =
max_lengths ? max_lengths[j] : (int) widths[j];
if (mw->matrix.column_alignments)
mw->matrix.column_alignments[j + position] =
alignments ? alignments[j] : XmALIGNMENT_BEGINNING;
if (mw->matrix.column_button_labels)
mw->matrix.column_button_labels[j + position] = False;
if (mw->matrix.column_label_alignments)
mw->matrix.column_label_alignments[j + position] =
label_alignments ? label_alignments[j] : XmALIGNMENT_BEGINNING;
if (mw->matrix.column_user_data)
mw->matrix.column_user_data[j + position] = (XtPointer) NULL;
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
mw->matrix.cell_widgets[j + position] = NULL;
#endif
if (mw->matrix.column_shadow_types)
mw->matrix.column_shadow_types[j + position] =
mw->matrix.cell_shadow_type;
if (mw->matrix.column_labels)
{
mw->matrix.column_labels[j + position] =
labels ? XtNewString(labels[j]) : XtNewString("");
xbaeParseColumnLabel(mw->matrix.column_labels[j + position],
&mw->matrix.column_label_lines[j + position]);
}
/*
* Add this new column to each row.
*/
for (i = 0; i < mw->matrix.rows; i++)
{
if (mw->matrix.cells)
mw->matrix.cells[i][j + position] = columns ?
XtNewString(columns[i * num_columns + j]) :
XtNewString("");
if (mw->matrix.colors)
mw->matrix.colors[i][j + position] =
colors ? colors[j] : mw->manager.foreground;
if (mw->matrix.cell_background)
mw->matrix.cell_background[i][j + position] =
backgrounds ? backgrounds[j] : mw->core.background_pixel;
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
mw->matrix.cell_widgets[i][j + position] = (Widget) NULL;
#endif
if (mw->matrix.cell_user_data)
mw->matrix.cell_user_data[i][j + position] = (XtPointer) NULL;
if (mw->matrix.cell_shadow_types)
mw->matrix.cell_shadow_types[i][j + position] =
mw->matrix.cell_shadow_type;
if (mw->matrix.selected_cells)
mw->matrix.selected_cells[i][j + position] = False;
#if XmVersion >= 1002
if (mw->matrix.highlighted_cells)
mw->matrix.highlighted_cells[i][j + position] = HighlightNone;
#endif
}
}
mw->matrix.columns += num_columns;
xbaeGetCellTotalWidth(mw);
/*
* See if the max number of column label lines changed
*/
if (mw->matrix.column_labels)
{
int end;
end = position + num_columns;
for (i = position; i < end; i++)
if (mw->matrix.column_label_lines[i].lines >
mw->matrix.column_label_maxlines)
mw->matrix.column_label_maxlines =
mw->matrix.column_label_lines[i].lines;
}
/*
* Recalculate the column positions
*/
xbaeFreeColumnPositions(mw);
mw->matrix.column_positions = CreateColumnPositions(mw);
xbaeGetColumnPositions(mw);
}
/*
* Delete columns from the internal cells data structure.
*/
static void
DeleteColumnsFromTable(mw, position, num_columns)
XbaeMatrixWidget mw;
int position;
int num_columns;
{
int i, j;
/*
* Free all the cells in the columns being deleted.
* Also free the String column labels and the associated ColumnLabelLines
* lengths arrays, and the column button label flags.
*/
for (j = position; j < position + num_columns; j++)
{
if (mw->matrix.cells)
for (i = 0; i < mw->matrix.rows; i++)
XtFree((XtPointer) mw->matrix.cells[i][j]);
if (mw->matrix.column_labels)
{
XtFree((XtPointer) mw->matrix.column_labels[j]);
XtFree((XtPointer) mw->matrix.column_label_lines[j].lengths);
}
}
/*
* Shift those columns after the ones being deleted, left.
* (unless we deleted columns from the right).
*/
if (position + num_columns < mw->matrix.columns)
{
BCOPY(&mw->matrix.column_widths[position + num_columns],
&mw->matrix.column_widths[position],
(mw->matrix.columns - position - num_columns) * sizeof(short));
if (mw->matrix.column_max_lengths)
BCOPY(&mw->matrix.column_max_lengths[position + num_columns],
&mw->matrix.column_max_lengths[position],
(mw->matrix.columns - position - num_columns) * sizeof(int));
if (mw->matrix.column_alignments)
BCOPY(&mw->matrix.column_alignments[position + num_columns],
&mw->matrix.column_alignments[position],
(mw->matrix.columns - position - num_columns) *
sizeof(unsigned char));
if (mw->matrix.column_button_labels)
BCOPY(&mw->matrix.column_button_labels[position + num_columns],
&mw->matrix.column_button_labels[position],
(mw->matrix.columns - position - num_columns) *
sizeof(Boolean));
if (mw->matrix.column_label_alignments)
BCOPY(&mw->matrix.column_label_alignments[position + num_columns],
&mw->matrix.column_label_alignments[position],
(mw->matrix.columns - position - num_columns) *
sizeof(unsigned char));
if (mw->matrix.column_user_data)
BCOPY(&mw->matrix.column_user_data[position + num_columns],
&mw->matrix.column_user_data[position],
(mw->matrix.columns - position - num_columns) *
sizeof(XtPointer));
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
BCOPY(&mw->matrix.cell_widgets[position + num_columns],
&mw->matrix.cell_widgets[position],
(mw->matrix.columns - position - num_columns) *
sizeof(Widget));
#endif
if (mw->matrix.column_shadow_types)
BCOPY(&mw->matrix.column_shadow_types[position + num_columns],
&mw->matrix.column_shadow_types[position],
(mw->matrix.columns - position - num_columns) *
sizeof(unsigned char));
if (mw->matrix.column_labels)
{
BCOPY(&mw->matrix.column_labels[position + num_columns],
&mw->matrix.column_labels[position],
(mw->matrix.columns - position - num_columns) *
sizeof(String));
BCOPY(&mw->matrix.column_label_lines[position + num_columns],
&mw->matrix.column_label_lines[position],
(mw->matrix.columns - position - num_columns) *
sizeof(ColumnLabelLinesRec));
}
/*
* Shift the columns in each row.
*/
for (i = 0; i < mw->matrix.rows; i++)
{
if (mw->matrix.cells)
BCOPY(&mw->matrix.cells[i][position + num_columns],
&mw->matrix.cells[i][position],
(mw->matrix.columns - position - num_columns) *
sizeof(String));
if (mw->matrix.colors)
BCOPY(&mw->matrix.colors[i][position + num_columns],
&mw->matrix.colors[i][position],
(mw->matrix.columns - position - num_columns) *
sizeof(Pixel));
if (mw->matrix.cell_background)
BCOPY(&mw->matrix.cell_background[i][position + num_columns],
&mw->matrix.cell_background[i][position],
(mw->matrix.columns - position - num_columns) *
sizeof(Pixel));
#if CELL_WIDGETS
if (mw->matrix.cell_widgets)
BCOPY(&mw->matrix.cell_widgets[i][position + num_columns],
&mw->matrix.cell_widgets[i][position],
(mw->matrix.columns - position - num_columns) *
sizeof(Widget));
#endif
if (mw->matrix.cell_user_data)
BCOPY(&mw->matrix.cell_user_data[i][position + num_columns],
&mw->matrix.cell_user_data[i][position],
(mw->matrix.columns - position - num_columns) *
sizeof(XtPointer));
if (mw->matrix.cell_shadow_types)
BCOPY(&mw->matrix.cell_shadow_types[i][position + num_columns],
&mw->matrix.cell_shadow_types[i][position],
(mw->matrix.columns - position - num_columns) *
sizeof(unsigned char));
if (mw->matrix.selected_cells)
BCOPY(&mw->matrix.selected_cells[i][position + num_columns],
&mw->matrix.selected_cells[i][position],
(mw->matrix.columns - position - num_columns) *
sizeof(Boolean));
#if XmVersion >= 1002
if (mw->matrix.highlighted_cells)
BCOPY(&mw->matrix.highlighted_cells[i][position + num_columns],
&mw->matrix.highlighted_cells[i][position],
(mw->matrix.columns - position - num_columns) *
sizeof(unsigned char));
#endif
}
}
mw->matrix.columns -= num_columns;
xbaeGetCellTotalWidth(mw);
/*
* See if the max number of column label lines changed
*/
if (mw->matrix.column_labels)
{
mw->matrix.column_label_maxlines =
mw->matrix.column_label_lines[0].lines;
for (i = 1; i < mw->matrix.columns; i++)
if (mw->matrix.column_label_lines[i].lines >
mw->matrix.column_label_maxlines)
mw->matrix.column_label_maxlines =
mw->matrix.column_label_lines[i].lines;
}
/*
* Recalculate the column positions
*/
xbaeFreeColumnPositions(mw);
mw->matrix.column_positions = CreateColumnPositions(mw);
xbaeGetColumnPositions(mw);
}
/*
* Matrix set_cell method
*/
void
#if NeedFunctionPrototypes
xbaeSetCell(XbaeMatrixWidget mw, int row, int column, const String value,
Boolean update_text)
#else
xbaeSetCell(mw, row, column, value, update_text)
XbaeMatrixWidget mw;
int row;
int column;
const String value;
Boolean update_text;
#endif
{
if (row >= mw->matrix.rows || row < 0 ||
column >= mw->matrix.columns || column < 0)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"xbaeSetCell", "badIndex", "XbaeMatrix",
"XbaeMatrix: Row or column out of bounds for xbaeSetCell.",
NULL, 0);
return;
}
/*
* If we have a draw cell callback, we must have a write cell callback
* also if we want to set the data. Use this callback to write the
* new data back to the application.
*/
if (mw->matrix.draw_cell_callback)
{
XbaeMatrixWriteCellCallbackStruct call_data;
if (mw->matrix.write_cell_callback)
{
call_data.reason = XbaeWriteCellReason;
call_data.event = (XEvent *)NULL;
call_data.row = row;
call_data.column = column;
call_data.string = value;
call_data.type = XbaeString;
call_data.pixmap = (Pixmap)NULL;
call_data.mask = (Pixmap)NULL;
XtCallCallbackList((Widget)mw, mw->matrix.write_cell_callback,
(XtPointer) &call_data);
}
}
else
{
/*
* Store the new value in the cell.
*/
if (!mw->matrix.cells && value[0] != 0)
/*
* The user typed something, there is no drawCellCallback and
* our cells have not been allocated :-(
* The typed value must be stored, so allocate the cells array
* now.
*/
xbaeCopyCells(mw);
/*
* Now we are free to store the value in the widget's cell array
*/
if (mw->matrix.cells && /* It's OK to store the value */
strcmp(mw->matrix.cells[row][column], value))
{
/*
* I'm not particularly keen on this code - ie. checking twice
* for mw->matrix.cells but it seemed like the only way around
* the problem AL (Nov 5, 1995).
*/
XtFree((XtPointer) mw->matrix.cells[row][column]);
mw->matrix.cells[row][column] = XtNewString(value);
}
else
return;
}
/*
* Draw the cell.
*/
if (xbaeIsCellVisible(mw, row, column))
{
xbaeClearCell(mw, row, column);
xbaeDrawCell(mw, row, column);
}
/*
* If we are editing this cell, load the textField too if update_text set.
*/
if (update_text && XtIsManaged(TextChild(mw)) &&
mw->matrix.current_row == row && mw->matrix.current_column == column)
{
String string;
/* Remove the modify verify callback when the text field is set.
It thinks we are modifying the value - Motif thinks that
it knows best but we know better! */
XtRemoveCallback(TextChild(mw), XmNmodifyVerifyCallback,
xbaeModifyVerifyCB, (XtPointer)mw);
/*
* We need to get the value to put back into the textField if the
* application has a draw cell callback so that any reformatting will
* be displayed. -cg May 13, 1999.
*/
if (mw->matrix.draw_cell_callback)
{
Pixmap pixmap, mask;
Pixel bg, fg;
int width, height, depth;
xbaeGetDrawCellValue(mw, mw->matrix.current_row,
mw->matrix.current_column, &string,
&pixmap, &mask, &width, &height,
&bg, &fg, &depth);
}
else
string = value;
if (string[0] == '\0')
XtVaSetValues(TextChild(mw),
XmNvalue, string,
NULL);
else
XmTextSetString(TextChild(mw), string);
XtAddCallback(TextChild(mw), XmNmodifyVerifyCallback,
xbaeModifyVerifyCB, (XtPointer)mw);
}
}
static Boolean
DoCommitEdit(mw, event)
XbaeMatrixWidget mw;
XEvent *event;
{
String cell;
if (!XtIsManaged(TextChild(mw)))
return True;
/*
* Get the value the user entered in the textField (this is a copy)
*/
cell = XmTextGetString(TextChild(mw));
/*
* Call the leaveCellCallback to see if we can leave the current cell.
*/
if (mw->matrix.leave_cell_callback)
{
XbaeMatrixLeaveCellCallbackStruct call_data;
call_data.reason = XbaeLeaveCellReason;
call_data.event = event;
call_data.row = mw->matrix.current_row;
call_data.column = mw->matrix.current_column;
call_data.value = cell;
call_data.doit = True;
XtCallCallbackList((Widget) mw, mw->matrix.leave_cell_callback,
(XtPointer)&call_data);
/*
* Application doesn't want to leave this cell. Make the cell visible
* and traverse to it so the user can see where they screwed up.
*/
if (!call_data.doit)
{
xbaeMakeCellVisible(
mw, mw->matrix.current_row, mw->matrix.current_column);
XmProcessTraversal(TextChild(mw), XmTRAVERSE_CURRENT);
XtFree((XtPointer) cell);
return False;
}
/*
* Use the applications value if it is different.
* If the application modified the string inplace, we will pick that
* up automatically.
*/
if (call_data.value != cell)
{
XtFree((XtPointer) cell);
cell = call_data.value;
}
}
/*
* Call the set_cell method to store the new value in the cell and redraw.
*/
(*((XbaeMatrixWidgetClass) XtClass(mw))->matrix_class.set_cell)
(mw, mw->matrix.current_row, mw->matrix.current_column, cell, True);
XtFree((XtPointer) cell);
return True;
}
/*
* Position and size the scrollbars and clip widget for our new size.
*/
void
xbaeResize(mw)
XbaeMatrixWidget mw;
{
int cell_width, cell_height, rows_visible;
Boolean has_horiz, has_vert;
Boolean scrollbar_top;
Boolean scrollbar_left;
int width = mw->core.width;
int height = mw->core.height;
/*
* Full size of widget (no SBs needed) - may be very large
*/
long int full_width = NON_FIXED_TOTAL_WIDTH(mw) + FIXED_COLUMN_WIDTH(mw) +
TRAILING_FIXED_COLUMN_WIDTH(mw) + ROW_LABEL_WIDTH(mw) +
2 * mw->manager.shadow_thickness;
long int full_height = CELL_TOTAL_HEIGHT(mw) + FIXED_ROW_HEIGHT(mw) +
TRAILING_FIXED_ROW_HEIGHT(mw) + COLUMN_LABEL_HEIGHT(mw) +
2 * mw->manager.shadow_thickness;
/*
* Portion of cells which are visible in clip widget
*/
int horiz_visible = NON_FIXED_TOTAL_WIDTH(mw) - HORIZ_ORIGIN(mw);
int vert_visible = CELL_TOTAL_HEIGHT(mw) -
VERT_ORIGIN(mw) * ROW_HEIGHT(mw);
/*
* Check the location of the scrollbars
*/
scrollbar_top = (mw->matrix.scrollbar_placement == XmTOP_LEFT ||
mw->matrix.scrollbar_placement == XmTOP_RIGHT);
scrollbar_left = (mw->matrix.scrollbar_placement == XmBOTTOM_LEFT ||
mw->matrix.scrollbar_placement == XmTOP_LEFT);
/*
* If our horizontal scrollbar display policy is constant,
* then we always have the horizontal scrollbar. If it is
* none, then we never have it. Otherwise, check if it
* is needed: if we are wider than the matrix's width,
* then we don't need it; if we are smaller, we do.
*/
if (mw->matrix.hsb_display_policy == XmDISPLAY_STATIC)
has_horiz = TRUE;
else if (mw->matrix.hsb_display_policy == XmDISPLAY_NONE)
has_horiz = FALSE;
else
{
if (width >= full_width)
has_horiz = False;
else
has_horiz = True;
}
if (has_horiz)
height -= HORIZ_SB_HEIGHT(mw);
/*
* Same reasoning for the vertical scrollbar.
*/
if (mw->matrix.vsb_display_policy == XmDISPLAY_STATIC)
has_vert = TRUE;
else if (mw->matrix.vsb_display_policy == XmDISPLAY_NONE)
has_vert = FALSE;
else
{
if (height >= full_height)
has_vert = False;
else
has_vert = True;
}
/*
* If we have a vertical scrollbar, adjust the width and
* recheck if we need the horizontal scrollbar.
*/
if (has_vert)
{
width -= VERT_SB_WIDTH(mw);
if ((XmDISPLAY_NONE != mw->matrix.hsb_display_policy) &&
(! has_horiz) && (width < full_width))
{
has_horiz = True;
height -= HORIZ_SB_HEIGHT(mw);
}
}
/*
* If widget is smaller than full size, move/resize the scrollbar and
* set sliderSize, also if cell_width/cell_height is greater than
* the amount of cell area visible, then we need to drag the cells
* back into the visible part of the clip widget and set the
* scrollbar value.
*
* Otherwise, the widget is larger than full size, so set
* cell_width/cell_height to size of cells and set origin to 0
* to force full cell area to be displayed
*
* We also need to move the textField correspondingly
*/
/*
* We were resized smaller than our max width.
*/
if (width < full_width)
{
int HSBwidth;
/*
* Calculate the width of the non-fixed visible cells.
*/
cell_width = mw->core.width - (FIXED_COLUMN_WIDTH(mw) +
TRAILING_FIXED_COLUMN_WIDTH(mw) +
ROW_LABEL_WIDTH(mw) +
2 * mw->manager.shadow_thickness);
/*
* Subtract the VSB if we have one.
*/
if (has_vert)
cell_width -= VERT_SB_WIDTH(mw);
if (cell_width <= 0)
cell_width = 1;
/*
* Adjust for shadow thickness.
*/
HSBwidth = cell_width + mw->manager.shadow_thickness *
(mw->matrix.fixed_columns ||
mw->matrix.trailing_fixed_columns ?
(mw->matrix.fixed_columns &&
mw->matrix.trailing_fixed_columns ? 0 : 1) : 2);
/*
* If the window is not full height, then place the HSB at the edge
* of the window. Is the window is larger than full height, then
* place the HSB immediately below the cell region.
*/
XtConfigureWidget(
HorizScrollChild(mw),
HSB_X_POSITION(mw),
(scrollbar_top && has_horiz) ? (Position) 0 :
((height < full_height) || mw->matrix.fill ?
(Position) (mw->core.height -
(HorizScrollChild(mw)->core.height +
2 * HorizScrollChild(mw)->core.border_width)) :
(Position) (full_height + mw->matrix.space)), HSBwidth,
HorizScrollChild(mw)->core.height,
HorizScrollChild(mw)->core.border_width);
/*
* If the cells are scrolled off to the left, then drag them
* back onto the screen.
*/
if (cell_width > horiz_visible)
{
if ((HORIZ_ORIGIN(mw) -= (cell_width - horiz_visible)) < 0)
{
HORIZ_ORIGIN(mw) = 0;
mw->matrix.left_column = 0;
}
if (XtIsManaged(TextChild(mw)))
XtMoveWidget(TextChild(mw),
TextChild(mw)->core.x +
(cell_width - horiz_visible),
TextChild(mw)->core.y);
}
/*
* Setup the HSB to reflect our new size.
*/
XtVaSetValues(HorizScrollChild(mw),
XmNpageIncrement, cell_width,
XmNsliderSize, cell_width,
XmNvalue, HORIZ_ORIGIN(mw),
NULL);
}
/*
* We were resized larger than the our max width. Drag the cells back
* onto the screen if they were scrolled off to the left.
*/
else
{
if (XtIsManaged(TextChild(mw)))
XtMoveWidget(TextChild(mw),
TextChild(mw)->core.x + HORIZ_ORIGIN(mw),
TextChild(mw)->core.y);
cell_width = NON_FIXED_TOTAL_WIDTH(mw);
if (cell_width <= 0) cell_width = 1;
HORIZ_ORIGIN(mw) = 0;
mw->matrix.left_column = 0;
if (has_horiz)
{
XtConfigureWidget(
HorizScrollChild(mw),
HSB_X_POSITION(mw),
(scrollbar_top && has_horiz) ? (Position) 0 :
((height < full_height) || mw->matrix.fill ?
(Position) (mw->core.height -
(HorizScrollChild(mw)->core.height +
2 * HorizScrollChild(mw)->core.border_width)) :
(Position) (full_height + mw->matrix.space)),
HSB_WIDTH(mw),
HorizScrollChild(mw)->core.height,
HorizScrollChild(mw)->core.border_width);
XtVaSetValues(HorizScrollChild(mw),
XmNpageIncrement, cell_width,
XmNsliderSize, cell_width,
XmNvalue, HORIZ_ORIGIN(mw),
NULL);
}
}
/*
* We were resized smaller than our max height.
*/
if (height < full_height)
{
int VSBheight;
/*
* Calculate the height of the non-fixed visible cells.
*/
cell_height = mw->core.height -
(FIXED_ROW_HEIGHT(mw) + TRAILING_FIXED_ROW_HEIGHT(mw) +
COLUMN_LABEL_HEIGHT(mw) + 2 * mw->manager.shadow_thickness);
/*
* Subtract the HSB if we have one.
*/
if (has_horiz)
cell_height -= HORIZ_SB_HEIGHT(mw);
if (cell_height <= 0)
cell_height = 1;
/*
* Adjust for shadow thickness.
*/
if (TRAILING_FIXED_ROW_HEIGHT(mw) > 0)
VSBheight = (cell_height / ROW_HEIGHT(mw)) * ROW_HEIGHT(mw) +
(mw->matrix.fixed_rows ? 0 : mw->manager.shadow_thickness);
else
VSBheight = cell_height +
((mw->matrix.fixed_rows ? 1 : 2) *
mw->manager.shadow_thickness);
/*
* If the window is not full width, then place the VSB at the edge
* of the window. Is the window is larger than full width, then
* place the VSB immediately to the right of the cell region.
*/
XtConfigureWidget(
VertScrollChild(mw),
(scrollbar_left && has_vert) ? (Position) 0 :
((width < full_width) || mw->matrix.fill ?
(Position) (mw->core.width -
(VertScrollChild(mw)->core.width + 2 *
VertScrollChild(mw)->core.border_width)) :
(Position) full_width + mw->matrix.space),
VSB_Y_POSITION(mw),
VertScrollChild(mw)->core.width, VSBheight > 0 ? VSBheight : 1,
VertScrollChild(mw)->core.border_width);
/*
* If the cells are scrolled off the top, then drag them
* back onto the screen.
*/
if (cell_height > vert_visible)
{
int rows = (cell_height - vert_visible) / ROW_HEIGHT(mw);
VERT_ORIGIN(mw) -= rows;
if (XtIsManaged(TextChild(mw)))
XtMoveWidget(TextChild(mw),
TextChild(mw)->core.x,
TextChild(mw)->core.y + rows * ROW_HEIGHT(mw));
}
/*
* Setup the VSB to reflect our new size.
*/
rows_visible = cell_height / ROW_HEIGHT(mw);
XtVaSetValues(VertScrollChild(mw),
XmNpageIncrement, rows_visible <= 0 ? 1 : rows_visible,
XmNsliderSize, rows_visible <= 0 ? 1 : rows_visible,
XmNvalue, VERT_ORIGIN(mw),
NULL);
}
/*
* We were resized larger than the our max height. Drag the cells back
* onto the screen if they were scrolled off the top.
*/
else
{
if (XtIsManaged(TextChild(mw)))
XtMoveWidget(TextChild(mw),
TextChild(mw)->core.x,
TextChild(mw)->core.y +
VERT_ORIGIN(mw) * ROW_HEIGHT(mw));
cell_height = CELL_TOTAL_HEIGHT(mw);
if (cell_height <= 0)
cell_height = 1;
rows_visible = mw->matrix.rows - mw->matrix.fixed_rows -
mw->matrix.trailing_fixed_rows;
VERT_ORIGIN(mw) = 0;
if (has_vert)
{
XtConfigureWidget(
VertScrollChild(mw),
(scrollbar_left && has_vert) ? (Position) 0 :
((width < full_width) || mw->matrix.fill ?
(Position)(mw->core.width -
(VertScrollChild(mw)->core.width +
2 * VertScrollChild(mw)->core.border_width)) :
(Position)full_width + mw->matrix.space),
VSB_Y_POSITION(mw),
VertScrollChild(mw)->core.width,
VSB_HEIGHT(mw),
VertScrollChild(mw)->core.border_width);
XtVaSetValues(
VertScrollChild(mw),
XmNpageIncrement, rows_visible <= 0 ? 1 : rows_visible,
XmNsliderSize, rows_visible <= 0 ? 1 : rows_visible,
XmNvalue, VERT_ORIGIN(mw),
NULL);
}
}
/*
* Map/unmap scrollbars based on flags set above
*/
if (has_horiz && !HorizScrollChild(mw)->core.managed)
{
XtManageChild(HorizScrollChild(mw));
/*
* Generate an expose over the horizontal scrollbar to ensure it gets
* drawn properly
*/
if (!mw->matrix.disable_redisplay && XtIsRealized((Widget)mw))
XClearArea(XtDisplay(mw), XtWindow(mw), 0, HORIZ_SB_POSITION(mw),
mw->core.width, scrollbar_top ? HORIZ_SB_HEIGHT(mw) :
mw->core.height - HORIZ_SB_POSITION(mw), True);
/*
* Take into account the little bit at the bottom of the screen
* if the scrollbar is in the top location.
*/
if (scrollbar_top && XtIsRealized((Widget)mw))
XClearArea(XtDisplay(mw), XtWindow(mw), 0,
TRAILING_FIXED_ROW_LABEL_OFFSET(mw), mw->core.width,
mw->core.height - TRAILING_FIXED_ROW_LABEL_OFFSET(mw),
True);
}
else if (!has_horiz && HorizScrollChild(mw)->core.managed)
{
/*
* Generate an expose over the horizontal scrollbar to ensure it gets
* drawn properly
*/
XtUnmanageChild(HorizScrollChild(mw));
if (!mw->matrix.disable_redisplay && XtIsRealized((Widget)mw))
XClearArea(XtDisplay(mw), XtWindow(mw), 0, HORIZ_SB_POSITION(mw),
mw->core.width, scrollbar_top ? HORIZ_SB_HEIGHT(mw) :
mw->core.height - HORIZ_SB_POSITION(mw), True);
/*
* Take into account the little bit at the bottom of the screen
* if the scrollbar is in the top location.
*/
if (scrollbar_top && XtIsRealized((Widget)mw))
XClearArea(XtDisplay(mw), XtWindow(mw), 0,
TRAILING_FIXED_ROW_LABEL_OFFSET(mw), mw->core.width,
mw->core.height - TRAILING_FIXED_ROW_LABEL_OFFSET(mw),
True);
}
if (has_vert && !VertScrollChild(mw)->core.managed)
{
/*
* Generate an expose over the vertical scrollbar region to ensure
* it gets drawn properly
*/
XtManageChild(VertScrollChild(mw));
if (!mw->matrix.disable_redisplay && XtIsRealized((Widget)mw))
XClearArea(XtDisplay(mw), XtWindow(mw), VERT_SB_POSITION(mw), 0,
VERT_SB_POSITION(mw) + VERT_SB_WIDTH(mw),
mw->core.height, True);
/*
* This one's a bit trickier! If the scrollbar appears on the
* left hand side then it's possible to have some area *under* the
* matrix that isn't redrawn properly. This will be most
* noticeable at the top and bottom of the matrix. As the matrix
* will move to the right by it's width, this width is the area
* that needs to be redrawn.
*/
if (scrollbar_left && XtIsRealized((Widget)mw))
XClearArea(XtDisplay(mw), XtWindow(mw),
FIXED_COLUMN_LABEL_OFFSET(mw) -
TRAILING_FIXED_COLUMN_WIDTH(mw), 0,
TRAILING_FIXED_COLUMN_WIDTH(mw) + VERT_SB_WIDTH(mw),
mw->core.height, True);
/*
* Also clear the area below the matrix as it can get a little
* confused too
*/
if(XtIsRealized((Widget)mw))
XClearArea(XtDisplay(mw), XtWindow(mw), 0,
TRAILING_FIXED_ROW_LABEL_OFFSET(mw), mw->core.width,
mw->core.height - TRAILING_FIXED_ROW_LABEL_OFFSET(mw),
True);
}
else if (!has_vert && VertScrollChild(mw)->core.managed)
{
/*
* Generate an expose over the vertical scrollbar region to ensure
* it gets drawn properly
*/
XtUnmanageChild(VertScrollChild(mw));
if (!mw->matrix.disable_redisplay && XtIsRealized((Widget)mw))
XClearArea(XtDisplay(mw), XtWindow(mw), VERT_SB_POSITION(mw), 0,
VERT_SB_POSITION(mw) + VERT_SB_WIDTH(mw),
mw->core.height, True);
/*
* Similar to the case above but we need to clear the are to the
* right of the matrix and only the width of the scrollbar itself
*/
if (scrollbar_left && XtIsRealized((Widget)mw))
XClearArea(XtDisplay(mw), XtWindow(mw),
TRAILING_FIXED_COLUMN_LABEL_OFFSET(mw) +
TRAILING_FIXED_COLUMN_WIDTH(mw), 0,
VERT_SB_WIDTH(mw) + mw->manager.shadow_thickness,
mw->core.height, True);
/*
* And also clear the area below the matrix as it can get a little
* confused too
*/
if (XtIsRealized((Widget)mw))
XClearArea(XtDisplay(mw), XtWindow(mw), 0,
TRAILING_FIXED_ROW_LABEL_OFFSET(mw), mw->core.width,
mw->core.height - TRAILING_FIXED_ROW_LABEL_OFFSET(mw),
True);
}
/*
* Now that we have cell_width & cell_height,
* make the clip widget this size. Height is truncated to the
* nearest row.
*/
XtConfigureWidget(ClipChild(mw),
FIXED_COLUMN_LABEL_OFFSET(mw),
FIXED_ROW_LABEL_OFFSET(mw),
cell_width, cell_height, 0);
/* Resize all the other clips */
if (mw->matrix.fixed_columns <= 0)
{
if (XtIsManaged(LeftClip(mw)))
XtUnmanageChild(LeftClip(mw));
}
else
{
XtConfigureWidget(LeftClip(mw),
COLUMN_LABEL_OFFSET(mw), FIXED_ROW_LABEL_OFFSET(mw),
FIXED_COLUMN_WIDTH(mw), cell_height, 0);
if (!XtIsManaged(LeftClip(mw)))
XtManageChild(LeftClip(mw));
}
if (mw->matrix.trailing_fixed_columns <= 0)
{
if (XtIsManaged(RightClip(mw)))
XtUnmanageChild(RightClip(mw));
}
else
{
XtConfigureWidget(RightClip(mw),
cell_width + FIXED_COLUMN_LABEL_OFFSET(mw),
FIXED_ROW_LABEL_OFFSET(mw),
TRAILING_FIXED_COLUMN_WIDTH(mw),
cell_height, 0);
if (!XtIsManaged(RightClip(mw)))
XtManageChild(RightClip(mw));
}
if (mw->matrix.fixed_rows <= 0)
{
if (XtIsManaged(TopClip(mw)))
XtUnmanageChild(TopClip(mw));
}
else
{
XtConfigureWidget(TopClip(mw),
FIXED_COLUMN_LABEL_OFFSET(mw), ROW_LABEL_OFFSET(mw),
cell_width, FIXED_ROW_HEIGHT(mw), 0);
if (!XtIsManaged(TopClip(mw)))
XtManageChild(TopClip(mw));
}
if (mw->matrix.trailing_fixed_rows <= 0)
{
if (XtIsManaged(BottomClip(mw)))
XtUnmanageChild(BottomClip(mw));
}
else
{
XtConfigureWidget(BottomClip(mw),
FIXED_COLUMN_LABEL_OFFSET(mw),
TRAILING_FIXED_ROW_LABEL_OFFSET(mw),
cell_width, TRAILING_FIXED_ROW_HEIGHT(mw), 0);
if (!XtIsManaged(BottomClip(mw)))
XtManageChild(BottomClip(mw));
}
/*
* The text field needs to be moved manually as we don't have
* the convenience of a clip widget to do it for us.
*/
if (mw->matrix.current_column >= TRAILING_HORIZ_ORIGIN(mw) &&
mw->matrix.current_parent == (Widget)mw &&
XtIsManaged(TextChild(mw)))
XtMoveWidget(TextChild(mw), RightClip(mw)->core.x +
mw->matrix.cell_shadow_thickness, TextChild(mw)->core.y);
/*
* Save the non-truncated height. We need this so we can draw
* the shadow correctly.
*/
mw->matrix.cell_visible_height = cell_height;
/*
* Set the clip_mask in our clipping GCs. This function relies on
* the Clip widget being the correct size (above).
*/
if (XtIsRealized((Widget)mw))
xbaeSetClipMask(mw, CLIP_NONE);
if (mw->matrix.resize_callback != NULL)
{
XbaeMatrixResizeCallbackStruct call_data;
call_data.reason = XbaeResizeReason;
call_data.event = (XEvent *)NULL;
call_data.row = mw->matrix.rows;
call_data.column = mw->matrix.columns;
call_data.width = mw->core.width;
call_data.height = mw->core.height;
XtCallCallbackList ((Widget)mw, mw->matrix.resize_callback,
(XtPointer) &call_data);
}
}
/*
* This is the modifyVerifyCallback we added to textField. We need to
* call Matrix's modifyVerifyCallback list with the textField info
* and the row/col that is changing.
*/
/* ARGSUSED */
void
xbaeModifyVerifyCB(w, client, call)
Widget w;
XtPointer client;
XtPointer call;
{
XbaeMatrixWidget mw = (XbaeMatrixWidget)client;
XmTextVerifyCallbackStruct *verify = (XmTextVerifyCallbackStruct *)call;
XbaeMatrixModifyVerifyCallbackStruct call_data;
if (!mw->matrix.modify_verify_callback)
return;
call_data.reason = XbaeModifyVerifyReason;
call_data.row = mw->matrix.current_row;
call_data.column = mw->matrix.current_column;
call_data.event = (XEvent *)NULL;
call_data.verify = verify;
call_data.prev_text = ((XmTextRec*)w)->text.value;
XtCallCallbackList((Widget) mw, mw->matrix.modify_verify_callback,
(XtPointer) & call_data);
}
/*
* Matrix edit_cell method
*/
void
xbaeEditCell(mw, event, row, column, params, nparams)
XbaeMatrixWidget mw;
XEvent *event;
int row;
int column;
String *params;
Cardinal nparams;
{
XbaeMatrixEnterCellCallbackStruct call_data;
Window newWin, oldWin;
int x, y;
Pixel fgcolor, bgcolor;
Boolean alt;
String string;
Widget oldWidget, newWidget;
#if CELL_WIDGETS
Widget userWidget;
#endif
if (row >= mw->matrix.rows || row < 0 ||
column >= mw->matrix.columns || column < 0)
{
/*
* If we have zero rows or columns, there are no cells
* available on which to place the text field so just return
*/
if (mw->matrix.rows == 0 || mw->matrix.columns == 0)
return;
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"editCell", "badIndex", "XbaeMatrix",
"XbaeMatrix: Row or column out of bounds for EditCell.",
NULL, 0);
return;
}
/*
* Attempt to commit the edit in the current cell. Return if we fail.
*/
if (!DoCommitEdit(mw, event))
return;
/*
* Scroll the cell onto the screen
*/
xbaeMakeCellVisible(mw, row, column);
/*
* Fixed cells may not be editable.
*/
if (IS_FIXED(mw, row, column) && !mw->matrix.traverse_fixed)
return;
/* get the window of the new cell position */
newWin = xbaeGetCellWindow(mw, &newWidget, row, column);
/*
* If we have an enterCellCallback, call it to see if the cell is
* editable.
*/
call_data.map = True;
call_data.doit = True;
call_data.position = -1;
call_data.select_text = False;
if (mw->matrix.enter_cell_callback)
{
call_data.reason = XbaeEnterCellReason;
call_data.event = event;
call_data.row = row;
call_data.column = column;
call_data.map = True;
call_data.num_params = nparams;
call_data.params = params;
XtCallCallbackList((Widget) mw, mw->matrix.enter_cell_callback,
(XtPointer) & call_data);
}
/* Get the window of the current cell so we can see if we need to move. */
oldWin = xbaeGetCellWindow(mw, &oldWidget, mw->matrix.current_row,
mw->matrix.current_column);
mw->matrix.current_row = row;
mw->matrix.current_column = column;
/*
* Unmap the textField to avoid flashing.
*/
if (XtIsManaged(TextChild(mw)) && XtIsRealized(TextChild(mw)))
XtUnmapWidget(TextChild(mw));
/*
* Convert the row/column to an xy position and move the textField
* to this position. (the xy position will be relative to the Clip
* widget if a non-fixed cells is being edited, relative to Matrix if
* a totally fixed cell is being edited (one of the corners), or one of
* the other clips otherwise.
*/
xbaeRowColToXY(mw, row, column, &x, &y);
#if CELL_WIDGETS
userWidget = mw->matrix.cell_widgets[row][column];
if (!userWidget)
{
#endif
/*
* We actually don't check for traverse_fixed here even though
* it looks like it might be needed. The reason is that we may
* need to reparent back onto the clip in case we were on the
* fixed area and then traverse_fixed has been set to False
* via SetValues. Doing this on the next traversal is probably
* preferable to magically warping the textField off the
* matrix on to the clip when traverseFixedCells changes. It
* also allows the user to finish editing the existing cell,
* but won't allow continued traversal on the fixed area. -CG
*/
/*
* The old check (oldWin != newWin) as criteria to reparent
* wasn't quite correct in the case of editable fixed columns;
* In this case the first time the cell was edited 'oldWin'
* and 'newWin' where both the left clip widget (which was correct)
* but the 'current_parent' was still the initial parent set in the
* 'Reslize' function (I think the clip widget).
* The result was that the text field was moved relative to wrong
* window and therefore appearing at a complete different position;
* I check now as additional criteria if the 'current_parent' widget
* is the same as 'newWidget'.
* It should fix the my problem without breaking anything else.
* The check (oldWin && newWin) for apps which call on startup
* editCell() without a realized widget tree. Without this check
* X errors would be the result.
*
* donato petrino, 1997/11/
*/
if ((oldWin != newWin ||
mw->matrix.current_parent != newWidget) &&
(oldWin && newWin))
{
XReparentWindow(XtDisplay(mw), XtWindow(TextChild(mw)), newWin,
x + mw->matrix.cell_shadow_thickness,
y + mw->matrix.cell_shadow_thickness);
mw->matrix.current_parent = newWidget;
/*
* Widget still needs moving, because all we have done
* above is redraw it's window. The widget itself doesn't
* know where it is and must be repositioned relative to
* it's (possibly new) window.
*/
}
XtMoveWidget(TextChild(mw),
x + mw->matrix.cell_shadow_thickness,
y + mw->matrix.cell_shadow_thickness);
#if CELL_WIDGETS
}
else
{
/*
* A user defined widget does not take into account the
* cell_highlight_thickness, so we must do it!
*/
XtMoveWidget(userWidget,
x + mw->matrix.cell_shadow_thickness +
mw->matrix.cell_highlight_thickness,
y + mw->matrix.cell_shadow_thickness +
mw->matrix.cell_highlight_thickness);
/* Force editing to be disabled */
call_data.doit = False;
}
#endif
/*
* Compute the foreground and background of the text widget
*/
alt = mw->matrix.alt_row_count ?
(row / mw->matrix.alt_row_count) % 2 : False;
if (mw->matrix.colors)
fgcolor = mw->matrix.colors[row][column];
else
fgcolor = mw->manager.foreground;
if (mw->matrix.text_background != mw->core.background_pixel)
bgcolor = mw->matrix.text_background;
else if (mw->matrix.cell_background &&
mw->matrix.cell_background[row][column] != mw->core.background_pixel)
bgcolor = mw->matrix.cell_background[row][column];
else
{
if (alt)
bgcolor = mw->matrix.odd_row_background;
else
bgcolor = mw->matrix.even_row_background;
}
/*
* If we're doing a drawCell, go ask the app what to put there.
*/
if (mw->matrix.draw_cell_callback)
{
Pixmap pixmap;
Pixmap mask;
int width, height, depth;
Pixel orig_bg, orig_fg;
orig_bg = bgcolor;
orig_fg = fgcolor;
if (xbaeGetDrawCellValue(
mw, row, column, &string, &pixmap, &mask, &width, &height,
&bgcolor, &fgcolor, &depth) == XbaePixmap)
{
/*
* If we're showing a pixmap, we don't want the TextField.
*/
return;
}
/*
* If we reverse selected then we would have reversed things we
* shouldn't have. We can detect this by checking bgcolor against
* orig_fg and fgcolor against orig_bg and setting the colors back
* to their non-selected values (as with an ordinary selected when
* it is being edited). -cg 23/7/99
*/
if (mw->matrix.reverse_select && mw->matrix.selected_cells &&
mw->matrix.selected_cells[row][column])
{
int new_fg = fgcolor;
int new_bg = bgcolor;
/* callback changed bg */
if (orig_fg != fgcolor)
new_bg = fgcolor;
else /* reset it */
new_bg = orig_bg;
/* callback changed fg */
if (orig_bg != bgcolor)
new_fg = bgcolor;
else /* reset it */
new_fg = orig_fg;
bgcolor = new_bg;
fgcolor = new_fg;
}
}
else
string = mw->matrix.cells ? mw->matrix.cells[row][column] : "";
/*
* Setup the textField for the new cell. If the modifyVerify CB
* rejects the new value, then it is the applications fault for
* loading the cell with a bad value to begin with.
*/
#if CELL_WIDGETS
if (!mw->matrix.cell_widgets[row][column])
{
#endif
/*
* Remove the modify verify callback when the text field is set.
* It thinks we are modifying the value but Motif thinks that
* it knows best and we know better!
*/
XtRemoveCallback(TextChild(mw), XmNmodifyVerifyCallback,
xbaeModifyVerifyCB, (XtPointer)mw);
XtVaSetValues(TextChild(mw),
XmNwidth, COLUMN_WIDTH(mw, column) -
mw->matrix.cell_shadow_thickness * 2,
XmNheight, (ROW_HEIGHT(mw) -
mw->matrix.cell_shadow_thickness * 2),
XmNmaxLength, (mw->matrix.column_max_lengths ?
mw->matrix.column_max_lengths[column] :
(int) mw->matrix.column_widths[column]),
XmNeditable, call_data.doit,
XmNcursorPositionVisible, call_data.doit,
XmNbackground, bgcolor,
XmNforeground, fgcolor,
NULL);
XtVaSetValues(TextChild(mw), XmNvalue, string, NULL);
XtAddCallback(TextChild(mw), XmNmodifyVerifyCallback,
xbaeModifyVerifyCB, (XtPointer)mw);
#if CELL_WIDGETS
}
else
XtVaSetValues(userWidget,
XmNwidth, COLUMN_WIDTH(mw, column) -
mw->matrix.cell_shadow_thickness * 2,
XmNheight, ROW_HEIGHT(mw)
- mw->matrix.cell_shadow_thickness * 2,
XmNbackground, bgcolor,
XmNforeground, fgcolor,
NULL);
#endif
/*
* No need to do anything else if the text field is not going to
* be mapped
*/
if (!call_data.map)
return;
/*
* Manage and map the textField
*/
#if CELL_WIDGETS
if (userWidget)
{
XtUnmanageChild(TextChild(mw));
XtManageChild(userWidget);
}
else
#endif
XtManageChild(TextChild(mw));
if (XtIsRealized(TextChild(mw))
#if CELL_WIDGETS
&& !userWidget
#endif
)
XtMapWidget(TextChild(mw));
#if CELL_WIDGETS
else if (XtIsRealized(userWidget) && userWidget)
XtMapWidget(userWidget);
if (call_data.doit && !userWidget)
#endif
/*
* Set the insert position of the cursor
*/
if (call_data.doit)
{
int position = call_data.position;
int length = strlen(string);
if (event && (event->type == ButtonPress ||
event->type == ButtonRelease ) &&
position < 0 && mw->matrix.calc_cursor_position)
{
/*
* The location of the pointer click needs to be calculated
* so the cursor can be positioned. If position is >= 0,
* it has been set in the enterCellCallback and must
* be honoured elsewhere.
*/
CellType cell;
int r, c;
/*
* The event must have occurred in a legal position
* otherwise control wouldn't have made it here
*/
(void)xbaeEventToXY(mw, event, &x, &y, &cell);
(void)xbaeXYToRowCol(mw, &x, &y, &r, &c, cell);
x -= mw->matrix.cell_shadow_thickness;
y = ROW_HEIGHT(mw) / 2; /* XXX should be real y! */
position = XmTextXYToPos(TextChild(mw), x, y);
}
if (call_data.select_text)
XmTextSetSelection(TextChild(mw), 0, length,
CurrentTime);
if (position < 0)
XmTextSetInsertionPosition(TextChild(mw), length);
else
XmTextSetInsertionPosition(
TextChild(mw), position > length ? length : position);
}
}
/*
* Matrix select_cell method
*/
void
xbaeSelectCell(mw, row, column)
XbaeMatrixWidget mw;
int row, column;
{
Boolean visible;
if (row >= mw->matrix.rows || row < 0 ||
column >= mw->matrix.columns || column < 0)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"selectCell", "badIndex", "XbaeMatrix",
"XbaeMatrix: Row or column out of bounds for SelectCell.",
NULL, 0);
return;
}
/* If no cells have been selected yet, allocate memory here */
if (!mw->matrix.selected_cells)
xbaeCopySelectedCells(mw);
/*
* Scroll the cell onto the screen
*/
visible = xbaeIsCellVisible(mw, row, column);
if (mw->matrix.scroll_select && !visible)
xbaeMakeCellVisible(mw, row, column);
/*
* If the cell is not already selected, select it and redraw it
*/
if (!mw->matrix.selected_cells[row][column])
{
mw->matrix.selected_cells[row][column] = True;
mw->matrix.num_selected_cells++;
if (mw->matrix.scroll_select || visible)
{
if (row >= TRAILING_VERT_ORIGIN(mw))
xbaeSetClipMask(mw, CLIP_TRAILING_FIXED_ROWS);
xbaeDrawCell(mw, row, column);
if (row >= TRAILING_VERT_ORIGIN(mw))
xbaeSetClipMask(mw, CLIP_NONE);
}
}
}
/*
* Matrix select_row method
*/
void
xbaeSelectRow(mw, row)
XbaeMatrixWidget mw;
int row;
{
int j, lc, rc;
Boolean fixed = False, trailing_fixed = False;
Boolean visible;
unsigned int clip_reason = CLIP_NONE, save_clip = CLIP_NONE;
if (row >= mw->matrix.rows || row < 0)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"selectRow", "badIndex", "XbaeMatrix",
"XbaeMatrix: Row out of bounds for SelectRow.",
NULL, 0);
return;
}
/* If no cells have been selected yet, allocate memory here */
if (!mw->matrix.selected_cells)
xbaeCopySelectedCells(mw);
visible = xbaeIsRowVisible(mw, row);
/*
* Scroll the row onto the screen
*/
if (mw->matrix.scroll_select)
xbaeMakeRowVisible(mw, row);
/*
* If the row is not visible, there's no need to redraw - but, we do
* need to update the selected cell resource
*/
if(!mw->matrix.scroll_select && !visible)
{
for (j = 0; j < mw->matrix.columns; j++)
if (!mw->matrix.selected_cells[row][j])
{
mw->matrix.num_selected_cells++;
mw->matrix.selected_cells[row][j] = True;
}
return;
}
/*
* Establish any necessary clipping for redrawing the cells
*/
save_clip = mw->matrix.current_clip;
if (row >= TRAILING_VERT_ORIGIN(mw))
clip_reason = CLIP_TRAILING_FIXED_ROWS;
if (CLIP_NONE != clip_reason)
xbaeSetClipMask(mw, CLIP_TRAILING_FIXED_ROWS);
/*
* For each cell in the row, if the cell is not already selected,
* select it and redraw it
*/
xbaeGetVisibleColumns(mw, &lc, &rc);
for (j = 0; j < mw->matrix.columns; j++)
{
if (!mw->matrix.selected_cells[row][j])
{
mw->matrix.selected_cells[row][j] = True;
mw->matrix.num_selected_cells++;
if ((j >= lc && j <= rc) ||
(j < (int)mw->matrix.fixed_columns) ||
(j >= TRAILING_HORIZ_ORIGIN(mw)))
{
if ((! fixed) && (j < (int)mw->matrix.fixed_columns))
{
fixed = True;
xbaeSetClipMask(mw, clip_reason | CLIP_FIXED_COLUMNS);
}
else if (fixed && (j >= (int)mw->matrix.fixed_columns) &&
(j < TRAILING_HORIZ_ORIGIN(mw)))
{
fixed = False;
xbaeSetClipMask(mw, clip_reason);
}
else if ((! trailing_fixed) && (j >= TRAILING_HORIZ_ORIGIN(mw)))
{
trailing_fixed = True;
xbaeSetClipMask(mw, clip_reason |
CLIP_TRAILING_FIXED_COLUMNS);
}
xbaeClearCell(mw, row, j);
xbaeDrawCell(mw, row, j);
}
}
}
if (save_clip != mw->matrix.current_clip)
xbaeSetClipMask(mw, CLIP_NONE);
}
/*
* Matrix select_column method
*/
void
xbaeSelectColumn(mw, column)
XbaeMatrixWidget mw;
int column;
{
int i, tr, br;
Boolean once = False;
unsigned int clip_reason = CLIP_NONE;
if (column >= mw->matrix.columns || column < 0)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"selectColumn", "badIndex", "XbaeMatrix",
"XbaeMatrix: Column out of bounds for SelectColumn.",
NULL, 0);
return;
}
/* If no cells have been selected yet, allocate memory here */
if (!mw->matrix.selected_cells)
xbaeCopySelectedCells(mw);
/*
* Scroll the column onto the screen
*/
if (mw->matrix.scroll_select)
xbaeMakeColumnVisible(mw, column);
/*
* No need to redraw unless the column is visible
*/
if (!mw->matrix.scroll_select && !xbaeIsColumnVisible(mw, column))
{
for (i = 0; i < mw->matrix.rows; i++)
if (!mw->matrix.selected_cells[i][column])
{
mw->matrix.num_selected_cells++;
mw->matrix.selected_cells[i][column] = True;
}
return;
}
/*
* Establish any necessary clipping for redrawing the cells
*/
if (column < (int)mw->matrix.fixed_columns)
clip_reason = CLIP_FIXED_COLUMNS;
else if (column >= TRAILING_HORIZ_ORIGIN(mw))
clip_reason = CLIP_TRAILING_FIXED_COLUMNS;
if (CLIP_NONE != clip_reason)
xbaeSetClipMask(mw, clip_reason | CLIP_VISIBLE_HEIGHT);
/*
* For each cell in the column, if the cell is not already selected,
* select it and redraw it
*/
xbaeGetVisibleRows(mw, &tr, &br);
for (i = 0; i < mw->matrix.rows; i++)
{
if (!mw->matrix.selected_cells[i][column])
{
mw->matrix.selected_cells[i][column] = True;
mw->matrix.num_selected_cells++;
if ((i >= tr && i <= br) ||
(i < (int)mw->matrix.fixed_rows) ||
(i >= TRAILING_VERT_ORIGIN(mw)))
{
if ((! once) && (i >= TRAILING_VERT_ORIGIN(mw)))
{
once = True;
xbaeSetClipMask(mw, clip_reason | CLIP_TRAILING_FIXED_ROWS);
}
xbaeClearCell(mw, i, column);
xbaeDrawCell(mw, i, column);
}
}
}
if (once || (CLIP_NONE != clip_reason))
xbaeSetClipMask(mw, CLIP_NONE);
}
/*
* Matrix deselect_all method
*/
void
xbaeDeselectAll(mw)
XbaeMatrixWidget mw;
{
int i, j;
int tr, br, lc, rc;
register Boolean do_row, once = False;
mw->matrix.num_selected_cells = 0;
/* If selected_cells is NULL, no cells have been selected yet */
if (!mw->matrix.selected_cells)
return;
xbaeGetVisibleCells(mw, &tr, &br, &lc, &rc);
for (i = 0; i < mw->matrix.rows; i++)
{
do_row = False;
if ((! once) && (i >= TRAILING_VERT_ORIGIN(mw)))
{
once = True;
xbaeSetClipMask(mw, CLIP_TRAILING_FIXED_ROWS);
}
for (j = 0; j < mw->matrix.columns; j++)
{
if (mw->matrix.selected_cells[i][j])
{
mw->matrix.selected_cells[i][j] = False;
if (((i < (int)mw->matrix.fixed_rows) ||
(i >= TRAILING_VERT_ORIGIN(mw)) ||
(i >= tr && i <= br)) &&
((j < (int)mw->matrix.fixed_columns) ||
(j >= TRAILING_HORIZ_ORIGIN(mw)) ||
(j >= lc && j <= rc)))
{
xbaeClearCell(mw, i, j);
xbaeDrawCell(mw, i, j);
do_row = True;
}
}
}
}
if (once)
xbaeSetClipMask(mw, CLIP_NONE);
}
/*
* Matrix select_all method
*/
void
xbaeSelectAll(mw)
XbaeMatrixWidget mw;
{
int i, j;
int tr, br, lc, rc;
register Boolean do_row, once = False;
xbaeGetVisibleCells(mw, &tr, &br, &lc, &rc);
if (!mw->matrix.selected_cells)
xbaeCopySelectedCells(mw);
for (i = 0; i < mw->matrix.rows; i++)
{
do_row = False;
if ((! once) && (i >= TRAILING_VERT_ORIGIN(mw)))
{
once = True;
xbaeSetClipMask(mw, CLIP_TRAILING_FIXED_ROWS);
}
for (j = 0; j < mw->matrix.columns; j++)
{
if (!mw->matrix.selected_cells[i][j])
{
mw->matrix.num_selected_cells++;
mw->matrix.selected_cells[i][j] = True;
if (((i < (int)mw->matrix.fixed_rows) ||
(i >= TRAILING_VERT_ORIGIN(mw)) ||
(i >= tr && i <= br)) &&
((j < (int)mw->matrix.fixed_columns) ||
(j >= TRAILING_HORIZ_ORIGIN(mw)) ||
(j >= lc && j <= rc)))
{
xbaeClearCell(mw, i, j);
xbaeDrawCell(mw, i, j);
do_row = True;
}
}
}
}
if (once)
xbaeSetClipMask(mw, CLIP_NONE);
}
/*
* Matrix deselect_cell method
*/
void
xbaeDeselectCell(mw, row, column)
XbaeMatrixWidget mw;
int row;
int column;
{
if (row >= mw->matrix.rows || row < 0 ||
column > mw->matrix.columns - 1 || column < 0)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"deselectCell", "badIndex", "XbaeMatrix",
"XbaeMatrix: Row or column out of bounds for DeselectCell.",
NULL, 0);
return;
}
if (!mw->matrix.selected_cells)
return;
if (mw->matrix.selected_cells[row][column])
{
mw->matrix.num_selected_cells--;
mw->matrix.selected_cells[row][column] = False;
if (xbaeIsCellVisible(mw, row, column))
{
if (row >= TRAILING_VERT_ORIGIN(mw))
xbaeSetClipMask(mw, CLIP_TRAILING_FIXED_ROWS);
xbaeClearCell(mw, row, column);
xbaeDrawCell(mw, row, column);
if (row >= TRAILING_VERT_ORIGIN(mw))
xbaeSetClipMask(mw, CLIP_NONE);
}
}
}
/*
* Matrix deselect_row method
*/
void
xbaeDeselectRow(mw, row)
XbaeMatrixWidget mw;
int row;
{
int j, lc, rc;
Boolean fixed = False, trailing_fixed = False;
unsigned int clip_reason = CLIP_NONE, save_clip;
if (row >= mw->matrix.rows || row < 0)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"deselectRow", "badIndex", "XbaeMatrix",
"XbaeMatrix: Row parameter out of bounds for DeselectRow.",
NULL, 0);
return;
}
if (!mw->matrix.selected_cells)
return;
/*
* Establish any necessary clipping for redrawing the cells
*/
save_clip = mw->matrix.current_clip;
if (row >= TRAILING_VERT_ORIGIN(mw))
clip_reason = CLIP_TRAILING_FIXED_ROWS;
if (CLIP_NONE != clip_reason)
xbaeSetClipMask(mw, CLIP_TRAILING_FIXED_ROWS);
/*
* For each cell in the row, if the cell is selected,
* deselect it and redraw it
*/
xbaeGetVisibleColumns(mw, &lc, &rc);
for (j = 0; j < mw->matrix.columns; j++)
{
if (mw->matrix.selected_cells[row][j])
{
mw->matrix.num_selected_cells--;
mw->matrix.selected_cells[row][j] = False;
if ((j >= lc && j <= rc) ||
(j < (int)mw->matrix.fixed_columns) ||
(j >= TRAILING_HORIZ_ORIGIN(mw)))
{
if ((! fixed) && (j < (int)mw->matrix.fixed_columns))
{
fixed = True;
xbaeSetClipMask(mw, clip_reason | CLIP_FIXED_COLUMNS);
}
else if (fixed && (j >= (int)mw->matrix.fixed_columns) &&
(j < TRAILING_HORIZ_ORIGIN(mw)))
{
fixed = False;
xbaeSetClipMask(mw, clip_reason);
}
else if ((! trailing_fixed) && (j >= TRAILING_HORIZ_ORIGIN(mw)))
{
trailing_fixed = True;
xbaeSetClipMask(mw, clip_reason | CLIP_TRAILING_FIXED_COLUMNS);
}
xbaeClearCell(mw, row, j);
xbaeDrawCell(mw, row, j);
}
}
}
if (save_clip != mw->matrix.current_clip)
xbaeSetClipMask(mw, CLIP_NONE);
}
/*
* Matrix deselect_column method
*/
void
xbaeDeselectColumn(mw, column)
XbaeMatrixWidget mw;
int column;
{
int i, tr, br;
Boolean once = False;
unsigned int clip_reason = CLIP_NONE;
if (column >= mw->matrix.columns || column < 0)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"deselectColumn", "badIndex", "XbaeMatrix",
"XbaeMatrix: Column parameter out of bounds for DeselectColumn.",
NULL, 0);
return;
}
if (!mw->matrix.selected_cells)
return;
/*
* Establish any necessary clipping for redrawing the cells
*/
if (column < (int)mw->matrix.fixed_columns)
clip_reason = CLIP_FIXED_COLUMNS;
else if (column >= TRAILING_HORIZ_ORIGIN(mw))
clip_reason = CLIP_TRAILING_FIXED_COLUMNS;
if (CLIP_NONE != clip_reason)
xbaeSetClipMask(mw, clip_reason | CLIP_VISIBLE_HEIGHT);
/*
* For each cell in the column, if the cell is selected,
* deselect it and redraw it
*/
xbaeGetVisibleRows(mw, &tr, &br);
for (i = 0; i < mw->matrix.rows; i++)
{
if (mw->matrix.selected_cells[i][column])
{
mw->matrix.num_selected_cells--;
mw->matrix.selected_cells[i][column] = False;
if ((i >= tr && i <= br) ||
(i < (int)mw->matrix.fixed_rows) ||
(i >= TRAILING_VERT_ORIGIN(mw)))
{
if ((! once) && (i >= TRAILING_VERT_ORIGIN(mw)))
{
once = True;
xbaeSetClipMask(mw, clip_reason | CLIP_TRAILING_FIXED_ROWS);
}
xbaeClearCell(mw, i, column);
xbaeDrawCell(mw, i, column);
}
}
}
if (once || (CLIP_NONE != clip_reason))
xbaeSetClipMask(mw, CLIP_NONE);
}
/*
* Matrix get_cell method
*/
String
xbaeGetCell(mw, row, column)
XbaeMatrixWidget mw;
int row, column;
{
String value;
if (row >= mw->matrix.rows || row < 0 ||
column > mw->matrix.columns - 1 || column < 0)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"getCell", "badIndex", "XbaeMatrix",
"XbaeMatrix: Row or column out of bounds for GetCell.",
NULL, 0);
return (NULL);
}
if (mw->matrix.draw_cell_callback)
{
Pixel bgcolor, fgcolor;
Pixmap pixmap, mask;
int width, height, depth;
if (xbaeGetDrawCellValue(mw, row, column, &value, &pixmap,
&mask, &width, &height, &bgcolor, &fgcolor,
&depth) == XbaePixmap)
value = "";
}
else if (!mw->matrix.cells)
return "";
else
value = mw->matrix.cells[row][column];
return value;
}
/*
* Matrix commit_edit method
*/
Boolean
#if NeedFunctionPrototypes
xbaeCommitEdit(XbaeMatrixWidget mw, XEvent *event, Boolean unmap)
#else
xbaeCommitEdit(mw, event, unmap)
XbaeMatrixWidget mw;
XEvent *event;
Boolean unmap;
#endif
{
Boolean commit;
if (!XtIsManaged(TextChild(mw)))
return True;
/*
* Attempt to commit the edit
*/
commit = DoCommitEdit(mw, event);
/*
* If the commit succeeded and we are supposed to unmap the textField,
* then hide the textField and traverse out
*/
if (commit && unmap)
{
XtUnmanageChild(TextChild(mw));
XmProcessTraversal(TextChild(mw), XmTRAVERSE_RIGHT);
}
return commit;
}
/*
* Matrix cancel_edit method
*/
void
#if NeedFunctionPrototypes
xbaeCancelEdit(XbaeMatrixWidget mw, Boolean unmap)
#else
xbaeCancelEdit(mw, unmap)
XbaeMatrixWidget mw;
Boolean unmap;
#endif
{
if (!XtIsManaged(TextChild(mw)))
return;
/*
* If unmap is set, hide the textField and traverse out.
*/
if (unmap)
{
XtUnmanageChild(TextChild(mw));
XmProcessTraversal(TextChild(mw), XmTRAVERSE_RIGHT);
}
/*
* Don't unmap, just restore original contents
*/
else if (!mw->matrix.draw_cell_callback)
{
XtVaSetValues(TextChild(mw),
XmNvalue, (mw->matrix.cells ?
mw->matrix.cells[mw->matrix.current_row]
[mw->matrix.current_column] : ""),
NULL);
}
else
{
/* Ask the application what should be in the cell */
String string;
Pixmap pixmap, mask;
Pixel bg, fg;
int width, height, depth;
if (xbaeGetDrawCellValue(mw, mw->matrix.current_row,
mw->matrix.current_column, &string,
&pixmap, &mask, &width, &height,
&bg, &fg, &depth) == XbaeString)
XtVaSetValues(TextChild(mw), XmNvalue, string, NULL);
}
}
/*
* Matrix add_rows method
*/
void
xbaeAddRows(mw, position, rows, labels, colors, backgrounds, num_rows)
XbaeMatrixWidget mw;
int position;
String *rows;
String *labels;
Pixel *colors;
Pixel *backgrounds;
int num_rows;
{
Boolean haveVSB, haveHSB;
/*
* Do some error checking.
*/
if (num_rows <= 0)
return;
if (position < 0 || position > mw->matrix.rows)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"addRows", "badPosition", "XbaeMatrix",
"XbaeMatrix: Position out of bounds in AddRows.",
NULL, 0);
return;
}
haveVSB = XtIsManaged(VertScrollChild(mw));
haveHSB = XtIsManaged(HorizScrollChild(mw));
/*
* If we add rows, and there is no drawCellCallback, we must allocate
* the cells array to prevent potential disaster
*/
if (!mw->matrix.cells && !mw->matrix.draw_cell_callback)
xbaeCopyCells(mw);
/*
* Add the new rows into the internal cells/labels data structure.
*/
AddRowsToTable(mw, position, rows, labels, colors, backgrounds, num_rows);
/*
* Reconfig the VSB maximum.
*/
XtVaSetValues(VertScrollChild(mw),
XmNmaximum, mw->matrix.rows ?
(mw->matrix.rows - (int) mw->matrix.fixed_rows -
(int) mw->matrix.trailing_fixed_rows) : 1,
NULL);
/*
* Relayout.
*/
xbaeResize(mw);
/*
* Call our cancel_edit method since the rows shifted underneath us
*/
(*((XbaeMatrixWidgetClass) XtClass(mw))->matrix_class.cancel_edit)
(mw, True);
if (!mw->matrix.disable_redisplay && XtIsRealized((Widget)mw))
{
Rectangle rect;
int x, y;
/*
* Determine which part of the non clip region needs to be
* redisplayed
*/
if (position >= (int)mw->matrix.fixed_rows)
{
xbaeRowColToXY(mw, position, mw->matrix.fixed_columns, &x, &y);
if (mw->matrix.scrollbar_placement == XmTOP_LEFT ||
mw->matrix.scrollbar_placement == XmTOP_RIGHT)
y += HORIZ_SB_SPACE(mw);
y += ROW_HEIGHT(mw) * mw->matrix.fixed_rows +
COLUMN_LABEL_HEIGHT(mw);
}
else
{
if (mw->matrix.scrollbar_placement == XmTOP_LEFT ||
mw->matrix.scrollbar_placement == XmTOP_RIGHT)
y = HORIZ_SB_SPACE(mw);
else
y = 0;
y += ROW_HEIGHT(mw) * position + COLUMN_LABEL_HEIGHT(mw);
}
SETRECT(rect, 0, y, mw->core.width, mw->core.height);
xbaeRedrawLabelsAndFixed(mw, &rect);
XClearArea(XtDisplay(mw), XtWindow(ClipChild(mw)),
rect.x1, rect.y1,
rect.x2 - rect.x1, rect.y2 - rect.y1, True);
/*
* If the scrollbars have just been mapped and there are
* labels then the labels shift around. The labels need
* to be redrawn
*/
if (!haveVSB && XtIsManaged(VertScrollChild(mw)) &&
mw->matrix.column_labels)
XClearArea(XtDisplay(mw), XtWindow(mw),
0, HORIZ_SB_OFFSET(mw), 0,
COLUMN_LABEL_HEIGHT(mw), True);
if ((!haveHSB && XtIsManaged(VertScrollChild(mw)) &&
mw->matrix.row_labels) ||
((mw->matrix.scrollbar_placement == XmTOP_LEFT ||
mw->matrix.scrollbar_placement == XmBOTTOM_LEFT) &&
!haveVSB && XtIsManaged(VertScrollChild(mw))))
XClearArea(XtDisplay(mw), XtWindow(mw),
VERT_SB_OFFSET(mw), 0, ROW_LABEL_WIDTH(mw), 0, True);
}
}
/*
* Matrix delete_rows method
*/
void
xbaeDeleteRows(mw, position, num_rows)
XbaeMatrixWidget mw;
int position;
int num_rows;
{
int max, value;
Boolean haveVSB;
Boolean haveHSB;
/*
* Do some error checking.
*/
if (num_rows <= 0)
return;
if (position < 0 || position + num_rows > mw->matrix.rows)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"deleteRows", "badPosition", "XbaeMatrix",
"XbaeMatrix: Position out of bounds in DeleteRows.",
NULL, 0);
return;
}
if (num_rows > (mw->matrix.rows - (int)mw->matrix.fixed_rows -
(int)mw->matrix.trailing_fixed_rows))
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"deleteRows", "tooMany", "XbaeMatrix",
"XbaeMatrix: Attempting to delete too many rows in DeleteRows.",
NULL, 0);
return;
}
haveVSB = XtIsManaged(VertScrollChild(mw));
haveHSB = XtIsManaged(HorizScrollChild(mw));
/*
* Delete the new rows from the internal cells/labels data structure.
*/
DeleteRowsFromTable(mw, position, num_rows);
/*
* Reconfig the VSB maximum. Reset the sliderSize to avoid warnings.
* Also check the scrollbar value to see that it's not out of range.
*/
XtVaGetValues(VertScrollChild(mw),
XmNvalue, &value,
NULL);
max = mw->matrix.rows ?
(mw->matrix.rows - (int) mw->matrix.fixed_rows -
(int) mw->matrix.trailing_fixed_rows) : 1;
XtVaSetValues(VertScrollChild(mw),
XmNvalue, (value >= max) ? max - 1 : value,
XmNmaximum, mw->matrix.rows - (int) mw->matrix.fixed_rows -
(int) mw->matrix.trailing_fixed_rows ?
(mw->matrix.rows - (int) mw->matrix.fixed_rows -
(int) mw->matrix.trailing_fixed_rows) : 1,
XmNsliderSize, 1,
NULL);
/*
* Relayout.
*/
xbaeResize(mw);
/*
* Call our cancel_edit method since the rows shifted underneath us
*/
(*((XbaeMatrixWidgetClass) XtClass(mw))->matrix_class.cancel_edit)
(mw, True);
if (!mw->matrix.disable_redisplay && XtIsRealized((Widget)mw))
{
Rectangle rect;
int y;
/*
* Determine which part of the non clip region needs to be
* redisplayed
*/
#if 0
dest_y = (position - mw->matrix.fixed_rows) * ROW_HEIGHT(mw);
src_y = dest_y + num_rows * ROW_HEIGHT(mw);
if (XtIsManaged(LeftClip(mw)))
{
if (src_y < LeftClip(mw)->core.height)
{
/* Copy what we can up to replace the deleted rows */
XCopyArea(XtDisplay(mw), XtWindow(LeftClip(mw)),
XtWindow(LeftClip(mw)), mw->matrix.draw_gc,
0, src_y, LeftClip(mw)->core.width,
LeftClip(mw)->core.height - src_y,
0, dest_y);
/* And clear the new area that needs to be redrawn */
XClearArea(XtDisplay(mw), XtWindow(LeftClip(mw)),
0, LeftClip(mw)->core.height - src_y,
LeftClip(mw)->core.width,
LeftClip(mw)->core.height - src_y, True);
}
}
if (XtIsManaged(RightClip(mw)))
{
if (src_y < RightClip(mw)->core.height)
{
XCopyArea(XtDisplay(mw), XtWindow(RightClip(mw)),
XtWindow(RightClip(mw)), mw->matrix.draw_gc,
0, src_y, RightClip(mw)->core.width,
RightClip(mw)->core.height - src_y,
0, dest_y);
XClearArea(XtDisplay(mw), XtWindow(RightClip(mw)),
0, RightClip(mw)->core.height - src_y,
RightClip(mw)->core.width,
RightClip(mw)->core.height - src_y, True);
}
}
#endif
y = ROW_LABEL_OFFSET(mw) + position * ROW_HEIGHT(mw);
SETRECT(rect, 0, y, mw->core.width, mw->core.height - y);
/* xxx could this use an XCopyArea() instead */
XClearArea(XtDisplay(mw), XtWindow(mw),
0, y, mw->core.width, mw->core.height - y, True);
xbaeRedrawLabelsAndFixed(mw, &rect);
y = (position - mw->matrix.fixed_rows) * ROW_HEIGHT(mw);
XClearArea(XtDisplay(mw), XtWindow(ClipChild(mw)),
0, y, rect.x2, mw->core.height - y, True);
/*
* If the scrollbars have just been unmapped and there are
* labels then the labels shift around. The labels need
* to be redrawn
*/
if (haveVSB && !XtIsManaged(VertScrollChild(mw)) &&
mw->matrix.column_labels)
XClearArea(XtDisplay(mw), XtWindow(mw),
0, HORIZ_SB_OFFSET(mw), 0,
COLUMN_LABEL_HEIGHT(mw), True);
if (haveHSB && !XtIsManaged(VertScrollChild(mw)) &&
mw->matrix.row_labels)
XClearArea(XtDisplay(mw), XtWindow(mw),
VERT_SB_OFFSET(mw), 0, ROW_LABEL_WIDTH(mw), 0, True);
#if 0
/*
* If we are deleting rows and there are different cell backgrounds
* or foregrounds and the deleted row was on the visible clip, then
* the colours can get confused.
*/
if (mw->matrix.colors || mw->matrix.even_row_background !=
mw->core.background_pixel || mw->matrix.odd_row_background !=
mw->core.background_pixel)
XbaeClipRedraw(ClipChild(mw));
#endif
}
}
/*
* Matrix add_columns method.
*/
void
xbaeAddColumns(mw, position, columns, labels, widths, max_lengths,
alignments, label_alignments, colors, backgrounds, num_columns)
XbaeMatrixWidget mw;
int position;
String *columns;
String *labels;
short *widths;
int *max_lengths;
unsigned char *alignments;
unsigned char *label_alignments;
Pixel *colors;
Pixel *backgrounds;
int num_columns;
{
Boolean haveVSB;
Boolean haveHSB;
/*
* Do some error checking.
*/
if (num_columns <= 0)
return;
if (position < 0 || position > mw->matrix.columns)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"addColumns", "badPosition", "XbaeMatrix",
"XbaeMatrix: Position out of bounds in AddColumns.",
NULL, 0);
return;
}
if (!widths)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"addColumns", "noWidths", "XbaeMatrix",
"XbaeMatrix: Must specify column widths in AddColumns.",
NULL, 0);
return;
}
/*
* If we add columns, and there is no drawCellCallback, we must allocate
* the cells array to prevent potential disaster
*/
if (!mw->matrix.cells && !mw->matrix.draw_cell_callback)
xbaeCopyCells(mw);
haveVSB = XtIsManaged(VertScrollChild(mw));
haveHSB = XtIsManaged(HorizScrollChild(mw));
/*
* Add the new rows into the internal cells/labels data structure.
*/
AddColumnsToTable(mw, position, columns, labels, widths, max_lengths,
alignments, label_alignments, colors, backgrounds,
num_columns);
/*
* Reconfig the HSB maximum.
*/
XtVaSetValues(HorizScrollChild(mw),
XmNmaximum, NON_FIXED_TOTAL_WIDTH(mw) ?
NON_FIXED_TOTAL_WIDTH(mw) : 1,
NULL);
/*
* Relayout.
*/
xbaeResize(mw);
/*
* Call our cancel_edit method since the columns shifted underneath us
*/
(*((XbaeMatrixWidgetClass) XtClass(mw))->matrix_class.cancel_edit)
(mw, True);
if (!mw->matrix.disable_redisplay && XtIsRealized((Widget)mw))
{
Rectangle rect;
int x, y;
/*
* Determine which part of the non clip region needs to be
* redisplayed
*/
if (position >= (int)mw->matrix.fixed_columns)
{
xbaeRowColToXY(mw, mw->matrix.fixed_columns, position, &x, &y);
if (mw->matrix.scrollbar_placement == XmTOP_LEFT ||
mw->matrix.scrollbar_placement == XmBOTTOM_LEFT)
x += VERT_SB_SPACE(mw);
x += COLUMN_POSITION(mw, mw->matrix.fixed_columns) +
ROW_LABEL_WIDTH(mw);
}
else
{
if (mw->matrix.scrollbar_placement == XmTOP_LEFT ||
mw->matrix.scrollbar_placement == XmBOTTOM_LEFT)
x = VERT_SB_SPACE(mw);
else
x = 0;
x += COLUMN_POSITION(mw, position) + ROW_LABEL_WIDTH(mw);
}
SETRECT(rect, x, 0, mw->core.width, mw->core.height);
xbaeRedrawLabelsAndFixed(mw, &rect);
XClearArea(XtDisplay(mw), XtWindow(ClipChild(mw)),
rect.x1, rect.y1,
rect.x2 - rect.x1, rect.y2 - rect.y1, True);
/*
* If the scrollbars have just been mapped and there are
* labels then the labels shift around. The labels need
* to be redrawn
*/
if ((!haveVSB && XtIsManaged(VertScrollChild(mw)) &&
mw->matrix.column_labels) ||
((mw->matrix.scrollbar_placement == XmTOP_LEFT ||
mw->matrix.scrollbar_placement == XmTOP_RIGHT) &&
!haveHSB && XtIsManaged(HorizScrollChild(mw))))
XClearArea(XtDisplay(mw), XtWindow(mw),
0, HORIZ_SB_OFFSET(mw), 0,
COLUMN_LABEL_HEIGHT(mw), True);
if ((!haveHSB && XtIsManaged(VertScrollChild(mw)) &&
mw->matrix.row_labels) ||
((mw->matrix.scrollbar_placement == XmTOP_LEFT ||
mw->matrix.scrollbar_placement == XmTOP_RIGHT)))
XClearArea(XtDisplay(mw), XtWindow(mw),
VERT_SB_OFFSET(mw), 0, ROW_LABEL_WIDTH(mw), 0, True);
}
}
/*
* Matrix delete_columns method
*/
void
xbaeDeleteColumns(mw, position, num_columns)
XbaeMatrixWidget mw;
int position;
int num_columns;
{
int maxlines;
Boolean haveVSB;
Boolean haveHSB;
/*
* Do some error checking.
*/
if (num_columns <= 0)
return;
if (position < 0 || position + num_columns > mw->matrix.columns)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"deleteColumns", "badPosition", "XbaeMatrix",
"XbaeMatrix: Position out of bounds in DeleteColumns.",
NULL, 0);
return;
}
if (num_columns > (mw->matrix.columns - (int)mw->matrix.fixed_columns -
(int)mw->matrix.trailing_fixed_columns))
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"deleteColumns", "tooMany", "XbaeMatrix",
"XbaeMatrix: Attempting to delete too many columns in DeleteColumns.",
NULL, 0);
return;
}
haveVSB = XtIsManaged(VertScrollChild(mw));
haveHSB = XtIsManaged(HorizScrollChild(mw));
maxlines = mw->matrix.column_label_maxlines;
/*
* Delete the new columns from the internal cells/labels data structure.
*/
DeleteColumnsFromTable(mw, position, num_columns);
/*
* Reconfig the HSB maximum. Reset the sliderSize to avoid warnings.
*/
XtVaSetValues(HorizScrollChild(mw),
XmNvalue, 0, /* value to 0 to stop sb from whinging */
XmNmaximum, NON_FIXED_TOTAL_WIDTH(mw) ?
NON_FIXED_TOTAL_WIDTH(mw) : 1,
XmNsliderSize, 1,
NULL);
/*
* Relayout.
*/
xbaeResize(mw);
/*
* Call our cancel_edit method since the columns shifted underneath us
*/
(*((XbaeMatrixWidgetClass) XtClass(mw))->matrix_class.cancel_edit)
(mw, True);
if (!mw->matrix.disable_redisplay && XtIsRealized((Widget)mw))
{
Rectangle rect;
int x, y;
if (maxlines != mw->matrix.column_label_maxlines)
{
/*
* If a column with a high label gets deleted, then the matrix
* gets pulled up the screen and leaves dangly bits underneath.
* Clear the whole area to ensure correct display and forget the
* rest of the calculation
*/
XClearArea(XtDisplay(mw), XtWindow(mw),
0, 0, 0 /*Full Width*/, 0 /*Full Height*/,
True);
return;
}
/*
* Determine which part of the non clip region needs to be
* redisplayed
*/
if (position >= (int)mw->matrix.fixed_columns)
{
xbaeRowColToXY(mw, mw->matrix.fixed_columns, position, &x, &y);
if (mw->matrix.scrollbar_placement == XmTOP_LEFT ||
mw->matrix.scrollbar_placement == XmBOTTOM_LEFT)
x += VERT_SB_SPACE(mw);
x += COLUMN_POSITION(mw, mw->matrix.fixed_columns) +
ROW_LABEL_WIDTH(mw);
}
else
{
if (mw->matrix.scrollbar_placement == XmTOP_LEFT ||
mw->matrix.scrollbar_placement == XmBOTTOM_LEFT)
x = VERT_SB_SPACE(mw);
else
x = 0;
x += COLUMN_POSITION(mw, position) + ROW_LABEL_WIDTH(mw);
}
SETRECT(rect, x, 0, mw->core.width, mw->core.height);
XClearArea(XtDisplay(mw), XtWindow(mw),
VISIBLE_WIDTH(mw) + FIXED_COLUMN_WIDTH(mw) +
TRAILING_FIXED_COLUMN_WIDTH(mw),
0,
mw->core.width, mw->core.height, True);
xbaeRedrawLabelsAndFixed(mw, &rect);
XClearArea(XtDisplay(mw), XtWindow(ClipChild(mw)),
rect.x1, rect.y1,
rect.x2 - rect.x1, rect.y2 - rect.y1, True);
/*
* If the scrollbars have just been unmapped and there are
* labels then the labels shift around. The labels need
* to be redrawn
*/
if (haveVSB && !XtIsManaged(VertScrollChild(mw)) &&
mw->matrix.column_labels)
XClearArea(XtDisplay(mw), XtWindow(mw),
0, HORIZ_SB_OFFSET(mw), 0,
COLUMN_LABEL_HEIGHT(mw), True);
if (haveHSB && !XtIsManaged(VertScrollChild(mw)) &&
mw->matrix.row_labels)
XClearArea(XtDisplay(mw), XtWindow(mw),
VERT_SB_OFFSET(mw), 0, ROW_LABEL_WIDTH(mw), 0, True);
}
}
/*
* Matrix set_row_colors method
*/
void
#if NeedFunctionPrototypes
xbaeSetRowColors(XbaeMatrixWidget mw, int position, Pixel *colors,
int num_colors, Boolean bg)
#else
xbaeSetRowColors(mw, position, colors, num_colors, bg)
XbaeMatrixWidget mw;
int position;
Pixel *colors;
int num_colors;
Boolean bg;
#endif
{
Rectangle rect;
int i, j;
Pixel **set;
Pixel pixel;
/*
* Do some error checking.
*/
if (num_colors <= 0)
return;
if (position < 0 || position + num_colors > mw->matrix.rows)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"setRowColors", "badPosition", "XbaeMatrix",
"XbaeMatrix: Position out of bounds or too many colors in SetRowColors.",
NULL, 0);
return;
}
/*
* If we don't have any colors yet, malloc them, and initialize
* unused entries to the appropriate color
*/
if ((!bg && !mw->matrix.colors) ||
(bg && !mw->matrix.cell_background))
{
if (!bg)
{
xbaeCreateColors(mw);
set = &mw->matrix.colors[0];
pixel = mw->manager.foreground;
for (i = 0; i < position; i++)
for (j = 0; j < mw->matrix.columns; j++)
set[i][j] = pixel;
for (i = position + num_colors; i < mw->matrix.rows; i++)
for (j = 0; j < mw->matrix.columns; j++)
set[i][j] = pixel;
}
else
xbaeCopyBackgrounds(mw);
}
if (!bg)
set = &mw->matrix.colors[0];
else
set = &mw->matrix.cell_background[0];
/*
* Set each row to the appropriate color
*/
for (i = 0; i < num_colors; i++)
for (j = 0; j < mw->matrix.columns; j++)
set[i + position][j] = colors[i];
if (XtIsRealized((Widget)mw))
{
/*
* Redraw all the visible non-fixed cells. We don't need to clear first
* since only the color changed.
*/
SETRECT(rect,
0, 0,
ClipChild(mw)->core.width - 1, ClipChild(mw)->core.height - 1);
xbaeRedrawCells(mw, &rect);
/*
* Redraw all the visible fixed cells (but not the labels).
* We don't need to clear first since only the color changed.
*/
SETRECT(rect,
ROW_LABEL_WIDTH(mw), COLUMN_LABEL_HEIGHT(mw),
mw->core.width - 1, mw->core.height - 1);
xbaeRedrawLabelsAndFixed(mw, &rect);
}
if (position <= mw->matrix.current_row &&
position + num_colors > mw->matrix.current_row &&
XtIsRealized(TextChild(mw)))
{
if (bg)
XtVaSetValues(TextChild(mw), XmNbackground,
mw->matrix.cell_background[mw->matrix.current_row]
[mw->matrix.current_column],
NULL);
else
XtVaSetValues(TextChild(mw), XmNforeground,
mw->matrix.colors[mw->matrix.current_row]
[mw->matrix.current_column],
NULL);
}
}
/*
* Matrix set_column_colors method
*/
void
#if NeedFunctionPrototypes
xbaeSetColumnColors(XbaeMatrixWidget mw, int position, Pixel *colors,
int num_colors, Boolean bg)
#else
xbaeSetColumnColors(mw, position, colors, num_colors, bg)
XbaeMatrixWidget mw;
int position;
Pixel *colors;
int num_colors;
Boolean bg;
#endif
{
Rectangle rect;
int i, j;
Pixel **set;
Pixel pixel;
/*
* Do some error checking.
*/
if (num_colors <= 0)
return;
if (position < 0 || position + num_colors > mw->matrix.columns)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"setColumnColors", "badPosition", "XbaeMatrix",
"XbaeMatrix: Position out of bounds or too many colors in SetColumnColors.",
NULL, 0);
return;
}
/*
* If we don't have any colors yet, malloc them, and initialize
* unused entries to foreground
*/
if ((!bg && !mw->matrix.colors) ||
(bg && !mw->matrix.cell_background))
{
if (!bg)
{
xbaeCreateColors(mw);
set = &mw->matrix.colors[0];
pixel = mw->manager.foreground;
for (i = 0; i < mw->matrix.rows; i++)
for (j = 0; j < position; j++)
set[i][j] = pixel;
for (i = 0; i < mw->matrix.rows; i++)
for (j = position + num_colors; j < mw->matrix.columns; j++)
set[i][j] = pixel;
}
else
xbaeCopyBackgrounds(mw);
}
if (!bg)
set = &mw->matrix.colors[0];
else
set = &mw->matrix.cell_background[0];
/*
* Set each column to the appropriate color
*/
for (i = 0; i < mw->matrix.rows; i++)
for (j = 0; j < num_colors; j++)
set[i][j + position] = colors[j];
if (XtIsRealized((Widget)mw))
{
/*
* Redraw all the visible non-fixed cells. We don't need to clear first
* since only the color changed.
*/
SETRECT(rect,
0, 0,
ClipChild(mw)->core.width - 1, ClipChild(mw)->core.height - 1);
xbaeRedrawCells(mw, &rect);
/*
* Redraw all the visible fixed cells (but not the labels).
* We don't need to clear first since only the color changed.
*/
SETRECT(rect,
ROW_LABEL_WIDTH(mw), COLUMN_LABEL_HEIGHT(mw),
mw->core.width - 1, mw->core.height - 1);
xbaeRedrawLabelsAndFixed(mw, &rect);
}
if (position <= mw->matrix.current_column &&
position + num_colors > mw->matrix.current_column &&
XtIsRealized(TextChild(mw)))
{
if (bg)
XtVaSetValues(TextChild(mw), XmNbackground,
mw->matrix.cell_background[mw->matrix.current_row]
[mw->matrix.current_column],
NULL);
else
XtVaSetValues(TextChild(mw), XmNforeground,
mw->matrix.colors[mw->matrix.current_row]
[mw->matrix.current_column],
NULL);
}
}
/*
* Matrix set_cell_color method
*/
void
#if NeedFunctionPrototypes
xbaeSetCellColor(XbaeMatrixWidget mw, int row, int column, Pixel color, Boolean bg)
#else
xbaeSetCellColor(mw, row, column, color, bg)
XbaeMatrixWidget mw;
int row;
int column;
Pixel color;
Boolean bg;
#endif
{
int i, j;
Pixel **set;
Pixel pixel;
/*
* Do some error checking.
*/
if (row >= mw->matrix.rows || row < 0 ||
column >= mw->matrix.columns || column < 0)
{
XtAppWarningMsg(
XtWidgetToApplicationContext((Widget) mw),
"xbaeSetCellColor", "badIndex", "XbaeMatrix",
"XbaeMatrix: Row or column out of bounds for xbaeSetCellColor.",
NULL, 0);
return;
}
/*
* If we don't have any colors yet, malloc them and initialize them
*/
if ((!bg && !mw->matrix.colors) ||
(bg && !mw->matrix.cell_background))
{
if (!bg)
{
xbaeCreateColors(mw);
set = &mw->matrix.colors[0];
pixel = mw->manager.foreground;
for (i = 0; i < mw->matrix.rows; i++)
for (j = 0; j < mw->matrix.columns; j++)
set[i][j] = pixel;
}
else
xbaeCopyBackgrounds(mw);
}
if (!bg)
set = &mw->matrix.colors[0];
else
set = &mw->matrix.cell_background[0];
/*
* Set the cell's color
*/
set[row][column] = color;
if (XtIsRealized((Widget)mw))
{
/*
* Redraw the cell if it is visible
*/
if (xbaeIsCellVisible(mw, row, column))
xbaeDrawCell(mw, row, column);
}
if (row == mw->matrix.current_row &&
column == mw->matrix.current_column && XtIsRealized(TextChild(mw)))
{
if (bg)
XtVaSetValues(TextChild(mw), XmNbackground,
mw->matrix.cell_background[mw->matrix.current_row]
[mw->matrix.current_column],
NULL);
else
XtVaSetValues(TextChild(mw), XmNforeground,
mw->matrix.colors[mw->matrix.current_row]
[mw->matrix.current_column],
NULL);
}
}
syntax highlighted by Code2HTML, v. 0.9.1