summaryrefslogtreecommitdiff
path: root/iup/src/iup_tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'iup/src/iup_tree.c')
-rwxr-xr-xiup/src/iup_tree.c397
1 files changed, 365 insertions, 32 deletions
diff --git a/iup/src/iup_tree.c b/iup/src/iup_tree.c
index c06e573..b5344f5 100755
--- a/iup/src/iup_tree.c
+++ b/iup/src/iup_tree.c
@@ -200,6 +200,240 @@ void iupTreeUpdateImages(Ihandle *ih)
iupClassObjectSetAttribute(ih, "IMAGEBRANCHEXPANDED", value, &inherit);
}
+void iupTreeSelectLastCollapsedBranch(Ihandle* ih, int *last_id)
+{
+ /* if last selected item is a branch, then select its children */
+ if (iupStrEqual(IupTreeGetAttribute(ih, "KIND", *last_id), "BRANCH") &&
+ iupStrEqual(IupTreeGetAttribute(ih, "STATE", *last_id), "COLLAPSED"))
+ {
+ int childcount = IupTreeGetInt(ih, "CHILDCOUNT", *last_id);
+ if (childcount > 0)
+ {
+ int start = *last_id + 1;
+ int end = *last_id + childcount;
+ IupSetfAttribute(ih, "MARK", "%d-%d", start, end);
+ *last_id = *last_id + childcount;
+ }
+ }
+}
+
+int iupTreeForEach(Ihandle* ih, iupTreeNodeFunc func, void* userdata)
+{
+ int i;
+ for (i = 0; i < ih->data->node_count; i++)
+ {
+ if (!func(ih, ih->data->node_cache[i].node_handle, i, userdata))
+ return 0;
+ }
+
+ return 1;
+}
+
+int iupTreeFindNodeId(Ihandle* ih, InodeHandle* node_handle)
+{
+ /* Unoptimized version:
+ int i;
+ for (i = 0; i < ih->data->node_count; i++)
+ {
+ if (ih->data->node_cache[i].node_handle == node_handle)
+ return i;
+ }
+ */
+ InodeData *node_cache = ih->data->node_cache;
+ while(node_cache->node_handle != node_handle &&
+ node_cache->node_handle != NULL) /* the cache always have zeros at the end */
+ node_cache++;
+
+ if (node_cache->node_handle != NULL)
+ return node_cache - ih->data->node_cache;
+ else
+ return -1;
+}
+
+static int iTreeFindUserDataId(Ihandle* ih, void* userdata)
+{
+ /* Unoptimized version:
+ int i;
+ for (i = 0; i < ih->data->node_count; i++)
+ {
+ if (ih->data->node_cache[i].node_handle == node_handle)
+ return i;
+ }
+ */
+ InodeData *node_cache = ih->data->node_cache;
+ while(node_cache->userdata != userdata &&
+ node_cache->node_handle != NULL) /* the cache always have zeros at the end */
+ node_cache++;
+
+ if (node_cache->node_handle != NULL)
+ return node_cache - ih->data->node_cache;
+ else
+ return -1;
+}
+
+static int iTreeGetIdFromString(const char* name_id)
+{
+ if (name_id && name_id[0])
+ {
+ int id = -1;
+ iupStrToInt(name_id, &id);
+ return id;
+ }
+ else
+ return -2;
+}
+
+InodeHandle* iupTreeGetNode(Ihandle* ih, int id)
+{
+ if (id >= 0 && id < ih->data->node_count)
+ return ih->data->node_cache[id].node_handle;
+ else if (id == -2)
+ return iupdrvTreeGetFocusNode(ih);
+ else
+ return NULL;
+}
+
+InodeHandle* iupTreeGetNodeFromString(Ihandle* ih, const char* name_id)
+{
+ return iupTreeGetNode(ih, iTreeGetIdFromString(name_id));
+}
+
+static void iTreeAddToCache(Ihandle* ih, int id, InodeHandle* node_handle)
+{
+ iupASSERT(id >= 0 && id < ih->data->node_count);
+ if (id < 0 || id >= ih->data->node_count)
+ return;
+
+ /* node_count here already contains the final count */
+
+ if (id == ih->data->node_count-1)
+ ih->data->node_cache[id].node_handle = node_handle;
+ else
+ {
+ /* open space for the new id */
+ int remain_count = ih->data->node_count-id;
+ memmove(ih->data->node_cache+id+1, ih->data->node_cache+id, remain_count*sizeof(InodeData));
+ ih->data->node_cache[id].node_handle = node_handle;
+ }
+
+ ih->data->node_cache[id].userdata = NULL;
+}
+
+static void iTreeIncCacheMem(Ihandle* ih)
+{
+ /* node_count here already contains the final count */
+
+ if (ih->data->node_count+10 > ih->data->node_cache_max)
+ {
+ int old_node_cache_max = ih->data->node_cache_max;
+ ih->data->node_cache_max += 20;
+ ih->data->node_cache = realloc(ih->data->node_cache, ih->data->node_cache_max*sizeof(InodeData));
+ memset(ih->data->node_cache+old_node_cache_max, 0, 20*sizeof(InodeData));
+ }
+}
+
+void iupTreeAddToCache(Ihandle* ih, int add, int kindPrev, InodeHandle* prevNode, InodeHandle* node_handle)
+{
+ int new_id = 0;
+
+ ih->data->node_count++;
+
+ /* node_count here already contains the final count */
+ iTreeIncCacheMem(ih);
+
+ if (prevNode)
+ {
+ if (add || kindPrev == ITREE_LEAF)
+ {
+ /* ADD implies always that id=prev_id+1 */
+ /* INSERT after a leaf implies always that new_id=prev_id+1 */
+ int prev_id = iupTreeFindNodeId(ih, prevNode);
+ new_id = prev_id+1;
+ }
+ else
+ {
+ /* INSERT after a branch implies always that new_id=prev_id+1+child_count */
+ int prev_id = iupTreeFindNodeId(ih, prevNode);
+ int child_count = iupdrvTreeTotalChildCount(ih, prevNode);
+ new_id = prev_id+1+child_count;
+ }
+ }
+
+ iTreeAddToCache(ih, new_id, node_handle);
+ iupAttribSetInt(ih, "LASTADDNODE", new_id);
+}
+
+void iupTreeDelFromCache(Ihandle* ih, int id, int count)
+{
+ int remain_count;
+
+ /* id can be the last node, actually==node_count becase node_count is already updated */
+ iupASSERT(id >= 0 && id <= ih->data->node_count);
+ if (id < 0 || id > ih->data->node_count)
+ return;
+
+ /* node_count here already contains the final count */
+
+ /* remove id+count */
+ remain_count = ih->data->node_count-id;
+ memmove(ih->data->node_cache+id, ih->data->node_cache+id+count, remain_count*sizeof(InodeData));
+
+ /* clear the remaining space */
+ memset(ih->data->node_cache+ih->data->node_count, 0, count*sizeof(InodeData));
+}
+
+void iupTreeCopyMoveCache(Ihandle* ih, int id_src, int id_dst, int count, int is_copy)
+{
+ int remain_count;
+
+ iupASSERT(id_src >= 0 && id_src < ih->data->node_count);
+ if (id_src < 0 || id_src >= ih->data->node_count)
+ return;
+
+ iupASSERT(id_dst >= 0 && id_dst < ih->data->node_count);
+ if (id_dst < 0 || id_dst >= ih->data->node_count)
+ return;
+
+ iupASSERT(id_dst < id_src || id_dst > id_src+count);
+ if (id_dst >= id_src && id_dst <= id_src+count)
+ return;
+
+ /* id_dst here points to the final position for a copy operation */
+
+ /* node_count here contains the final count for a copy operation */
+ iTreeIncCacheMem(ih);
+
+ /* add space for new nodes */
+ remain_count = ih->data->node_count - (id_dst + count);
+ memmove(ih->data->node_cache+id_dst+count, ih->data->node_cache+id_dst, remain_count*sizeof(InodeData));
+
+ /* compensate because we add space for new nodes */
+ if (id_src > id_dst)
+ id_src += count;
+
+ if (is_copy)
+ {
+ /* during a copy, the userdata is not reused, so clear it */
+ memset(ih->data->node_cache+id_dst, 0, count*sizeof(InodeData));
+ }
+ else /* move = copy + delete */
+ {
+ /* copy userdata from src to dst */
+ memcpy(ih->data->node_cache+id_dst, ih->data->node_cache+id_src, count*sizeof(InodeData));
+
+ /* remove the src */
+ remain_count = ih->data->node_count - (id_src + count);
+ memmove(ih->data->node_cache+id_src, ih->data->node_cache+id_src+count, remain_count*sizeof(InodeData));
+
+ /* clear the remaining space */
+ memset(ih->data->node_cache+ih->data->node_count-count, 0, count*sizeof(InodeData));
+ }
+}
+
+
+/*************************************************************************/
+
+
char* iupTreeGetSpacingAttrib(Ihandle* ih)
{
char *str = iupStrGetMemory(50);
@@ -221,8 +455,10 @@ static int iTreeSetMarkModeAttrib(Ihandle* ih, const char* value)
ih->data->mark_mode = ITREE_MARK_MULTIPLE;
else
ih->data->mark_mode = ITREE_MARK_SINGLE;
+
if (ih->handle)
- iupdrvTreeUpdateMarkMode(ih);
+ iupdrvTreeUpdateMarkMode(ih); /* for this to work, must update during map */
+
return 0;
}
@@ -290,7 +526,7 @@ static int iTreeSetShowDragDropAttrib(Ihandle* ih, const char* value)
static int iTreeSetAddLeafAttrib(Ihandle* ih, const char* name_id, const char* value)
{
- if (!ih->handle) /* do not store the action before map */
+ if (!ih->handle) /* do not do the action before map */
return 0;
iupdrvTreeAddNode(ih, name_id, ITREE_LEAF, value, 1);
return 0;
@@ -298,7 +534,7 @@ static int iTreeSetAddLeafAttrib(Ihandle* ih, const char* name_id, const char* v
static int iTreeSetAddBranchAttrib(Ihandle* ih, const char* name_id, const char* value)
{
- if (!ih->handle) /* do not store the action before map */
+ if (!ih->handle) /* do not do the action before map */
return 0;
iupdrvTreeAddNode(ih, name_id, ITREE_BRANCH, value, 1);
return 0;
@@ -306,7 +542,7 @@ static int iTreeSetAddBranchAttrib(Ihandle* ih, const char* name_id, const char*
static int iTreeSetInsertLeafAttrib(Ihandle* ih, const char* name_id, const char* value)
{
- if (!ih->handle) /* do not store the action before map */
+ if (!ih->handle) /* do not do the action before map */
return 0;
iupdrvTreeAddNode(ih, name_id, ITREE_LEAF, value, 0);
return 0;
@@ -314,7 +550,7 @@ static int iTreeSetInsertLeafAttrib(Ihandle* ih, const char* name_id, const char
static int iTreeSetInsertBranchAttrib(Ihandle* ih, const char* name_id, const char* value)
{
- if (!ih->handle) /* do not store the action before map */
+ if (!ih->handle) /* do not do the action before map */
return 0;
iupdrvTreeAddNode(ih, name_id, ITREE_BRANCH, value, 0);
return 0;
@@ -338,6 +574,74 @@ static int iTreeSetAddExpandedAttrib(Ihandle* ih, const char* value)
return 0;
}
+static char* iTreeGetCountAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(10);
+ sprintf(str, "%d", ih->data->node_count);
+ return str;
+}
+
+static char* iTreeGetTotalChildCountAttrib(Ihandle* ih, const char* name_id)
+{
+ char* str;
+ InodeHandle* node_handle = iupTreeGetNodeFromString(ih, name_id);
+ if (!node_handle)
+ return NULL;
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", iupdrvTreeTotalChildCount(ih, node_handle));
+ return str;
+}
+
+
+static char* iTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id)
+{
+ int id;
+ char* str = (char*)(name_id+1); /* skip ':' */
+ void* userdata = NULL;
+ if (sscanf(str, "%p", &userdata)!=1)
+ return NULL;
+ id = iTreeFindUserDataId(ih, userdata);
+ if (id == -1)
+ return NULL;
+ str = iupStrGetMemory(16);
+ sprintf(str, "%d", id);
+ return str;
+}
+
+static char* iTreeGetUserDataAttrib(Ihandle* ih, const char* name_id)
+{
+ int id = iTreeGetIdFromString(name_id);
+ if (id >= 0 && id < ih->data->node_count)
+ return ih->data->node_cache[id].userdata;
+ else if (id == -2)
+ {
+ InodeHandle* node_handle = iupdrvTreeGetFocusNode(ih);
+ id = iupTreeFindNodeId(ih, node_handle);
+ if (id >= 0 && id < ih->data->node_count)
+ return ih->data->node_cache[id].userdata;
+ }
+ return NULL;
+}
+
+static int iTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int id = iTreeGetIdFromString(name_id);
+ if (id >= 0 && id < ih->data->node_count)
+ ih->data->node_cache[id].userdata = (void*)value;
+ else if (id == -2)
+ {
+ InodeHandle* node_handle = iupdrvTreeGetFocusNode(ih);
+ id = iupTreeFindNodeId(ih, node_handle);
+ if (id >= 0 && id < ih->data->node_count)
+ ih->data->node_cache[id].userdata = (void*)value;
+ }
+ return 0;
+}
+
+
+/*************************************************************************/
+
static int iTreeCreateMethod(Ihandle* ih, void **params)
{
(void)params;
@@ -348,10 +652,20 @@ static int iTreeCreateMethod(Ihandle* ih, void **params)
IupSetAttribute(ih, "EXPAND", "YES");
ih->data->add_expanded = 1;
+ ih->data->node_cache_max = 20;
+ ih->data->node_cache = calloc(ih->data->node_cache_max, sizeof(InodeData));
return IUP_NOERROR;
}
+static void iTreeDestroyMethod(Ihandle* ih)
+{
+ if (ih->data->node_cache)
+ free(ih->data->node_cache);
+}
+
+/*************************************************************************/
+
Ihandle* IupTree(void)
{
return IupCreate("tree");
@@ -371,15 +685,15 @@ Iclass* iupTreeGetClass(void)
/* Class functions */
ic->Create = iTreeCreateMethod;
ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
- ic->UnMap = iupdrvBaseUnMapMethod;
+ ic->Destroy = iTreeDestroyMethod;
/* Callbacks */
iupClassRegisterCallback(ic, "SELECTION_CB", "ii");
iupClassRegisterCallback(ic, "MULTISELECTION_CB", "Ii");
+ iupClassRegisterCallback(ic, "MULTIUNSELECTION_CB", "Ii");
iupClassRegisterCallback(ic, "BRANCHOPEN_CB", "i");
iupClassRegisterCallback(ic, "BRANCHCLOSE_CB", "i");
iupClassRegisterCallback(ic, "EXECUTELEAF_CB", "i");
- iupClassRegisterCallback(ic, "RENAMENODE_CB", "is");
iupClassRegisterCallback(ic, "SHOWRENAME_CB", "i");
iupClassRegisterCallback(ic, "RENAME_CB", "is");
iupClassRegisterCallback(ic, "DRAGDROP_CB", "iiii");
@@ -392,9 +706,12 @@ Iclass* iupTreeGetClass(void)
iupBaseRegisterVisualAttrib(ic);
/* IupTree Attributes - GENERAL */
- iupClassRegisterAttribute(ic, "SHOWDRAGDROP", iTreeGetShowDragDropAttrib, iTreeSetShowDragDropAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
- iupClassRegisterAttribute(ic, "SHOWRENAME", iTreeGetShowRenameAttrib, iTreeSetShowRenameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
- iupClassRegisterAttribute(ic, "ADDEXPANDED", iTreeGetAddExpandedAttrib, iTreeSetAddExpandedAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWDRAGDROP", iTreeGetShowDragDropAttrib, iTreeSetShowDragDropAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWRENAME", iTreeGetShowRenameAttrib, iTreeSetShowRenameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ADDEXPANDED", iTreeGetAddExpandedAttrib, iTreeSetAddExpandedAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "COUNT", iTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "LASTADDNODE", NULL, NULL, IUPAF_SAMEASSYSTEM, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ADDROOT", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
/* IupTree Attributes - MARKS */
iupClassRegisterAttribute(ic, "CTRL", NULL, iTreeSetCtrlAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
@@ -406,6 +723,11 @@ Iclass* iupTreeGetClass(void)
iupClassRegisterAttributeId(ic, "ADDBRANCH", NULL, iTreeSetAddBranchAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
iupClassRegisterAttributeId(ic, "INSERTLEAF", NULL, iTreeSetInsertLeafAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
iupClassRegisterAttributeId(ic, "INSERTBRANCH", NULL, iTreeSetInsertBranchAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - NODES */
+ iupClassRegisterAttributeId(ic, "TOTALCHILDCOUNT", iTreeGetTotalChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "FINDUSERDATA", iTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "USERDATA", iTreeGetUserDataAttrib, iTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT);
/* Default node images */
iTreeInitializeImages();
@@ -415,18 +737,23 @@ Iclass* iupTreeGetClass(void)
return ic;
}
-
/********************************************************************************************/
-
-void IupTreeSetAttribute(Ihandle* ih, const char* a, int id, char* v)
+void IupTreeSetAttribute(Ihandle* ih, const char* a, int id, const char* v)
{
char* attr = iupStrGetMemory(50);
sprintf(attr, "%s%d", a, id);
IupSetAttribute(ih, attr, v);
}
-void IupTreeStoreAttribute(Ihandle* ih, const char* a, int id, char* v)
+void IupTreeSetAttributeHandle(Ihandle* ih, const char* a, int id, Ihandle* ih_named)
+{
+ char* attr = iupStrGetMemory(50);
+ sprintf(attr, "%s%d", a, id);
+ IupSetAttributeHandle(ih, attr, ih_named);
+}
+
+void IupTreeStoreAttribute(Ihandle* ih, const char* a, int id, const char* v)
{
char* attr = iupStrGetMemory(50);
sprintf(attr, "%s%d", a, id);
@@ -454,7 +781,7 @@ float IupTreeGetFloat(Ihandle* ih, const char* a, int id)
return IupGetFloat(ih, attr);
}
-void IupTreeSetfAttribute(Ihandle* ih, const char* a, int id, char* f, ...)
+void IupTreeSetfAttribute(Ihandle* ih, const char* a, int id, const char* f, ...)
{
static char v[SHRT_MAX];
char* attr = iupStrGetMemory(50);
@@ -466,34 +793,40 @@ void IupTreeSetfAttribute(Ihandle* ih, const char* a, int id, char* f, ...)
IupStoreAttribute(ih, attr, v);
}
-
/************************************************************************************/
-
int IupTreeSetUserId(Ihandle* ih, int id, void* userdata)
{
- char attr[30];
- sprintf(attr,"USERDATA%d",id);
- IupSetAttribute(ih, attr, userdata);
- return IupGetAttribute(ih, attr)? 1: 0;
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return 0;
+
+ if (id >= 0 && id < ih->data->node_count)
+ {
+ ih->data->node_cache[id].userdata = userdata;
+ return 1;
+ }
+
+ return 0;
}
int IupTreeGetId(Ihandle* ih, void *userdata)
{
- int id = -1;
- char* value;
- char attr[30];
- sprintf(attr,"FINDUSERDATA:%p",userdata);
- value = IupGetAttribute(ih, attr);
- if (!value) return -1;
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return -1;
- iupStrToInt(value, &id);
- return id;
+ return iTreeFindUserDataId(ih, userdata);
}
void* IupTreeGetUserId(Ihandle* ih, int id)
{
- char attr[30];
- sprintf(attr,"USERDATA%d",id);
- return IupGetAttribute(ih, attr);
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ if (id >= 0 && id < ih->data->node_count)
+ return ih->data->node_cache[id].userdata;
+
+ return NULL;
}