/** \file * \brief IupMatrix Expansion Library. * * See Copyright Notice in "iup.h" */ #include #include #include #include "iup.h" #include "iupcbs.h" #include "iupcontrols.h" #include "iup_object.h" #include "iup_childtree.h" #include "iup_register.h" #include "iup_attrib.h" #include "iup_str.h" #include "iup_assert.h" #include "iup_matrixex.h" static IattribSetFunc iMatrixSetUndoRedoAttrib = NULL; typedef struct _IundoData { int cell_count; const char* name; Itable* data_table; } IundoData; static void iMatrixExUndoDataInit(IundoData* undo_data, const char* name) { undo_data->cell_count = 0; undo_data->name = name; undo_data->data_table = iupTableCreate(IUPTABLE_STRINGINDEXED); if (name) { char str[50] = "IUP_"; strcat(str, name); name = IupGetLanguageString(str); if (name != str) undo_data->name = name; } } static void iMatrixExUndoDataClear(IundoData* undo_data) { iupTableDestroy(undo_data->data_table); memset(undo_data, 0, sizeof(IundoData)); } static void iMatrixExUndoDataAddCell(IundoData* undo_data, int lin, int col, const char* value) { char id[40]; sprintf(id, "%d:%d", lin, col); if (!value) iupTableSet(undo_data->data_table, id, (void*)"", IUPTABLE_POINTER); /* store NULL pointers so they can be restored later */ else iupTableSet(undo_data->data_table, id, (void*)value, IUPTABLE_STRING); undo_data->cell_count++; } static int iMatrixExUndoDataSwap(ImatExData* matex_data, IundoData* undo_data) { char* id = iupTableFirst(undo_data->data_table); while (id) { char *value, *old_value; int lin=1, col=1; iupStrToIntInt(id, &lin, &col, ':'); value = (char*)iupTableGetCurr(undo_data->data_table); old_value = iupStrDup(iupMatrixExGetCellValue(matex_data->ih, lin, col, 0)); /* get internal value */ iupMatrixExSetCellValue(matex_data->ih, lin, col, value); if (!old_value) iupTableSetCurr(undo_data->data_table, (void*)"", IUPTABLE_POINTER); else { iupTableSetCurr(undo_data->data_table, (void*)old_value, IUPTABLE_STRING); free(old_value); } if (!iupMatrixExBusyInc(matex_data)) return 0; id = iupTableNext(undo_data->data_table); } return 1; } static void iMatrixExUndoStackInit(ImatExData* matex_data) { if (!matex_data->undo_stack) matex_data->undo_stack = iupArrayCreate(40, sizeof(IundoData)); } static void iMatrixUndoStackAdd(ImatExData* matex_data, const char* name) { int i, undo_stack_count = iupArrayCount(matex_data->undo_stack); IundoData* undo_stack_data = (IundoData*)iupArrayGetData(matex_data->undo_stack); /* Remove all Redo data */ for (i=matex_data->undo_stack_pos; iundo_stack, matex_data->undo_stack_pos, undo_stack_count-matex_data->undo_stack_pos); undo_stack_data = (IundoData*)iupArrayInc(matex_data->undo_stack); iMatrixExUndoDataInit(&(undo_stack_data[matex_data->undo_stack_pos]), name); } void iupMatrixExUndoPushBegin(ImatExData* matex_data, const char* name) { if (!matex_data->undo_stack_hold) { iMatrixUndoStackAdd(matex_data, name); matex_data->undo_stack_hold = 1; } } void iupMatrixExUndoPushEnd(ImatExData* matex_data) { if (matex_data->undo_stack_hold) { matex_data->undo_stack_pos++; matex_data->undo_stack_hold = 0; } } static int iMatrixSetUndoPushCellAttrib(Ihandle* ih, int lin, int col, const char* value) { ImatExData* matex_data = (ImatExData*)iupAttribGet(ih, "_IUP_MATEX_DATA"); IundoData* undo_stack_data; if (matex_data->undo_stack_hold) { undo_stack_data = (IundoData*)iupArrayGetData(matex_data->undo_stack); iMatrixExUndoDataAddCell(&(undo_stack_data[matex_data->undo_stack_pos]), lin, col, value); } else { iMatrixUndoStackAdd(matex_data, "SETCELL"); undo_stack_data = (IundoData*)iupArrayGetData(matex_data->undo_stack); iMatrixExUndoDataAddCell(&(undo_stack_data[matex_data->undo_stack_pos]), lin, col, value); matex_data->undo_stack_pos++; } return 0; } static int iMatrixSetUndoClearAttrib(Ihandle* ih, const char* value) { ImatExData* matex_data = (ImatExData*)iupAttribGet(ih, "_IUP_MATEX_DATA"); int undo_stack_count = matex_data->undo_stack? iupArrayCount(matex_data->undo_stack): 0; if (undo_stack_count) { int i; IundoData* undo_stack_data = (IundoData*)iupArrayGetData(matex_data->undo_stack); for (i=0; iundo_stack, 0, undo_stack_count); matex_data->undo_stack_pos = 0; } (void)value; return 0; } static char* iMatrixGetUndoCountAttrib(Ihandle* ih) { ImatExData* matex_data = (ImatExData*)iupAttribGet(ih, "_IUP_MATEX_DATA"); int undo_stack_count = iupArrayCount(matex_data->undo_stack); if (matex_data->undo_stack && undo_stack_count) return iupStrReturnInt(undo_stack_count); return NULL; } static char* iMatrixGetUndoNameAttrib(Ihandle* ih, int id) { ImatExData* matex_data = (ImatExData*)iupAttribGet(ih, "_IUP_MATEX_DATA"); int undo_stack_count = iupArrayCount(matex_data->undo_stack); if (matex_data->undo_stack && undo_stack_count) { IundoData* undo_stack_data = (IundoData*)iupArrayGetData(matex_data->undo_stack); if (id < 0 || id >= undo_stack_count) return NULL; return iupStrReturnStr(undo_stack_data[id].name); } return NULL; } static int iMatrixSetUndoAttrib(Ihandle* ih, const char* value) { ImatExData* matex_data = (ImatExData*)iupAttribGet(ih, "_IUP_MATEX_DATA"); int undo_stack_count = matex_data->undo_stack? iupArrayCount(matex_data->undo_stack): 0; if (undo_stack_count && matex_data->undo_stack_pos>0) { int i, count = 1, total_cell_count = 0; IundoData* undo_stack_data = (IundoData*)iupArrayGetData(matex_data->undo_stack); iupStrToInt(value, &count); if (count > matex_data->undo_stack_pos) count = matex_data->undo_stack_pos; for (i=0; iundo_stack_pos-1 - i].cell_count; iMatrixSetUndoRedoAttrib(ih, "NO"); /* Disable Undo/Redo systrem during restore */ iupMatrixExBusyStart(matex_data, total_cell_count, "UNDO"); for (i=0; iundo_stack_pos-1 - i]))) { matex_data->undo_stack_pos -= i; iMatrixSetUndoRedoAttrib(ih, "Yes"); return 0; } } iupMatrixExBusyEnd(matex_data); iMatrixSetUndoRedoAttrib(ih, "Yes"); matex_data->undo_stack_pos -= i; iupBaseCallValueChangedCb(ih); } return 0; } static char* iMatrixGetUndoAttrib(Ihandle* ih) { ImatExData* matex_data = (ImatExData*)iupAttribGet(ih, "_IUP_MATEX_DATA"); int undo_stack_count = matex_data->undo_stack? iupArrayCount(matex_data->undo_stack): 0; if (undo_stack_count) return iupStrReturnBoolean(matex_data->undo_stack_pos>0); return NULL; } static char* iMatrixGetRedoAttrib(Ihandle* ih) { ImatExData* matex_data = (ImatExData*)iupAttribGet(ih, "_IUP_MATEX_DATA"); int undo_stack_count = matex_data->undo_stack? iupArrayCount(matex_data->undo_stack): 0; if (undo_stack_count) return iupStrReturnBoolean(matex_data->undo_stack_posundo_stack? iupArrayCount(matex_data->undo_stack): 0; if (undo_stack_count && matex_data->undo_stack_posundo_stack); iupStrToInt(value, &count); if (count > undo_stack_count - matex_data->undo_stack_pos) count = undo_stack_count - matex_data->undo_stack_pos; for (i=0; iundo_stack_pos + i].cell_count; iMatrixSetUndoRedoAttrib(ih, "NO"); /* Disable Undo/Redo systrem during restore */ iupMatrixExBusyStart(matex_data, total_cell_count, "REDO"); for (i=0; iundo_stack_pos + i]))) { matex_data->undo_stack_pos += i; iMatrixSetUndoRedoAttrib(ih, "Yes"); return 0; } } iupMatrixExBusyEnd(matex_data); iMatrixSetUndoRedoAttrib(ih, "Yes"); matex_data->undo_stack_pos += i; iupBaseCallValueChangedCb(ih); } return 0; } static int iMatrixSetUndoPushBeginAttrib(Ihandle* ih, const char* value) { ImatExData* matex_data = (ImatExData*)iupAttribGet(ih, "_IUP_MATEX_DATA"); iupMatrixExUndoPushBegin(matex_data, value); return 0; } static int iMatrixSetUndoPushEndAttrib(Ihandle* ih, const char* value) { ImatExData* matex_data = (ImatExData*)iupAttribGet(ih, "_IUP_MATEX_DATA"); iupMatrixExUndoPushEnd(matex_data); (void)value; return 0; } static int iMatrixExSetUndoRedoAttrib(Ihandle* ih, const char* value) { ImatExData* matex_data = (ImatExData*)iupAttribGet(ih, "_IUP_MATEX_DATA"); if (iupStrBoolean(value)) iMatrixExUndoStackInit(matex_data); else iMatrixSetUndoClearAttrib(ih, NULL); return iMatrixSetUndoRedoAttrib(ih, value); } static void iMatrixUndoListUpdate(ImatExData* matex_data, Ihandle* ih_list) { int pos, item; char* undostr = IupGetLanguageString("IUP_UNDONAME"); char* redostr = IupGetLanguageString("IUP_REDONAME"); int undo_stack_count = iupArrayCount(matex_data->undo_stack); IundoData* undo_stack_data = (IundoData*)iupArrayGetData(matex_data->undo_stack); item = 1; for (pos=0; posundo_stack_pos; pos++) { IupSetfAttributeId(ih_list, "", item, "%s: %s", undostr, undo_stack_data[pos].name); item++; } IupSetStrAttributeId(ih_list, "", item, "_@IUP_CURRENTSTATE"); item++; for (pos=matex_data->undo_stack_pos; posundo_stack_pos) { if (pos < matex_data->undo_stack_pos) IupSetInt(matex_data->ih, "UNDO", matex_data->undo_stack_pos-pos); else if (pos > matex_data->undo_stack_pos) IupSetInt(matex_data->ih, "REDO", pos-matex_data->undo_stack_pos); iMatrixUndoListUpdate(matex_data, ih_list); } } (void)text; return IUP_DEFAULT; } static Ihandle* iMatrixExUndoCreateDialog(ImatExData* matex_data) { Ihandle* dlg, *parent, *list; list = IupList(NULL); IupSetAttribute(list, "EXPAND","YES"); IupSetAttribute(list, "DROPDOWN","NO"); IupSetAttribute(list, "VISIBLECOLUMNS" ,"25"); IupSetAttribute(list, "VISIBLELINES" ,"10"); IupSetCallback (list, "ACTION" ,(Icallback)iMatrixExUndoListAction_CB); iMatrixUndoListUpdate(matex_data, list); parent = IupGetDialog(matex_data->ih); dlg = IupDialog(list); IupSetAttribute(dlg, "MAXBOX" ,"NO"); IupSetAttribute(dlg, "MINBOX" ,"NO"); IupSetAttribute(dlg, "TOOLBOX","YES"); IupSetStrAttribute(dlg, "TITLE" ,"_@IUP_UNDOLIST"); IupSetAttributeHandle(dlg,"PARENTDIALOG", parent); IupSetAttribute(dlg, "MATRIX_EX_DATA", (char*)matex_data); /* do not use "_IUP_MATEX_DATA" to enable inheritance */ if (IupGetAttribute(parent, "ICON")) IupSetStrAttribute(dlg,"ICON", IupGetAttribute(parent, "ICON")); else IupSetStrAttribute(dlg,"ICON", IupGetGlobal("ICON")); return dlg; } void iupMatrixExUndoShowDialog(ImatExData* matex_data) { int x, y; Ihandle* dlg_undo = iMatrixExUndoCreateDialog(matex_data); iupMatrixExGetDialogPosition(matex_data, &x, &y); IupPopup(dlg_undo, x, y); IupDestroy(dlg_undo); } void iupMatrixExRegisterUndo(Iclass* ic) { /* Already defined in IupMatrix, redefined here */ if (!iMatrixSetUndoRedoAttrib) iupClassRegisterGetAttribute(ic, "UNDOREDO", NULL, &iMatrixSetUndoRedoAttrib, NULL, NULL, NULL); iupClassRegisterReplaceAttribFunc(ic, "UNDOREDO", NULL, iMatrixExSetUndoRedoAttrib); iupClassRegisterAttribute(ic, "UNDO", iMatrixGetUndoAttrib, iMatrixSetUndoAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "REDO", iMatrixGetRedoAttrib, iMatrixSetRedoAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "UNDOCLEAR", NULL, iMatrixSetUndoClearAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "UNDONAME", iMatrixGetUndoNameAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "UNDOCOUNT", iMatrixGetUndoCountAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); /* Internal attributes */ iupClassRegisterAttributeId2(ic, "UNDOPUSHCELL", NULL, iMatrixSetUndoPushCellAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "UNDOPUSHBEGIN", NULL, iMatrixSetUndoPushBeginAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "UNDOPUSHEND", NULL, iMatrixSetUndoPushEndAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); }