419 lines
13 KiB
C
Executable File
419 lines
13 KiB
C
Executable File
/** \file
|
|
* \brief IupMatrix control core
|
|
*
|
|
* See Copyright Notice in "iup.h"
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include "iup.h"
|
|
#include "iupcbs.h"
|
|
#include "iupcontrols.h"
|
|
|
|
#include <cd.h>
|
|
|
|
#include "iup_object.h"
|
|
#include "iup_attrib.h"
|
|
#include "iup_str.h"
|
|
#include "iup_stdcontrols.h"
|
|
#include "iup_controls.h"
|
|
#include "iup_register.h"
|
|
|
|
#include "iupmat_def.h"
|
|
#include "iupmat_getset.h"
|
|
#include "iupmat_draw.h"
|
|
#include "iupmat_aux.h"
|
|
|
|
|
|
/* Exported to IupMatrixEx */
|
|
char* iupMatrixExGetCellValue(Ihandle* ih, int lin, int col, int display)
|
|
{
|
|
if (display)
|
|
return iupMatrixGetValueDisplay(ih, lin, col); /* Display value */
|
|
else
|
|
return iupMatrixGetValue(ih, lin, col); /* Internal value (Maximum Precision) */
|
|
}
|
|
|
|
/* Exported to IupMatrixEx */
|
|
void iupMatrixExSetCellValue(Ihandle* ih, int lin, int col, const char* value)
|
|
{
|
|
iupMatrixModifyValue(ih, lin, col, value);
|
|
}
|
|
|
|
static int iMatrixInitNumericColumns(Ihandle* ih, int col)
|
|
{
|
|
if (!iupMATRIX_CHECK_COL(ih, col))
|
|
return 0;
|
|
|
|
if (!ih->data->numeric_columns)
|
|
ih->data->numeric_columns = (ImatNumericData*)calloc(ih->data->columns.num_alloc, sizeof(ImatNumericData));
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int iMatrixSetNumericFlag(Ihandle* ih, int col, unsigned char attr, int set)
|
|
{
|
|
if (!iMatrixInitNumericColumns(ih, col))
|
|
return 0;
|
|
|
|
if (set)
|
|
ih->data->numeric_columns[col].flags |= attr;
|
|
else
|
|
ih->data->numeric_columns[col].flags &= ~attr;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int iMatrixSetNumericQuantityIndexAttrib(Ihandle* ih, int col, const char* value)
|
|
{
|
|
int quantity;
|
|
int set = iupStrToInt(value, &quantity); /* if NULL or fail will unset */
|
|
if (iMatrixSetNumericFlag(ih, col, IMAT_IS_NUMERIC, set) && set)
|
|
{
|
|
/* no need to check for a valid quantity since it is done by the actual unit implementation */
|
|
ih->data->numeric_columns[col].quantity = (unsigned char)quantity;
|
|
ih->data->numeric_convert_func = (ImatNumericConvertFunc)IupGetCallback(ih, "NUMERICCONVERT_FUNC"); /* valid only during set of NUMERICQUANTITY */
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int iMatrixSetNumericFormatAttrib(Ihandle* ih, int col, const char* value)
|
|
{
|
|
return iMatrixSetNumericFlag(ih, col, IMAT_HAS_FORMAT, value!=NULL);
|
|
}
|
|
|
|
static int iMatrixSetNumericFormatPrecisionAttrib(Ihandle* ih, int col, const char* value)
|
|
{
|
|
int precision;
|
|
if (iupStrToInt(value, &precision))
|
|
{
|
|
if (col == IUP_INVALID_ID)
|
|
IupSetStrf(ih, "NUMERICFORMATDEF", "%%.%df", precision);
|
|
else
|
|
IupSetStrfId(ih, "NUMERICFORMAT", col, "%%.%df", precision);
|
|
}
|
|
else
|
|
{
|
|
if (col == IUP_INVALID_ID)
|
|
IupSetAttribute(ih, "NUMERICFORMATDEF", NULL);
|
|
else
|
|
IupSetAttributeId(ih, "NUMERICFORMAT", col, NULL);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static char* iMatrixGetNumericDecimalSymbolAttrib(Ihandle* ih)
|
|
{
|
|
char* value = iupAttribGet(ih, "NUMERICDECIMALSYMBOL");
|
|
if (!value)
|
|
value = IupGetGlobal("DEFAULTDECIMALSYMBOL");
|
|
return value;
|
|
}
|
|
|
|
static char* iMatrixGetNumericFormatPrecisionAttrib(Ihandle* ih, int col)
|
|
{
|
|
int precision;
|
|
char* value = iupAttribGetId(ih, "NUMERICFORMAT", col);
|
|
if (!value)
|
|
value = iupMatrixGetNumericFormatDef(ih);
|
|
|
|
if (!value)
|
|
return NULL;
|
|
|
|
precision = iupStrGetFormatPrecision(value);
|
|
if (precision == -1)
|
|
return NULL;
|
|
|
|
return iupStrReturnInt(precision);
|
|
}
|
|
|
|
static int iMatrixSetNumericFormatTitleAttrib(Ihandle* ih, int col, const char* value)
|
|
{
|
|
return iMatrixSetNumericFlag(ih, col, IMAT_HAS_FORMATTITLE, value!=NULL);
|
|
}
|
|
|
|
static int iMatrixSetNumericUnitIndexAttrib(Ihandle* ih, int col, const char* value)
|
|
{
|
|
int unit;
|
|
if (iupStrToInt(value, &unit))
|
|
{
|
|
if (!iMatrixInitNumericColumns(ih, col))
|
|
return 0;
|
|
|
|
/* no need to check for a valid unit since it is done by the actual unit implementation */
|
|
ih->data->numeric_columns[col].unit = (unsigned char)unit;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int iMatrixSetNumericUnitShownIndexAttrib(Ihandle* ih, int col, const char* value)
|
|
{
|
|
int unit_shown;
|
|
if (iupStrToInt(value, &unit_shown))
|
|
{
|
|
if (!iMatrixInitNumericColumns(ih, col))
|
|
return 0;
|
|
|
|
/* no need to check for a valid unit since it is done by the actual unit implementation */
|
|
ih->data->numeric_columns[col].unit_shown = (unsigned char)unit_shown;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static IFniii iMatrixQSort_sort_cb = NULL;
|
|
static Ihandle* iMatrixQSort_ih = NULL;
|
|
static int iMatrixQSort_col = 0;
|
|
|
|
static int iMatrixCompareCallbackFunc(const void* elem1, const void* elem2)
|
|
{
|
|
int lin1 = *((int*)elem1);
|
|
int lin2 = *((int*)elem2);
|
|
return iMatrixQSort_sort_cb(iMatrixQSort_ih, iMatrixQSort_col, lin1, lin2);
|
|
}
|
|
|
|
typedef struct _ImatSortNumber {
|
|
int lin;
|
|
double number;
|
|
} ImatSortNumber;
|
|
|
|
static int iMatrixCompareNumberFunc(const void* elem1, const void* elem2)
|
|
{
|
|
ImatSortNumber* num1 = (ImatSortNumber*)elem1;
|
|
ImatSortNumber* num2 = (ImatSortNumber*)elem2;
|
|
if (num1->number < num2->number)
|
|
return -1;
|
|
if (num1->number > num2->number)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int iMatrixQSort_utf8 = 0;
|
|
static int iMatrixQSort_casesensitive = 1;
|
|
|
|
typedef struct _ImatSortText {
|
|
int lin;
|
|
char* text;
|
|
} ImatSortText;
|
|
|
|
static int iMatrixCompareTextFunc(const void* elem1, const void* elem2)
|
|
{
|
|
ImatSortText* txt1 = (ImatSortText*)elem1;
|
|
ImatSortText* txt2 = (ImatSortText*)elem2;
|
|
if ((!txt1->text || txt1->text[0]==0) && (!txt2->text || txt2->text[0]==0)) return 0;
|
|
if (!txt1->text || txt1->text[0]==0) return -1; /* txt1 < txt2 => -1 */
|
|
if (!txt2->text || txt2->text[0]==0) return 1;
|
|
return iupStrCompare(txt1->text, txt2->text, iMatrixQSort_casesensitive, iMatrixQSort_utf8);
|
|
}
|
|
|
|
static int iMatrixSetSortColumnAttrib(Ihandle* ih, int col, const char* value)
|
|
{
|
|
int lines_num = ih->data->lines.num;
|
|
int lin, lin1=1, lin2=lines_num-1; /* ALL */
|
|
int ascending;
|
|
int* sort_line_index;
|
|
IFniii sort_cb;
|
|
|
|
/* Notice that sort_line_index[0] is always 0 */
|
|
|
|
if (!ih->data->sort_line_index)
|
|
ih->data->sort_line_index = (int*)calloc(ih->data->lines.num_alloc, sizeof(int));
|
|
|
|
sort_line_index = ih->data->sort_line_index;
|
|
|
|
if (!ih->data->sort_has_index)
|
|
{
|
|
for (lin = 0; lin < lines_num; lin++)
|
|
sort_line_index[lin] = lin;
|
|
}
|
|
|
|
if (iupStrEqualNoCase(value, "RESET"))
|
|
{
|
|
ih->data->sort_has_index = 0;
|
|
iupAttribSetId(ih, "SORTSIGN", ih->data->last_sort_col, NULL);
|
|
ih->data->last_sort_col = 0;
|
|
|
|
iupMatrixDraw(ih, 1);
|
|
iupAttribSet(ih, "SORTCOLUMNINTERVAL", NULL);
|
|
return 0;
|
|
}
|
|
|
|
if (iupStrEqualNoCase(value, "INVERT"))
|
|
{
|
|
int l1, l2;
|
|
|
|
if (!ih->data->sort_has_index)
|
|
return 0;
|
|
|
|
IupGetIntInt(ih, "SORTCOLUMNINTERVAL", &lin1, &lin2);
|
|
|
|
for (l1=lin1,l2=lin2; l1<l2; ++l1,--l2)
|
|
{
|
|
int tmp = sort_line_index[l1];
|
|
sort_line_index[l1] = sort_line_index[l2];
|
|
sort_line_index[l2] = tmp;
|
|
}
|
|
|
|
if (iupStrEqualNoCase(iupAttribGetId(ih, "SORTSIGN", ih->data->last_sort_col), "UP"))
|
|
iupAttribSetId(ih, "SORTSIGN", ih->data->last_sort_col, "DOWN");
|
|
else
|
|
iupAttribSetId(ih, "SORTSIGN", ih->data->last_sort_col, "UP");
|
|
|
|
iupMatrixDraw(ih, 1);
|
|
return 0;
|
|
}
|
|
|
|
if (!iupMATRIX_CHECK_COL(ih, col))
|
|
return 0;
|
|
|
|
if (!iupStrEqualNoCase(value, "ALL"))
|
|
iupStrToIntInt(value, &lin1, &lin2, '-');
|
|
|
|
iupAttribSetStrf(ih, "SORTCOLUMNINTERVAL", "%d,%d", lin1, lin2);
|
|
|
|
if (lin1 < 1) lin1 = 1;
|
|
if (lin2 < lin1) lin2 = lin1;
|
|
|
|
ascending = iupStrEqualNoCase(iupAttribGetStr(ih, "SORTCOLUMNORDER"), "ASCENDING");
|
|
|
|
sort_cb = (IFniii)IupGetCallback(ih, "SORTCOLUMNCOMPARE_CB");
|
|
if (sort_cb)
|
|
{
|
|
iMatrixQSort_sort_cb = sort_cb;
|
|
iMatrixQSort_ih = ih;
|
|
iMatrixQSort_col = col;
|
|
qsort(sort_line_index+lin1,lin2-lin1+1,sizeof(int),iMatrixCompareCallbackFunc);
|
|
}
|
|
else
|
|
{
|
|
if (ih->data->numeric_columns && ih->data->numeric_columns[col].flags & IMAT_IS_NUMERIC)
|
|
{
|
|
ImatSortNumber* sort_line_number = (ImatSortNumber*)malloc((lin2-lin1+1)*sizeof(ImatSortNumber));
|
|
|
|
for (lin=lin1; lin<=lin2; lin++)
|
|
{
|
|
sort_line_number[lin-lin1].lin = sort_line_index[lin];
|
|
sort_line_number[lin-lin1].number = iupMatrixGetValueNumeric(ih, lin, col);
|
|
}
|
|
|
|
qsort(sort_line_number,lin2-lin1+1,sizeof(ImatSortNumber), iMatrixCompareNumberFunc);
|
|
|
|
for (lin=lin1; lin<=lin2; lin++)
|
|
{
|
|
if (ascending)
|
|
sort_line_index[lin] = sort_line_number[lin-lin1].lin;
|
|
else
|
|
sort_line_index[lin2 - (lin-lin1)] = sort_line_number[lin-lin1].lin;
|
|
}
|
|
|
|
free(sort_line_number);
|
|
}
|
|
else
|
|
{
|
|
ImatSortText* sort_line_text = (ImatSortText*)malloc((lin2-lin1+1)*sizeof(ImatSortText));
|
|
|
|
for (lin=lin1; lin<=lin2; lin++)
|
|
{
|
|
sort_line_text[lin-lin1].lin = sort_line_index[lin];
|
|
sort_line_text[lin-lin1].text = iupMatrixGetValueDisplay(ih, lin, col);
|
|
|
|
if (ih->data->callback_mode)
|
|
sort_line_text[lin-lin1].text = iupStrDup(sort_line_text[lin-lin1].text);
|
|
}
|
|
|
|
iMatrixQSort_utf8 = IupGetInt(NULL, "UTF8MODE");
|
|
iMatrixQSort_casesensitive = iupAttribGetInt(ih, "SORTCOLUMNCASESENSITIVE");
|
|
qsort(sort_line_text,lin2-lin1+1,sizeof(ImatSortText), iMatrixCompareTextFunc);
|
|
|
|
for (lin=lin1; lin<=lin2; lin++)
|
|
{
|
|
if (ascending)
|
|
sort_line_index[lin] = sort_line_text[lin-lin1].lin;
|
|
else
|
|
sort_line_index[lin2 - (lin-lin1)] = sort_line_text[lin-lin1].lin;
|
|
|
|
if (ih->data->callback_mode && sort_line_text[lin-lin1].text)
|
|
free(sort_line_text[lin-lin1].text);
|
|
}
|
|
|
|
free(sort_line_text);
|
|
}
|
|
}
|
|
|
|
iupAttribSetId(ih, "SORTSIGN", ih->data->last_sort_col, NULL);
|
|
if (ascending)
|
|
iupAttribSetId(ih, "SORTSIGN", col, "DOWN");
|
|
else
|
|
iupAttribSetId(ih, "SORTSIGN", col, "UP");
|
|
|
|
ih->data->sort_has_index = 1;
|
|
ih->data->last_sort_col = col;
|
|
iupMatrixDraw(ih, 1);
|
|
return 0;
|
|
}
|
|
|
|
static char* iMatrixGetLastSortColumnAttrib(Ihandle* ih)
|
|
{
|
|
return iupStrReturnInt(ih->data->last_sort_col);
|
|
}
|
|
|
|
static char* iMatrixGetSortLineIndexAttrib(Ihandle* ih, int lin)
|
|
{
|
|
if (lin > 0 && lin < ih->data->lines.num && ih->data->sort_has_index)
|
|
return iupStrReturnInt(ih->data->sort_line_index[lin]);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static int iMatrixSetUndoRedoAttrib(Ihandle* ih, const char* value)
|
|
{
|
|
if (iupStrBoolean(value))
|
|
ih->data->undo_redo = 1;
|
|
else
|
|
ih->data->undo_redo = 0;
|
|
return 0;
|
|
}
|
|
|
|
static char* iMatrixGetUndoRedoAttrib(Ihandle* ih)
|
|
{
|
|
return iupStrReturnBoolean(ih->data->undo_redo);
|
|
}
|
|
|
|
void iupMatrixRegisterEx(Iclass* ic)
|
|
{
|
|
/* Undocumented features, will be exposed in IupMatrixEx */
|
|
|
|
/* IupMatrixEx Attributes - Numeric Columns */
|
|
iupClassRegisterAttributeId(ic, "NUMERICQUANTITYINDEX", NULL, iMatrixSetNumericQuantityIndexAttrib, IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttributeId(ic, "NUMERICFORMAT", NULL, iMatrixSetNumericFormatAttrib, IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttributeId(ic, "NUMERICFORMATPRECISION", iMatrixGetNumericFormatPrecisionAttrib, iMatrixSetNumericFormatPrecisionAttrib, IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttributeId(ic, "NUMERICFORMATTITLE", NULL, iMatrixSetNumericFormatTitleAttrib, IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttributeId(ic, "NUMERICUNITINDEX", NULL, iMatrixSetNumericUnitIndexAttrib, IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttributeId(ic, "NUMERICUNITSHOWNINDEX", NULL, iMatrixSetNumericUnitShownIndexAttrib, IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttribute(ic, "NUMERICFORMATDEF", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttribute(ic, "NUMERICDECIMALSYMBOL", iMatrixGetNumericDecimalSymbolAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
|
|
|
|
iupClassRegisterCallback(ic, "NUMERICGETVALUE_CB", "ii=d");
|
|
iupClassRegisterCallback(ic, "NUMERICSETVALUE_CB", "iid");
|
|
|
|
/* IupMatrixEx Attributes - Sort Columns */
|
|
iupClassRegisterAttribute(ic, "LASTSORTCOLUMN", iMatrixGetLastSortColumnAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttributeId(ic, "SORTCOLUMN", NULL, iMatrixSetSortColumnAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttribute(ic, "SORTCOLUMNORDER", NULL, NULL, IUPAF_SAMEASSYSTEM, "ASCENDING", IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttribute(ic, "SORTCOLUMNCASESENSITIVE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttribute(ic, "SORTCOLUMNINTERVAL", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
|
|
iupClassRegisterAttributeId(ic, "SORTLINEINDEX", iMatrixGetSortLineIndexAttrib, NULL, IUPAF_READONLY | IUPAF_NO_INHERIT);
|
|
|
|
iupClassRegisterCallback(ic, "SORTCOLUMNCOMPARE_CB", "iii");
|
|
|
|
/* IupMatrixEx Attributes - Undo/Redo */
|
|
iupClassRegisterAttribute(ic, "UNDOREDO", iMatrixGetUndoRedoAttrib, iMatrixSetUndoRedoAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
|
|
}
|
|
|