iup-stack/iup/srccontrols/matrix/iupmat_ex.c

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);
}