463 lines
11 KiB
C
463 lines
11 KiB
C
|
/** \file
|
||
|
* \brief iupmatrix control
|
||
|
* auxiliary functions
|
||
|
*
|
||
|
* See Copyright Notice in "iup.h"
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include "iup.h"
|
||
|
#include "iupcbs.h"
|
||
|
|
||
|
#include <cd.h>
|
||
|
|
||
|
#include "iup_object.h"
|
||
|
#include "iup_attrib.h"
|
||
|
#include "iup_str.h"
|
||
|
#include "iup_drvfont.h"
|
||
|
#include "iup_stdcontrols.h"
|
||
|
#include "iup_drv.h"
|
||
|
|
||
|
#include "iupmat_def.h"
|
||
|
#include "iupmat_aux.h"
|
||
|
#include "iupmat_getset.h"
|
||
|
#include "iupmat_numlc.h"
|
||
|
|
||
|
|
||
|
int iupMatrixAuxIsFullVisibleLast(ImatLinColData *p)
|
||
|
{
|
||
|
int i, sum = 0;
|
||
|
|
||
|
for(i = p->first; i <= p->last; i++)
|
||
|
{
|
||
|
sum += p->dt[i].size;
|
||
|
if (i==p->first)
|
||
|
sum -= p->first_offset;
|
||
|
}
|
||
|
|
||
|
if (sum > p->current_visible_size)
|
||
|
return 0;
|
||
|
else
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int iupMatrixAuxIsCellStartVisible(Ihandle* ih, int lin, int col)
|
||
|
{
|
||
|
if (iupMatrixAuxIsCellVisible(ih, lin, col))
|
||
|
{
|
||
|
if (col == ih->data->columns.first && ih->data->columns.first_offset!=0)
|
||
|
return 0;
|
||
|
if (lin == ih->data->lines.first && ih->data->lines.first_offset!=0)
|
||
|
return 0;
|
||
|
if (col == ih->data->columns.last && !iupMatrixAuxIsFullVisibleLast(&ih->data->columns))
|
||
|
return 0;
|
||
|
if (lin == ih->data->lines.last && !iupMatrixAuxIsFullVisibleLast(&ih->data->lines))
|
||
|
return 0;
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int iupMatrixAuxIsCellVisible(Ihandle* ih, int lin, int col)
|
||
|
{
|
||
|
if ((col < ih->data->columns.num_noscroll) &&
|
||
|
(lin >= ih->data->lines.first) && (lin <= ih->data->lines.last))
|
||
|
return 1;
|
||
|
|
||
|
if ((lin < ih->data->lines.num_noscroll) &&
|
||
|
(col >= ih->data->columns.first) && (col <= ih->data->columns.last))
|
||
|
return 1;
|
||
|
|
||
|
if ((lin >= ih->data->lines.first) && (lin <= ih->data->lines.last) &&
|
||
|
(col >= ih->data->columns.first) && (col <= ih->data->columns.last))
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void iupMatrixAuxAdjustFirstFromLast(ImatLinColData* p)
|
||
|
{
|
||
|
int i, sum = 0;
|
||
|
|
||
|
/* adjust "first" according to "last" */
|
||
|
|
||
|
i = p->last;
|
||
|
sum = p->dt[i].size;
|
||
|
while (i>p->num_noscroll && sum < p->current_visible_size)
|
||
|
{
|
||
|
i--;
|
||
|
sum += p->dt[i].size;
|
||
|
}
|
||
|
|
||
|
if (i == p->num_noscroll && sum < p->current_visible_size)
|
||
|
{
|
||
|
/* if there are room for everyone then position at start */
|
||
|
p->first = p->num_noscroll;
|
||
|
p->first_offset = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* the "while" found an index for first */
|
||
|
p->first = i;
|
||
|
|
||
|
/* position at the remaing space */
|
||
|
p->first_offset = sum - p->current_visible_size;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void iupMatrixAuxAdjustFirstFromScrollPos(ImatLinColData* p, int scroll_pos)
|
||
|
{
|
||
|
int index, sp, offset = 0;
|
||
|
|
||
|
sp = 0;
|
||
|
for(index = p->num_noscroll; index < p->num; index++)
|
||
|
{
|
||
|
sp += p->dt[index].size;
|
||
|
if (sp > scroll_pos)
|
||
|
{
|
||
|
sp -= p->dt[index].size; /* get the previous value */
|
||
|
offset = scroll_pos - sp;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (index == p->num)
|
||
|
{
|
||
|
if (p->num == p->num_noscroll)
|
||
|
{
|
||
|
/* did NOT go trough the "for" above */
|
||
|
offset = scroll_pos;
|
||
|
index = p->num_noscroll; /* redundant, just for the record */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* go all the way trough the "for" above, but still sp < scroll_pos */
|
||
|
offset = scroll_pos - sp;
|
||
|
index = p->num-1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p->first = index;
|
||
|
p->first_offset = offset;
|
||
|
}
|
||
|
|
||
|
/* Calculate the size, in pixels, of the invisible columns/lines,
|
||
|
the left/above of the first column/line.
|
||
|
In fact the start position of the visible area.
|
||
|
Depends on the first visible column/line.
|
||
|
-> m : choose will operate on lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL]
|
||
|
*/
|
||
|
void iupMatrixAuxUpdateScrollPos(Ihandle* ih, int m)
|
||
|
{
|
||
|
int i, sb, SB, scroll_pos;
|
||
|
char* POS;
|
||
|
ImatLinColData *p;
|
||
|
|
||
|
sb = iupMatrixGetScrollbar(ih);
|
||
|
|
||
|
if (m == IMAT_PROCESS_LIN)
|
||
|
{
|
||
|
p = &(ih->data->lines);
|
||
|
SB = IUP_SB_VERT;
|
||
|
POS = "POSY";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p = &(ih->data->columns);
|
||
|
SB = IUP_SB_HORIZ;
|
||
|
POS = "POSX";
|
||
|
}
|
||
|
|
||
|
/* "first" was changed, so update "last" and the scroll pos */
|
||
|
|
||
|
if (p->total_visible_size <= p->current_visible_size)
|
||
|
{
|
||
|
/* the matrix is fully visible */
|
||
|
p->first = p->num_noscroll;
|
||
|
p->first_offset = 0;
|
||
|
p->last = p->num==p->num_noscroll? p->num_noscroll: p->num-1;
|
||
|
|
||
|
if (sb & SB)
|
||
|
IupSetAttribute(ih, POS, "0");
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* must check if it is a valid position */
|
||
|
scroll_pos = 0;
|
||
|
for(i = p->num_noscroll; i < p->first; i++)
|
||
|
scroll_pos += p->dt[i].size;
|
||
|
scroll_pos += p->first_offset;
|
||
|
|
||
|
if (scroll_pos + p->current_visible_size > p->total_visible_size)
|
||
|
{
|
||
|
/* invalid condition, must recalculate so it is valid */
|
||
|
scroll_pos = p->total_visible_size - p->current_visible_size;
|
||
|
|
||
|
/* position first and first_offset, according to scroll pos */
|
||
|
iupMatrixAuxAdjustFirstFromScrollPos(p, scroll_pos);
|
||
|
}
|
||
|
|
||
|
/* update last */
|
||
|
iupMatrixAuxUpdateLast(p);
|
||
|
|
||
|
/* update scroll pos */
|
||
|
if (sb & SB)
|
||
|
IupSetInt(ih, POS, scroll_pos);
|
||
|
}
|
||
|
|
||
|
/* Calculate which is the last visible column/line of the matrix.
|
||
|
Depends on the first visible column/line. */
|
||
|
void iupMatrixAuxUpdateLast(ImatLinColData *p)
|
||
|
{
|
||
|
if (p->current_visible_size > 0)
|
||
|
{
|
||
|
int i, sum = 0;
|
||
|
|
||
|
/* Find which is the last column/line.
|
||
|
Start in the first visible and continue adding the widths
|
||
|
up to the visible size */
|
||
|
for(i = p->first; i < p->num; i++)
|
||
|
{
|
||
|
sum += p->dt[i].size;
|
||
|
if (i==p->first)
|
||
|
sum -= p->first_offset;
|
||
|
|
||
|
if(sum >= p->current_visible_size)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (i == p->num)
|
||
|
{
|
||
|
if (p->num == p->num_noscroll)
|
||
|
p->last = p->num_noscroll;
|
||
|
else
|
||
|
p->last = p->num-1;
|
||
|
}
|
||
|
else
|
||
|
p->last = i;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* There is no space for any column, set the last column as 0 */
|
||
|
p->last = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Fill the sizes array with the width/heigh of all the columns/lines.
|
||
|
Calculate the value of total_visible_size */
|
||
|
static void iMatrixAuxFillSizeVec(Ihandle* ih, int m)
|
||
|
{
|
||
|
int i;
|
||
|
ImatLinColData *p;
|
||
|
|
||
|
if (m == IMAT_PROCESS_LIN)
|
||
|
p = &(ih->data->lines);
|
||
|
else
|
||
|
p = &(ih->data->columns);
|
||
|
|
||
|
/* Calculate total width/height of the matrix and the width/height of each column */
|
||
|
p->total_visible_size = 0;
|
||
|
p->total_size = 0;
|
||
|
for (i = 0; i < p->num; i++)
|
||
|
{
|
||
|
if (m == IMAT_PROCESS_LIN)
|
||
|
p->dt[i].size = iupMatrixGetLineHeight(ih, i, 1);
|
||
|
else
|
||
|
p->dt[i].size = iupMatrixGetColumnWidth(ih, i, 1);
|
||
|
|
||
|
if (i >= p->num_noscroll)
|
||
|
p->total_visible_size += p->dt[i].size;
|
||
|
|
||
|
p->total_size += p->dt[i].size;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int iMatrixAuxUpdateVisibleSize(Ihandle* ih, int m)
|
||
|
{
|
||
|
char *D, *AUTOHIDE, *MAX;
|
||
|
ImatLinColData *p;
|
||
|
int canvas_size, fixed_size, i, SB;
|
||
|
|
||
|
if (m == IMAT_PROCESS_LIN)
|
||
|
{
|
||
|
D = "DY";
|
||
|
MAX = "YMAX";
|
||
|
|
||
|
/* when configuring the vertical scrollbar check if horizontal scrollbar can be hidden */
|
||
|
AUTOHIDE = "XAUTOHIDE";
|
||
|
SB = IUP_SB_HORIZ;
|
||
|
|
||
|
p = &(ih->data->lines);
|
||
|
canvas_size = iupMatrixGetHeight(ih);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
D = "DX";
|
||
|
MAX = "XMAX";
|
||
|
|
||
|
/* when configuring the horizontal scrollbar check if vertical scrollbar can be hidden */
|
||
|
AUTOHIDE = "YAUTOHIDE";
|
||
|
SB = IUP_SB_VERT;
|
||
|
|
||
|
p = &(ih->data->columns);
|
||
|
canvas_size = iupMatrixGetWidth(ih);
|
||
|
}
|
||
|
|
||
|
fixed_size = 0;
|
||
|
for (i=0; i<p->num_noscroll; i++)
|
||
|
fixed_size += p->dt[i].size;
|
||
|
|
||
|
/* Matrix useful area is the current size minus the non scrollable area */
|
||
|
p->current_visible_size = canvas_size - fixed_size;
|
||
|
if (p->current_visible_size > p->total_visible_size)
|
||
|
p->current_visible_size = p->total_visible_size;
|
||
|
|
||
|
if (!p->total_visible_size || p->current_visible_size == p->total_visible_size)
|
||
|
{
|
||
|
IupSetAttribute(ih, MAX, "0");
|
||
|
IupSetAttribute(ih, D, "0"); /* this can generate resize+redraw events */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int sb = iupMatrixGetScrollbar(ih);
|
||
|
if (ih->data->limit_expand && (sb & SB) && iupAttribGetBoolean(ih, AUTOHIDE))
|
||
|
{
|
||
|
/* Must perform an extra check or the scrollbar will be always visible */
|
||
|
int sb_size = iupMatrixGetScrollbarSize(ih);
|
||
|
if (p->current_visible_size + sb_size == p->total_visible_size)
|
||
|
p->current_visible_size = p->total_visible_size;
|
||
|
}
|
||
|
|
||
|
IupSetInt(ih, MAX, p->total_visible_size);
|
||
|
IupSetInt(ih, D, p->current_visible_size); /* this can generate resize+redraw events */
|
||
|
}
|
||
|
|
||
|
return IupGetInt(ih, "SB_RESIZE");
|
||
|
}
|
||
|
|
||
|
int iupMatrixAuxCalcSizes(Ihandle* ih)
|
||
|
{
|
||
|
int sb_resize_col, sb_resize_lin;
|
||
|
ih->data->need_calcsize = 0; /* do it before UpdateVisibleSize */
|
||
|
|
||
|
iMatrixAuxFillSizeVec(ih, IMAT_PROCESS_COL);
|
||
|
iMatrixAuxFillSizeVec(ih, IMAT_PROCESS_LIN);
|
||
|
|
||
|
/* this could change the size of the drawing area,
|
||
|
and trigger a resize event, then another calcsize. */
|
||
|
sb_resize_col = iMatrixAuxUpdateVisibleSize(ih, IMAT_PROCESS_COL);
|
||
|
sb_resize_lin = iMatrixAuxUpdateVisibleSize(ih, IMAT_PROCESS_LIN);
|
||
|
|
||
|
/* when removing lines the first can be positioned after the last line */
|
||
|
if (ih->data->lines.first > ih->data->lines.num-1)
|
||
|
{
|
||
|
ih->data->lines.first_offset = 0;
|
||
|
if (ih->data->lines.num == ih->data->lines.num_noscroll)
|
||
|
ih->data->lines.first = ih->data->lines.num_noscroll;
|
||
|
else
|
||
|
ih->data->lines.first = ih->data->lines.num-1;
|
||
|
}
|
||
|
if (ih->data->columns.first > ih->data->columns.num-1)
|
||
|
{
|
||
|
ih->data->columns.first_offset = 0;
|
||
|
if (ih->data->columns.num == ih->data->columns.num_noscroll)
|
||
|
ih->data->columns.first = ih->data->columns.num_noscroll;
|
||
|
else
|
||
|
ih->data->columns.first = ih->data->columns.num-1;
|
||
|
}
|
||
|
|
||
|
/* make sure scroll pos is consistent */
|
||
|
iupMatrixAuxUpdateScrollPos(ih, IMAT_PROCESS_COL);
|
||
|
iupMatrixAuxUpdateScrollPos(ih, IMAT_PROCESS_LIN);
|
||
|
|
||
|
return sb_resize_col || sb_resize_lin;
|
||
|
}
|
||
|
|
||
|
int iupMatrixAuxCallLeaveCellCb(Ihandle* ih)
|
||
|
{
|
||
|
if (ih->data->columns.num > 1 && ih->data->lines.num > 1)
|
||
|
{
|
||
|
IFnii cb = (IFnii)IupGetCallback(ih, "LEAVEITEM_CB");
|
||
|
if(cb)
|
||
|
return cb(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell);
|
||
|
}
|
||
|
return IUP_DEFAULT;
|
||
|
}
|
||
|
|
||
|
void iupMatrixAuxCallEnterCellCb(Ihandle* ih)
|
||
|
{
|
||
|
if (ih->data->columns.num > 1 && ih->data->lines.num > 1)
|
||
|
{
|
||
|
IFnii cb = (IFnii)IupGetCallback(ih, "ENTERITEM_CB");
|
||
|
if (cb)
|
||
|
cb(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int iupMatrixAuxCallEditionCbLinCol(Ihandle* ih, int lin, int col, int mode, int update)
|
||
|
{
|
||
|
IFniiii cb;
|
||
|
|
||
|
if (iupAttribGetBoolean(ih, "READONLY"))
|
||
|
return IUP_IGNORE;
|
||
|
|
||
|
cb = (IFniiii)IupGetCallback(ih, "EDITION_CB");
|
||
|
if (cb)
|
||
|
{
|
||
|
if (lin != 0 && ih->data->sort_has_index)
|
||
|
lin = ih->data->sort_line_index[lin];
|
||
|
|
||
|
return cb(ih, lin, col, mode, update);
|
||
|
}
|
||
|
return IUP_DEFAULT;
|
||
|
}
|
||
|
|
||
|
static void iMatrixAuxCopyValue(Ihandle* ih, int lin1, int col1, int lin2, int col2)
|
||
|
{
|
||
|
char* value = iupMatrixGetValue(ih, lin1, col1);
|
||
|
iupMatrixModifyValue(ih, lin2, col2, value);
|
||
|
}
|
||
|
|
||
|
void iupMatrixAuxCopyLin(Ihandle* ih, int from_lin, int to_lin)
|
||
|
{
|
||
|
int col, columns_num = ih->data->columns.num;
|
||
|
|
||
|
/* since we can not undo the attribute copy, disable data undo */
|
||
|
int old_undo = ih->data->undo_redo;
|
||
|
ih->data->undo_redo = 0;
|
||
|
|
||
|
for(col = 0; col < columns_num; col++)
|
||
|
iMatrixAuxCopyValue(ih, from_lin, col, to_lin, col);
|
||
|
|
||
|
ih->data->undo_redo = old_undo;
|
||
|
|
||
|
iupBaseCallValueChangedCb(ih);
|
||
|
|
||
|
iupMatrixCopyLinAttributes(ih, from_lin, to_lin);
|
||
|
}
|
||
|
|
||
|
void iupMatrixAuxCopyCol(Ihandle* ih, int from_col, int to_col)
|
||
|
{
|
||
|
int lin, lines_num = ih->data->lines.num;
|
||
|
|
||
|
/* since we can not undo the attribute copy, disable data undo */
|
||
|
int old_undo = ih->data->undo_redo;
|
||
|
ih->data->undo_redo = 0;
|
||
|
|
||
|
for(lin = 0; lin < lines_num; lin++)
|
||
|
iMatrixAuxCopyValue(ih, lin, from_col, lin, to_col);
|
||
|
|
||
|
ih->data->undo_redo = old_undo;
|
||
|
|
||
|
iupBaseCallValueChangedCb(ih);
|
||
|
|
||
|
iupMatrixCopyColAttributes(ih, from_col, to_col);
|
||
|
}
|