From eed0eb6a476d54ce19aeff137984aa981d9e3976 Mon Sep 17 00:00:00 2001 From: Pixel Date: Tue, 15 Jun 2010 00:59:57 -0700 Subject: Upgrading to iup 3.1 --- rclua5 | 19591 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 19591 insertions(+) create mode 100644 rclua5 (limited to 'rclua5') diff --git a/rclua5 b/rclua5 new file mode 100644 index 0000000..00d4139 --- /dev/null +++ b/rclua5 @@ -0,0 +1,19591 @@ +diff --git a/iup/COPYRIGHT b/iup/COPYRIGHT +index dd31d6c..0061f2d 100755 +--- a/iup/COPYRIGHT ++++ b/iup/COPYRIGHT +@@ -7,7 +7,7 @@ and commercial purposes at absolutely no cost. +  + =============================================================================== +  +-Copyright (C) 1994-2009 Tecgraf, PUC-Rio. ++Copyright (C) 1994-2010 Tecgraf, PUC-Rio. +  + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal +diff --git a/iup/etc/iup.rc b/iup/etc/iup.rc +index eab8cf5..49c324d 100755 +--- a/iup/etc/iup.rc ++++ b/iup/etc/iup.rc +@@ -12,7 +12,7 @@ BEGIN + VALUE "CompanyName", "Tecgraf/PUC-Rio\0" + VALUE "FileDescription", "IUP - Portable User Interface\0" + VALUE "FileVersion", "3.0.0\0" +- VALUE "LegalCopyright", "Copyright © 1994-2009 Tecgraf, PUC-Rio.\0" ++ VALUE "LegalCopyright", "Copyright © 1994-2010 Tecgraf, PUC-Rio.\0" + VALUE "OriginalFilename", "iup.dll\0" + VALUE "ProductName", "IUP for Windows\0" + VALUE "ProductVersion", "3.0.0\0" +diff --git a/iup/include/iup.h b/iup/include/iup.h +index 9913329..2d33b98 100755 +--- a/iup/include/iup.h ++++ b/iup/include/iup.h +@@ -19,11 +19,11 @@ extern "C" { +  +  + #define IUP_NAME "IUP - Portable User Interface" +-#define IUP_COPYRIGHT "Copyright (C) 1994-2009 Tecgraf, PUC-Rio." ++#define IUP_COPYRIGHT "Copyright (C) 1994-2010 Tecgraf, PUC-Rio." + #define IUP_DESCRIPTION "Portable toolkit for building graphical user interfaces." +-#define IUP_VERSION "3.0" /* bug fixes are reported only by IupVersion functions */ +-#define IUP_VERSION_NUMBER 300000 +-#define IUP_VERSION_DATE "2009/10/02" ++#define IUP_VERSION "3.1" /* bug fixes are reported only by IupVersion functions */ ++#define IUP_VERSION_NUMBER 301000 ++#define IUP_VERSION_DATE "2010/04/22" +  + typedef struct Ihandle_ Ihandle; + typedef int (*Icallback)(Ihandle*); +@@ -38,6 +38,7 @@ void IupImageLibOpen (void); +  + int IupMainLoop (void); + int IupLoopStep (void); ++int IupLoopStepWait (void); + int IupMainLoopLevel (void); + void IupFlush (void); + void IupExitLoop (void); +@@ -148,6 +149,7 @@ Ihandle* IupNormalizerv(Ihandle* *ih_list); + Ihandle* IupCbox (Ihandle* child, ...); + Ihandle* IupCboxv (Ihandle* *children); + Ihandle* IupSbox (Ihandle *child); ++Ihandle* IupSplit (Ihandle* child1, Ihandle* child2); +  + Ihandle* IupFrame (Ihandle* child); +  +@@ -197,12 +199,13 @@ int IupTreeSetUserId(Ihandle* ih, int id, void* userid); + void* IupTreeGetUserId(Ihandle* ih, int id); + int IupTreeGetId(Ihandle* ih, void *userid); +  +-void IupTreeSetAttribute (Ihandle* ih, const char* name, int id, char* value); +-void IupTreeStoreAttribute(Ihandle* ih, const char* name, int id, char* value); ++void IupTreeSetAttribute (Ihandle* ih, const char* name, int id, const char* value); ++void IupTreeStoreAttribute(Ihandle* ih, const char* name, int id, const char* value); + char* IupTreeGetAttribute (Ihandle* ih, const char* name, int id); + int IupTreeGetInt (Ihandle* ih, const char* name, int id); + float IupTreeGetFloat (Ihandle* ih, const char* name, int id); +-void IupTreeSetfAttribute (Ihandle* ih, const char* name, int id, char* format, ...); ++void IupTreeSetfAttribute (Ihandle* ih, const char* name, int id, const char* format, ...); ++void IupTreeSetAttributeHandle(Ihandle* ih, const char* a, int id, Ihandle* ih_named); +  +  + /************************************************************************/ +@@ -338,7 +341,7 @@ int IupMain (int argc, char** argv); /* In C++ we have to declare the prototype + #endif +  + /****************************************************************************** +-* Copyright (C) 1994-2009 Tecgraf, PUC-Rio. ++* Copyright (C) 1994-2010 Tecgraf, PUC-Rio. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the +diff --git a/iup/include/iupcbs.h b/iup/include/iupcbs.h +index f33166b..70d117f 100755 +--- a/iup/include/iupcbs.h ++++ b/iup/include/iupcbs.h +@@ -24,7 +24,7 @@ typedef int (*IFnnii)(Ihandle*, Ihandle*, int, int); /* drop_cb */ + typedef int (*IFnnn)(Ihandle*, Ihandle*, Ihandle*); /* tabchange_cb */ + typedef int (*IFnss)(Ihandle*, char *, char *); /* file_cb */ + typedef int (*IFns)(Ihandle*, char *); /* multiselect_cb */ +-typedef int (*IFnis)(Ihandle*, int, char *); /* text_action, multiline_action, edit_cb, renamenode_cb, rename_cb */ ++typedef int (*IFnis)(Ihandle*, int, char *); /* text_action, multiline_action, edit_cb, rename_cb */ + typedef int (*IFnsii)(Ihandle*, char*, int, int); /* list_action */ + typedef int (*IFnsiii)(Ihandle*, char*, int, int, int); /* dropfiles_cb */ + typedef int (*IFniis)(Ihandle*, int, int, char*); /* motion_cb, click_cb, value_edit_cb */ +diff --git a/iup/include/iupcontrols.h b/iup/include/iupcontrols.h +index c7bc566..a30d407 100755 +--- a/iup/include/iupcontrols.h ++++ b/iup/include/iupcontrols.h +@@ -15,9 +15,6 @@ extern "C" { + int IupControlsOpen(void); + void IupControlsClose(void); /* for backward compatibility only, does nothing since IUP 3 */ +  +-void IupOldValOpen(void); +-void IupOldTabsOpen(void); +- + Ihandle* IupColorbar(void); + Ihandle* IupCells(void); + Ihandle *IupColorBrowser(void); +diff --git a/iup/include/iuplua.h b/iup/include/iuplua.h +index dc660b5..854a858 100755 +--- a/iup/include/iuplua.h ++++ b/iup/include/iuplua.h +@@ -23,7 +23,7 @@ int iuplua_dofile (char *filename); +  + #ifdef LUA_TNONE /* Lua 5 */ + int iuplua_open(lua_State *L); +-int iupkey_open(lua_State *L); ++int iupkey_open(lua_State *L); /* does nothing, kept for backward compatibility */ + int iuplua_close(lua_State * L); +  + /* utilities */ +diff --git a/iup/mak.vc8/iupgtk.vcproj b/iup/mak.vc8/iupgtk.vcproj +index 5d0a8e2..9fccbb2 100755 +--- a/iup/mak.vc8/iupgtk.vcproj ++++ b/iup/mak.vc8/iupgtk.vcproj +@@ -143,6 +143,10 @@ + > +  +  ++  ++  +  +diff --git a/iup/mak.vc8/iuplua5.vcproj b/iup/mak.vc8/iuplua5.vcproj +index 0c62f76..1245e86 100755 +--- a/iup/mak.vc8/iuplua5.vcproj ++++ b/iup/mak.vc8/iuplua5.vcproj +@@ -123,6 +123,10 @@ + > +  +  ++  ++  +  +@@ -307,6 +311,10 @@ + > +  +  ++  ++  +  +diff --git a/iup/mak.vc8/iupmot.vcproj b/iup/mak.vc8/iupmot.vcproj +index aedd67e..d2d1780 100755 +--- a/iup/mak.vc8/iupmot.vcproj ++++ b/iup/mak.vc8/iupmot.vcproj +@@ -161,6 +161,10 @@ + > +  +  ++  ++  +  +diff --git a/iup/mak.vc8/iupsample.vcproj b/iup/mak.vc8/iupsample.vcproj +index bddc4f6..dde33fd 100755 +--- a/iup/mak.vc8/iupsample.vcproj ++++ b/iup/mak.vc8/iupsample.vcproj +@@ -616,6 +616,13 @@ +  ++  ++  ++  +  +  ++  ++  ++  +  +  +  +  +  +  ++  ++  +  +@@ -255,6 +259,14 @@ + > +  +  ++  ++  ++  ++  +  +@@ -298,6 +310,10 @@ + RelativePath="..\test\vbox.c" + > +  ++  ++  +  +  +  +diff --git a/iup/mak.vc8/iuptestgtk.vcproj b/iup/mak.vc8/iuptestgtk.vcproj +index 46d9e49..017bb69 100755 +--- a/iup/mak.vc8/iuptestgtk.vcproj ++++ b/iup/mak.vc8/iuptestgtk.vcproj +@@ -154,6 +154,10 @@ + > +  +  ++  ++  +  +@@ -246,6 +250,14 @@ + > +  +  ++  ++  ++  ++  +  +@@ -289,6 +301,10 @@ + RelativePath="..\test\vbox.c" + > +  ++  ++  +  +  +  +diff --git a/iup/mak.vc8/iupwin.vcproj b/iup/mak.vc8/iupwin.vcproj +index c1e2434..cf53df8 100755 +--- a/iup/mak.vc8/iupwin.vcproj ++++ b/iup/mak.vc8/iupwin.vcproj +@@ -176,6 +176,10 @@ + > +  +  ++  ++  +  +diff --git a/iup/mak.vc9/iup.sln b/iup/mak.vc9/iup.sln +index 898c75f..47e2076 100755 +--- a/iup/mak.vc9/iup.sln ++++ b/iup/mak.vc9/iup.sln +@@ -95,6 +95,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iuplua5_exe", "iupluaexe5.v + {1EBC7A53-4677-AAAA-1234-49D301F17D85} = {1EBC7A53-4677-AAAA-1234-49D301F17D85} + {1EBC7A53-4677-75D7-8D4A-49D301F17D85} = {1EBC7A53-4677-75D7-8D4A-49D301F17D85} + {1EBC7A53-4677-ADF1-8D4A-49D301F17D85} = {1EBC7A53-4677-ADF1-8D4A-49D301F17D85} ++ {1EBC7A53-4677-FFFF-1234-49D301F17D85} = {1EBC7A53-4677-FFFF-1234-49D301F17D85} + {B4823266-DF8C-4EFB-91C0-C7688C234EAC} = {B4823266-DF8C-4EFB-91C0-C7688C234EAC} + {5EEFE977-C56D-462F-BDEE-12A5452EB8CC} = {5EEFE977-C56D-462F-BDEE-12A5452EB8CC} + {5EEFE977-C56D-462F-BDEE-12A5452EB8CC} = {5EEFE977-C56D-462F-BDEE-12A5452EB8CC} +@@ -196,6 +197,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iuplua5gtk_exe", "iupluaexe + {E251B4F4-0B0A-482B-BA18-2509ADC4B6AA} = {E251B4F4-0B0A-482B-BA18-2509ADC4B6AA} + EndProjectSection + EndProject ++Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{B24D8E0A-2EB5-4C49-A146-C0AABEF81788}" ++EndProject + Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 +@@ -285,7 +288,6 @@ Global + {2F92EC58-D94C-40BF-8C82-77607C72E1E3} = {FC52B7B5-744E-45D6-815C-3502F9D965E7} + {9462FDEA-3E53-4250-8710-DD50AF48607C} = {FC52B7B5-744E-45D6-815C-3502F9D965E7} + {C684B76D-52EC-49CE-84F2-B031509419A5} = {FC52B7B5-744E-45D6-815C-3502F9D965E7} +- {A60D658D-766C-40DB-BAFF-59AB884D86FB} = {11041D08-354A-4300-9624-41277E67DE34} + {1EBC7A53-4677-4C3A-8DFF-269001F17D85} = {11041D08-354A-4300-9624-41277E67DE34} + {1EBC7A53-4677-4C3A-8DFF-49DFF4417D85} = {11041D08-354A-4300-9624-41277E67DE34} + {1EBC7A53-33FF-4C3A-8DFF-49D301F17D85} = {11041D08-354A-4300-9624-41277E67DE34} +@@ -293,7 +295,6 @@ Global + {1EBC7A53-4677-1234-DDDD-49DFF4417D85} = {11041D08-354A-4300-9624-41277E67DE34} + {B4823266-DF8C-4EFB-91C0-C7E78C234EAC} = {11041D08-354A-4300-9624-41277E67DE34} + {1EBC7A53-4677-4C3A-8DFF-49D301F17D85} = {11041D08-354A-4300-9624-41277E67DE34} +- {A60D658D-766C-40DB-BAE4-59AB884D86FB} = {1CBEAA34-BA34-497D-A775-B9AF6F905696} + {1EBC7A53-4677-ADF1-8D4A-49D301F17D85} = {1CBEAA34-BA34-497D-A775-B9AF6F905696} + {1EBC7A53-4677-75D7-8D4A-49D301F17D85} = {1CBEAA34-BA34-497D-A775-B9AF6F905696} + {1EBC7A53-4677-4C3A-8D4A-49D301157985} = {1CBEAA34-BA34-497D-A775-B9AF6F905696} +@@ -302,7 +303,12 @@ Global + {B4823266-DF8C-4EFB-91C0-C7688C234EAC} = {1CBEAA34-BA34-497D-A775-B9AF6F905696} + {1EBC7A53-4677-4C3A-8D4A-49D301F17D85} = {1CBEAA34-BA34-497D-A775-B9AF6F905696} + {1EBC7A53-4677-FFFF-1234-49D301F17D85} = {1CBEAA34-BA34-497D-A775-B9AF6F905696} +- {389DF3C9-A628-4F6D-8C52-8924FA01DE66} = {1CBEAA34-BA34-497D-A775-B9AF6F905696} ++ {A60D658D-766C-40DB-BAFF-59AB884D86FB} = {B24D8E0A-2EB5-4C49-A146-C0AABEF81788} ++ {A60D658D-766C-40DB-BAE4-59AB884D86FB} = {B24D8E0A-2EB5-4C49-A146-C0AABEF81788} ++ {389DF3C9-A628-4F6D-8C52-8924FA01DE66} = {B24D8E0A-2EB5-4C49-A146-C0AABEF81788} ++ {2F92EC58-D94C-40BF-4444-77607C72E1E3} = {B24D8E0A-2EB5-4C49-A146-C0AABEF81788} ++ {E7D19356-B0AB-44AD-ACCB-5FFFCC4837BE} = {B24D8E0A-2EB5-4C49-A146-C0AABEF81788} ++ {0F789DF8-22CC-4392-98DB-AC3960FAD4EA} = {B24D8E0A-2EB5-4C49-A146-C0AABEF81788} + EndGlobalSection + GlobalSection(DevPartner) = postSolution + EndGlobalSection +diff --git a/iup/mak.vc9/iupcontrols.vcproj b/iup/mak.vc9/iupcontrols.vcproj +index 6a452af..2a7875c 100755 +--- a/iup/mak.vc9/iupcontrols.vcproj ++++ b/iup/mak.vc9/iupcontrols.vcproj +@@ -311,14 +311,6 @@ + > +  +  +-  +-  +-  +-  +  +  +  ++  ++  +  +@@ -583,17 +587,6 @@ + > +  +  +-  +-  +-  +-  +-  +  +  +  +diff --git a/iup/mak.vc9/iupgtk.vcproj b/iup/mak.vc9/iupgtk.vcproj +index 17281f1..a84dd4a 100755 +--- a/iup/mak.vc9/iupgtk.vcproj ++++ b/iup/mak.vc9/iupgtk.vcproj +@@ -95,6 +95,10 @@ + > +  +  ++  ++  +  +diff --git a/iup/mak.vc9/iuplua3.vcproj b/iup/mak.vc9/iuplua3.vcproj +index 9993c1c..e46f316 100755 +--- a/iup/mak.vc9/iuplua3.vcproj ++++ b/iup/mak.vc9/iuplua3.vcproj +@@ -116,6 +116,10 @@ + > +  +  ++  ++  +  +@@ -164,6 +168,10 @@ + > +  +  ++  ++  +  +diff --git a/iup/mak.vc9/iuplua5.vcproj b/iup/mak.vc9/iuplua5.vcproj +index 17d9a55..ad13650 100755 +--- a/iup/mak.vc9/iuplua5.vcproj ++++ b/iup/mak.vc9/iuplua5.vcproj +@@ -231,6 +231,10 @@ + > +  +  ++  ++  +  +@@ -407,6 +411,10 @@ + > +  +  ++  ++  +  +diff --git a/iup/mak.vc9/iupluaexe5.vcproj b/iup/mak.vc9/iupluaexe5.vcproj +index db6804a..39d15f2 100755 +--- a/iup/mak.vc9/iupluaexe5.vcproj ++++ b/iup/mak.vc9/iupluaexe5.vcproj +@@ -72,7 +72,7 @@ + OutputFile="$(OutDir)/iuplua51.exe" + LinkIncremental="1" + SuppressStartupBanner="true" +- AdditionalLibraryDirectories="..\..\im\lib;..\..\cd\lib;..\lib;..\..\lua5.1\lib\vc9;..\..\luagl\lib\static" ++ AdditionalLibraryDirectories="..\..\im\lib;..\..\cd\lib;..\lib;..\..\lua5.1\lib\vc9;..\..\luagl\lib\static;..\..\lfs\lib\vc9" + GenerateManifest="false" + GenerateDebugInformation="true" + SubSystem="1" +diff --git a/iup/mak.vc9/iupmot.vcproj b/iup/mak.vc9/iupmot.vcproj +index 9bbfa5c..5c40695 100755 +--- a/iup/mak.vc9/iupmot.vcproj ++++ b/iup/mak.vc9/iupmot.vcproj +@@ -109,6 +109,10 @@ + > +  +  ++  ++  +  +diff --git a/iup/mak.vc9/iupsample.vcproj b/iup/mak.vc9/iupsample.vcproj +index 144f3ba..0e10bb6 100755 +--- a/iup/mak.vc9/iupsample.vcproj ++++ b/iup/mak.vc9/iupsample.vcproj +@@ -45,7 +45,7 @@ + Optimization="0" + AdditionalIncludeDirectories="..\include;..\..\cd\include" + PreprocessorDefinitions="WIN32;_DEBUG;_WIN32_WINNT=0x0500;_WIN32_IE=0x0500;_CRT_SECURE_NO_DEPRECATE;__IUPDEF_H" +- ExceptionHandling="0" ++ ExceptionHandling="1" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + UsePrecompiledHeader="0" +diff --git a/iup/mak.vc9/iupsamplegtk.vcproj b/iup/mak.vc9/iupsamplegtk.vcproj +index 24da672..485b773 100755 +--- a/iup/mak.vc9/iupsamplegtk.vcproj ++++ b/iup/mak.vc9/iupsamplegtk.vcproj +@@ -617,7 +617,6 @@ + > +  +  +  +  +  +  ++  ++  +  +diff --git a/iup/mak.vc9/iuptestgtk.vcproj b/iup/mak.vc9/iuptestgtk.vcproj +index 4cbc9da..d8c092c 100755 +--- a/iup/mak.vc9/iuptestgtk.vcproj ++++ b/iup/mak.vc9/iuptestgtk.vcproj +@@ -73,6 +73,7 @@ + LinkIncremental="1" + SuppressStartupBanner="true" + AdditionalLibraryDirectories="..\lib;d:\lng\gtk\lib;..\..\cd\lib;D:\LNG\vld\lib" ++ GenerateManifest="false" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb" + SubSystem="1" +@@ -262,6 +263,10 @@ + > +  +  ++  ++  +  +diff --git a/iup/mak.vc9/iupwin.vcproj b/iup/mak.vc9/iupwin.vcproj +index 15578a9..94ef390 100755 +--- a/iup/mak.vc9/iupwin.vcproj ++++ b/iup/mak.vc9/iupwin.vcproj +@@ -248,6 +248,10 @@ + > +  +  ++  ++  +  +  +  +diff --git a/iup/src/Makefile b/iup/src/Makefile +index 028047f..e666555 100755 +--- a/iup/src/Makefile ++++ b/iup/src/Makefile +@@ -1,9 +1,12 @@ +  +-.PHONY: do_all iup iupgtk +-do_all: iup iupgtk ++.PHONY: do_all iup iupgtk iupmot ++do_all: iup +  + iup: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak  ++ @$(MAKE) --no-print-directory -f ../tecmake.mak  +  + iupgtk: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak USE_GTK=Yes ++ @$(MAKE) --no-print-directory -f ../tecmake.mak USE_GTK=Yes ++ ++iupmot: ++ @$(MAKE) --no-print-directory -f ../tecmake.mak USE_MOTIF=Yes +diff --git a/iup/src/config.mak b/iup/src/config.mak +index e857643..82b8452 100755 +--- a/iup/src/config.mak ++++ b/iup/src/config.mak +@@ -2,9 +2,31 @@ PROJNAME = iup + LIBNAME = iup + OPT = YES +  +-#ifdef DBG ++ifdef GTK_DEFAULT ++ ifdef USE_MOTIF ++ # Build Motif version in Linux,Darwin,FreeBSD ++ LIBNAME = iupmot ++ else ++ ifeq ($(findstring Win, $(TEC_SYSNAME)), ) ++ # Force definition if not in Windows ++ USE_GTK = Yes ++ endif ++ endif ++else  ++ ifdef USE_GTK ++ # Build GTK version in IRIX,SunOS,AIX,Win32 ++ LIBNAME = iupgtk ++ else ++ ifeq ($(findstring Win, $(TEC_SYSNAME)), ) ++ # Force definition if not in Windows ++ USE_MOTIF = Yes ++ endif ++ endif ++endif ++ ++ifdef DBG + DEFINES += IUP_ASSERT +-#endif  ++endif  +  + INCLUDES = ../include . +  +@@ -17,19 +39,14 @@ SRC = iup_array.c iup_callback.c iup_dlglist.c iup_attrib.c iup_focus.c iup_font + iup_user.c iup_button.c iup_radio.c iup_toggle.c iup_progressbar.c iup_text.c iup_val.c \ + iup_box.c iup_hbox.c iup_vbox.c iup_cbox.c iup_class.c iup_classbase.c iup_maskmatch.c \ + iup_mask.c iup_maskparse.c iup_tabs.c iup_spin.c iup_list.c iup_getparam.c \ +- iup_sbox.c iup_normalizer.c iup_tree.c ++ iup_sbox.c iup_normalizer.c iup_tree.c iup_split.c +  + ifdef USE_GTK +- ifndef GTK_DEFAULT +- # Build GTK version in IRIX,SunOS,AIX,Win32 +- LIBNAME := iupgtk +- endif +- + DEFINES += GTK_DISABLE_DEPRECATED + INCLUDES += gtk + SRC += gtk/iupgtk_common.c gtk/iupgtk_focus.c gtk/iupgtk_font.c gtk/iupgtk_clipboard.c \ + gtk/iupgtk_globalattrib.c gtk/iupgtk_key.c gtk/iupgtk_tips.c \ +- gtk/iupgtk_loop.c gtk/iupgtk_open.c gtk/iupgtk_messagedlg.c \ ++ gtk/iupgtk_loop.c gtk/iupgtk_open.c gtk/iupgtk_messagedlg.c gtk/iupgtk_draw.c \ + gtk/iupgtk_dialog.c gtk/iupgtk_timer.c gtk/iupgtk_image.c gtk/iupgtk_label.c \ + gtk/iupgtk_colordlg.c gtk/iupgtk_fontdlg.c gtk/iupgtk_filedlg.c \ + gtk/iupgtk_button.c gtk/iupgtk_toggle.c gtk/iupgtk_progressbar.c \ +@@ -40,7 +57,11 @@ ifdef USE_GTK + DEFINES += _WIN32_WINNT=0x0500 _WIN32_IE=0x0500 WINVER=0x0500 NOTREEVIEW + SRC += win/iupwindows_main.c win/iupwindows_help.c win/iupwindows_info.c + else +- SRC += gtk/iupgtk_help.c mot/iupunix_info.c ++ ifdef GTK_MAC ++ SRC += gtk/iupmac_help.c gtk/iupmac_info.c ++ else ++ SRC += gtk/iupgtk_help.c mot/iupunix_info.c ++ endif + endif +  + ifdef USE_HILDON +@@ -49,42 +70,35 @@ ifdef USE_GTK + LIBS += hildon-1 + endif + else +- ifneq ($(findstring Win, $(TEC_SYSNAME)), ) +-  +- SRC += win/iupwin_common.c win/iupwin_brush.c win/iupwin_focus.c win/iupwin_font.c \ +- win/iupwin_globalattrib.c win/iupwin_handle.c win/iupwin_key.c \ +- win/iupwin_loop.c win/iupwin_open.c win/iupwin_tips.c win/iupwin_info.c \ +- win/iupwin_dialog.c win/iupwin_messagedlg.c win/iupwin_timer.c \ +- win/iupwin_image.c win/iupwin_label.c win/iupwin_canvas.c win/iupwin_frame.c \ +- win/iupwin_colordlg.c win/iupwin_fontdlg.c win/iupwin_filedlg.c \ +- win/iupwin_button.c win/iupwin_draw.c win/iupwin_toggle.c win/iupwin_clipboard.c \ +- win/iupwin_progressbar.c win/iupwin_text.c win/iupwin_val.c \ +- win/iupwin_tabs.c win/iupwin_menu.c win/iupwin_list.c win/iupwin_tree.c +-  +- SRC += win/iupwindows_main.c win/iupwindows_help.c win/iupwindows_info.c +-  +- INCLUDES += win +- DEFINES += _WIN32_WINNT=0x0500 _WIN32_IE=0x0500 WINVER=0x0500 NOTREEVIEW +- else +- ifdef GTK_DEFAULT +- # Build Motif version in Linux,Darwin,FreeBSD +- LIBNAME := iupmot +- endif  +-  +- SRC += mot/iupmot_common.c mot/iupmot_color.c mot/iupmot_focus.c mot/iupmot_font.c \ +- mot/iupmot_key.c mot/iupmot_loop.c mot/iupmot_open.c mot/iupmot_tips.c \ +- mot/iupmot_globalattrib.c mot/iupmot_dialog.c mot/iupmot_messagedlg.c \ +- mot/iupmot_timer.c mot/iupmot_image.c mot/iupmot_label.c mot/iupmot_canvas.c \ +- mot/iupmot_colordlg.c mot/iupmot_fontdlg.c mot/iupmot_filedlg.c mot/iupmot_frame.c \ +- mot/iupmot_button.c mot/iupmot_toggle.c mot/iupmot_progressbar.c mot/iupmot_clipboard.c \ +- mot/iupmot_text.c mot/iupmot_val.c mot/iupmot_tabs.c mot/iupmot_menu.c \ +- mot/iupmot_list.c mot/iupmot_tree.c +-  +- SRC += mot/iupunix_help.c mot/iupunix_info.c +-  +- INCLUDES += mot +- USE_MOTIF=Yes  +- endif ++ifdef USE_MOTIF ++ SRC += mot/iupmot_common.c mot/iupmot_color.c mot/iupmot_focus.c mot/iupmot_font.c \ ++ mot/iupmot_key.c mot/iupmot_loop.c mot/iupmot_open.c mot/iupmot_tips.c \ ++ mot/iupmot_globalattrib.c mot/iupmot_dialog.c mot/iupmot_messagedlg.c mot/iupmot_draw.c \ ++ mot/iupmot_timer.c mot/iupmot_image.c mot/iupmot_label.c mot/iupmot_canvas.c \ ++ mot/iupmot_colordlg.c mot/iupmot_fontdlg.c mot/iupmot_filedlg.c mot/iupmot_frame.c \ ++ mot/iupmot_button.c mot/iupmot_toggle.c mot/iupmot_progressbar.c mot/iupmot_clipboard.c \ ++ mot/iupmot_text.c mot/iupmot_val.c mot/iupmot_tabs.c mot/iupmot_menu.c \ ++ mot/iupmot_list.c mot/iupmot_tree.c ++  ++ SRC += mot/iupunix_help.c mot/iupunix_info.c ++ ++ INCLUDES += mot ++else ++ SRC += win/iupwin_common.c win/iupwin_brush.c win/iupwin_focus.c win/iupwin_font.c \ ++ win/iupwin_globalattrib.c win/iupwin_handle.c win/iupwin_key.c \ ++ win/iupwin_loop.c win/iupwin_open.c win/iupwin_tips.c win/iupwin_info.c \ ++ win/iupwin_dialog.c win/iupwin_messagedlg.c win/iupwin_timer.c \ ++ win/iupwin_image.c win/iupwin_label.c win/iupwin_canvas.c win/iupwin_frame.c \ ++ win/iupwin_colordlg.c win/iupwin_fontdlg.c win/iupwin_filedlg.c \ ++ win/iupwin_button.c win/iupwin_draw.c win/iupwin_toggle.c win/iupwin_clipboard.c \ ++ win/iupwin_progressbar.c win/iupwin_text.c win/iupwin_val.c \ ++ win/iupwin_tabs.c win/iupwin_menu.c win/iupwin_list.c win/iupwin_tree.c ++  ++ SRC += win/iupwindows_main.c win/iupwindows_help.c win/iupwindows_info.c ++ ++ INCLUDES += win ++ DEFINES += _WIN32_WINNT=0x0500 _WIN32_IE=0x0500 WINVER=0x0500 NOTREEVIEW ++endif + endif +  + ifeq "$(TEC_SYSNAME)" "SunOS" +@@ -113,6 +127,6 @@ ifeq "$(TEC_UNAME)" "dll" + endif +  + ifeq "$(TEC_UNAME)" "owc1" +- # Necessary or IUP will not work in Open Watcom ++ # Necessary or IUP 3 will not work in Open Watcom + DBG=Yes + endif +diff --git a/iup/src/gtk/iupgtk_button.c b/iup/src/gtk/iupgtk_button.c +index 18be87c..f8474ae 100755 +--- a/iup/src/gtk/iupgtk_button.c ++++ b/iup/src/gtk/iupgtk_button.c +@@ -150,8 +150,10 @@ static int gtkButtonSetPaddingAttrib(Ihandle* ih, const char* value) + gtk_alignment_set_padding(alignment, ih->data->vert_padding, ih->data->vert_padding,  + ih->data->horiz_padding, ih->data->horiz_padding); + } ++ return 0; + } +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + #ifdef WIN32 +@@ -366,12 +368,12 @@ static int gtkButtonMapMethod(Ihandle* ih) + ih->data->type = IUP_BUTTON_IMAGE; +  + value = iupAttribGet(ih, "TITLE"); +- if (value) ++ if (value && *value!=0) + { + GtkSettings* settings = gtk_widget_get_settings(ih->handle); + g_object_set(settings, "gtk-button-images", (int)TRUE, NULL); +  +- gtk_button_set_label((GtkButton*)ih->handle, value); ++ gtk_button_set_label((GtkButton*)ih->handle, iupgtkStrConvertToUTF8(value)); + ih->data->type |= IUP_BUTTON_TEXT; +  + #if GTK_CHECK_VERSION(2, 10, 0) +@@ -397,7 +399,7 @@ static int gtkButtonMapMethod(Ihandle* ih) + #endif + } + else +- gtk_button_set_label((GtkButton*)ih->handle, title); ++ gtk_button_set_label((GtkButton*)ih->handle, iupgtkStrConvertToUTF8(title)); + ih->data->type = IUP_BUTTON_TEXT; + } +  +diff --git a/iup/src/gtk/iupgtk_canvas.c b/iup/src/gtk/iupgtk_canvas.c +index daae4ad..3af48a4 100755 +--- a/iup/src/gtk/iupgtk_canvas.c ++++ b/iup/src/gtk/iupgtk_canvas.c +@@ -537,8 +537,8 @@ static int gtkCanvasMapMethod(Ihandle* ih) +  + /* To receive mouse events on a drawing area, you will need to enable them. */ + gtk_widget_add_events(ih->handle, GDK_EXPOSURE_MASK| +- GDK_POINTER_MOTION_MASK|GDK_BUTTON_MOTION_MASK| +- GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK| ++ GDK_POINTER_MOTION_MASK|GDK_POINTER_MOTION_HINT_MASK| ++ GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|GDK_BUTTON_MOTION_MASK| + GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK| + GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK| + GDK_FOCUS_CHANGE_MASK|GDK_STRUCTURE_MASK); +@@ -611,14 +611,15 @@ void iupdrvCanvasInitClass(Iclass* ic) + iupClassRegisterAttribute(ic, "YAUTOHIDE", NULL, gtkCanvasSetYAutoHideAttrib, "YES", NULL, IUPAF_DEFAULT); /* force new default value */ +  + iupClassRegisterAttribute(ic, "DRAWABLE", gtkCanvasGetDrawableAttrib, NULL, NULL, NULL, IUPAF_NO_STRING); +- //iupClassRegisterAttribute(ic, "CD_GDK", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); +  + /* IupCanvas Windows or X only */ +-#ifdef WIN32  +- iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); +-#else +- iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); +- iupClassRegisterAttribute(ic, "XDISPLAY", (IattribGetFunc)iupdrvGetDisplay, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); ++#ifndef GTK_MAC ++ #ifdef WIN32  ++ iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); ++ #else ++ iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); ++ iupClassRegisterAttribute(ic, "XDISPLAY", (IattribGetFunc)iupdrvGetDisplay, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); ++ #endif + #endif + } +  +diff --git a/iup/src/gtk/iupgtk_common.c b/iup/src/gtk/iupgtk_common.c +index 40368f2..d84c1c8 100755 +--- a/iup/src/gtk/iupgtk_common.c ++++ b/iup/src/gtk/iupgtk_common.c +@@ -91,13 +91,13 @@ void iupdrvBaseUnMapMethod(Ihandle* ih) + gtk_widget_destroy(widget); /* To match the call to gtk_*****_new */ + } +  +-void iupdrvDisplayUpdate(Ihandle *ih) ++void iupdrvPostRedraw(Ihandle *ih) + { + /* Post a REDRAW */ + gtk_widget_queue_draw(ih->handle); + } +  +-void iupdrvDisplayRedraw(Ihandle *ih) ++void iupdrvRedrawNow(Ihandle *ih) + { + GdkWindow* window = ih->handle->window; + /* Post a REDRAW */ +@@ -202,7 +202,11 @@ void iupdrvSetVisible(Ihandle* ih, int visible) +  + int iupdrvIsVisible(Ihandle* ih) + { ++#if GTK_CHECK_VERSION(2, 18, 0) ++ if (gtk_widget_get_visible(ih->handle)) ++#else + if (GTK_WIDGET_VISIBLE(ih->handle)) ++#endif + { + /* if marked as visible, since we use gtk_widget_hide and NOT gtk_widget_hide_all + must check its parents. */ +@@ -211,7 +215,11 @@ int iupdrvIsVisible(Ihandle* ih) + { + if (parent->iclass->nativetype != IUP_TYPEVOID) + { ++#if GTK_CHECK_VERSION(2, 18, 0) ++ if (!gtk_widget_get_visible(parent->handle)) ++#else + if (!GTK_WIDGET_VISIBLE(parent->handle)) ++#endif + return 0; + } +  +@@ -225,7 +233,11 @@ int iupdrvIsVisible(Ihandle* ih) +  + int iupdrvIsActive(Ihandle *ih) + { +- return (GTK_WIDGET_IS_SENSITIVE(ih->handle)); ++#if GTK_CHECK_VERSION(2, 18, 0) ++ return gtk_widget_is_sensitive(ih->handle); ++#else ++ return GTK_WIDGET_IS_SENSITIVE(ih->handle); ++#endif + } +  + void iupdrvSetActive(Ihandle* ih, int enable) +@@ -424,9 +436,11 @@ static GdkCursor* gtkGetCursor(Ihandle* ih, const char* name) + { "RESIZE_N", GDK_TOP_SIDE}, + { "RESIZE_S", GDK_BOTTOM_SIDE}, + { "RESIZE_NS", GDK_SB_V_DOUBLE_ARROW}, ++ { "SPLITTER_HORIZ", GDK_SB_V_DOUBLE_ARROW}, + { "RESIZE_W", GDK_LEFT_SIDE}, + { "RESIZE_E", GDK_RIGHT_SIDE}, + { "RESIZE_WE", GDK_SB_H_DOUBLE_ARROW}, ++ { "SPLITTER_VERT", GDK_SB_H_DOUBLE_ARROW}, + { "RESIZE_NE", GDK_TOP_RIGHT_CORNER}, + { "RESIZE_SE", GDK_BOTTOM_RIGHT_CORNER}, + { "RESIZE_NW", GDK_TOP_LEFT_CORNER}, +@@ -571,18 +585,24 @@ void iupdrvDrawFocusRect(Ihandle* ih, void* _gc, int x, int y, int w, int h) + { + GdkWindow* window = ih->handle->window; + GtkStyle *style = gtk_widget_get_style(ih->handle); ++#if GTK_CHECK_VERSION(2, 18, 0) ++ GtkStateType state = gtk_widget_get_state(ih->handle); ++#else ++ GtkStateType state = GTK_WIDGET_STATE(ih->handle); ++#endif ++ gtk_paint_focus(style, window, state, NULL, ih->handle, NULL, x, y, w, h); + (void)_gc; +- +- gtk_paint_focus(style, window, GTK_WIDGET_STATE(ih->handle), NULL, ih->handle, NULL, x, y, w, h); + } +  + void iupdrvBaseRegisterCommonAttrib(Iclass* ic) + { ++#ifndef GTK_MAC + #ifdef WIN32  + iupClassRegisterAttribute(ic, "HFONT", iupgtkGetFontIdAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + #else + iupClassRegisterAttribute(ic, "XFONTID", iupgtkGetFontIdAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + #endif ++#endif + iupClassRegisterAttribute(ic, "PANGOFONTDESC", iupgtkGetPangoFontDescAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + } +  +@@ -789,7 +809,17 @@ char* iupgtkStrConvertFromFilename(const char* str) /* From Filename to IUP */ +  + gboolean iupgtkMotionNotifyEvent(GtkWidget *widget, GdkEventMotion *evt, Ihandle *ih) + { +- IFniis cb = (IFniis)IupGetCallback(ih,"MOTION_CB"); ++ IFniis cb; ++ ++ if (evt->is_hint) ++ { ++ int x, y; ++ gdk_window_get_pointer(widget->window, &x, &y, NULL); ++ evt->x = x; ++ evt->y = y; ++ } ++ ++ cb = (IFniis)IupGetCallback(ih,"MOTION_CB"); + if (cb) + { + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; +@@ -818,6 +848,23 @@ gboolean iupgtkButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih) +  + iupgtkButtonKeySetStatus(evt->state, evt->button, status, doubleclick); +  ++ if (doubleclick) ++ { ++ /* Must compensate the fact that in GTK there is an extra button press event  ++ when occours a double click, we compensate that completing the event  ++ with a button release before the double click. */ ++ ++ status[5] = ' '; /* clear double click */ ++ ++ ret = cb(ih, b, 0, (int)evt->x, (int)evt->y, status); /* release */ ++ if (ret==IUP_CLOSE) ++ IupExitLoop(); ++ else if (ret==IUP_IGNORE) ++ return TRUE; ++ ++ status[5] = 'D'; /* restore double click */ ++ } ++ + ret = cb(ih, b, press, (int)evt->x, (int)evt->y, status); + if (ret==IUP_CLOSE) + IupExitLoop(); +diff --git a/iup/src/gtk/iupgtk_dialog.c b/iup/src/gtk/iupgtk_dialog.c +index 46c0ce1..ff0d8f2 100755 +--- a/iup/src/gtk/iupgtk_dialog.c ++++ b/iup/src/gtk/iupgtk_dialog.c +@@ -120,12 +120,13 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu + static int native_border = 0; + static int native_caption = 0; +  +- int has_caption = iupAttribGetBoolean(ih, "MAXBOX") || +- iupAttribGetBoolean(ih, "MINBOX") || +- iupAttribGetBoolean(ih, "MENUBOX") ||  +- IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ ++ int has_titlebar = iupAttribGetBoolean(ih, "RESIZE") || /* GTK and Motif only */ ++ iupAttribGetBoolean(ih, "MAXBOX") || ++ iupAttribGetBoolean(ih, "MINBOX") || ++ iupAttribGetBoolean(ih, "MENUBOX") ||  ++ IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ +  +- int has_border = has_caption || ++ int has_border = has_titlebar || + iupAttribGetBoolean(ih, "RESIZE") || + iupAttribGetBoolean(ih, "BORDER"); +  +@@ -147,7 +148,7 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu + *border = win_border; +  + *caption = 0; +- if (has_caption) ++ if (has_titlebar) + *caption = win_caption; +  + if (!native_border && *border) +@@ -171,7 +172,7 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu + } +  + *caption = 0; +- if (has_caption) ++ if (has_titlebar) + { + if (native_caption) + *caption = native_caption; +@@ -429,6 +430,7 @@ static int gtkDialogMapMethod(Ihandle* ih) + int functions = 0; + InativeHandle* parent; + GtkWidget* fixed; ++ int has_titlebar = 0; +  + #ifdef HILDON + if (iupAttribGetBoolean(ih, "HILDONWINDOW"))  +@@ -494,33 +496,41 @@ static int gtkDialogMapMethod(Ihandle* ih) + iupAttribSetStr(ih, "MINBOX", "NO"); + } +  +- if (IupGetAttribute(ih, "TITLE")) { /* must use IupGetAttribute to check from the native implementation */ +- functions |= GDK_FUNC_MOVE; +- decorations |= GDK_DECOR_TITLE; +- } +- +- if (iupAttribGetBoolean(ih, "MENUBOX")) { ++ if (iupAttribGet(ih, "TITLE")) ++ has_titlebar = 1; ++ if (iupAttribGetBoolean(ih, "MENUBOX"))  ++ { + functions |= GDK_FUNC_CLOSE; + decorations |= GDK_DECOR_MENU; ++ has_titlebar = 1; + } +- +- if (iupAttribGetBoolean(ih, "MINBOX")) { ++ if (iupAttribGetBoolean(ih, "MINBOX"))  ++ { + functions |= GDK_FUNC_MINIMIZE; + decorations |= GDK_DECOR_MINIMIZE; ++ has_titlebar = 1; + } +- +- if (iupAttribGetBoolean(ih, "MAXBOX")) { ++ if (iupAttribGetBoolean(ih, "MAXBOX"))  ++ { + functions |= GDK_FUNC_MAXIMIZE; + decorations |= GDK_DECOR_MAXIMIZE; ++ has_titlebar = 1; + } +- +- if (iupAttribGetBoolean(ih, "RESIZE")) { ++ if (iupAttribGetBoolean(ih, "RESIZE"))  ++ { + functions |= GDK_FUNC_RESIZE; + decorations |= GDK_DECOR_RESIZEH; +- } +  +- if (iupAttribGetBoolean(ih, "BORDER")) +- decorations |= GDK_DECOR_BORDER; ++ decorations |= GDK_DECOR_BORDER; /* has_border */ ++ } ++ if (has_titlebar) ++ { ++ functions |= GDK_FUNC_MOVE; ++ decorations |= GDK_DECOR_TITLE; ++ gtk_window_set_title((GtkWindow*)ih->handle, ""); ++ } ++ if (iupAttribGetBoolean(ih, "BORDER") || has_titlebar) ++ decorations |= GDK_DECOR_BORDER; /* has_border */ +  + if (decorations == 0) + gtk_window_set_decorated((GtkWindow*)ih->handle, FALSE); +@@ -980,11 +990,12 @@ void iupdrvDialogInitClass(Iclass* ic) + iupClassRegisterCallback(ic, "TRAYCLICK_CB", "iii"); +  + /* Driver Dependent Attribute functions */ +- +-#ifdef WIN32  +- iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); +-#else +- iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); ++#ifndef GTK_MAC ++ #ifdef WIN32  ++ iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); ++ #else ++ iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); ++ #endif + #endif +  + /* Visual */ +diff --git a/iup/src/gtk/iupgtk_drv.h b/iup/src/gtk/iupgtk_drv.h +index ade2a4a..bf567d6 100755 +--- a/iup/src/gtk/iupgtk_drv.h ++++ b/iup/src/gtk/iupgtk_drv.h +@@ -59,8 +59,8 @@ void iupgtkFontUpdateObjectPangoLayout(Ihandle* ih, gpointer object); + /* There are PANGO_SCALE Pango units in one device unit.  + For an output backend where a device unit is a pixel,  + a size value of 10 * PANGO_SCALE gives 10 pixels. */ +-#define IUPGTK_PANGOUNITS2PIXELS(_x) (((_x) + PANGO_SCALE/2) / PANGO_SCALE) +-#define IUPGTK_PIXELS2PANGOUNITS(_x) ((_x) * PANGO_SCALE) ++#define iupGTK_PANGOUNITS2PIXELS(_x) (((_x) + PANGO_SCALE/2) / PANGO_SCALE) ++#define iupGTK_PIXELS2PANGOUNITS(_x) ((_x) * PANGO_SCALE) +  +  + /* open */ +diff --git a/iup/src/gtk/iupgtk_filedlg.c b/iup/src/gtk/iupgtk_filedlg.c +index 5426910..a326c72 100755 +--- a/iup/src/gtk/iupgtk_filedlg.c ++++ b/iup/src/gtk/iupgtk_filedlg.c +@@ -77,6 +77,8 @@ static void gtkFileDlgGetMultipleFiles(Ihandle* ih, GSList* list) + cur_len = iupArrayCount(names_array); + all_names = iupArrayAdd(names_array, dir_len+1); + memcpy(all_names+cur_len, filename, dir_len); ++ all_names[cur_len+dir_len] = '0'; ++ iupAttribStoreStr(ih, "DIRECTORY", all_names); + all_names[cur_len+dir_len] = '|'; +  + dir_len++; /* skip separator */ +@@ -101,10 +103,14 @@ static void gtkFileDlgGetMultipleFiles(Ihandle* ih, GSList* list) + iupArrayDestroy(names_array); + } +  +-#ifdef WIN32 +-#include  ++#ifdef GTK_MAC ++ #include  + #else +-#include  ++ #ifdef WIN32 ++ #include  ++ #else ++ #include  ++ #endif + #endif +  + static void gtkFileDlgUpdatePreviewGLCanvas(Ihandle* ih) +@@ -112,10 +118,12 @@ static void gtkFileDlgUpdatePreviewGLCanvas(Ihandle* ih) + Ihandle* glcanvas = IupGetAttributeHandle(ih, "PREVIEWGLCANVAS"); + if (glcanvas) + { +-#ifdef WIN32  +- iupAttribSetStr(glcanvas, "HWND", iupAttribGet(ih, "HWND")); +-#else +- iupAttribSetStr(glcanvas, "XWINDOW", iupAttribGet(ih, "XWINDOW")); ++#ifndef GTK_MAC ++ #ifdef WIN32  ++ iupAttribSetStr(glcanvas, "HWND", iupAttribGet(ih, "HWND")); ++ #else ++ iupAttribSetStr(glcanvas, "XWINDOW", iupAttribGet(ih, "XWINDOW")); ++ #endif + #endif + glcanvas->iclass->Map(glcanvas); + } +@@ -126,12 +134,15 @@ static void gtkFileDlgPreviewRealize(GtkWidget *widget, Ihandle *ih) + iupAttribSetStr(ih, "PREVIEWDC", iupgtkGetNativeGraphicsContext(widget)); + iupAttribSetStr(ih, "WID", (char*)widget); +  +-#ifdef WIN32  +- iupAttribSetStr(ih, "HWND", (char*)GDK_WINDOW_HWND(widget->window)); +-#else +- iupAttribSetStr(ih, "XWINDOW", (char*)GDK_WINDOW_XID(widget->window)); +- iupAttribSetStr(ih, "XDISPLAY", (char*)iupdrvGetDisplay()); ++#ifndef GTK_MAC ++ #ifdef WIN32  ++ iupAttribSetStr(ih, "HWND", (char*)GDK_WINDOW_HWND(widget->window)); ++ #else ++ iupAttribSetStr(ih, "XWINDOW", (char*)GDK_WINDOW_XID(widget->window)); ++ iupAttribSetStr(ih, "XDISPLAY", (char*)iupdrvGetDisplay()); ++ #endif + #endif ++ + gtkFileDlgUpdatePreviewGLCanvas(ih); + } +  +@@ -174,11 +185,11 @@ static void gtkFileDlgUpdatePreview(GtkFileChooser *file_chooser, Ihandle* ih) + { + char *filename = gtk_file_chooser_get_preview_filename(file_chooser); +  ++ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (iupdrvIsFile(filename)) +- { +- IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + cb(ih, iupgtkStrConvertFromFilename(filename), "SELECT"); +- } ++ else ++ cb(ih, iupgtkStrConvertFromFilename(filename), "OTHER"); +  + g_free (filename); +  +@@ -469,6 +480,13 @@ static int gtkFileDlgPopup(Ihandle* ih, int x, int y) + char* filename = (char*)file_list->data; + iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(filename)); + g_free(filename); ++ ++ /* store the DIRECTORY */ ++ { ++ char* dir = iupStrFileGetPath(iupAttribGet(ih, "VALUE")); ++ iupAttribStoreStr(ih, "DIRECTORY", dir); ++ free(dir); ++ } + } +  + g_slist_free(file_list); +@@ -481,6 +499,14 @@ static int gtkFileDlgPopup(Ihandle* ih, int x, int y) + iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(filename)); + file_exist = iupdrvIsFile(filename); + dir_exist = iupdrvIsDirectory(filename); ++ ++ if (file_exist) ++ { ++ char* dir = iupStrFileGetPath(filename); ++ iupAttribStoreStr(ih, "DIRECTORY", dir); ++ free(dir); ++ } ++ + g_free(filename); + } +  +@@ -507,8 +533,11 @@ static int gtkFileDlgPopup(Ihandle* ih, int x, int y) + { + /* GtkFileChooser does not change the current directory */ + char* dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog)); +- if (dir) iupdrvSetCurrentDirectory(dir); +- g_free(dir); ++ if (dir)  ++ { ++ iupdrvSetCurrentDirectory(dir); ++ g_free(dir); ++ } + } + } + else +diff --git a/iup/src/gtk/iupgtk_font.c b/iup/src/gtk/iupgtk_font.c +index f7ff348..1139f62 100755 +--- a/iup/src/gtk/iupgtk_font.c ++++ b/iup/src/gtk/iupgtk_font.c +@@ -132,9 +132,9 @@ static IgtkFont* gtkFindFont(const char *standardfont) +  + metrics = pango_context_get_metrics(gtk_fonts_context, fontdesc, pango_context_get_language(gtk_fonts_context)); + fonts[i].charheight = pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics); +- fonts[i].charheight = IUPGTK_PANGOUNITS2PIXELS(fonts[i].charheight); ++ fonts[i].charheight = iupGTK_PANGOUNITS2PIXELS(fonts[i].charheight); + fonts[i].charwidth = pango_font_metrics_get_approximate_char_width(metrics); +- fonts[i].charwidth = IUPGTK_PANGOUNITS2PIXELS(fonts[i].charwidth); ++ fonts[i].charwidth = iupGTK_PANGOUNITS2PIXELS(fonts[i].charwidth); + pango_font_metrics_unref(metrics);  +  + gtkFontUpdate(&(fonts[i])); +diff --git a/iup/src/gtk/iupgtk_fontdlg.c b/iup/src/gtk/iupgtk_fontdlg.c +index 5769cbc..dca0232 100755 +--- a/iup/src/gtk/iupgtk_fontdlg.c ++++ b/iup/src/gtk/iupgtk_fontdlg.c +@@ -24,7 +24,7 @@ static int gtkFontDlgPopup(Ihandle* ih, int x, int y) + InativeHandle* parent = iupDialogGetNativeParent(ih); + GtkFontSelectionDialog* dialog; + int response; +- char* preview_text; ++ char* preview_text, *standardfont; +  + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); +@@ -36,7 +36,10 @@ static int gtkFontDlgPopup(Ihandle* ih, int x, int y) + if (parent) + gtk_window_set_transient_for((GtkWindow*)dialog, (GtkWindow*)parent); +  +- gtk_font_selection_dialog_set_font_name(dialog, iupAttribGet(ih, "VALUE")); ++ standardfont = iupAttribGet(ih, "VALUE"); ++ if (!standardfont) ++ standardfont = IupGetGlobal("DEFAULTFONT"); ++ gtk_font_selection_dialog_set_font_name(dialog, standardfont); +  + preview_text = iupAttribGet(ih, "PREVIEWTEXT"); + if (preview_text) +diff --git a/iup/src/gtk/iupgtk_frame.c b/iup/src/gtk/iupgtk_frame.c +index 022c6c7..25595be 100755 +--- a/iup/src/gtk/iupgtk_frame.c ++++ b/iup/src/gtk/iupgtk_frame.c +@@ -41,8 +41,11 @@ static char* gtkFrameGetTitleAttrib(Ihandle* ih) +  + static int gtkFrameSetTitleAttrib(Ihandle* ih, const char* value) + { +- GtkFrame* frame = (GtkFrame*)ih->handle; +- gtk_frame_set_label(frame, iupgtkStrConvertToUTF8(value)); ++ if (iupAttribGetStr(ih, "_IUPFRAME_HAS_TITLE")) ++ { ++ GtkFrame* frame = (GtkFrame*)ih->handle; ++ gtk_frame_set_label(frame, iupgtkStrConvertToUTF8(value)); ++ } + return 0; + } +  +@@ -57,7 +60,11 @@ static int gtkFrameSetBgColorAttrib(Ihandle* ih, const char* value) + if (label) + iupgtkBaseSetBgColor(label, r, g, b); +  +- iupgtkBaseSetBgColor(ih->handle, r, g, b); ++ if (iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) ++ { ++ GtkWidget* fixed = gtk_bin_get_child((GtkBin*)ih->handle); ++ iupgtkBaseSetBgColor(fixed, r, g, b); ++ } +  + return 1; + } +@@ -120,10 +127,19 @@ static int gtkFrameMapMethod(Ihandle* ih) + gtk_frame_set_shadow_type((GtkFrame*)ih->handle, GTK_SHADOW_IN); + else + gtk_frame_set_shadow_type((GtkFrame*)ih->handle, GTK_SHADOW_ETCHED_IN); ++ ++ if (iupAttribGet(ih, "BGCOLOR")) ++ iupAttribSetStr(ih, "_IUPFRAME_HAS_BGCOLOR", "1"); + } +  + /* the container that will receive the child element. */ + fixed = gtk_fixed_new(); ++ if (iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) ++#if GTK_CHECK_VERSION(2, 18, 0) ++ gtk_widget_set_has_window(fixed, TRUE); ++#else ++ gtk_fixed_set_has_window((GtkFixed*)fixed, TRUE); ++#endif + gtk_container_add((GtkContainer*)ih->handle, fixed); + gtk_widget_show(fixed); +  +diff --git a/iup/src/gtk/iupgtk_key.c b/iup/src/gtk/iupgtk_key.c +index 5aec919..ed485a7 100755 +--- a/iup/src/gtk/iupgtk_key.c ++++ b/iup/src/gtk/iupgtk_key.c +@@ -316,9 +316,9 @@ gboolean iupgtkKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) + if (code == 0)  + return FALSE; +  +- /* Avoid duplicate calls if a child of the dialog contains the focus. +- GTK will call the callback for the child and for the dialog */ +- if (ih->iclass->nativetype == IUP_TYPEDIALOG && ih != IupGetFocus()) ++ /* Avoid duplicate calls if a child of a native container contains the focus. ++ GTK will call the callback for the child and for the container. */ ++ if (ih->iclass->childtype != IUP_CHILDNONE && ih != IupGetFocus()) + return FALSE; +  + result = iupKeyCallKeyCb(ih, code); +@@ -390,33 +390,33 @@ gboolean iupgtkKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) + void iupgtkButtonKeySetStatus(guint state, unsigned int but, char* status, int doubleclick) + { + if (state & GDK_SHIFT_MASK) +- iupKEYSETSHIFT(status); ++ iupKEY_SETSHIFT(status); +  + if (state & GDK_CONTROL_MASK) +- iupKEYSETCONTROL(status);  ++ iupKEY_SETCONTROL(status);  +  + if ((state & GDK_BUTTON1_MASK) || but==1) +- iupKEYSETBUTTON1(status); ++ iupKEY_SETBUTTON1(status); +  + if ((state & GDK_BUTTON2_MASK) || but==2) +- iupKEYSETBUTTON2(status); ++ iupKEY_SETBUTTON2(status); +  + if ((state & GDK_BUTTON3_MASK) || but==3) +- iupKEYSETBUTTON3(status); ++ iupKEY_SETBUTTON3(status); +  + if ((state & GDK_BUTTON4_MASK) || but==4) +- iupKEYSETBUTTON4(status); ++ iupKEY_SETBUTTON4(status); +  + if ((state & GDK_BUTTON5_MASK) || but==5) +- iupKEYSETBUTTON5(status); ++ iupKEY_SETBUTTON5(status); +  + if (state & GDK_MOD1_MASK || state & GDK_MOD5_MASK) /* Alt */ +- iupKEYSETALT(status); ++ iupKEY_SETALT(status); +  + if (state & GDK_MOD4_MASK) /* Apple/Win */ +- iupKEYSETSYS(status); ++ iupKEY_SETSYS(status); +  + if (doubleclick) +- iupKEYSETDOUBLE(status); ++ iupKEY_SETDOUBLE(status); + } +  +diff --git a/iup/src/gtk/iupgtk_label.c b/iup/src/gtk/iupgtk_label.c +index 49d5c6d..f95f576 100755 +--- a/iup/src/gtk/iupgtk_label.c ++++ b/iup/src/gtk/iupgtk_label.c +@@ -133,8 +133,10 @@ static int gtkLabelSetPaddingAttrib(Ihandle* ih, const char* value) + { + GtkMisc* misc = (GtkMisc*)ih->handle; + gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding); ++ return 0; + } +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static char* gtkLabelGetPangoLayoutAttrib(Ihandle* ih) +diff --git a/iup/src/gtk/iupgtk_list.c b/iup/src/gtk/iupgtk_list.c +index 80f6cce..48fa88e 100755 +--- a/iup/src/gtk/iupgtk_list.c ++++ b/iup/src/gtk/iupgtk_list.c +@@ -113,6 +113,8 @@ void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value) + GtkTreeIter iter; + gtk_list_store_insert(GTK_LIST_STORE(model), &iter, pos); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, iupgtkStrConvertToUTF8(value), -1); ++ ++ iupListUpdateOldValue(ih, pos, 0); + } +  + void iupdrvListRemoveItem(Ihandle* ih, int pos) +@@ -127,14 +129,24 @@ void iupdrvListRemoveItem(Ihandle* ih, int pos) + int curpos = gtk_combo_box_get_active((GtkComboBox*)ih->handle); + if (pos == curpos) + { +- if (curpos > 0) curpos--; +- else curpos++; ++ if (curpos > 0)  ++ curpos--; ++ else  ++ { ++ curpos=1; ++ if (iupdrvListGetCount(ih)==1) ++ curpos = -1; /* remove the selection */ ++ } +  ++ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkListComboBoxChanged), ih); + gtk_combo_box_set_active((GtkComboBox*)ih->handle, curpos); ++ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkListComboBoxChanged), ih); + } + } +  + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); ++ ++ iupListUpdateOldValue(ih, pos, 1); + } + } +  +@@ -177,7 +189,7 @@ static int gtkListSetStandardFontAttrib(Ihandle* ih, const char* value) + static char* gtkListGetIdValueAttrib(Ihandle* ih, const char* name_id) + { + int pos = iupListGetPos(ih, name_id); +- if (pos != -1) ++ if (pos >= 0) + { + GtkTreeIter iter; + GtkTreeModel* model = gtkListGetModel(ih); +@@ -349,7 +361,7 @@ static int gtkListSetValueAttrib(Ihandle* ih, const char* value) + GtkTreeModel *model = gtkListGetModel(ih); + g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkListComboBoxChanged), ih); + if (iupStrToInt(value, &pos)==1 &&  +- (pos>0 && pos0 && pos<=gtk_tree_model_iter_n_children(model, NULL))) + { + gtk_combo_box_set_active((GtkComboBox*)ih->handle, pos-1); /* IUP starts at 1 */ + iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos); +@@ -788,9 +800,10 @@ static int gtkListSetNCAttrib(Ihandle* ih, const char* value) + { + GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + gtk_entry_set_max_length(entry, ih->data->nc); ++ return 0; + } +- +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int gtkListSetClipboardAttrib(Ihandle *ih, const char *value) +@@ -1364,9 +1377,9 @@ static int gtkListMapMethod(Ihandle* ih) + if (!ih->data->has_editbox && ih->data->is_multiple) + { + gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); +-#if GTK_CHECK_VERSION(2, 10, 0) ++ #if GTK_CHECK_VERSION(2, 10, 0) + gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(ih->handle), TRUE); +-#endif ++ #endif + } + else + gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); +diff --git a/iup/src/gtk/iupgtk_loop.c b/iup/src/gtk/iupgtk_loop.c +index e349a45..704923e 100755 +--- a/iup/src/gtk/iupgtk_loop.c ++++ b/iup/src/gtk/iupgtk_loop.c +@@ -69,6 +69,13 @@ int IupMainLoop(void) + return IUP_NOERROR; + } +  ++int IupLoopStepWait(void) ++{ ++ if (gtk_main_iteration_do(TRUE)) ++ return IUP_CLOSE; ++ return IUP_DEFAULT; ++} ++ + int IupLoopStep(void) + { + if (gtk_main_iteration_do(FALSE)) +diff --git a/iup/src/gtk/iupgtk_menu.c b/iup/src/gtk/iupgtk_menu.c +index c12fbea..772f4cf 100755 +--- a/iup/src/gtk/iupgtk_menu.c ++++ b/iup/src/gtk/iupgtk_menu.c +@@ -245,11 +245,19 @@ static int gtkMenuMapMethod(Ihandle* ih) + return IUP_NOERROR; + } +  ++static void gtkMenuUnMapMethod(Ihandle* ih) ++{ ++ if (iupMenuIsMenuBar(ih)) ++ ih->parent = NULL; ++ ++ iupdrvBaseUnMapMethod(ih); ++} ++ + void iupdrvMenuInitClass(Iclass* ic) + { + /* Driver Dependent Class functions */ + ic->Map = gtkMenuMapMethod; +- ic->UnMap = iupdrvBaseUnMapMethod; ++ ic->UnMap = gtkMenuUnMapMethod; +  + /* Used by iupdrvMenuGetMenuBarSize */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, NULL, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_DEFAULT); /* use inheritance to retrieve standard fonts */ +@@ -337,15 +345,10 @@ static int gtkItemSetValueAttrib(Ihandle* ih, const char* value) +  + static char* gtkItemGetValueAttrib(Ihandle* ih) + { +- if (GTK_IS_CHECK_MENU_ITEM(ih->handle)) +- { +- if (gtk_check_menu_item_get_active((GtkCheckMenuItem*)ih->handle)) +- return "ON"; +- else +- return "OFF"; +- } ++ if (GTK_IS_CHECK_MENU_ITEM(ih->handle) && gtk_check_menu_item_get_active((GtkCheckMenuItem*)ih->handle)) ++ return "ON"; + else +- return NULL; ++ return "OFF"; + } +  + static int gtkItemMapMethod(Ihandle* ih) +diff --git a/iup/src/gtk/iupgtk_open.c b/iup/src/gtk/iupgtk_open.c +index 66e46e8..962f760 100755 +--- a/iup/src/gtk/iupgtk_open.c ++++ b/iup/src/gtk/iupgtk_open.c +@@ -20,7 +20,52 @@ +  + #include "iupgtk_drv.h" +  ++#ifdef GTK_MAC ++#include  +  ++char* iupgtkGetNativeWindowHandle(Ihandle* ih) ++{ ++ GdkWindow* window = ih->handle->window; ++ if (window) ++ return (char*)window; ++ else ++ return NULL; ++} ++ ++void* iupgtkGetNativeGraphicsContext(GtkWidget* widget) ++{ ++ return (void*)gdk_gc_new((GdkDrawable*)widget->window); ++} ++ ++void iupgtkReleaseNativeGraphicsContext(GtkWidget* widget, void* gc) ++{ ++ g_object_unref(gc); ++ (void)widget; ++} ++ ++void* iupdrvGetDisplay(void) ++{ ++ GdkDisplay* display = gdk_display_get_default(); ++ return display; ++} ++ ++void iupgtkPushVisualAndColormap(void* visual, void* colormap) ++{ ++ GdkColormap* gdk_colormap; ++ GdkVisual *gdk_visual = gdk_visual_get_best(); ++ ++ gdk_colormap = gdk_colormap_new(gdk_visual, FALSE); ++ ++ gtk_widget_push_colormap(gdk_colormap); ++ ++ /* gtk_widget_push_visual is now deprecated */ ++} ++ ++static void gtkSetDrvGlobalAttrib(void) ++{ ++} ++ ++#else + #ifdef WIN32 /******************************** WIN32 ************************************/ + #include  +  +@@ -115,6 +160,8 @@ static void gtkSetDrvGlobalAttrib(void) +  + #endif +  ++#endif ++ + static void gtkSetGlobalColorAttrib(const char* name, GdkColor *color) + { + iupGlobalSetDefaultColorAttrib(name, (int)iupCOLOR16TO8(color->red),  +diff --git a/iup/src/gtk/iupgtk_tabs.c b/iup/src/gtk/iupgtk_tabs.c +index 8029826..6b5aa66 100755 +--- a/iup/src/gtk/iupgtk_tabs.c ++++ b/iup/src/gtk/iupgtk_tabs.c +@@ -76,13 +76,13 @@ static void gtkTabsUpdatePageBgColor(Ihandle* ih, unsigned char r, unsigned char +  + for (child = ih->firstchild; child; child = child->brother) + { +- GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); +- if (tab_page) ++ GtkWidget* tab_container = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); ++ if (tab_container) + { + GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL"); + if (tab_label) + iupgtkBaseSetBgColor(tab_label, r, g, b); +- iupgtkBaseSetBgColor(tab_page, r, g, b); ++ iupgtkBaseSetBgColor(tab_container, r, g, b); + } + } + } +@@ -121,15 +121,18 @@ static int gtkTabsSetPaddingAttrib(Ihandle* ih, const char* value) + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); +  + if (ih->handle) ++ { + gtkTabsUpdatePagePadding(ih); +- return 0; ++ return 0; ++ } ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static void gtkTabsUpdateTabType(Ihandle* ih) + { +- GtkNotebook* tab_page = (GtkNotebook*)ih->handle; + int iup2gtk[4] = {GTK_POS_TOP, GTK_POS_BOTTOM, GTK_POS_LEFT, GTK_POS_RIGHT}; +- gtk_notebook_set_tab_pos(tab_page, iup2gtk[ih->data->type]); ++ gtk_notebook_set_tab_pos((GtkNotebook*)ih->handle, iup2gtk[ih->data->type]); + } +  + static int gtkTabsSetTabTypeAttrib(Ihandle* ih, const char* value) +@@ -144,7 +147,7 @@ static int gtkTabsSetTabTypeAttrib(Ihandle* ih, const char* value) + ih->data->type = ITABS_TOP; +  + if (ih->handle) +- gtkTabsUpdateTabType(ih); ++ gtkTabsUpdateTabType(ih); /* for this to work must be updated in map */ +  + return 0; + } +@@ -171,7 +174,7 @@ static int gtkTabsSetTabTitleAttrib(Ihandle* ih, const char* name_id, const char + GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL"); + if (tab_label) + { +- GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); ++ GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_PAGE"); + gtk_label_set_text((GtkLabel*)tab_label, iupgtkStrConvertToUTF8(value)); + gtk_notebook_set_menu_label_text((GtkNotebook*)ih->handle, tab_page, gtk_label_get_text((GtkLabel*)tab_label)); + } +@@ -238,8 +241,10 @@ void gtkTabSwitchPage(GtkNotebook* notebook, GtkNotebookPage *page, int pos, Iha + IFnnn cb; + Ihandle* child = IupGetChild(ih, pos); + Ihandle* prev_child = IupGetChild(ih, iupdrvTabsGetCurrentTab(ih)); +- IupSetAttribute(child, "VISIBLE", "YES"); +- IupSetAttribute(prev_child, "VISIBLE", "NO"); ++ GtkWidget* tab_container = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); ++ GtkWidget* prev_tab_container = (GtkWidget*)iupAttribGet(prev_child, "_IUPTAB_CONTAINER"); ++ if (tab_container) gtk_widget_show(tab_container); ++ if (prev_tab_container) gtk_widget_hide(prev_tab_container); +  + if (iupAttribGet(ih, "_IUPGTK_IGNORE_CHANGE")) + return; +@@ -263,7 +268,7 @@ static void gtkTabsChildAddedMethod(Ihandle* ih, Ihandle* child) +  + if (ih->handle) + { +- GtkWidget* tab_page; ++ GtkWidget *tab_page, *tab_container; + GtkWidget *tab_label = NULL, *tab_image = NULL; + char *tabtitle, *tabimage; + int pos; +@@ -271,9 +276,13 @@ static void gtkTabsChildAddedMethod(Ihandle* ih, Ihandle* child) +  + pos = IupGetChildPos(ih, child); +  +- tab_page = gtk_fixed_new(); ++ tab_page = gtk_vbox_new(FALSE, 0); + gtk_widget_show(tab_page); +  ++ tab_container = gtk_fixed_new(); ++ gtk_widget_show(tab_container); ++ gtk_container_add((GtkContainer*)tab_page, tab_container); ++ + tabtitle = iupAttribGet(child, "TABTITLE"); + if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos); + tabimage = iupAttribGet(child, "TABIMAGE"); +@@ -327,9 +336,10 @@ static void gtkTabsChildAddedMethod(Ihandle* ih, Ihandle* child) +  + iupAttribSetStr(child, "_IUPGTK_TABIMAGE", (char*)tab_image); /* store it even if its NULL */ + iupAttribSetStr(child, "_IUPGTK_TABLABEL", (char*)tab_label); +- iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)tab_page); ++ iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)tab_container); ++ iupAttribSetStr(child, "_IUPTAB_PAGE", (char*)tab_page); + iupStrToRGB(IupGetAttribute(ih, "BGCOLOR"), &r, &g, &b); +- iupgtkBaseSetBgColor(tab_page, r, g, b); ++ iupgtkBaseSetBgColor(tab_container, r, g, b); +  + if (tabtitle) + { +@@ -354,10 +364,8 @@ static void gtkTabsChildAddedMethod(Ihandle* ih, Ihandle* child) +  + iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", NULL); +  +- if (pos == iupdrvTabsGetCurrentTab(ih)) +- IupSetAttribute(child, "VISIBLE", "YES"); +- else +- IupSetAttribute(child, "VISIBLE", "NO"); ++ if (pos != iupdrvTabsGetCurrentTab(ih)) ++ gtk_widget_hide(tab_container); + } + } +  +@@ -365,10 +373,11 @@ static void gtkTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) + { + if (ih->handle) + { +- GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); ++ GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_PAGE"); + if (tab_page) + { + int pos = gtk_notebook_page_num((GtkNotebook*)ih->handle, tab_page); ++ iupTabsTestRemoveTab(ih, pos); +  + iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", "1"); + gtk_notebook_remove_page((GtkNotebook*)ih->handle, pos); +@@ -377,6 +386,7 @@ static void gtkTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) + iupAttribSetStr(child, "_IUPGTK_TABIMAGE", NULL); + iupAttribSetStr(child, "_IUPGTK_TABLABEL", NULL); + iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL); ++ iupAttribSetStr(child, "_IUPTAB_PAGE", NULL); + } + } + } +@@ -440,5 +450,5 @@ void iupdrvTabsInitClass(Iclass* ic) + iupClassRegisterAttribute(ic, "TABORIENTATION", iupTabsGetTabOrientationAttrib, gtkTabsSetTabOrientationAttrib, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TABTITLE", NULL, gtkTabsSetTabTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, gtkTabsSetTabImageAttrib, IUPAF_NO_INHERIT); +- iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, gtkTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); ++ iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, gtkTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + } +diff --git a/iup/src/gtk/iupgtk_text.c b/iup/src/gtk/iupgtk_text.c +index 4c2906a..d0909d7 100755 +--- a/iup/src/gtk/iupgtk_text.c ++++ b/iup/src/gtk/iupgtk_text.c +@@ -101,7 +101,7 @@ static void gtkTextParseParagraphFormat(Ihandle* formattag, GtkTextTag* tag) + align = PANGO_TAB_LEFT; + free(str); +  +- pango_tab_array_set_tab(tabs, i, align, IUPGTK_PIXELS2PANGOUNITS(pos)); ++ pango_tab_array_set_tab(tabs, i, align, iupGTK_PIXELS2PANGOUNITS(pos)); + i++; + if (i == 32) break; + } +@@ -171,7 +171,7 @@ static void gtkTextParseCharacterFormat(Ihandle* formattag, GtkTextTag* tag) + else  + iupStrToInt(format, &val); +  +- val = IUPGTK_PIXELS2PANGOUNITS(val); ++ val = iupGTK_PIXELS2PANGOUNITS(val); + g_object_set(G_OBJECT(tag), "rise", val, NULL); + } +  +@@ -214,7 +214,7 @@ static void gtkTextParseCharacterFormat(Ihandle* formattag, GtkTextTag* tag) + { + if (val < 0) /* in pixels */ + { +- val = IUPGTK_PIXELS2PANGOUNITS(-val); ++ val = iupGTK_PIXELS2PANGOUNITS(-val); + g_object_set(G_OBJECT(tag), "size", val, NULL); + } + else /* in points */ +@@ -387,8 +387,8 @@ static int gtkTextConvertXYToPos(Ihandle* ih, int x, int y) +  + /* transform to Layout coordinates */ + gtk_entry_get_layout_offsets(GTK_ENTRY(ih->handle), &off_x, &off_y); +- x = IUPGTK_PIXELS2PANGOUNITS(x - off_x);  +- y = IUPGTK_PIXELS2PANGOUNITS(y - off_y); ++ x = iupGTK_PIXELS2PANGOUNITS(x - off_x);  ++ y = iupGTK_PIXELS2PANGOUNITS(y - off_y); +  + pango_layout_xy_to_index(gtk_entry_get_layout(GTK_ENTRY(ih->handle)), x, y, &pos, &trailing); + return pos; +@@ -851,7 +851,7 @@ static char* gtkTextGetValueAttrib(Ihandle* ih) +  + static int gtkTextSetInsertAttrib(Ihandle* ih, 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; + if (!value) + return 0; +@@ -875,7 +875,8 @@ static int gtkTextSetInsertAttrib(Ihandle* ih, const char* value) +  + static int gtkTextSetAppendAttrib(Ihandle* ih, const char* value) + { +- if (!ih->handle) /* do not store the action before map */ ++ gint pos; ++ if (!ih->handle) /* do not do the action before map */ + return 0; + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); +@@ -884,13 +885,18 @@ static int gtkTextSetAppendAttrib(Ihandle* ih, const char* value) + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_end_iter(buffer, &iter); +- if (ih->data->append_newline) ++ pos = gtk_text_buffer_get_char_count(buffer); ++ if (ih->data->append_newline && pos!=0) + gtk_text_buffer_insert(buffer, &iter, "\n", 1); + gtk_text_buffer_insert(buffer, &iter, iupgtkStrConvertToUTF8(value), -1); + } + else + { +- gint pos = strlen(gtk_entry_get_text(GTK_ENTRY(ih->handle)))+1; ++#if GTK_CHECK_VERSION(2, 14, 0) ++ pos = gtk_entry_get_text_length(GTK_ENTRY(ih->handle))+1; ++#else ++ pos = strlen(gtk_entry_get_text(GTK_ENTRY(ih->handle)))+1; ++#endif + gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &pos); + } + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); +@@ -946,8 +952,10 @@ static int gtkTextSetPaddingAttrib(Ihandle* ih, const char* value) + gtk_entry_set_inner_border(GTK_ENTRY(ih->handle), &border); + #endif + } ++ return 0; + } +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int gtkTextSetNCAttrib(Ihandle* ih, const char* value) +@@ -955,10 +963,14 @@ static int gtkTextSetNCAttrib(Ihandle* ih, const char* value) + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = INT_MAX; +  +- if (!ih->data->is_multiline && ih->handle) +- gtk_entry_set_max_length(GTK_ENTRY(ih->handle), ih->data->nc); +- +- return 0; ++ if (ih->handle) ++ { ++ if (!ih->data->is_multiline) ++ gtk_entry_set_max_length(GTK_ENTRY(ih->handle), ih->data->nc); ++ return 0; ++ } ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int gtkTextSetClipboardAttrib(Ihandle *ih, const char *value) +diff --git a/iup/src/gtk/iupgtk_toggle.c b/iup/src/gtk/iupgtk_toggle.c +index 8ff7df5..040beda 100755 +--- a/iup/src/gtk/iupgtk_toggle.c ++++ b/iup/src/gtk/iupgtk_toggle.c +@@ -213,8 +213,10 @@ static int gtkToggleSetPaddingAttrib(Ihandle* ih, const char* value) + GtkButton* button = (GtkButton*)ih->handle; + GtkMisc* misc = (GtkMisc*)gtk_button_get_image(button); + gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding); ++ return 0; + } +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int gtkToggleSetFgColorAttrib(Ihandle* ih, const char* value) +diff --git a/iup/src/gtk/iupgtk_tree.c b/iup/src/gtk/iupgtk_tree.c +index d408f27..9595ada 100755 +--- a/iup/src/gtk/iupgtk_tree.c ++++ b/iup/src/gtk/iupgtk_tree.c +@@ -31,33 +31,50 @@ + #include "iup_drvinfo.h" + #include "iupgtk_drv.h" +  ++ ++/* IMPORTANT:  ++ ++ GtkTreeStore uses the "user_data" field of the GtkTreeIter  ++ to store the node pointer that is position independent. ++ So we use it as a reference to the node in the cache, just like in Motif and Windows. ++ ++ BUT if GTK change its implementation this must be changed also. See "gtk_tree_store.c". ++ ++ ABOUT SELECTIONS: ++ ++ From the GTK documentation on GtkTreeSelection ++ ++ "Additionally, you cannot change the selection of a row on the model  ++ that is not currently displayed by the view without expanding its parents first." ++*/ ++ + enum + { +- IUPGTK_TREE_IMAGE, ++ IUPGTK_TREE_IMAGE, /* "pixbuf", "pixbuf-expander-closed" */ + IUPGTK_TREE_HAS_IMAGE, +- IUPGTK_TREE_IMAGE_EXPANDED, ++ IUPGTK_TREE_IMAGE_EXPANDED, /* "pixbuf-expander-open" */ + IUPGTK_TREE_HAS_IMAGE_EXPANDED, +- IUPGTK_TREE_TITLE, +- IUPGTK_TREE_KIND, +- IUPGTK_TREE_COLOR, +- IUPGTK_TREE_FONT, +- IUPGTK_TREE_USERDATA ++ IUPGTK_TREE_TITLE, /* "text" */ ++ IUPGTK_TREE_KIND, /* "is-expander" */ ++ IUPGTK_TREE_COLOR, /* "foreground-gdk" */ ++ IUPGTK_TREE_FONT, /* "font-desc" */ ++ IUPGTK_TREE_SELECT, ++ IUPGTK_TREE_LAST_DATA /* used as a count */ + }; +  +-static GtkTreeIter gtkTreeInvalidIter = {0,0,0,0}; ++static void gtkTreeRebuildNodeCache(Ihandle* ih, int id, GtkTreeIter iterItem); +  + /*****************************************************************************/ + /* COPYING ITEMS (Branches and its children) */ + /*****************************************************************************/ + /* Insert the copied item in a new location. Returns the new item. */ +-static void gtkTreeCopyItem(GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeIter* iterParent, int position, GtkTreeIter *iterNewItem, int full_copy) ++static void gtkTreeCopyItem(Ihandle* ih, GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeIter* iterParent, int position, GtkTreeIter *iterNewItem) + { + GtkTreeStore* store = GTK_TREE_STORE(model); + int kind; + char* title; + gboolean has_image, has_image_expanded; + PangoFontDescription* font; +- void* userdata; + GdkColor *color; + GdkPixbuf* image, *image_expanded; +  +@@ -69,9 +86,10 @@ static void gtkTreeCopyItem(GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeI + IUPGTK_TREE_KIND, &kind, + IUPGTK_TREE_COLOR, &color,  + IUPGTK_TREE_FONT, &font,  +- IUPGTK_TREE_USERDATA, &userdata, + -1); +  ++ /* Add the new node */ ++ ih->data->node_count++; + if (position == 2) + gtk_tree_store_append(store, iterNewItem, iterParent); + else if (position == 1) /* copy as first child of expanded branch */ +@@ -79,9 +97,6 @@ static void gtkTreeCopyItem(GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeI + else /* copy as next brother of item or collapsed branch */ + gtk_tree_store_insert_after(store, iterNewItem, NULL, iterParent); /* iterParent is sibling of the new item */ +  +- if (full_copy) /* during a full copy the userdata reference is not copied */ +- userdata = NULL; +- + gtk_tree_store_set(store, iterNewItem, IUPGTK_TREE_IMAGE, image, + IUPGTK_TREE_HAS_IMAGE, has_image, + IUPGTK_TREE_IMAGE_EXPANDED, image_expanded, +@@ -90,21 +105,21 @@ static void gtkTreeCopyItem(GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeI + IUPGTK_TREE_KIND, kind, + IUPGTK_TREE_COLOR, color,  + IUPGTK_TREE_FONT, font, +- IUPGTK_TREE_USERDATA, userdata, ++ IUPGTK_TREE_SELECT, 0, + -1); + } +  +-static void gtkTreeCopyChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, int full_copy) ++static void gtkTreeCopyChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst) + { + GtkTreeIter iterChildSrc; + int hasItem = gtk_tree_model_iter_children(model, &iterChildSrc, iterItemSrc); /* get the firstchild */ + while(hasItem) + { + GtkTreeIter iterNewItem; +- gtkTreeCopyItem(model, &iterChildSrc, iterItemDst, 2, &iterNewItem, full_copy); /* append always */ ++ gtkTreeCopyItem(ih, model, &iterChildSrc, iterItemDst, 2, &iterNewItem); /* append always */ +  + /* Recursively transfer all the items */ +- gtkTreeCopyChildren(ih, model, &iterChildSrc, &iterNewItem, full_copy);  ++ gtkTreeCopyChildren(ih, model, &iterChildSrc, &iterNewItem);  +  + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterChildSrc); +@@ -112,9 +127,17 @@ static void gtkTreeCopyChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *i + } +  + /* Copies all items in a branch to a new location. Returns the new branch node. */ +-static void gtkTreeCopyNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, GtkTreeIter* iterNewItem, int full_copy) ++static void gtkTreeCopyMoveNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, GtkTreeIter* iterNewItem, int is_copy) + { + int kind, position = 0; /* insert after iterItemDst */ ++ int id_new, count, id_src, id_dst; ++ ++ int old_count = ih->data->node_count; ++ ++ id_src = iupTreeFindNodeId(ih, iterItemSrc); ++ id_dst = iupTreeFindNodeId(ih, iterItemDst); ++ id_new = id_dst+1; /* contains the position for a copy operation */ ++ + gtk_tree_model_get(model, iterItemDst, IUPGTK_TREE_KIND, &kind, -1); +  + if (kind == ITREE_BRANCH) +@@ -122,346 +145,311 @@ static void gtkTreeCopyNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterI + GtkTreePath* path = gtk_tree_model_get_path(model, iterItemDst); + if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + position = 1; /* insert as first child of iterItemDst */ ++ else ++ { ++ int child_count = iupdrvTreeTotalChildCount(ih, iterItemDst); ++ id_new += child_count; ++ } + gtk_tree_path_free(path); + } +  +- gtkTreeCopyItem(model, iterItemSrc, iterItemDst, position, iterNewItem, full_copy);  ++ /* move to the same place does nothing */ ++ if (!is_copy && id_new == id_src) ++ { ++ iterNewItem->stamp = 0; ++ return; ++ } +  +- gtkTreeCopyChildren(ih, model, iterItemSrc, iterNewItem, full_copy); +-} ++ gtkTreeCopyItem(ih, model, iterItemSrc, iterItemDst, position, iterNewItem);  +  +-/*****************************************************************************/ +-/* FINDING ITEMS */ +-/*****************************************************************************/ ++ gtkTreeCopyChildren(ih, model, iterItemSrc, iterNewItem); +  +-static void gtkTreeInvertAllNodeMarking(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter* iterItem) +-{ +- GtkTreeIter iterChild; +- int hasItem = TRUE; ++ count = ih->data->node_count - old_count; ++ iupTreeCopyMoveCache(ih, id_src, id_new, count, is_copy); +  +- while(hasItem) ++ if (!is_copy) + { +- if(gtk_tree_selection_iter_is_selected(selection, iterItem)) +- gtk_tree_selection_unselect_iter(selection, iterItem); +- else +- gtk_tree_selection_select_iter(selection, iterItem); ++ /* Deleting the node of its old position */ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); ++ gtk_tree_store_remove(GTK_TREE_STORE(model), iterItemSrc); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); +  +- /* Check whether we have child items */ +- if(gtk_tree_model_iter_has_child(model, iterItem)) +- { +- gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ +- gtkTreeInvertAllNodeMarking(ih, model, selection, &iterChild); +- } ++ /* restore count, because we remove src */ ++ ih->data->node_count = old_count; +  +- /* Go to next sibling item */ +- hasItem = gtk_tree_model_iter_next(model, iterItem); ++ /* compensate position for a move */ ++ if (id_new > id_src) ++ id_new -= count; + } ++ ++ gtkTreeRebuildNodeCache(ih, id_new, *iterNewItem); + } +  +-static GtkTreeIter gtkTreeFindVisibleNodeId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode) ++/*****************************************************************************/ ++/* FINDING ITEMS */ ++/*****************************************************************************/ ++ ++static void gtkTreeIterInit(Ihandle* ih, GtkTreeIter* iterItem, InodeHandle* node_handle) + { +- GtkTreeIter iterChild; +- GtkTreePath* path; +- int hasItem = TRUE; ++ iterItem->stamp = ih->data->stamp; ++ iterItem->user_data = node_handle; ++ iterItem->user_data2 = NULL; ++ iterItem->user_data3 = NULL; ++} +  +- while(hasItem) +- { +- /* ID control to traverse items */ +- ih->data->id_control++; /* not the real id since it counts only the visible ones */ ++static int gtkTreeIsNodeSelected(GtkTreeModel* model, GtkTreeIter *iterItem) ++{ ++ gboolean selected = 0; ++ gtk_tree_model_get(model, iterItem, IUPGTK_TREE_SELECT, &selected, -1); ++ return selected; ++} +  +- /* StateID founded! */ +- if(iterItem.user_data == iterNode.user_data) +- return iterItem; ++static void gtkTreeSelectNodeRaw(GtkTreeModel* model, GtkTreeIter *iterItem, int select) ++{ ++ /* Cannot change the selection of a row on the model that is not currently displayed.  ++ So we store the selection state here. And update the actual state when the node becames visible. */ ++ gtk_tree_store_set(GTK_TREE_STORE(model), iterItem, IUPGTK_TREE_SELECT, select, -1); ++} +  +- path = gtk_tree_model_get_path(model, &iterItem); ++static void gtkTreeSelectNode(GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter *iterItem, int select) ++{ ++ if (select == -1) ++ select = !gtkTreeIsNodeSelected(model, iterItem); /* toggle */ +  +- /* Check whether we have child items and it is expanded (visible) */ +- if (gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) +- { +- gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ +- iterChild = gtkTreeFindVisibleNodeId(ih, model, iterChild, iterNode); ++ gtkTreeSelectNodeRaw(model, iterItem, select); +  +- /* StateID founded! */ +- if(iterChild.user_data) +- { +- gtk_tree_path_free(path); +- return iterChild; +- } +- } ++ if (select) ++ gtk_tree_selection_select_iter(selection, iterItem); ++ else ++ gtk_tree_selection_unselect_iter(selection, iterItem); ++} +  +- gtk_tree_path_free(path); +- /* Go to next sibling item */ +- hasItem = gtk_tree_model_iter_next(model, &iterItem); ++static void gtkTreeSelectAll(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, int selected) ++{ ++ int i; ++ GtkTreeIter iterItem; ++ ++ for (i = 0; i < ih->data->node_count; i++) ++ { ++ gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); ++ gtkTreeSelectNodeRaw(model, &iterItem, selected); + } +  +- return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ ++ if (selected) ++ gtk_tree_selection_select_all(selection); ++ else ++ gtk_tree_selection_unselect_all(selection); + } +  +-static GtkTreeIter gtkTreeFindVisibleNodeFromId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem) ++static void gtkTreeInvertAllNodeMarking(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection) + { +- GtkTreeIter iterChild; +- GtkTreePath* path; +- int hasItem = TRUE; ++ int i; ++ GtkTreeIter iterItem; +  +- while(hasItem) ++ for (i = 0; i < ih->data->node_count; i++) + { +- /* ID control to traverse items */ +- ih->data->id_control--; /* not the real id since it counts only the visible ones */ ++ gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); ++ gtkTreeSelectNode(model, selection, &iterItem, -1); ++ } ++} +  +- /* StateID founded! */ +- if(ih->data->id_control < 0) +- return iterItem; ++static void gtkTreeSelectRange(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter *iterItem1, GtkTreeIter *iterItem2, int clear) ++{ ++ int i; ++ int id1 = iupTreeFindNodeId(ih, iterItem1->user_data); ++ int id2 = iupTreeFindNodeId(ih, iterItem2->user_data); ++ GtkTreeIter iterItem; +  +- path = gtk_tree_model_get_path(model, &iterItem); ++ if (id1 > id2) ++ { ++ int tmp = id1; ++ id1 = id2; ++ id2 = tmp; ++ } +  +- /* Check whether we have child items and it is expanded (visible) */ +- if(gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) ++ for (i = 0; i < ih->data->node_count; i++) ++ { ++ gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); ++ if (i < id1 || i > id2) + { +- gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ +- iterChild = gtkTreeFindVisibleNodeFromId(ih, model, iterChild); +- +- /* StateID founded! */ +- if(ih->data->id_control < 0) +- { +- gtk_tree_path_free(path); +- return iterChild; +- } ++ if (clear) ++ gtkTreeSelectNode(model, selection, &iterItem, 0); + } +- +- gtk_tree_path_free(path); +- /* Go to next sibling item */ +- hasItem = gtk_tree_model_iter_next(model, &iterItem); ++ else ++ gtkTreeSelectNode(model, selection, &iterItem, 1); + } +- +- return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ + } +  +-static GtkTreeIter gtkTreeGetLastVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem) ++static int gtkTreeIsNodeVisible(Ihandle* ih, GtkTreeModel* model, InodeHandle* node_handle, InodeHandle* *nodeLastParent) + { +- GtkTreeIter iterChild, iterPrev = gtkTreeInvalidIter; +- GtkTreePath* path = gtk_tree_model_get_path(model, &iterItem); +- +- /* Check whether we have child items and it is expanded (visible) */ +- if(gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) +- { +- int hasItem = TRUE; +- gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ ++ GtkTreeIter iterItem, iterParent; ++ GtkTreePath* path; ++ int is_visible; +  +- while(hasItem) +- { +- iterPrev = iterChild; ++ gtkTreeIterInit(ih, &iterItem, node_handle); +  +- /* Go to next sibling item */ +- hasItem = gtk_tree_model_iter_next(model, &iterChild); +- } ++ if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem) || ++ iterParent.user_data == *nodeLastParent) ++ return 1; +  +- iterItem = gtkTreeGetLastVisibleNode(ih, model, iterPrev); +- } ++ path = gtk_tree_model_get_path(model, &iterParent); ++ is_visible = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); + gtk_tree_path_free(path); +  +- return iterItem; ++ if (!is_visible) ++ return 0; ++ ++ /* save last parent */ ++ *nodeLastParent = iterParent.user_data; ++ return 1; + } +  +-static GtkTreeIter gtkTreeFindNodeID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode) ++static void gtkTreeGetLastVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem) + { +- GtkTreeIter iterChild; +- int hasItem = TRUE; ++ int i; ++ InodeHandle* nodeLastParent = NULL; +  +- while(hasItem) ++ for (i = ih->data->node_count-1; i >= 0; i--) + { +- /* ID control to traverse items */ +- ih->data->id_control++; +- +- /* StateID founded! */ +- if (iterItem.user_data == iterNode.user_data) +- return iterItem; +- +- /* Check whether we have child items */ +- if (gtk_tree_model_iter_has_child(model, &iterItem)) ++ if (gtkTreeIsNodeVisible(ih, model, ih->data->node_cache[i].node_handle, &nodeLastParent)) + { +- gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ +- iterChild = gtkTreeFindNodeID(ih, model, iterChild, iterNode); +- +- /* StateID founded! */ +- if(iterChild.user_data) +- return iterChild; ++ gtkTreeIterInit(ih, iterItem, ih->data->node_cache[i].node_handle); ++ return; + } +- +- /* Go to next sibling item */ +- hasItem = gtk_tree_model_iter_next(model, &iterItem); + } +  +- return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ ++ gtkTreeIterInit(ih, iterItem, ih->data->node_cache[0].node_handle); /* root is always visible */ + } +  +-static int gtkTreeGetNodeId(Ihandle* ih, GtkTreeIter iterItem) ++static void gtkTreeGetNextVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, int count) + { +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- GtkTreeIter iterRoot; +- gtk_tree_model_get_iter_first(model, &iterRoot); +- +- ih->data->id_control = -1; +- iterItem = gtkTreeFindNodeID(ih, model, iterRoot, iterItem); +- if (iterItem.user_data) +- return ih->data->id_control; +- else +- return -1; +-} ++ int i, id; ++ InodeHandle* nodeLastParent = NULL; +  +-static GtkTreeIter gtkTreeFindUserData(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, void* userdata) +-{ +- GtkTreeIter iterChild; +- int hasItem = TRUE; +- void* node_userdata; ++ id = iupTreeFindNodeId(ih, iterItem->user_data); ++ id += count; +  +- while(hasItem) ++ for (i = id; i < ih->data->node_count; i++) + { +- /* ID control to traverse items */ +- ih->data->id_control++; ++ if (gtkTreeIsNodeVisible(ih, model, ih->data->node_cache[i].node_handle, &nodeLastParent)) ++ { ++ gtkTreeIterInit(ih, iterItem, ih->data->node_cache[i].node_handle); ++ return; ++ } ++ } +  +- gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &node_userdata, -1); ++ gtkTreeIterInit(ih, iterItem, ih->data->node_cache[0].node_handle); /* root is always visible */ ++} +  +- /* userdata founded! */ +- if (node_userdata == userdata) +- return iterItem; ++static void gtkTreeGetPreviousVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, int count) ++{ ++ int i, id; ++ InodeHandle* nodeLastParent = NULL; +  +- /* Check whether we have child items */ +- if (gtk_tree_model_iter_has_child(model, &iterItem)) +- { +- gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ +- iterChild = gtkTreeFindUserData(ih, model, iterChild, userdata); ++ id = iupTreeFindNodeId(ih, iterItem->user_data); ++ id -= count; +  +- /* userdata founded! */ +- if (iterChild.user_data) +- return iterChild; ++ for (i = id; i >= 0; i--) ++ { ++ if (gtkTreeIsNodeVisible(ih, model, ih->data->node_cache[i].node_handle, &nodeLastParent)) ++ { ++ gtkTreeIterInit(ih, iterItem, ih->data->node_cache[i].node_handle); ++ return; + } +- +- /* Go to next sibling item */ +- hasItem = gtk_tree_model_iter_next(model, &iterItem); + } +  +- return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ ++ gtkTreeGetLastVisibleNode(ih, model, iterItem); + } +  +-static int gtkTreeGetUserDataId(Ihandle* ih, GtkTreeModel* model, void* userdata) ++static int gtkTreeFindNodeId(Ihandle* ih, GtkTreeIter* iterItem) + { +- GtkTreeIter iterRoot, iterItem; +- gtk_tree_model_get_iter_first(model, &iterRoot); +- +- ih->data->id_control = -1; +- iterItem = gtkTreeFindUserData(ih, model, iterRoot, userdata); +- if (iterItem.user_data) +- return ih->data->id_control; +- else +- return -1; ++ return iupTreeFindNodeId(ih, iterItem->user_data); + } +  +-static void gtkTreeCallNodeRemovedRec(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, IFnis cb) ++static void gtkTreeCallNodeRemovedRec(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, IFns cb, int *id) + { + GtkTreeIter iterChild; +- int hasItem = TRUE; +- void* node_userdata; ++ int hasItem; ++ int old_id = *id; +  ++ /* Check whether we have child items */ ++ /* remove from children first */ ++ hasItem = gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ + while(hasItem) + { +- /* ID control to traverse items */ +- ih->data->id_control++; +- +- gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &node_userdata, -1); +- +- cb(ih, ih->data->id_control, (char*)node_userdata); +- +- /* Check whether we have child items */ +- if (gtk_tree_model_iter_has_child(model, &iterItem)) +- { +- gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ +- gtkTreeCallNodeRemovedRec(ih, model, iterChild, cb); +- } ++ /* go recursive to children */ ++ gtkTreeCallNodeRemovedRec(ih, model, &iterChild, cb, id); +  + /* Go to next sibling item */ +- hasItem = gtk_tree_model_iter_next(model, &iterItem); ++ hasItem = gtk_tree_model_iter_next(model, &iterChild); + } ++ ++ /* actually do it for the node */ ++ ih->data->node_count--; ++ (*id)++; ++ ++ cb(ih, (char*)ih->data->node_cache[old_id].userdata); + } +  + static void gtkTreeCallNodeRemoved(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem) + { +- IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB"); ++ int old_count = ih->data->node_count; ++ int id = iupTreeFindNodeId(ih, iterItem->user_data); ++ int old_id = id; ++ ++ IFns cb = (IFns)IupGetCallback(ih, "NODEREMOVED_CB"); + if (cb)  ++ gtkTreeCallNodeRemovedRec(ih, model, iterItem, cb, &id); ++ else + { +- ih->data->id_control = gtkTreeGetNodeId(ih, *iterItem)-1; +- gtkTreeCallNodeRemovedRec(ih, model, *iterItem, cb); ++ int removed_count = iupdrvTreeTotalChildCount(ih, iterItem->user_data)+1; ++ ih->data->node_count -= removed_count; + } ++ ++ iupTreeDelFromCache(ih, old_id, old_count-ih->data->node_count); + } +  +-static gboolean gtkTreeFindNodeFromID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, int *id) ++static void gtkTreeCallNodeRemovedAll(Ihandle* ih) + { +- GtkTreeIter iterChild; +- int hasItem = TRUE; ++ IFns cb = (IFns)IupGetCallback(ih, "NODEREMOVED_CB"); ++ int i, old_count = ih->data->node_count; +  +- while(hasItem) ++ if (cb) + { +- /* ID control to traverse items */ +- (*id)--; +- +- /* StateID founded! */ +- if (*id < 0) +- return TRUE; +- +- /* Check whether we have child items */ +- if (gtk_tree_model_iter_has_child(model, iterItem)) ++ for (i = 0; i < ih->data->node_count; i++) + { +- gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ +-  +- if (gtkTreeFindNodeFromID(ih, model, &iterChild, id)) +- { +- *iterItem = iterChild; +- return TRUE; +- } ++ cb(ih, (char*)ih->data->node_cache[i].userdata); + } +- +- /* Go to next sibling item */ +- hasItem = gtk_tree_model_iter_next(model, iterItem); + } +  +- return FALSE; ++ ih->data->node_count = 0; ++ ++ iupTreeDelFromCache(ih, 0, old_count); + } +  +-static gboolean gtkTreeFindNodeFromString(Ihandle* ih, GtkTreeModel* model, const char* name_id, GtkTreeIter *iterItem) ++static gboolean gtkTreeFindNodeFromString(Ihandle* ih, const char* name_id, GtkTreeIter *iterItem) + { +- if (name_id[0]) +- { +- int id; +- if (iupStrToInt(name_id, &id)) +- { +- gtk_tree_model_get_iter_first(model, iterItem); +- return gtkTreeFindNodeFromID(ih, model, iterItem, &id); +- } +- } +- else +- { +- GtkTreePath* path = NULL; +- gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); +- if (path) +- { +- gtk_tree_model_get_iter(model, iterItem, path); +- gtk_tree_path_free(path); +- return TRUE; +- } +- } +- return FALSE; ++ InodeHandle* node_handle = iupTreeGetNodeFromString(ih, name_id); ++ if (!node_handle) ++ return FALSE; ++ ++ gtkTreeIterInit(ih, iterItem, node_handle); ++ return TRUE; + } +  + /*****************************************************************************/ + /* MANIPULATING IMAGES */ + /*****************************************************************************/ +-static void gtkTreeUpdateImages(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, int mode) ++static void gtkTreeUpdateImages(Ihandle* ih, int mode) + { +- GtkTreeIter iterChild; +- int hasItem = TRUE; +- int kind; ++ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ++ GtkTreeIter iterItem; ++ int i, kind; +  +- while(hasItem) ++ for (i=0; idata->node_count; i++) + { ++ gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); ++ + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); +  + if (kind == ITREE_BRANCH) +@@ -480,14 +468,6 @@ static void gtkTreeUpdateImages(Ihandle* ih, GtkTreeModel* model, GtkTreeIter it + if (!has_image) + gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, -1); + } +- +- if (gtk_tree_model_iter_has_child(model, &iterItem)) +- { +- +- /* Recursively traverse child items */ +- gtk_tree_model_iter_children(model, &iterChild, &iterItem); +- gtkTreeUpdateImages(ih, model, iterChild, mode); +- } + } + else  + { +@@ -499,9 +479,6 @@ static void gtkTreeUpdateImages(Ihandle* ih, GtkTreeModel* model, GtkTreeIter it + gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, -1); + } + } +- +- /* Go to next sibling item */ +- hasItem = gtk_tree_model_iter_next(model, &iterItem); + } + } +  +@@ -536,26 +513,49 @@ void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* t + GtkTreeIter iterPrev, iterNewItem, iterParent; + GtkTreePath* path; + GdkColor color = {0L,0,0,0}; +- int kindPrev; +- +- if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterPrev)) +- return; ++ int kindPrev = -1; +  +- gtk_tree_model_get(GTK_TREE_MODEL(store), &iterPrev, IUPGTK_TREE_KIND, &kindPrev, -1); ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterPrev)) ++ { ++ /* check if the root was really specified */ ++ int id = 0; ++ if (!iupStrToInt(name_id, &id) || id != -1) ++ return; ++ } ++ else ++ gtk_tree_model_get(GTK_TREE_MODEL(store), &iterPrev, IUPGTK_TREE_KIND, &kindPrev, -1); +  +- if (kindPrev == ITREE_BRANCH && add) +- gtk_tree_store_insert(store, &iterNewItem, &iterPrev, 0); /* iterPrev is parent of the new item (firstchild of it) */ ++ if (kindPrev != -1) ++ { ++ /* Add the new node */ ++ if (kindPrev == ITREE_BRANCH && add) ++ gtk_tree_store_insert(store, &iterNewItem, &iterPrev, 0); /* iterPrev is parent of the new item (firstchild of it) */ ++ else ++ gtk_tree_store_insert_after(store, &iterNewItem, NULL, &iterPrev); /* iterPrev is sibling of the new item */ ++ iupTreeAddToCache(ih, add, kindPrev, iterPrev.user_data, iterNewItem.user_data); ++ } + else +- gtk_tree_store_insert_after(store, &iterNewItem, NULL, &iterPrev); /* iterPrev is sibling of the new item */ ++ { ++ gtk_tree_store_append(store, &iterNewItem, NULL); /* root node */ ++ iupTreeAddToCache(ih, 0, 0, NULL, iterNewItem.user_data); ++ ++ /* store the stamp for the tree */ ++ ih->data->stamp = iterNewItem.stamp; ++ } +  + iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color); +  ++ if (!title) ++ title = ""; ++ + /* set the attributes of the new node */ + gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_HAS_IMAGE, FALSE, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, + IUPGTK_TREE_TITLE, iupgtkStrConvertToUTF8(title), + IUPGTK_TREE_KIND, kind, +- IUPGTK_TREE_COLOR, &color, -1); ++ IUPGTK_TREE_COLOR, &color,  ++ IUPGTK_TREE_SELECT, 0, ++ -1); +  + if (kind == ITREE_LEAF) + gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, -1); +@@ -563,56 +563,113 @@ void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* t + gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, + IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, -1); +  +- if (kindPrev == ITREE_BRANCH && add) +- iterParent = iterPrev; +- else +- gtk_tree_model_iter_parent(GTK_TREE_MODEL(store), &iterParent, &iterNewItem); ++ if (kindPrev != -1) ++ { ++ if (kindPrev == ITREE_BRANCH && add) ++ iterParent = iterPrev; ++ else if (!gtk_tree_model_iter_parent(GTK_TREE_MODEL(store), &iterParent, &iterNewItem)) ++ return; +  +- /* If this is the first child of the parent, then handle the ADDEXPANDED attribute */ +- if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), &iterParent) == 1) ++ /* If this is the first child of the parent, then handle the ADDEXPANDED attribute */ ++ if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), &iterParent) == 1) ++ { ++ path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterParent); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", "1"); ++ if (ih->data->add_expanded) ++ gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE); ++ else ++ gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", NULL); ++ gtk_tree_path_free(path); ++ } ++ } ++ else + { +- int depth; +- path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterParent); +- depth = gtk_tree_path_get_depth(path)-1; +- if (ih->data->add_expanded || depth==0) /* if this is the first child of the root, expand always */ ++ if (ih->data->node_count == 1) + { +- iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB", "1"); +- gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE); ++ /* MarkStart node */ ++ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)iterNewItem.user_data); ++ ++ /* Set the default VALUE */ ++ path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterNewItem); ++ gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); ++ gtk_tree_path_free(path); + } +- else +- gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); +- gtk_tree_path_free(path); + } + } +  +-static void gtkTreeAddRootNode(Ihandle* ih) ++ ++/*****************************************************************************/ ++/* AUXILIAR FUNCTIONS */ ++/*****************************************************************************/ ++ ++ ++static void gtkTreeChildRebuildCacheRec(Ihandle* ih, GtkTreeModel *model, GtkTreeIter *iterItem, int *id) + { +- GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); +- GtkTreePath* path; +- GtkTreeIter iterRoot; +- GdkColor color = {0L,0,0,0}; ++ GtkTreeIter iterChild; ++ int hasItem = gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ ++ while(hasItem) ++ { ++ (*id)++; ++ ih->data->node_cache[*id].node_handle = iterChild.user_data; +  +- iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color); ++ /* go recursive to children */ ++ gtkTreeChildRebuildCacheRec(ih, model, &iterChild, id); ++ ++ /* Go to next sibling item */ ++ hasItem = gtk_tree_model_iter_next(model, &iterChild); ++ } ++} +  +- gtk_tree_store_append(store, &iterRoot, NULL); /* root node */ +- gtk_tree_store_set(store, &iterRoot, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, +- IUPGTK_TREE_HAS_IMAGE, FALSE, +- IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, +- IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, +- IUPGTK_TREE_KIND, ITREE_BRANCH, +- IUPGTK_TREE_COLOR, &color, -1); ++static void gtkTreeRebuildNodeCache(Ihandle* ih, int id, GtkTreeIter iterItem) ++{ ++ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ++ ih->data->node_cache[id].node_handle = iterItem.user_data; ++ gtkTreeChildRebuildCacheRec(ih, model, &iterItem, &id); ++} ++ ++static void gtkTreeChildCountRec(GtkTreeModel *model, GtkTreeIter *iterItem, int *count) ++{ ++ GtkTreeIter iterChild; ++ int hasItem = gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ ++ while(hasItem) ++ { ++ (*count)++; +  +- path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterRoot); +- /* MarkStart node */ +- iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)path); ++ /* go recursive to children */ ++ gtkTreeChildCountRec(model, &iterChild, count); +  +- /* Set the default VALUE */ +- gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); ++ /* Go to next sibling item */ ++ hasItem = gtk_tree_model_iter_next(model, &iterChild); ++ } ++} ++ ++int iupdrvTreeTotalChildCount(Ihandle* ih, InodeHandle* node_handle) ++{ ++ int count = 0; ++ GtkTreeIter iterItem; ++ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ++ gtkTreeIterInit(ih, &iterItem, node_handle); ++ gtkTreeChildCountRec(model, &iterItem, &count); ++ return count; ++} ++ ++InodeHandle* iupdrvTreeGetFocusNode(Ihandle* ih) ++{ ++ GtkTreePath* path = NULL; ++ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); ++ if (path) ++ { ++ GtkTreeIter iterItem; ++ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ++ gtk_tree_model_get_iter(model, &iterItem, path); ++ gtk_tree_path_free(path); ++ return iterItem.user_data; ++ } ++ ++ return NULL; + } +  +-/*****************************************************************************/ +-/* AUXILIAR FUNCTIONS */ +-/*****************************************************************************/ + static void gtkTreeOpenCloseEvent(Ihandle* ih) + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +@@ -620,7 +677,7 @@ static void gtkTreeOpenCloseEvent(Ihandle* ih) + GtkTreePath* path; + int kind; +  +- if (!gtkTreeFindNodeFromString(ih, model, "", &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, "", &iterItem)) + return; +  + path = gtk_tree_model_get_path(model, &iterItem); +@@ -637,27 +694,22 @@ static void gtkTreeOpenCloseEvent(Ihandle* ih) + } + } +  +-static gboolean gtkTreeSelected_Foreach_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list) ++typedef struct _gtkTreeSelectMinMax + { +- GtkTreeRowReference *rowref; +- +- rowref = gtk_tree_row_reference_new(model, path); +- *rowref_list = g_list_append(*rowref_list, rowref); ++ Ihandle* ih; ++ int id1, id2; ++} gtkTreeSelectMinMax; +  +- (void)iter; +- return FALSE; /* do not stop walking the store, call us with next row */ +-} +- +-static gboolean gtkTreeSelected_Iter_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list) ++static gboolean gtkTreeSelected_Foreach_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iterItem, gtkTreeSelectMinMax *minmax) + { +- GtkTreeRowReference *rowref; +- GtkTreeIter iterParent; +- if (!gtk_tree_model_iter_parent(model, &iterParent, iter)) /* the root node can't be deleted */ +- return FALSE; /* do not stop walking the store, call us with next row */ +- +- rowref = gtk_tree_row_reference_new(model, path); +- *rowref_list = g_list_append(*rowref_list, rowref); ++ int id = iupTreeFindNodeId(minmax->ih, iterItem->user_data); ++ if (id < minmax->id1) ++ minmax->id1 = id; ++ if (id > minmax->id2) ++ minmax->id2 = id; +  ++ (void)model; ++ (void)path; + return FALSE; /* do not stop walking the store, call us with next row */ + } +  +@@ -672,45 +724,48 @@ static void gtkTreeCallMultiSelectionCb(Ihandle* ih) + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); +- GtkTreeIter iterRoot; +- GList *rr_list = NULL; +- GList *node; +- int* id_rowItem; +- int count_selected_rows, i = 0; ++ GtkTreeIter iterItem; ++ int i = 0, countItems; ++ gtkTreeSelectMinMax minmax; +  +- gtk_tree_model_get_iter_first(model, &iterRoot); ++ minmax.ih = ih; ++ minmax.id1 = ih->data->node_count; ++ minmax.id2 = -1; +  +- gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Foreach_Func, &rr_list); +- count_selected_rows = g_list_length(rr_list); +- id_rowItem = malloc(sizeof(int) * count_selected_rows); ++ gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Foreach_Func, &minmax); ++ if (minmax.id2 == -1) ++ return; +  +- for(node = rr_list; node != NULL; node = node->next) ++ /* interactive selection of several nodes will NOT select hidden nodes, ++ so make sure that they are selected. */ ++ for(i = minmax.id1; i <= minmax.id2; i++) + { +- GtkTreePath* path = gtk_tree_row_reference_get_path(node->data); +- if (path) +- { +- GtkTreeIter iterItem; +- gtk_tree_model_get_iter(model, &iterItem, path); +- +- id_rowItem[i] = gtkTreeGetNodeId(ih, iterItem); +- i++; +- +- gtk_tree_path_free(path); +- } ++ gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); ++ if (!gtkTreeIsNodeSelected(model, &iterItem)) ++ gtkTreeSelectNodeRaw(model, &iterItem, 1); + } +  +- g_list_foreach(rr_list, (GFunc) gtk_tree_row_reference_free, NULL); +- g_list_free(rr_list); ++ /* if last selected item is a branch, then select its children */ ++ iupTreeSelectLastCollapsedBranch(ih, &(minmax.id2)); ++ ++ countItems = minmax.id2-minmax.id1+1; +  + if (cbMulti) +- cbMulti(ih, id_rowItem, count_selected_rows); +- else + { +- for (i=0; ihandle))); + GtkTreeIter iterItem; + GtkTreePath* path; ++ int kind; +  +- if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), value, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, value, &iterItem)) + return 0; +  + path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterItem); +  +- if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) ++ gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1); ++ if (kind == ITREE_LEAF) ++ gtk_tree_view_expand_to_path(GTK_TREE_VIEW(ih->handle), path); ++ else ++ { ++ int expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); + gtk_tree_view_expand_to_path(GTK_TREE_VIEW(ih->handle), path); ++ if (!expanded) gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); ++ } +  + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE, 0, 0); /* scroll to visible */ +  +@@ -788,34 +851,23 @@ static int gtkTreeSetExpandAllAttrib(Ihandle* ih, const char* value) + if (iupStrBoolean(value)) + gtk_tree_view_expand_all(GTK_TREE_VIEW(ih->handle)); + else +- { +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- GtkTreeIter iterRoot; +- GtkTreePath* pathRoot; +- + gtk_tree_view_collapse_all(GTK_TREE_VIEW(ih->handle)); +  +- /* The root node is always expanded */ +- gtk_tree_model_get_iter_first(model, &iterRoot); +- pathRoot = gtk_tree_model_get_path(model, &iterRoot); +- gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), pathRoot, FALSE); +- gtk_tree_path_free(pathRoot); +- } +- + return 0; + } +  + static char* gtkTreeGetDepthAttrib(Ihandle* ih, const char* name_id) + { +- char* depth; ++ char* str; + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) ++ ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return NULL; +  +- depth = iupStrGetMemory(10); +- sprintf(depth, "%d", gtk_tree_store_iter_depth(store, &iterItem)); +- return depth; ++ str = iupStrGetMemory(10); ++ sprintf(str, "%d", gtk_tree_store_iter_depth(store, &iterItem)); ++ return str; + } +  + static int gtkTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +@@ -824,14 +876,14 @@ static int gtkTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char + GtkTreeIter iterItemSrc, iterItemDst, iterNewItem; + GtkTreeIter iterParent, iterNextParent; +  +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; +  + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItemSrc)) + return 0; +  +- if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst)) ++ if (!gtkTreeFindNodeFromString(ih, value, &iterItemDst)) + return 0; +  + /* If Drag item is an ancestor of Drop item then return */ +@@ -843,12 +895,8 @@ static int gtkTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char + iterParent = iterNextParent; + } +  +- /* Copying the node and its children to the new position */ +- gtkTreeCopyNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 0); /* not a full copy, preserve user data */ +- +- /* Deleting the node of its old position */ +- /* do not delete the user data, we copy the references in CopyNode */ +- gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItemSrc); ++ /* Move the node and its children to the new position */ ++ gtkTreeCopyMoveNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 0); +  + return 0; + } +@@ -859,14 +907,14 @@ static int gtkTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char + GtkTreeIter iterItemSrc, iterItemDst, iterNewItem; + GtkTreeIter iterParent, iterNextParent; +  +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; +  + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItemSrc)) + return 0; +  +- if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst)) ++ if (!gtkTreeFindNodeFromString(ih, value, &iterItemDst)) + return 0; +  + /* If Drag item is an ancestor of Drop item then return */ +@@ -878,8 +926,8 @@ static int gtkTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char + iterParent = iterNextParent; + } +  +- /* Copying the node and its children to the new position */ +- gtkTreeCopyNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 1); ++ /* Copy the node and its children to the new position */ ++ gtkTreeCopyMoveNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 1); +  + return 0; + } +@@ -891,7 +939,7 @@ static char* gtkTreeGetColorAttrib(Ihandle* ih, const char* name_id) + GtkTreeIter iterItem; + GdkColor *color; +  +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return NULL; +  + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_COLOR, &color, -1); +@@ -912,7 +960,7 @@ static int gtkTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* v + GdkColor color; + unsigned char r, g, b; +  +- if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return 0; +  + if (!iupStrToRGB(value, &r, &g, &b)) +@@ -931,14 +979,14 @@ static char* gtkTreeGetParentAttrib(Ihandle* ih, const char* name_id) + GtkTreeIter iterParent; + char* str; +  +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return NULL; +  + if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem)) + return NULL; +  + str = iupStrGetMemory(10); +- sprintf(str, "%d", gtkTreeGetNodeId(ih, iterParent)); ++ sprintf(str, "%d", gtkTreeFindNodeId(ih, &iterParent)); + return str; + } +  +@@ -948,7 +996,7 @@ static char* gtkTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) + GtkTreeIter iterItem; + char* str; +  +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return NULL; +  + str = iupStrGetMemory(10); +@@ -956,40 +1004,13 @@ static char* gtkTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) + return str; + } +  +-static int gtkTreeCount(GtkTreeModel* model, GtkTreeIter iterBranch) +-{ +- GtkTreeIter iterChild; +- int count = 0; +- int hasItem = gtk_tree_model_iter_children(model, &iterChild, &iterBranch); /* get the firstchild */ +- count++; +- while(hasItem) +- { +- count += gtkTreeCount(model, iterChild); +- +- /* Go to next sibling item */ +- hasItem = gtk_tree_model_iter_next(model, &iterChild); +- } +- +- return count; +-} +- +-static char* gtkTreeGetCountAttrib(Ihandle* ih) +-{ +- GtkTreeIter iterRoot; +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- char* str = iupStrGetMemory(10); +- gtk_tree_model_get_iter_first(model, &iterRoot); +- sprintf(str, "%d", gtkTreeCount(model, iterRoot)); +- return str; +-} +- + static char* gtkTreeGetKindAttrib(Ihandle* ih, const char* name_id) + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + int kind; +  +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return NULL; +  + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); +@@ -1005,7 +1026,7 @@ static char* gtkTreeGetStateAttrib(Ihandle* ih, const char* name_id) + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; +  +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return NULL; +  + if (gtk_tree_model_iter_has_child(model, &iterItem)) +@@ -1028,13 +1049,20 @@ static int gtkTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* v + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + GtkTreePath* path; ++ int kind; +  +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return 0; +  +- path = gtk_tree_model_get_path(model, &iterItem); +- gtkTreeExpandItem(ih, path, iupStrEqualNoCase(value, "EXPANDED")); +- gtk_tree_path_free(path); ++ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); ++ if (kind == ITREE_BRANCH) ++ { ++ path = gtk_tree_model_get_path(model, &iterItem); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", "1"); ++ gtkTreeExpandItem(ih, path, iupStrEqualNoCase(value, "EXPANDED")); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", NULL); ++ gtk_tree_path_free(path); ++ } +  + return 0; + } +@@ -1050,7 +1078,7 @@ static char* gtkTreeGetTitleAttrib(Ihandle* ih, const char* name_id) + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return NULL; + return gtkTreeGetTitle(model, iterItem); + } +@@ -1059,8 +1087,10 @@ static int gtkTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* v + { + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return 0; ++ if (!value) ++ value = ""; + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_TITLE, iupgtkStrConvertToUTF8(value), -1); + return 0; + } +@@ -1070,7 +1100,7 @@ static int gtkTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const cha + PangoFontDescription* fontdesc = NULL; + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return 0; + if (value) + fontdesc = iupgtkGetPangoFontDesc(value); +@@ -1083,49 +1113,12 @@ static char* gtkTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) + PangoFontDescription* fontdesc; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return NULL; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_FONT, &fontdesc, -1); + return pango_font_description_to_string(fontdesc); + } +  +-static char* gtkTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id) +-{ +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- int id; +- char* str = (char*)(name_id+1); /* skip ':' */ +- void* userdata = NULL; +- if (sscanf(str, "%p", &userdata)!=1) +- return NULL; +- id = gtkTreeGetUserDataId(ih, model, userdata); +- if (id == -1) +- return NULL; +- str = iupStrGetMemory(16); +- sprintf(str, "%d", id); +- return str; +-} +- +-static char* gtkTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) +-{ +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- GtkTreeIter iterItem; +- char* userdata; +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) +- return NULL; +- gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &userdata, -1); +- return userdata; +-} +- +-static int gtkTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) +-{ +- GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); +- GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) +- return 0; +- gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_USERDATA, value, -1); +- return 0; +-} +- + static char* gtkTreeGetValueAttrib(Ihandle* ih) + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +@@ -1140,67 +1133,117 @@ static char* gtkTreeGetValueAttrib(Ihandle* ih) + gtk_tree_path_free(path); +  + str = iupStrGetMemory(16); +- sprintf(str, "%d", gtkTreeGetNodeId(ih, iterItem)); ++ sprintf(str, "%d", gtkTreeFindNodeId(ih, &iterItem)); + return str; + } +  +- return "0"; /* default VALUE is root */ ++ if (ih->data->node_count) ++ return "0"; /* default VALUE is root */ ++ else ++ return "-1"; ++} ++ ++static char* gtkTreeGetMarkedNodesAttrib(Ihandle* ih) ++{ ++ char* str = iupStrGetMemory(ih->data->node_count+1); ++ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ++ GtkTreeIter iterItem; ++ int i; ++ ++ for (i=0; idata->node_count; i++) ++ { ++ gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); ++ if (gtkTreeIsNodeSelected(model, &iterItem)) ++ str[i] = '+'; ++ else ++ str[i] = '-'; ++ } ++ ++ str[ih->data->node_count] = 0; ++ return str; ++} ++ ++static int gtkTreeSetMarkedNodesAttrib(Ihandle* ih, const char* value) ++{ ++ int count, i; ++ GtkTreeModel* model; ++ GtkTreeIter iterItem; ++ GtkTreeSelection* selection; ++ ++ if (ih->data->mark_mode==ITREE_MARK_SINGLE || !value) ++ return 0; ++ ++ count = strlen(value); ++ if (count > ih->data->node_count) ++ count = ih->data->node_count; ++ ++ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); ++ model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ++ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); ++ ++ for (i=0; idata->node_cache[i].node_handle); ++ if (value[i] == '+') ++ gtkTreeSelectNode(model, selection, &iterItem, 1); ++ else ++ gtkTreeSelectNode(model, selection, &iterItem, 0); ++ } ++ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); ++ ++ return 0; + } +  + static int gtkTreeSetMarkAttrib(Ihandle* ih, const char* value) + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); +- GtkTreeIter iterRoot; +  + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + return 0; +  +- gtk_tree_model_get_iter_first(model, &iterRoot); +- + if(iupStrEqualNoCase(value, "BLOCK")) + { ++ GtkTreeIter iterItem1, iterItem2; + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); +- gtk_tree_selection_select_range(selection, (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"), pathFocus); ++ gtk_tree_model_get_iter(model, &iterItem1, pathFocus); + gtk_tree_path_free(pathFocus); ++ ++ gtkTreeIterInit(ih, &iterItem2, iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE")); ++ ++ gtkTreeSelectRange(ih, model, selection, &iterItem1, &iterItem2, 0); + } + else if(iupStrEqualNoCase(value, "CLEARALL")) +- gtk_tree_selection_unselect_all(selection); ++ gtkTreeSelectAll(ih, model, selection, 0); + else if(iupStrEqualNoCase(value, "MARKALL")) +- gtk_tree_selection_select_all(selection); ++ gtkTreeSelectAll(ih, model, selection, 1); + else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */ +- gtkTreeInvertAllNodeMarking(ih, model, selection, &iterRoot); ++ gtkTreeInvertAllNodeMarking(ih, model, selection); + else if(iupStrEqualPartial(value, "INVERT")) + { + /* iupStrEqualPartial allows the use of "INVERTid" form */ + GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, model, &value[strlen("INVERT")], &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, &value[strlen("INVERT")], &iterItem)) + return 0; +  +- if(gtk_tree_selection_iter_is_selected(selection, &iterItem)) +- gtk_tree_selection_unselect_iter(selection, &iterItem); +- else +- gtk_tree_selection_select_iter(selection, &iterItem); ++ gtkTreeSelectNode(model, selection, &iterItem, -1); /* toggle */ + } + else + { +- GtkTreePath *path1, *path2; + GtkTreeIter iterItem1, iterItem2; + char str1[50], str2[50]; + if (iupStrToStrStr(value, str1, str2, '-')!=2) + return 0; +  +- if (!gtkTreeFindNodeFromString(ih, model, str1, &iterItem1)) ++ if (!gtkTreeFindNodeFromString(ih, str1, &iterItem1)) + return 0; +- if (!gtkTreeFindNodeFromString(ih, model, str2, &iterItem2)) ++ if (!gtkTreeFindNodeFromString(ih, str2, &iterItem2)) + return 0; +  +- path1 = gtk_tree_model_get_path(model, &iterItem1); +- path2 = gtk_tree_model_get_path(model, &iterItem2); +- gtk_tree_selection_select_range(selection, path1, path2); +- gtk_tree_path_free(path1); +- gtk_tree_path_free(path2); ++ gtkTreeSelectRange(ih, model, selection, &iterItem1, &iterItem2, 0); + } +  + return 1; +@@ -1210,148 +1253,112 @@ static int gtkTreeSetValueAttrib(Ihandle* ih, const char* value) + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); +- GtkTreeIter iterRoot, iterItem; ++ GtkTreeIter iterItem; + GtkTreePath* path; ++ int kind; +  + if (gtkTreeSetMarkAttrib(ih, value)) + return 0; +  +- gtk_tree_model_get_iter_first(model, &iterRoot); +- +- if (iupStrEqualNoCase(value, "ROOT")) +- iterItem = iterRoot; ++ if (iupStrEqualNoCase(value, "ROOT") || iupStrEqualNoCase(value, "FIRST")) ++ gtk_tree_model_get_iter_first(model, &iterItem); + else if(iupStrEqualNoCase(value, "LAST")) +- iterItem = gtkTreeGetLastVisibleNode(ih, model, iterRoot); ++ gtkTreeGetLastVisibleNode(ih, model, &iterItem); + else if(iupStrEqualNoCase(value, "PGUP")) + { +- GtkTreeIter iterPrev; +- + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); +- gtk_tree_model_get_iter(model, &iterPrev, pathFocus); ++ gtk_tree_model_get_iter(model, &iterItem, pathFocus); + gtk_tree_path_free(pathFocus); +  +- ih->data->id_control = -1; +- gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterPrev); +- ih->data->id_control -= 10; /* less 10 visible nodes */ +- +- if(ih->data->id_control < 0) +- ih->data->id_control = 0; /* Begin of tree = Root id */ +- +- iterItem = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); ++ gtkTreeGetPreviousVisibleNode(ih, model, &iterItem, 10); + } + else if(iupStrEqualNoCase(value, "PGDN")) + { +- GtkTreeIter iterNext; +- + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); +- gtk_tree_model_get_iter(model, &iterNext, pathFocus); ++ gtk_tree_model_get_iter(model, &iterItem, pathFocus); + gtk_tree_path_free(pathFocus); +  +- ih->data->id_control = -1; +- gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterNext); +- ih->data->id_control += 10; /* more 10 visible nodes */ +- +- iterNext = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); +- +- if (ih->data->id_control >= 0) +- iterNext = gtkTreeGetLastVisibleNode(ih, model, iterRoot); +- +- iterItem = iterNext; ++ gtkTreeGetNextVisibleNode(ih, model, &iterItem, 10); + } + else if(iupStrEqualNoCase(value, "NEXT")) + { +- GtkTreeIter iterNext; +- + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); +- gtk_tree_model_get_iter(model, &iterNext, pathFocus); ++ gtk_tree_model_get_iter(model, &iterItem, pathFocus); + gtk_tree_path_free(pathFocus); +  +- ih->data->id_control = -1; +- gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterNext); +- ih->data->id_control++; /* more 1 visible node */ +- +- iterNext = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); +- +- if (ih->data->id_control >= 0) +- iterNext = gtkTreeGetLastVisibleNode(ih, model, iterRoot); +- +- iterItem = iterNext; ++ gtkTreeGetNextVisibleNode(ih, model, &iterItem, 1); + } + else if(iupStrEqualNoCase(value, "PREVIOUS")) + { +- GtkTreeIter iterPrev; +- + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); +- gtk_tree_model_get_iter(model, &iterPrev, pathFocus); ++ gtk_tree_model_get_iter(model, &iterItem, pathFocus); + gtk_tree_path_free(pathFocus); +  +- ih->data->id_control = -1; +- gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterPrev); +- ih->data->id_control--; /* less 1 visible node */ +- +- if (ih->data->id_control < 0) +- ih->data->id_control = 0; +- +- iterItem = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); +- if (!iterItem.user_data) +- return 0; ++ gtkTreeGetPreviousVisibleNode(ih, model, &iterItem, 1); + } + else + { +- if (!gtkTreeFindNodeFromString(ih, model, value, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, value, &iterItem)) + return 0; + } +  + /* select */ + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + { +- iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", "1"); +- gtk_tree_selection_select_iter(selection, &iterItem); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); ++ gtkTreeSelectNode(model, selection, &iterItem, 1); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + } +  + path = gtk_tree_model_get_path(model, &iterItem); ++ ++ /* make it visible */ ++ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); ++ if (kind == ITREE_LEAF) ++ gtk_tree_view_expand_to_path(GTK_TREE_VIEW(ih->handle), path); ++ else ++ { ++ int expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); ++ gtk_tree_view_expand_to_path(GTK_TREE_VIEW(ih->handle), path); ++ if (!expanded) gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); ++ } ++ + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE, 0, 0); /* scroll to visible */ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); /* set focus */ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); ++ + gtk_tree_path_free(path); +  +- iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", gtkTreeGetNodeId(ih, iterItem)); ++ iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", gtkTreeFindNodeId(ih, &iterItem)); +  + return 0; + }  +  + static int gtkTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) + { +- GtkTreePath *pathMarkStart, *pathMarkStartPrev; +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return 0; +  +- pathMarkStart = gtk_tree_model_get_path(model, &iterItem); +- +- pathMarkStartPrev = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"); +- if (pathMarkStartPrev) +- gtk_tree_path_free(pathMarkStartPrev); +- +- iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)pathMarkStart); ++ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)iterItem.user_data); +  + return 1; + } +  + static char* gtkTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) + { +- GtkTreeSelection* selection; +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ++ GtkTreeModel* model; + GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return 0; +  +- selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); +- if (gtk_tree_selection_iter_is_selected(selection, &iterItem)) ++ model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ++ if (gtkTreeIsNodeSelected(model, &iterItem)) + return "YES"; + else + return "NO"; +@@ -1359,87 +1366,99 @@ static char* gtkTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) +  + static int gtkTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value) + { ++ GtkTreeModel* model; + GtkTreeSelection* selection; +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return 0; +  +- iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", "1"); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); +  + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); ++ model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + if (iupStrBoolean(value)) +- gtk_tree_selection_select_iter(selection, &iterItem); ++ gtkTreeSelectNode(model, selection, &iterItem, 1); + else +- gtk_tree_selection_unselect_iter(selection, &iterItem); ++ gtkTreeSelectNode(model, selection, &iterItem, 0); ++ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); +  + return 0; + } +  + static int gtkTreeSetDelNodeAttrib(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; +- if (iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */ ++ if (iupStrEqualNoCase(value, "ALL")) + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- GtkTreeIter iterItem; +- GtkTreeIter iterParent; ++ gtkTreeCallNodeRemovedAll(ih); +  +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) +- return 0; ++ /* deleting the reference node (and it's children) */ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); ++ gtk_tree_store_clear(GTK_TREE_STORE(model)); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); ++ return 0; ++ } ++ if (iupStrEqualNoCase(value, "SELECTED")) /* selected here means the reference node */ ++ { ++ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ++ GtkTreeIter iterItem; +  +- if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem)) /* the root node can't be deleted */ ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return 0; +  + gtkTreeCallNodeRemoved(ih, model, &iterItem); +  +- /* deleting the specified node (and it's children) */ ++ /* deleting the reference node (and it's children) */ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + } +- else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */ ++ else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the reference node */ + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem, iterChild; + int hasChildren; +  +- if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return 0; +  + hasChildren = gtk_tree_model_iter_children(model, &iterChild, &iterItem); +  +- /* deleting the selected node's children */ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); ++ ++ /* deleting the reference node children */ + while(hasChildren) + { + gtkTreeCallNodeRemoved(ih, model, &iterChild); + hasChildren = gtk_tree_store_remove(GTK_TREE_STORE(model), &iterChild); + } ++ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + } + else if(iupStrEqualNoCase(value, "MARKED")) /* Delete the array of marked nodes */ + { ++ int i; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); +- GList *rr_list = NULL; +- GList *node; ++ GtkTreeIter iterItem; +  +- gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Iter_Func, &rr_list); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); +  +- for(node = rr_list; node != NULL; node = node->next) ++ for(i = 1; i < ih->data->node_count; /* increment only if not removed */) + { +- GtkTreePath* path = gtk_tree_row_reference_get_path(node->data); +- if (path) ++ gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); ++ if (gtkTreeIsNodeSelected(model, &iterItem)) + { +- GtkTreeIter iterItem; +- if (gtk_tree_model_get_iter(model, &iterItem, path)) +- { +- gtkTreeCallNodeRemoved(ih, model, &iterItem); +- gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem); +- } +- gtk_tree_path_free(path); ++ gtkTreeCallNodeRemoved(ih, model, &iterItem); ++ gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem); + } +- gtk_tree_row_reference_free(node->data); ++ else ++ i++; + } +- g_list_free(rr_list); ++ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + } +  + return 0; +@@ -1450,36 +1469,11 @@ static int gtkTreeSetRenameAttrib(Ihandle* ih, const char* value) + if (ih->data->show_rename) + { + GtkTreePath* path; +- IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); + GtkTreeViewColumn *focus_column; +- + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, &focus_column); +- +- if (cbShowRename) +- { +- GtkTreeIter iterItem; +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- gtk_tree_model_get_iter(model, &iterItem, path); +- cbShowRename(ih, gtkTreeGetNodeId(ih, iterItem)); +- } +- + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, focus_column, TRUE); + gtk_tree_path_free(path); + } +- else +- { +- IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB"); +- if (cbRenameNode) +- { +- GtkTreePath* path; +- GtkTreeIter iterItem; +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); +- gtk_tree_model_get_iter(model, &iterItem, path); +- gtk_tree_path_free(path); +- cbRenameNode(ih, gtkTreeGetNodeId(ih, iterItem), gtkTreeGetTitle(model, iterItem));  +- } +- } +  + (void)value; + return 0; +@@ -1491,7 +1485,7 @@ static int gtkTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GdkPixbuf* pixExpand = iupImageGetImage(value, ih, 0); + GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return 0; +  + gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1); +@@ -1514,7 +1508,7 @@ static int gtkTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* v + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GdkPixbuf* pixImage = iupImageGetImage(value, ih, 0); + GtkTreeIter iterItem; +- if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) ++ if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) + return 0; +  + if (pixImage) +@@ -1539,42 +1533,30 @@ static int gtkTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* v +  + static int gtkTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) + { +- GtkTreeIter iterRoot; +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + ih->data->def_image_expanded = iupImageGetImage(value, ih, 0); +  +- gtk_tree_model_get_iter_first(model, &iterRoot); +- +- /* Update all images, starting at root node */ +- gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_EXPANDED); ++ /* Update all images */ ++ gtkTreeUpdateImages(ih, ITREE_UPDATEIMAGE_EXPANDED); +  + return 1; + } +  + static int gtkTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) + { +- GtkTreeIter iterRoot; +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + ih->data->def_image_collapsed = iupImageGetImage(value, ih, 0); +  +- gtk_tree_model_get_iter_first(model, &iterRoot); +- +- /* Update all images, starting at root node */ +- gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_COLLAPSED); ++ /* Update all images */ ++ gtkTreeUpdateImages(ih, ITREE_UPDATEIMAGE_COLLAPSED); +  + return 1; + } +  + static int gtkTreeSetImageLeafAttrib(Ihandle* ih, const char* value) + { +- GtkTreeIter iterRoot; +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + ih->data->def_image_leaf = iupImageGetImage(value, ih, 0); +  +- gtk_tree_model_get_iter_first(model, &iterRoot); +- +- /* Update all images, starting at root node */ +- gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_LEAF); ++ /* Update all images */ ++ gtkTreeUpdateImages(ih, ITREE_UPDATEIMAGE_LEAF); +  + return 1; + } +@@ -1655,6 +1637,7 @@ void iupdrvTreeUpdateMarkMode(Ihandle *ih) + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && !ih->data->show_dragdrop) + { + #if GTK_CHECK_VERSION(2, 10, 0) ++ if (iupAttribGetInt(ih, "RUBBERBAND")) + gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(ih->handle), TRUE); + #endif + } +@@ -1704,6 +1687,19 @@ static void gtkTreeCellTextEditingStarted(GtkCellRenderer *cell, GtkCellEditable + PangoFontDescription* fontdesc = NULL; + GdkColor *color = NULL; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ++ IFni cbShowRename; ++ ++ gtk_tree_model_get_iter_from_string(model, &iterItem, path_string); ++ ++ cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); ++ if (cbShowRename && cbShowRename(ih, gtkTreeFindNodeId(ih, &iterItem))==IUP_IGNORE) ++ { ++ /* TODO: non of these worked: ++ gtk_cell_renderer_stop_editing(cell, TRUE); ++ gtk_cell_editable_editing_done(editable); */ ++ gtk_editable_set_editable(GTK_EDITABLE(editable), FALSE); ++ return; ++ } +  + value = iupAttribGetStr(ih, "RENAMECARET"); + if (value) +@@ -1713,7 +1709,6 @@ static void gtkTreeCellTextEditingStarted(GtkCellRenderer *cell, GtkCellEditable + if (value) + gtkTreeSetRenameSelectionPos(editable, value); +  +- gtk_tree_model_get_iter_from_string(model, &iterItem, path_string); + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_FONT, &fontdesc, -1); + if (fontdesc) + gtk_widget_modify_font(GTK_WIDGET(editable), fontdesc); +@@ -1732,7 +1727,7 @@ static void gtkTreeCellTextEdited(GtkCellRendererText *cell, gchar *path_string, + IFnis cbRename; +  + if (!new_text) +- return; ++ new_text = ""; +  + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + if (!gtk_tree_model_get_iter_from_string(model, &iterItem, path_string)) +@@ -1741,7 +1736,7 @@ static void gtkTreeCellTextEdited(GtkCellRendererText *cell, gchar *path_string, + cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); + if (cbRename) + { +- if (cbRename(ih, gtkTreeGetNodeId(ih, iterItem), iupgtkStrConvertFromUTF8(new_text)) == IUP_IGNORE) ++ if (cbRename(ih, gtkTreeFindNodeId(ih, &iterItem), iupgtkStrConvertFromUTF8(new_text)) == IUP_IGNORE) + return; + } +  +@@ -1766,8 +1761,8 @@ static int gtkTreeCallDragDropCb(Ihandle* ih, GtkTreeIter *iterDrag, GtkTreeIter +  + if (cbDragDrop) + { +- int drag_id = gtkTreeGetNodeId(ih, *iterDrag); +- int drop_id = gtkTreeGetNodeId(ih, *iterDrop); ++ int drag_id = gtkTreeFindNodeId(ih, iterDrag); ++ int drop_id = gtkTreeFindNodeId(ih, iterDrop); + return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl); + } +  +@@ -1804,22 +1799,17 @@ static void gtkTreeDragDataReceived(GtkWidget *widget, GdkDragContext *context, + { + GtkTreeIter iterNewItem; +  +- /* Copy the dragged item to the new position. */ +- gtkTreeCopyNode(ih, model, &iterDrag, &iterDrop, &iterNewItem, is_ctrl); +- +- if (!is_ctrl) +- { +- /* do not delete the user data, we copy the references in CopyNode */ +- gtk_tree_store_remove(GTK_TREE_STORE(model), &iterDrag); +- } ++ /* Copy or move the dragged item to the new position. */ ++ gtkTreeCopyMoveNode(ih, model, &iterDrag, &iterDrop, &iterNewItem, is_ctrl); +  + /* set focus and selection */ ++ if (iterNewItem.stamp) + { + GtkTreePath *pathNew; + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); +  + pathNew = gtk_tree_model_get_path(model, &iterNewItem); +- gtk_tree_selection_select_path(selection, pathNew); ++ gtkTreeSelectNode(model, selection, &iterNewItem, 1); +  + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), pathNew, NULL, FALSE, 0, 0); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), pathNew, NULL, FALSE); +@@ -1927,10 +1917,24 @@ static void gtkTreeDragBegin(GtkWidget *widget, GdkDragContext *context, Ihandle + (void)widget; + } +  ++static gboolean gtkTreeSelectionFunc(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean selected, Ihandle* ih) ++{ ++ GtkTreeIter iterItem; ++ gtk_tree_model_get_iter(model, &iterItem, path); ++ gtkTreeSelectNodeRaw(model, &iterItem, !selected); ++ (void)ih; ++ (void)selection; ++ return TRUE; ++} ++ + static void gtkTreeSelectionChanged(GtkTreeSelection* selection, Ihandle* ih) + { + IFnii cbSelec; + int is_ctrl = 0; ++ (void)selection; ++ ++ if (iupAttribGet(ih, "_IUPTREE_IGNORE_SELECTION_CB")) ++ return; +  + if (ih->data->mark_mode == ITREE_MARK_MULTIPLE) + { +@@ -1953,25 +1957,17 @@ static void gtkTreeSelectionChanged(GtkTreeSelection* selection, Ihandle* ih) + if (cbSelec) + { + int curpos = -1, is_selected = 0; ++ GtkTreeIter iterFocus; ++ GtkTreePath* pathFocus; ++ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +  +- if (iupAttribGet(ih, "_IUP_IGNORE_SELECTION")) +- { +- iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", NULL); +- return; +- } +- ++ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); ++ if (pathFocus) + { +- GtkTreeIter iterFocus; +- GtkTreePath* pathFocus; +- GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); +- gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); +- if (pathFocus) +- { +- gtk_tree_model_get_iter(model, &iterFocus, pathFocus); +- gtk_tree_path_free(pathFocus); +- curpos = gtkTreeGetNodeId(ih, iterFocus); +- is_selected = gtk_tree_selection_iter_is_selected(selection, &iterFocus); +- } ++ gtk_tree_model_get_iter(model, &iterFocus, pathFocus); ++ gtk_tree_path_free(pathFocus); ++ curpos = gtkTreeFindNodeId(ih, &iterFocus); ++ is_selected = gtkTreeIsNodeSelected(model, &iterFocus); + } +  + if (curpos == -1) +@@ -1993,18 +1989,52 @@ static void gtkTreeSelectionChanged(GtkTreeSelection* selection, Ihandle* ih) + } + } +  ++static void gtkTreeUpdateSelectionChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter *iterItem) ++{ ++ int expanded; ++ GtkTreeIter iterChild; ++ int hasItem = gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ ++ while(hasItem) ++ { ++ if (gtkTreeIsNodeSelected(model, &iterChild)) ++ gtk_tree_selection_select_iter(selection, &iterChild); ++ ++ expanded = 0; ++ if (gtk_tree_model_iter_has_child(model, &iterChild)) ++ { ++ GtkTreePath* path = gtk_tree_model_get_path(model, &iterChild); ++ expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); ++ gtk_tree_path_free(path); ++ } ++ ++ /* Recursive only if expanded */ ++ if (expanded) ++ gtkTreeUpdateSelectionChildren(ih, model, selection, &iterChild);  ++ ++ /* Go to next sibling item */ ++ hasItem = gtk_tree_model_iter_next(model, &iterChild); ++ } ++} ++ ++static void gtkTreeRowExpanded(GtkTreeView* tree_view, GtkTreeIter *iterItem, GtkTreePath *path, Ihandle* ih) ++{ ++ GtkTreeSelection* selection = gtk_tree_view_get_selection(tree_view); ++ GtkTreeModel* model = gtk_tree_view_get_model(tree_view); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); ++ gtkTreeUpdateSelectionChildren(ih, model, selection, iterItem); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); ++ (void)path; ++} ++ + static gboolean gtkTreeTestExpandRow(GtkTreeView* tree_view, GtkTreeIter *iterItem, GtkTreePath *path, Ihandle* ih) + { + IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB"); + if (cbBranchOpen) + { +- if (iupAttribGet(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB")) +- { +- iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB", NULL); ++ if (iupAttribGet(ih, "_IUPTREE_IGNORE_BRANCH_CB")) + return FALSE; +- } +  +- if (cbBranchOpen(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE) ++ if (cbBranchOpen(ih, gtkTreeFindNodeId(ih, iterItem)) == IUP_IGNORE) + return TRUE; /* prevent the change */ + } +  +@@ -2018,7 +2048,10 @@ static gboolean gtkTreeTestCollapseRow(GtkTreeView* tree_view, GtkTreeIter *iter + IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); + if (cbBranchClose) + { +- if (cbBranchClose(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE) ++ if (iupAttribGet(ih, "_IUPTREE_IGNORE_BRANCH_CB")) ++ return FALSE; ++ ++ if (cbBranchClose(ih, gtkTreeFindNodeId(ih, iterItem)) == IUP_IGNORE) + return TRUE; + } +  +@@ -2042,7 +2075,7 @@ static void gtkTreeRowActived(GtkTreeView* tree_view, GtkTreePath *path, GtkTree +  + /* just to leaf nodes */ + if(gtk_tree_model_iter_has_child(model, &iterItem) == 0 && kind == ITREE_LEAF) +- cbExecuteLeaf(ih, gtkTreeGetNodeId(ih, iterItem)); ++ cbExecuteLeaf(ih, gtkTreeFindNodeId(ih, &iterItem)); +  + (void)column; + (void)tree_view; +@@ -2057,11 +2090,57 @@ static int gtkTreeConvertXYToPos(Ihandle* ih, int x, int y) + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_model_get_iter(model, &iterItem, path); + gtk_tree_path_free (path); +- return gtkTreeGetNodeId(ih, iterItem); ++ return gtkTreeFindNodeId(ih, &iterItem); + } + return -1; + } +  ++static Iarray* gtkTreeGetSelectedArrayId(Ihandle* ih) ++{ ++ Iarray* selarray = iupArrayCreate(1, sizeof(int)); ++ int i; ++ GtkTreeIter iterItem; ++ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ++ ++ for (i = 0; i < ih->data->node_count; i++) ++ { ++ gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); ++ if (gtkTreeIsNodeSelected(model, &iterItem)) ++ { ++ int* id_hitem = (int*)iupArrayInc(selarray); ++ int j = iupArrayCount(selarray); ++ id_hitem[j-1] = i; ++ } ++ } ++ ++ return selarray; ++} ++ ++static void gtkTreeCallMultiUnSelectionCb(Ihandle* ih) ++{ ++ IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTIUNSELECTION_CB"); ++ IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); ++ if (cbSelec || cbMulti) ++ { ++ Iarray* markedArray = gtkTreeGetSelectedArrayId(ih); ++ int* id_hitem = (int*)iupArrayGetData(markedArray); ++ int i, count = iupArrayCount(markedArray); ++ ++ if (count > 1) ++ { ++ if (cbMulti) ++ cbMulti(ih, id_hitem, iupArrayCount(markedArray)); ++ else ++ { ++ for (i=0; itype == GDK_BUTTON_PRESS && evt->button == 1) /* left single press */ ++ { ++ iupAttribSetInt(ih, "_IUPTREE_DRAG_X", (int)evt->x); ++ iupAttribSetInt(ih, "_IUPTREE_DRAG_Y", (int)evt->y); ++ ++ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE &&  ++ !(evt->state & GDK_SHIFT_MASK) && !(evt->state & GDK_CONTROL_MASK)) ++ { ++ gtkTreeCallMultiUnSelectionCb(ih); ++ iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1"); ++ } ++ } + else if (evt->type == GDK_BUTTON_RELEASE && evt->button == 1) /* left single release */ + { + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & GDK_SHIFT_MASK)) +@@ -2109,16 +2200,7 @@ static gboolean gtkTreeButtonEvent(GtkWidget *treeview, GdkEventButton *evt, Iha + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "2"); + } + } +- else if (evt->type == GDK_BUTTON_PRESS && evt->button == 1) /* left single press */ +- { +- iupAttribSetInt(ih, "_IUPTREE_DRAG_X", (int)evt->x); +- iupAttribSetInt(ih, "_IUPTREE_DRAG_Y", (int)evt->y); +  +- if (ih->data->mark_mode==ITREE_MARK_MULTIPLE &&  +- !(evt->state & GDK_SHIFT_MASK) && !(evt->state & GDK_CONTROL_MASK)) +- iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1"); +- } +-  + return FALSE; + } +  +@@ -2159,29 +2241,14 @@ static void gtkTreeEnableDragDrop(Ihandle* ih) + { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 } + }; +  +- if (iupAttribGetBoolean(ih, "AUTODRAGDROP")) +- { +- gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW(ih->handle), +- GDK_BUTTON1_MASK, +- row_targets, +- G_N_ELEMENTS(row_targets), +- GDK_ACTION_MOVE|GDK_ACTION_COPY); +- gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW(ih->handle), +- row_targets, +- G_N_ELEMENTS(row_targets), +- GDK_ACTION_MOVE|GDK_ACTION_COPY); +- } +- else +- { +- gtk_drag_source_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); +- gtk_drag_dest_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); ++ gtk_drag_source_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); ++ gtk_drag_dest_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); +  +- g_signal_connect(G_OBJECT(ih->handle), "drag-begin", G_CALLBACK(gtkTreeDragBegin), ih); +- g_signal_connect(G_OBJECT(ih->handle), "drag-motion", G_CALLBACK(gtkTreeDragMotion), ih); +- g_signal_connect(G_OBJECT(ih->handle), "drag-leave", G_CALLBACK(gtkTreeDragLeave), NULL); +- g_signal_connect(G_OBJECT(ih->handle), "drag-drop", G_CALLBACK(gtkTreeDragDrop), ih); +- g_signal_connect(G_OBJECT(ih->handle), "drag-data-received", G_CALLBACK(gtkTreeDragDataReceived), ih); +- } ++ g_signal_connect(G_OBJECT(ih->handle), "drag-begin", G_CALLBACK(gtkTreeDragBegin), ih); ++ g_signal_connect(G_OBJECT(ih->handle), "drag-motion", G_CALLBACK(gtkTreeDragMotion), ih); ++ g_signal_connect(G_OBJECT(ih->handle), "drag-leave", G_CALLBACK(gtkTreeDragLeave), NULL); ++ g_signal_connect(G_OBJECT(ih->handle), "drag-drop", G_CALLBACK(gtkTreeDragDrop), ih); ++ g_signal_connect(G_OBJECT(ih->handle), "drag-data-received", G_CALLBACK(gtkTreeDragDataReceived), ih); + } +  + /*****************************************************************************/ +@@ -2194,8 +2261,16 @@ static int gtkTreeMapMethod(Ihandle* ih) + GtkTreeSelection* selection; + GtkTreeViewColumn *column; +  +- store = gtk_tree_store_new(9, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, +- G_TYPE_STRING, G_TYPE_INT, GDK_TYPE_COLOR, PANGO_TYPE_FONT_DESCRIPTION, G_TYPE_POINTER); ++ store = gtk_tree_store_new(IUPGTK_TREE_LAST_DATA,  ++ GDK_TYPE_PIXBUF, /* IUPGTK_TREE_IMAGE */ ++ G_TYPE_BOOLEAN, /* IUPGTK_TREE_HAS_IMAGE */ ++ GDK_TYPE_PIXBUF, /* IUPGTK_TREE_IMAGE_EXPANDED */ ++ G_TYPE_BOOLEAN, /* IUPGTK_TREE_HAS_IMAGE_EXPANDED */ ++ G_TYPE_STRING, /* IUPGTK_TREE_TITLE */ ++ G_TYPE_INT, /* IUPGTK_TREE_KIND */ ++ GDK_TYPE_COLOR, /* IUPGTK_TREE_COLOR */ ++ PANGO_TYPE_FONT_DESCRIPTION, /* IUPGTK_TREE_FONT */ ++ G_TYPE_BOOLEAN); /* IUPGTK_TREE_SELECT */ +  + ih->handle = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); +  +@@ -2262,8 +2337,9 @@ static int gtkTreeMapMethod(Ihandle* ih) + gtk_scrolled_window_set_policy(scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); +  + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); +-  + gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); ++ gtk_tree_selection_set_select_function(selection, (GtkTreeSelectionFunc)gtkTreeSelectionFunc, ih, NULL); ++ + gtk_tree_view_set_reorderable(GTK_TREE_VIEW(ih->handle), FALSE); +  + /* callbacks */ +@@ -2279,6 +2355,7 @@ static int gtkTreeMapMethod(Ihandle* ih) + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih); +  ++ g_signal_connect(G_OBJECT(ih->handle), "row-expanded", G_CALLBACK(gtkTreeRowExpanded), ih); + g_signal_connect(G_OBJECT(ih->handle), "test-expand-row", G_CALLBACK(gtkTreeTestExpandRow), ih); + g_signal_connect(G_OBJECT(ih->handle), "test-collapse-row", G_CALLBACK(gtkTreeTestCollapseRow), ih); + g_signal_connect(G_OBJECT(ih->handle), "row-activated", G_CALLBACK(gtkTreeRowActived), ih); +@@ -2301,7 +2378,8 @@ static int gtkTreeMapMethod(Ihandle* ih) + ih->data->def_image_collapsed = iupImageGetImage("IMGCOLLAPSED", ih, 0); + ih->data->def_image_expanded = iupImageGetImage("IMGEXPANDED", ih, 0); +  +- gtkTreeAddRootNode(ih); ++ if (iupAttribGetInt(ih, "ADDROOT")) ++ iupdrvTreeAddNode(ih, "-1", ITREE_BRANCH, "", 0); +  + /* configure for DRAG&DROP of files */ + if (IupGetCallback(ih, "DROPFILES_CB")) +@@ -2309,13 +2387,23 @@ static int gtkTreeMapMethod(Ihandle* ih) +  + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkTreeConvertXYToPos); +  ++ iupdrvTreeUpdateMarkMode(ih); ++ + return IUP_NOERROR; + } +  ++static void gtkTreeUnMapMethod(Ihandle* ih) ++{ ++ ih->data->node_count = 0; ++ ++ iupdrvBaseUnMapMethod(ih); ++} ++ + void iupdrvTreeInitClass(Iclass* ic) + { + /* Driver Dependent Class functions */ + ic->Map = gtkTreeMapMethod; ++ ic->UnMap = gtkTreeUnMapMethod; +  + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTreeSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); +@@ -2324,7 +2412,6 @@ void iupdrvTreeInitClass(Iclass* ic) + /* IupTree Attributes - GENERAL */ + iupClassRegisterAttribute(ic, "EXPANDALL", NULL, gtkTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INDENTATION", gtkTreeGetIndentationAttrib, gtkTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT); +- iupClassRegisterAttribute(ic, "COUNT", gtkTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, gtkTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, gtkTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); +@@ -2345,7 +2432,6 @@ void iupdrvTreeInitClass(Iclass* ic) + iupClassRegisterAttributeId(ic, "COLOR", gtkTreeGetColorAttrib, gtkTreeSetColorAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "NAME", gtkTreeGetTitleAttrib, gtkTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLE", gtkTreeGetTitleAttrib, gtkTreeSetTitleAttrib, IUPAF_NO_INHERIT); +- iupClassRegisterAttributeId(ic, "USERDATA", gtkTreeGetUserDataAttrib, gtkTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); +  + iupClassRegisterAttributeId(ic, "CHILDCOUNT", gtkTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLEFONT", gtkTreeGetTitleFontAttrib, gtkTreeSetTitleFontAttrib, IUPAF_NO_INHERIT); +@@ -2355,6 +2441,7 @@ void iupdrvTreeInitClass(Iclass* ic) + iupClassRegisterAttribute (ic, "MARK", NULL, gtkTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "STARTING", NULL, gtkTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARKSTART", NULL, gtkTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); ++ iupClassRegisterAttribute (ic, "MARKEDNODES", gtkTreeGetMarkedNodesAttrib, gtkTreeSetMarkedNodesAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +  + iupClassRegisterAttribute (ic, "VALUE", gtkTreeGetValueAttrib, gtkTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +  +@@ -2363,7 +2450,7 @@ void iupdrvTreeInitClass(Iclass* ic) + iupClassRegisterAttribute(ic, "RENAME", NULL, gtkTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "MOVENODE", NULL, gtkTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COPYNODE", NULL, gtkTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); +- iupClassRegisterAttributeId(ic, "FINDUSERDATA", gtkTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); +  +- iupClassRegisterAttribute (ic, "AUTODRAGDROP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT); ++ /* IupTree Attributes - GTK Only */ ++ iupClassRegisterAttribute (ic, "RUBBERBAND", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + } +diff --git a/iup/src/iup.c b/iup/src/iup.c +index df4bf34..d103af5 100755 +--- a/iup/src/iup.c ++++ b/iup/src/iup.c +@@ -36,8 +36,10 @@ + * \subsection com File Comments (at start) + * - Check an existant file for example. + *  +- * \subsection inc Include Defines +- * - __IUPXXX_H (same file name, upper case, "__" preffix and replace "." by "_") ++ * \subsection def Defines ++ * - __IUPXXX_H (for include file, same file name, upper case, "__" preffix and replace "." by "_") ++ * - IUP_XXX (for enumerations) ++ * - iupXXX (for macros, complement with Function Names rules) + *  + * \subsection doc Documentation + * - In the header, using Doxygen commands. +@@ -58,7 +60,7 @@ + #include "iup.h" +  + /* This appears only here to avoid changing the iup.h header fo bug fixes */ +-#define IUP_VERSION_FIX " RC3" ++#define IUP_VERSION_FIX "" + #define IUP_VERSION_FIX_NUMBER 0 +  + const char iup_ident[] =  +diff --git a/iup/src/iup.def b/iup/src/iup.def +index d0dcfbd..56e7225 100755 +--- a/iup/src/iup.def ++++ b/iup/src/iup.def +@@ -27,6 +27,8 @@ IupGetFunction + IupGetGlobal + IupGetHandle + IupGetInt ++IupGetInt2 ++IupGetIntInt + IupGetLanguage + IupGetName + IupHbox +@@ -40,6 +42,7 @@ IupListDialog + IupLoad + IupLoadBuffer + IupLoopStep ++IupLoopStepWait + IupMainLoop + IupMap + IupMapFont +@@ -68,6 +71,7 @@ IupShowXY + IupStoreAttribute + IupStoreGlobal + IupSubmenu ++IupSplit + IupText + IupToggle + IupUnMapFont +@@ -135,6 +139,7 @@ IupTextConvertLinColToPos + IupTextConvertPosToLinCol + IupUpdateChildren + IupTreeSetAttribute  ++IupTreeSetAttributeHandle + IupTreeStoreAttribute + IupTreeGetAttribute  + IupTreeGetInt  +@@ -175,8 +180,8 @@ iupdrvFontGetStringWidth + iupdrvFontGetMultiLineStringSize + iupdrvFontGetCharSize + iupdrvDrawFocusRect +-iupdrvDisplayUpdate +-iupdrvDisplayRedraw ++iupdrvPostRedraw ++iupdrvRedrawNow + iupdrvBaseUnMapMethod + iupdrvBaseSetZorderAttrib + iupdrvBaseSetTipVisibleAttrib +@@ -351,3 +356,17 @@ iupArrayCreate + iupArrayCount + iupArrayAdd + iupSaveImageAsText ++iupDrawCreateCanvas ++iupDrawKillCanvas ++iupDrawFlush ++iupDrawGetSize ++iupDrawParentBackground ++iupDrawRectangle ++iupDrawLine ++iupDrawArc ++iupDrawPolygon ++iupDrawResetClip ++iupDrawSetClipRect ++iupDrawText ++iupDrawUpdateSize ++iupDrawImage +diff --git a/iup/src/iup_attrib.c b/iup/src/iup_attrib.c +index 2bbb80a..bf9576e 100755 +--- a/iup/src/iup_attrib.c ++++ b/iup/src/iup_attrib.c +@@ -63,7 +63,7 @@ char* IupGetAttributes(Ihandle *ih) + name = iupTableFirst(ih->attrib); + while (name) + { +- if (!iupAttribIsInternal(name)) ++ if (!iupATTRIB_ISINTERNAL(name)) + { + if (buffer[0] != 0) + strcat(buffer,","); +@@ -115,6 +115,14 @@ void iupAttribUpdateFromParent(Ihandle* ih) + } + } +  ++static int iAttribIsInherit(Ihandle* ih, const char* name) ++{ ++ int inherit; ++ char *def_value; ++ iupClassObjectGetAttributeInfo(ih, name, &def_value, &inherit); ++ return inherit; ++} ++ + static void iAttribNotifyChildren(Ihandle *ih, const char* name, const char *value) + { + int inherit; +@@ -123,17 +131,36 @@ static void iAttribNotifyChildren(Ihandle *ih, const char* name, const char *val + { + if (!iupTableGet(child->attrib, name)) + { +- /* set on the class */ +- iupClassObjectSetAttribute(child, name, value, &inherit); ++ /* set only if an inheritable attribute at the child */ ++ if (iAttribIsInherit(child, name)) ++ { ++ /* set on the class */ ++ iupClassObjectSetAttribute(child, name, value, &inherit); +  +- if (inherit) /* inherit can be different for the child */ + iAttribNotifyChildren(child, name, value); ++ } + } +  + child = child->brother; + } + } +  ++void iupAttribUpdateChildren(Ihandle* ih) ++{ ++ char *name = iupTableFirst(ih->attrib); ++ while (name) ++ { ++ if (!iupATTRIB_ISINTERNAL(name) && iAttribIsInherit(ih, name)) ++ { ++ /* retrieve from the table */ ++ char* value = iupTableGet(ih->attrib, name); ++ iAttribNotifyChildren(ih, name, value); ++ } ++ ++ name = iupTableNext(ih->attrib); ++ } ++} ++ + void iupAttribUpdate(Ihandle* ih) + { + char** name_array; +@@ -159,7 +186,7 @@ void iupAttribUpdate(Ihandle* ih) + for (i = 0; i < count; i++) + { + name = name_array[i]; +- if (!iupAttribIsInternal(name)) ++ if (!iupATTRIB_ISINTERNAL(name)) + { + /* retrieve from the table */ + value = iupTableGet(ih->attrib, name); +@@ -196,7 +223,7 @@ void IupSetAttribute(Ihandle *ih, const char* name, const char *value) + if (!iupObjectCheck(ih)) + return; +  +- if (iupAttribIsInternal(name)) ++ if (iupATTRIB_ISINTERNAL(name)) + iupAttribSetStr(ih, name, value); + else + { +@@ -225,7 +252,7 @@ void IupStoreAttribute(Ihandle *ih, const char* name, const char *value) + if (!iupObjectCheck(ih)) + return; +  +- if (iupAttribIsInternal(name)) ++ if (iupATTRIB_ISINTERNAL(name)) + iupAttribStoreStr(ih, name, value); + else + { +@@ -257,7 +284,7 @@ char* IupGetAttribute(Ihandle *ih, const char* name) + if (!value) + value = iupAttribGet(ih, name); +  +- if (!value && !iupAttribIsInternal(name)) ++ if (!value && !iupATTRIB_ISINTERNAL(name)) + { + if (inherit) + { +@@ -346,6 +373,16 @@ void iupAttribSetHandleName(Ihandle *ih) + IupSetHandle(str_name, ih); + } +  ++char* iupAttribGetHandleName(Ihandle *ih) ++{ ++ char str_name[100]; ++ sprintf(str_name, "_IUP_NAME(%p)", ih); ++ if (IupGetHandle(str_name)==ih) ++ return iupStrGetMemoryCopy(str_name); ++ else ++ return NULL; ++} ++ + void IupSetAttributeHandle(Ihandle *ih, const char* name, Ihandle *ih_named) + { + int inherit; +@@ -426,7 +463,7 @@ void iupAttribSetInt(Ihandle *ih, const char* name, int num) +  + void iupAttribSetFloat(Ihandle *ih, const char* name, float num) + { +- iupAttribSetStrf(ih, name, "%f", (double)num); ++ iupAttribSetStrf(ih, name, "%g", (double)num); + } +  + int iupAttribGetBoolean(Ihandle* ih, const char* name) +@@ -479,7 +516,7 @@ char* iupAttribGetStr(Ihandle* ih, const char* name) +  + value = iupTableGet(ih->attrib, name); +  +- if (!value && !iupAttribIsInternal(name)) ++ if (!value && !iupATTRIB_ISINTERNAL(name)) + { + int inherit; + char *def_value; +@@ -555,6 +592,15 @@ static void iAttribCapture(char* env_buffer, char* dlm) + env_buffer[i-1]='\0'; /* discard delimiter */ + } +  ++static void iAttribSkipComment(void) ++{ ++ int c; ++ do ++ { ++ c = *env_str; ++env_str; ++ } while ((c > 0) && (c != '\n')); ++} ++ + static int iAttribToken(char* env_buffer) + { + for (;;) +@@ -565,6 +611,11 @@ static int iAttribToken(char* env_buffer) + case 0: + return IUPLEX_TK_END; +  ++ case '#': /* Skip comment */ ++ case '%': /* Skip comment */ ++ iAttribSkipComment(); ++ continue; ++ + case ' ': /* ignore whitespace */ + case '\t': + case '\n': +@@ -609,7 +660,7 @@ static void iAttribParse(Ihandle *ih, const char* str) + { + switch (iAttribToken(env_buffer)) + { +- case IUPLEX_TK_END: /* procedimento igual ao IUPLEX_TK_COMMA */ ++ case IUPLEX_TK_END: /* same as IUPLEX_TK_COMMA */ + end = 1; + case IUPLEX_TK_COMMA: + if (name) +diff --git a/iup/src/iup_attrib.h b/iup/src/iup_attrib.h +index 993dd3c..8593d6e 100755 +--- a/iup/src/iup_attrib.h ++++ b/iup/src/iup_attrib.h +@@ -28,7 +28,7 @@ extern "C" { +  + /** Returns true if the attribute name if in the internal format "_IUP...". + * \ingroup attrib */ +-#define iupAttribIsInternal(_name) ((_name[0] == '_' && _name[1] == 'I' && _name[2] == 'U' && _name[3] == 'P')? 1: 0) ++#define iupATTRIB_ISINTERNAL(_name) ((_name[0] == '_' && _name[1] == 'I' && _name[2] == 'U' && _name[3] == 'P')? 1: 0) +  + /** Returns true if the attribute name is a known pointer. + * \ingroup attrib */ +@@ -102,16 +102,23 @@ float iupAttribGetFloat(Ihandle* ih, const char* name); + * \ingroup attrib */ + void iupAttribSetHandleName(Ihandle *ih); +  ++/** Returns the internal name if set. ++ * \ingroup attrib */ ++char* iupAttribGetHandleName(Ihandle *ih); ++ +  + /* For all attributes in the evironment, call the class SetAttribute only. +- * Called only after the element is mapped. */ ++ * Called only after the element is mapped, but before the children are mapped. */ + void iupAttribUpdate(Ihandle* ih);  +  + /* For all registered inherited attributes, checks the parent tree and  + * call the class SetAttribute if the attribute is defined. +- * Called only after the element is mapped. */ ++ * Called only after the element is mapped, but before the children are mapped. */ + void iupAttribUpdateFromParent(Ihandle* ih); +  ++/* For all attributes in the evironment, call the class SetAttribute only for the children. ++ * Called only after the element is mapped, and after the children are mapped. */ ++void iupAttribUpdateChildren(Ihandle* ih); +  +  + /* Other functions declared in and implemented here.  +diff --git a/iup/src/iup_box.c b/iup/src/iup_box.c +index 54e56d9..111cab4 100755 +--- a/iup/src/iup_box.c ++++ b/iup/src/iup_box.c +@@ -172,9 +172,9 @@ static int iBoxSetCMarginAttrib(Ihandle* ih, const char* value) + iupdrvFontGetCharSize(ih, &charwidth, &charheight); + iupStrToIntInt(value, &cmargin_x, &cmargin_y, 'x'); + if (cmargin_x!=-1) +- ih->data->margin_x = iupHEIGHT2RASTER(cmargin_x, charheight); ++ ih->data->margin_x = iupWIDTH2RASTER(cmargin_x, charwidth); + if (cmargin_y!=-1) +- ih->data->margin_x = iupWIDTH2RASTER(cmargin_y, charwidth); ++ ih->data->margin_y = iupHEIGHT2RASTER(cmargin_y, charheight); + return 0; + } +  +@@ -227,8 +227,12 @@ Iclass* iupBoxClassBase(void) + /* boxes only */ + iupClassRegisterAttribute(ic, "GAP", iBoxGetGapAttrib, iBoxSetGapAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CGAP", iBoxGetCGapAttrib, iBoxSetCGapAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED); ++ iupClassRegisterAttribute(ic, "NGAP", iBoxGetGapAttrib, iBoxSetGapAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); ++ iupClassRegisterAttribute(ic, "NCGAP", iBoxGetCGapAttrib, iBoxSetCGapAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MARGIN", iBoxGetMarginAttrib, iBoxSetMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CMARGIN", iBoxGetCMarginAttrib, iBoxSetCMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); ++ iupClassRegisterAttribute(ic, "NMARGIN", iBoxGetMarginAttrib, iBoxSetMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); ++ iupClassRegisterAttribute(ic, "NCMARGIN", iBoxGetCMarginAttrib, iBoxSetCMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); +  + iupClassRegisterAttribute(ic, "EXPANDCHILDREN", iBoxGetExpandChildrenAttrib, iBoxSetExpandChildrenAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "HOMOGENEOUS", iBoxGetHomogeneousAttrib, iBoxSetHomogeneousAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); +diff --git a/iup/src/iup_button.c b/iup/src/iup_button.c +index 7719663..56befe2 100755 +--- a/iup/src/iup_button.c ++++ b/iup/src/iup_button.c +@@ -100,8 +100,9 @@ static void iButtonComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *ex + char* value = iupAttribGet(ih, "IMAGE"); + if (value) + { ++ char* title = iupAttribGet(ih, "TITLE"); + type = IUP_BUTTON_IMAGE; +- if (iupAttribGet(ih, "TITLE")) ++ if (title && *title!=0) + type |= IUP_BUTTON_TEXT; + } + else +diff --git a/iup/src/iup_canvas.c b/iup/src/iup_canvas.c +index 5eda988..46fefd9 100755 +--- a/iup/src/iup_canvas.c ++++ b/iup/src/iup_canvas.c +@@ -55,14 +55,14 @@ void iupCanvasCalcScrollRealPos(double min, double max, double *pos, + char* iupCanvasGetPosXAttrib(Ihandle* ih) + { + char* str = iupStrGetMemory(20); +- sprintf(str, "%f", ih->data->posx); ++ sprintf(str, "%g", ih->data->posx); + return str; + } +  + char* iupCanvasGetPosYAttrib(Ihandle* ih) + { + char* str = iupStrGetMemory(20); +- sprintf(str, "%f", ih->data->posy); ++ sprintf(str, "%g", ih->data->posy); + return str; + } +  +diff --git a/iup/src/iup_classattrib.c b/iup/src/iup_classattrib.c +index df8f873..3ac780c 100755 +--- a/iup/src/iup_classattrib.c ++++ b/iup/src/iup_classattrib.c +@@ -55,7 +55,7 @@ static const char* iClassFindId(const char* name) + { + if (*name >= '0' && *name <= '9') + return name; +- if (*name == '*' || *name == ':') ++ if (*name == '*' || *name == ':' || *name == '-') + return name; +  + name++; +@@ -94,7 +94,6 @@ int iupClassObjectSetAttribute(Ihandle* ih, const char* name, const char * value + const char* name_id = iClassFindId(name); + if (name_id) + { +- IattribFunc* afunc; + const char* partial_name = iClassCutNameId(name, name_id); + if (!partial_name) + partial_name = "IDVALUE"; /* pure numbers are used as attributes in IupList and IupMatrix,  +@@ -474,8 +473,12 @@ void iupClassObjectEnsureDefaultAttributes(Ihandle* ih) + (afunc->call_global_default && iupGlobalDefaultColorChanged(afunc->default_value))) + { + if ((!ih->handle && (afunc->flags & IUPAF_NOT_MAPPED)) || +- (ih->handle && !(afunc->flags & IUPAF_NOT_MAPPED) && !iupAttribGet(ih, name))) +- afunc->set(ih, iClassGetDefaultValue(afunc)); ++ (ih->handle && !(afunc->flags & IUPAF_NOT_MAPPED))) ++ { ++ char* value = iupAttribGet(ih, name); ++ if (!value) /* if set will be updated later */ ++ afunc->set(ih, iClassGetDefaultValue(afunc)); ++ } + } + } +  +diff --git a/iup/src/iup_classbase.c b/iup/src/iup_classbase.c +index 9cb9e63..03a98d1 100755 +--- a/iup/src/iup_classbase.c ++++ b/iup/src/iup_classbase.c +@@ -164,8 +164,7 @@ static char* iBaseGetPositionAttrib(Ihandle* ih) +  + static int iBaseSetPositionAttrib(Ihandle* ih, const char* value) + { +- if (ih->is_floating) +- iupStrToIntInt(value, &ih->x, &ih->y, ','); ++ iupStrToIntInt(value, &ih->x, &ih->y, ','); + return 0; + } +  +@@ -211,7 +210,7 @@ char* iupBaseGetVisibleAttrib(Ihandle* ih) + int iupBaseSetVisibleAttrib(Ihandle* ih, const char* value) + { + iupdrvSetVisible(ih, iupStrBoolean(value)); +- return 0; ++ return 1; /* must be 1 to mark when set at the element */ + } +  + char* iupBaseNativeParentGetBgColorAttrib(Ihandle* ih) +@@ -410,15 +409,19 @@ void iupBaseRegisterCommonAttrib(Iclass* ic) + iupClassRegisterAttribute(ic, "FLOATING", iBaseGetFloatingAttrib, iBaseSetFloatingAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "EXPAND", iBaseGetExpandAttrib, iBaseSetExpandAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NORMALIZERGROUP", NULL, iBaseSetNormalizerGroupAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); ++ iupClassRegisterAttribute(ic, "EXPANDWEIGTH", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); +  + /* make sure everyone has the correct default value */ +- iupClassRegisterAttribute(ic, "VISIBLE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "ACTIVE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + if (ic->is_interactive) + iupClassRegisterAttribute(ic, "CANFOCUS", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + else + iupClassRegisterAttribute(ic, "CANFOCUS", NULL, NULL, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NO_INHERIT); +  ++ /* if not native container, must set at children, ++ native container will automatically hide its children. */ ++ iupClassRegisterAttribute(ic, "VISIBLE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); /* let the attribute to be propagated to children */ ++ + iupClassRegisterAttribute(ic, "SIZE", iupBaseGetSizeAttrib, iupBaseSetSizeAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, iupBaseSetRasterSizeAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CHARSIZE", iupBaseGetCharSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); +@@ -439,7 +442,7 @@ void iupBaseRegisterCommonAttrib(Iclass* ic) +  + void iupBaseRegisterVisualAttrib(Iclass* ic) + { +- iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, iupBaseSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); /* VISIBLE inheritance comes from the native system */ ++ iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, iupBaseSetVisibleAttrib, "YES", "NO", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); +  + iupClassRegisterAttribute(ic, "ZORDER", NULL, iupdrvBaseSetZorderAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); +diff --git a/iup/src/iup_dialog.c b/iup/src/iup_dialog.c +index d70e12c..1aaf095 100755 +--- a/iup/src/iup_dialog.c ++++ b/iup/src/iup_dialog.c +@@ -220,11 +220,19 @@ static void iDialogDestroyMethod(Ihandle* ih) + iupDlgListRemove(ih); + } +  ++static int iDialogSetMenuAttrib(Ihandle* ih, const char* value); ++ + static void iDialogComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) + { + int decorwidth, decorheight; + Ihandle* child = ih->firstchild; +  ++ /* if does not have a menu, but the attribute is defined, ++ try to update the menu before retrieving the decoration. */ ++ char* value = iupAttribGet(ih, "MENU"); ++ if (!ih->data->menu && value) ++ iDialogSetMenuAttrib(ih, value); ++ + iupDialogGetDecorSize(ih, &decorwidth, &decorheight); + *w = decorwidth; + *h = decorheight; +@@ -278,20 +286,22 @@ static void iDialogAfterShow(Ihandle* ih) + { + Ihandle* old_focus; + IFni show_cb; ++ int show_state; +  + /* process all pending messages */ + IupFlush(); +  + old_focus = IupGetFocus(); ++ show_state = ih->data->show_state; +  + show_cb = (IFni)IupGetCallback(ih, "SHOW_CB"); +- if (show_cb && show_cb(ih, ih->data->show_state) == IUP_CLOSE) ++ if (show_cb && show_cb(ih, show_state) == IUP_CLOSE) + { + IupExitLoop(); + return; + } +  +- if (ih->data->show_state == IUP_SHOW) ++ if (show_state == IUP_SHOW) + { + if (show_cb) + IupFlush(); /* again to update focus */ +@@ -718,7 +728,8 @@ Iclass* iupDialogGetClass(void) + iupBaseRegisterVisualAttrib(ic); +  + /* Overwrite Visual */ +- iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, iDialogSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NO_INHERIT); /* the only case where VISIBLE default is NO */ ++ /* the only case where VISIBLE default is NO, and must not be propagated to the dialog children */ ++ iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, iDialogSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NO_INHERIT);  +  + /* IupDialog only */ + iupClassRegisterAttribute(ic, "MENU", NULL, iDialogSetMenuAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); +diff --git a/iup/src/iup_drv.h b/iup/src/iup_drv.h +index 5cdb8e7..1071347 100755 +--- a/iup/src/iup_drv.h ++++ b/iup/src/iup_drv.h +@@ -60,11 +60,11 @@ void iupdrvSetActive(Ihandle* ih, int enable); +  + /** Post a redraw of a control. + * \ingroup drv */ +-void iupdrvDisplayUpdate(Ihandle *ih); ++void iupdrvPostRedraw(Ihandle *ih); +  + /** Force a redraw of a control. + * \ingroup drv */ +-void iupdrvDisplayRedraw(Ihandle *ih); ++void iupdrvRedrawNow(Ihandle *ih); +  + /** Reparent the native control. + * \ingroup drv */ +diff --git a/iup/src/iup_focus.c b/iup/src/iup_focus.c +index be54b75..fc0579c 100755 +--- a/iup/src/iup_focus.c ++++ b/iup/src/iup_focus.c +@@ -220,15 +220,25 @@ void iupFocusPrevious(Ihandle *ih) + /* local variables */ + static Ihandle* iup_current_focus = NULL; +  ++Ihandle* IupGetFocus(void) ++{ ++ return iup_current_focus; ++} ++ ++void iupSetCurrentFocus(Ihandle *ih) ++{ ++ iup_current_focus = ih; ++} ++ + Ihandle *IupSetFocus(Ihandle *ih) + { +- Ihandle* old_focus = iup_current_focus; ++ Ihandle* old_focus = IupGetFocus(); +  + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return old_focus; +  +- /* iup_current_focus is NOT set here,  ++ /* Current focus is NOT set here,  + only in the iupCallGetFocusCb */ +  + if (iupFocusCanAccept(ih))  +@@ -237,16 +247,11 @@ Ihandle *IupSetFocus(Ihandle *ih) + return old_focus; + } +  +-Ihandle *IupGetFocus(void) +-{ +- return iup_current_focus; +-} +- + void iupCallGetFocusCb(Ihandle *ih) + { + Icallback cb; +  +- if (ih == iup_current_focus) /* avoid duplicate messages */ ++ if (ih == IupGetFocus()) /* avoid duplicate messages */ + return; +  + cb = (Icallback)IupGetCallback(ih, "GETFOCUS_CB"); +@@ -258,14 +263,14 @@ void iupCallGetFocusCb(Ihandle *ih) + if (cb2) cb2(ih, 1); + } +  +- iup_current_focus = ih; ++ iupSetCurrentFocus(ih); + } +  + void iupCallKillFocusCb(Ihandle *ih) + { + Icallback cb; +  +- if (ih != iup_current_focus) /* avoid duplicate messages */ ++ if (ih != IupGetFocus()) /* avoid duplicate messages */ + return; +  + cb = IupGetCallback(ih, "KILLFOCUS_CB"); +@@ -277,5 +282,5 @@ void iupCallKillFocusCb(Ihandle *ih) + if (cb2) cb2(ih, 0); + } +  +- iup_current_focus = NULL; ++ iupSetCurrentFocus(NULL); + } +diff --git a/iup/src/iup_focus.h b/iup/src/iup_focus.h +index 239e233..9fb4e58 100755 +--- a/iup/src/iup_focus.h ++++ b/iup/src/iup_focus.h +@@ -39,6 +39,7 @@ Ihandle* iupFocusNextInteractive(Ihandle *ih); + void iupFocusNext(Ihandle *ih); + void iupFocusPrevious(Ihandle *ih); +  ++void iupSetCurrentFocus(Ihandle *ih); +  + /* Other functions declared in and implemented here.  + IupPreviousField +diff --git a/iup/src/iup_getparam.c b/iup/src/iup_getparam.c +index 1418aa5..7fd6a94 100755 +--- a/iup/src/iup_getparam.c ++++ b/iup/src/iup_getparam.c +@@ -45,6 +45,14 @@ static int iParamButtonCancel_CB(Ihandle* self) + return IUP_CLOSE; + } +  ++static int iParamButtonHelp_CB(Ihandle* self) ++{ ++ Ihandle* dlg = IupGetDialog(self); ++ Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB"); ++ if (cb) cb(dlg, -4, (void*)iupAttribGet(dlg, "USER_DATA")); ++ return IUP_DEFAULT; ++} ++ + static int iParamToggleAction_CB(Ihandle *self, int v) + { + Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM"); +@@ -288,7 +296,7 @@ static int iParamColorButton_CB(Ihandle *self, int button, int pressed) +  + IupPopup(dlg, IUP_CENTER, IUP_CENTER); +  +- if (IupGetInt(dlg, "STATUS") != -1) ++ if (IupGetInt(dlg, "STATUS")==1) + { + char* value = IupGetAttribute(dlg, "VALUE"); + IupSetAttribute(textbox, "VALUE", value); +@@ -381,11 +389,13 @@ static int iParamSpinInt_CB(Ihandle *self, int pos) + static Ihandle* iParamCreateBox(Ihandle* param) + { + Ihandle *box, *ctrl = NULL, *label; +- char *type; ++ char *type = iupAttribGet(param, "TYPE"); ++ ++ if (iupStrEqual(type, "BUTTONNAMES")) ++ return NULL; +  + label = IupLabel(iupAttribGet(param, "TITLE")); +  +- type = iupAttribGet(param, "TYPE"); + if (iupStrEqual(type, "SEPARATOR")) + { + box = IupHbox(label, NULL); +@@ -563,7 +573,7 @@ static Ihandle* iParamCreateBox(Ihandle* param) + float step = iupAttribGetFloat(param, "STEP"); + float val = iupAttribGetFloat(param, "VALUE"); + if (step == 0) step = (max-min)/20.0f; +- IupSetfAttribute(ctrl, "MASKFLOAT", "%f:%f", (double)min, (double)max); ++ IupSetfAttribute(ctrl, "MASKFLOAT", "%g:%g", (double)min, (double)max); +  + /* here spin is always [0-spinmax] converted to [min-max] */ +  +@@ -584,7 +594,7 @@ static Ihandle* iParamCreateBox(Ihandle* param) + if (min == 0) + IupSetAttribute(ctrl, "MASK", IUP_MASK_UFLOAT); + else +- IupSetfAttribute(ctrl, "MASKFLOAT", "%f:%f", (double)min, (double)1.0e10); ++ IupSetfAttribute(ctrl, "MASKFLOAT", "%g:%g", (double)min, (double)1.0e10); + IupAppend(box, ctrl); + } + else +@@ -620,6 +630,7 @@ static Ihandle* iParamCreateBox(Ihandle* param) + } + IupSetfAttribute(ctrl, "SPINMAX", "%d", max); + IupSetfAttribute(ctrl, "SPINMIN", "%d", min); ++ IupSetfAttribute(ctrl, "MASKINT", "%d:%d", min, max); + } + else if (iupAttribGetInt(param, "PARTIAL")) + { +@@ -696,7 +707,7 @@ static Ihandle* iParamCreateBox(Ihandle* param) +  + static Ihandle* IupParamDlgP(Ihandle** params) + { +- Ihandle *dlg, *button_ok, *button_cancel,  ++ Ihandle *dlg, *button_ok, *button_cancel, *button_help=NULL,  + *dlg_box, *button_box, *param_box; + int i, lbl_width, p, expand; +  +@@ -713,7 +724,23 @@ static Ihandle* IupParamDlgP(Ihandle** params) + i = 0; expand = 0; + while (params[i] != NULL) + { +- IupAppend(param_box, iParamCreateBox(params[i])); ++ Ihandle* box = iParamCreateBox(params[i]); ++ if (box) ++ IupAppend(param_box, box); ++ else /* buttonnames */ ++ { ++ char* value = iupAttribGet(params[i], "_IUPGP_OK"); ++ if (value && *value) IupSetAttribute(button_ok, "TITLE", value); ++ value = iupAttribGet(params[i], "_IUPGP_CANCEL"); ++ if (value && *value) IupSetAttribute(button_cancel, "TITLE", value); ++ value = iupAttribGet(params[i], "_IUPGP_HELP"); ++ if (value && *value)  ++ { ++ button_help = IupButton(value, NULL); ++ IupSetAttribute(button_help, "PADDING", "20x0"); ++ IupSetCallback(button_help, "ACTION", (Icallback)iParamButtonHelp_CB); ++ } ++ } +  + if (IupGetInt(params[i], "EXPAND")) + expand = 1; +@@ -725,6 +752,7 @@ static Ihandle* IupParamDlgP(Ihandle** params) + IupFill(), + button_ok, + button_cancel, ++ button_help, + NULL); + IupSetAttribute(button_box,"MARGIN","0x0"); + IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL"); +@@ -926,6 +954,23 @@ static void iParamSetFileOptions(char* extra, Ihandle* param) + iupAttribStoreStr(param, "_IUPGP_NOOVERWRITEPROMPT", nooverwriteprompt); + } +  ++static void iParamSetButtonNames(char* extra, Ihandle* param) ++{ ++ char *ok, *cancel, *help; ++ int count; ++ ++ if (!extra) ++ return; ++ ++ ok = iParamGetNextStrItem(extra, ',', &count); extra += count; ++ cancel = iParamGetNextStrItem(extra, ',', &count); extra += count; ++ help = iParamGetNextStrItem(extra, ',', &count); extra += count; ++ ++ iupAttribStoreStr(param, "_IUPGP_OK", ok); ++ iupAttribStoreStr(param, "_IUPGP_CANCEL", cancel); ++ iupAttribStoreStr(param, "_IUPGP_HELP", help); ++} ++ + static void iParamSetListItems(char* extra, Ihandle* param) + { + int d = 1, count; +@@ -1082,6 +1127,12 @@ static Ihandle *IupParamf(const char* format, int *line_size) + iupAttribSetStr(param, "TYPE", "SEPARATOR"); + iupAttribSetStr(param, "DATA_TYPE", "-1"); /* NONE */ + break; ++ case 'u': ++ iupAttribSetStr(param, "TYPE", "BUTTONNAMES"); ++ iupAttribSetStr(param, "DATA_TYPE", "-1"); /* NONE */ ++ extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count; ++ iParamSetButtonNames(extra, param); ++ break; + default: + return NULL; + } +@@ -1099,7 +1150,7 @@ static Ihandle *IupParamf(const char* format, int *line_size) +  + int iupGetParamCount(const char *format, int *param_extra) + { +- int param_count = 0, sep = 0; ++ int param_count = 0, extra = 0; + const char* s = format; +  + *param_extra = 0; +@@ -1107,14 +1158,20 @@ int iupGetParamCount(const char *format, int *param_extra) + { + if (*s == '%' && *(s+1) == 't') /* do not count separator lines */ + { +- sep = 1; ++ extra = 1; ++ (*param_extra)++; ++ } ++ ++ if (*s == '%' && *(s+1) == 'u') /* do not count button names lines */ ++ { ++ extra = 1; + (*param_extra)++; + } +  + if (*s == '\n') + { +- if (sep) +- sep = 0; ++ if (extra) ++ extra = 0; + else + param_count++; + } +@@ -1154,21 +1211,21 @@ int IupGetParamv(const char* title, Iparamcb action, void* user_data, const char + return 0; +  + data_type = IupGetInt(params[i], "DATA_TYPE"); +- if (data_type == 1) +- { +- int *data_int = (int*)(param_data[p]); +- if (!data_int) return 0; +- iupAttribSetStrf(params[i], "VALUE", "%d", *data_int); +- p++; +- } +- else if (data_type == 2) ++ if (data_type == 2) /* float */ + { + float *data_float = (float*)(param_data[p]); + if (!data_float) return 0; + iupAttribSetStrf(params[i], "VALUE", "%g", *data_float); + p++; + } +- else if (data_type == 0) ++ else if (data_type == 1) /* integer */ ++ { ++ int *data_int = (int*)(param_data[p]); ++ if (!data_int) return 0; ++ iupAttribSetStrf(params[i], "VALUE", "%d", *data_int); ++ p++; ++ } ++ else if (data_type == 0) /* string */ + { + char *data_str = (char*)(param_data[p]); + if (!data_str) return 0; +diff --git a/iup/src/iup_globalattrib.c b/iup/src/iup_globalattrib.c +index 00586fb..d1a2584 100755 +--- a/iup/src/iup_globalattrib.c ++++ b/iup/src/iup_globalattrib.c +@@ -129,12 +129,14 @@ int iupGlobalIsPointer(const char* name) + static struct { + const char *name; + } ptr_table[] = { +-#ifdef WIN32 ++#ifndef GTK_MAC ++ #ifdef WIN32 + {"HINSTANCE"}, +-#else ++ #else + {"XDISPLAY"}, + {"XSCREEN"}, + {"APPSHELL"}, ++ #endif + #endif + }; + #define PTR_TABLE_SIZE ((sizeof ptr_table)/(sizeof ptr_table[0])) +diff --git a/iup/src/iup_hbox.c b/iup/src/iup_hbox.c +index e790636..a8a93a3 100755 +--- a/iup/src/iup_hbox.c ++++ b/iup/src/iup_hbox.c +@@ -213,6 +213,13 @@ static void iHboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) + else + { + int empty = (child->expand & IUP_EXPAND_W1)? empty_w1: ((child->expand & IUP_EXPAND_W0)? empty_w0: 0); ++ char* weigth_str = iupAttribGet(child, "EXPANDWEIGTH"); ++ if (weigth_str) ++ { ++ float weigth;  ++ if (iupStrToFloat(weigth_str, &weigth)) ++ empty = iupROUND(empty * weigth); ++ } + iupBaseSetCurrentSize(child, child->naturalwidth+empty, client_height, shrink); + } +  +diff --git a/iup/src/iup_key.h b/iup/src/iup_key.h +index 37d6c9d..9b30bc4 100755 +--- a/iup/src/iup_key.h ++++ b/iup/src/iup_key.h +@@ -51,16 +51,16 @@ void iupKeyInit(void); +  + #define IUPKEY_STATUS_SIZE 11 /* 10 chars + null */ + #define IUPKEY_STATUS_INIT " " /* 10 spaces */ +-#define iupKEYSETSHIFT(_s) (_s[0]='S') +-#define iupKEYSETCONTROL(_s) (_s[1]='C') +-#define iupKEYSETBUTTON1(_s) (_s[2]='1') +-#define iupKEYSETBUTTON2(_s) (_s[3]='2') +-#define iupKEYSETBUTTON3(_s) (_s[4]='3') +-#define iupKEYSETDOUBLE(_s) (_s[5]='D') +-#define iupKEYSETALT(_s) (_s[6]='A') +-#define iupKEYSETSYS(_s) (_s[7]='Y') +-#define iupKEYSETBUTTON4(_s) (_s[8]='4') +-#define iupKEYSETBUTTON5(_s) (_s[9]='5') ++#define iupKEY_SETSHIFT(_s) (_s[0]='S') ++#define iupKEY_SETCONTROL(_s) (_s[1]='C') ++#define iupKEY_SETBUTTON1(_s) (_s[2]='1') ++#define iupKEY_SETBUTTON2(_s) (_s[3]='2') ++#define iupKEY_SETBUTTON3(_s) (_s[4]='3') ++#define iupKEY_SETDOUBLE(_s) (_s[5]='D') ++#define iupKEY_SETALT(_s) (_s[6]='A') ++#define iupKEY_SETSYS(_s) (_s[7]='Y') ++#define iupKEY_SETBUTTON4(_s) (_s[8]='4') ++#define iupKEY_SETBUTTON5(_s) (_s[9]='5') +  +  + #ifdef __cplusplus +diff --git a/iup/src/iup_layout.c b/iup/src/iup_layout.c +index b96293c..0ccd496 100755 +--- a/iup/src/iup_layout.c ++++ b/iup/src/iup_layout.c +@@ -43,7 +43,7 @@ static void iLayoutDisplayUpdateChildren(Ihandle *ih) + iLayoutDisplayUpdateChildren(child); +  + if (child->handle && child->iclass->nativetype != IUP_TYPEVOID) +- iupdrvDisplayUpdate(child); ++ iupdrvPostRedraw(child); + } + } +  +@@ -54,7 +54,7 @@ void IupUpdate(Ihandle* ih) + return; +  + if (ih->handle && ih->iclass->nativetype != IUP_TYPEVOID) +- iupdrvDisplayUpdate(ih); ++ iupdrvPostRedraw(ih); + } +  + void IupUpdateChildren(Ihandle* ih) +@@ -74,7 +74,7 @@ static void iLayoutDisplayRedrawChildren(Ihandle *ih) + iLayoutDisplayRedrawChildren(child); +  + if (child->handle && child->iclass->nativetype != IUP_TYPEVOID) +- iupdrvDisplayRedraw(child); ++ iupdrvRedrawNow(child); + } + } +  +@@ -85,7 +85,7 @@ void IupRedraw(Ihandle* ih, int children) + return; +  + if (ih->handle && ih->iclass->nativetype != IUP_TYPEVOID) +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); +  + if (children) + iLayoutDisplayRedrawChildren(ih); +@@ -136,7 +136,7 @@ void iupLayoutCompute(Ihandle* ih) + iupBaseSetPosition(ih, 0, 0); + } +  +-static void iLayoutSetMinMaxSize(Ihandle* ih, int *w, int *h) ++void iupLayoutSetMinMaxSize(Ihandle* ih, int *w, int *h) + { + if (ih->has_minsize) + { +@@ -163,7 +163,8 @@ void iupBaseComputeNaturalSize(Ihandle* ih) + ih->naturalwidth = ih->userwidth; + ih->naturalheight = ih->userheight; +  +- if (ih->iclass->childtype!=IUP_CHILDNONE || ih->iclass->nativetype == IUP_TYPEDIALOG) ++ if (ih->iclass->childtype!=IUP_CHILDNONE ||  ++ ih->iclass->nativetype == IUP_TYPEDIALOG) /* pre-defined dialogs can restrict the number of children */ + { + int w=0, h=0, children_expand; +  +@@ -190,7 +191,7 @@ void iupBaseComputeNaturalSize(Ihandle* ih) + ih->naturalheight = iupMAX(ih->naturalheight, h); +  + /* crop the natural size */ +- iLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight)); ++ iupLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight)); + } + } + else  +@@ -198,15 +199,15 @@ void iupBaseComputeNaturalSize(Ihandle* ih) + /* for non-container only compute if user size is not defined */ + if (ih->naturalwidth <= 0 || ih->naturalheight <= 0) + { +- int w=0, h=0; +- iupClassObjectComputeNaturalSize(ih, &w, &h, NULL); ++ int w=0, h=0, children_expand; ++ iupClassObjectComputeNaturalSize(ih, &w, &h, &children_expand); +  + if (ih->naturalwidth <= 0) ih->naturalwidth = w; + if (ih->naturalheight <= 0) ih->naturalheight = h; + } +  + /* crop the natural size */ +- iLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight)); ++ iupLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight)); + } + } +  +@@ -259,7 +260,7 @@ void iupBaseSetCurrentSize(Ihandle* ih, int w, int h, int shrink) +  + /* crop the current size if expanded */ + if (ih->expand & IUP_EXPAND_WIDTH || ih->expand & IUP_EXPAND_HEIGHT) +- iLayoutSetMinMaxSize(ih, &(ih->currentwidth), &(ih->currentheight)); ++ iupLayoutSetMinMaxSize(ih, &(ih->currentwidth), &(ih->currentheight)); + } + } +  +diff --git a/iup/src/iup_layout.h b/iup/src/iup_layout.h +index a2a0c29..775e5a2 100755 +--- a/iup/src/iup_layout.h ++++ b/iup/src/iup_layout.h +@@ -16,6 +16,8 @@ extern "C" { + void iupLayoutCompute(Ihandle* ih); /* can be called before map */ + void iupLayoutUpdate(Ihandle* ih); /* called only after map */ +  ++void iupLayoutSetMinMaxSize(Ihandle* ih, int *w, int *h); ++ + /* Other functions declared in and implemented here.  + IupRefresh + */ +diff --git a/iup/src/iup_ledlex.c b/iup/src/iup_ledlex.c +index 3283a43..5cf8640 100755 +--- a/iup/src/iup_ledlex.c ++++ b/iup/src/iup_ledlex.c +@@ -35,7 +35,7 @@ static struct /* lexical variables */ + static int iLexGetChar (void); + static int iLexToken(int *erro); + static int iLexCapture (char* dlm); +-static int iLexSkip (char* dlm); ++static void iLexSkipComment (void); + static int iLexCaptureAttr (void); +  + int iupLexStart(const char* filename, int is_file) /* initialize lexical analysis */ +@@ -186,9 +186,9 @@ static int iLexToken(int *erro) + case ']': + return IUPLEX_TK_ENDATTR; +  +- case '#': /* iLexSkip comment */ +- case '%': /* iLexSkip comment */ +- iLexSkip ("\n\r"); ++ case '#': /* Skip comment */ ++ case '%': /* Skip comment */ ++ iLexSkipComment(); + continue; +  + case ' ': /* ignore whitespace */ +@@ -276,14 +276,13 @@ static int iLexCaptureAttr (void) + return c; /* return delimiter */ + } +  +-static int iLexSkip (char* dlm) ++static void iLexSkipComment (void) + { + int c; + do + { +- c = iLexGetChar (); +- } while ((c > 0) && !strchr (dlm,c)); +- return c; /* return delimiter */ ++ c = iLexGetChar(); ++ } while ((c > 0) && (c != '\n')); + } +  + static int iLexGetChar (void) +diff --git a/iup/src/iup_list.c b/iup/src/iup_list.c +index 5965665..1077d98 100755 +--- a/iup/src/iup_list.c ++++ b/iup/src/iup_list.c +@@ -53,6 +53,37 @@ static void iListCallActionCallback(Ihandle* ih, IFnsii cb, int pos, int state) + IupExitLoop(); + } +  ++void iupListUpdateOldValue(Ihandle* ih, int pos, int removed) ++{ ++ if (!ih->data->has_editbox) ++ { ++ char* old_value = iupAttribGet(ih, "_IUPLIST_OLDVALUE"); ++ if (old_value) ++ { ++ int old_pos = atoi(old_value)-1; /* was in IUP reference, starting at 1 */ ++ if (ih->data->is_dropdown || !ih->data->is_multiple) ++ { ++ if (old_pos >= pos) ++ { ++ if (removed && old_pos == pos) ++ { ++ /* when the current item is removed nothing remains selected */ ++ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); ++ } ++ else ++ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", removed? old_pos-1: old_pos+1); ++ } ++ } ++ else ++ { ++ /* multiple selection on a non drop-down list. */ ++ char* value = IupGetAttribute(ih, "VALUE"); ++ iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value); ++ } ++ } ++ } ++} ++ + void iupListSingleCallActionCallback(Ihandle* ih, IFnsii cb, int pos) + { + char* old_str = iupAttribGet(ih, "_IUPLIST_OLDVALUE"); +@@ -77,7 +108,7 @@ void iupListMultipleCallActionCallback(Ihandle* ih, IFnsii cb, IFns multi_cb, in + char* old_str = iupAttribGet(ih, "_IUPLIST_OLDVALUE"); + int old_count = old_str? strlen(old_str): 0; +  +- char* str = iupStrGetMemory(count+1); ++ char* str = malloc(count+1); + memset(str, '-', count); + str[count]=0; + for (i=0; i count-1) return -1; ++ if (pos == count) return -2; ++ if (pos > count) return -1; +  + return pos; + } +@@ -217,7 +254,10 @@ int iupListSetIdValueAttrib(Ihandle* ih, const char* name_id, const char* value) + if (pos >= 0 && pos <= count-1) + { + if (pos == 0) ++ { + iupdrvListRemoveAllItems(ih); ++ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); ++ } + else + { + int i = pos; +@@ -245,7 +285,7 @@ int iupListSetIdValueAttrib(Ihandle* ih, const char* name_id, const char* value) +  + static int iListSetAppendItemAttrib(Ihandle* ih, 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; + if (value) + iupdrvListAppendItem(ih, value); +@@ -254,27 +294,32 @@ static int iListSetAppendItemAttrib(Ihandle* ih, const char* value) +  + static int iListSetInsertItemAttrib(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; + if (value) + { + int pos = iupListGetPos(ih, name_id); +- if (pos!=-1) ++ if (pos >= 0) + iupdrvListInsertItem(ih, pos, value); ++ else if (pos == -2) ++ iupdrvListAppendItem(ih, value); + } + return 0; + } +  + static int iListSetRemoveItemAttrib(Ihandle* ih, 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; + if (!value) ++ { + iupdrvListRemoveAllItems(ih); ++ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); ++ } + else + { + int pos = iupListGetPos(ih, value); +- if (pos!=-1) ++ if (pos >= 0) + iupdrvListRemoveItem(ih, pos); + } + return 0; +diff --git a/iup/src/iup_list.h b/iup/src/iup_list.h +index 045116b..05fe9f8 100755 +--- a/iup/src/iup_list.h ++++ b/iup/src/iup_list.h +@@ -30,6 +30,7 @@ char* iupListGetNCAttrib(Ihandle* ih); + char* iupListGetPaddingAttrib(Ihandle* ih); + char* iupListGetSpacingAttrib(Ihandle* ih); + void iupListSingleCallDblClickCallback(Ihandle* ih, IFnis cb, int pos); ++void iupListUpdateOldValue(Ihandle* ih, int pos, int removed); +  + struct _IcontrolData  + { +diff --git a/iup/src/iup_names.c b/iup/src/iup_names.c +index 9ec01a6..18ca3ef 100755 +--- a/iup/src/iup_names.c ++++ b/iup/src/iup_names.c +@@ -14,11 +14,41 @@ + #include "iup_object.h" + #include "iup_class.h" + #include "iup_assert.h" ++#include "iup_attrib.h" + #include "iup_str.h" +  +  + static Itable *inames_strtable = NULL; /* table indexed by name containing Ihandle* address */ +-static Itable *inames_ihtable = NULL; /* table indexed by Ihandle* address containing names */ ++ ++void iupNamesInit(void) ++{ ++ inames_strtable = iupTableCreate(IUPTABLE_STRINGINDEXED); ++} ++ ++void iupNamesFinish(void) ++{ ++ iupTableDestroy(inames_strtable); ++ inames_strtable = NULL; ++} ++ ++static Ihandle* iNameGetTopParent(Ihandle* ih) ++{ ++ Ihandle* parent = ih; ++ while (parent->parent) ++ parent = parent->parent; ++ return parent; ++} ++ ++static int iNameCheckArray(Ihandle** ih_array, int count, Ihandle* ih) ++{ ++ int i; ++ for (i = 0; i < count; i++) ++ { ++ if (ih_array[i] == ih) ++ return 0; ++ } ++ return 1; ++} +  + void iupNamesDestroyHandles(void) + { +@@ -37,10 +67,14 @@ void iupNamesDestroyHandles(void) + while (name) + { + ih = (Ihandle*)iupTableGetCurr(inames_strtable); +- if (iupObjectCheck(ih)) ++ if (iupObjectCheck(ih)) /* here must be a handle */ + { +- ih_array[i] = ih; +- i++; ++ ih = iNameGetTopParent(ih); ++ if (iNameCheckArray(ih_array, i, ih)) ++ { ++ ih_array[i] = ih; ++ i++; ++ } + } + name = iupTableNext(inames_strtable); + } +@@ -48,44 +82,28 @@ void iupNamesDestroyHandles(void) + count = i; + for (i = 0; i < count; i++) + { +- if (iupObjectCheck(ih_array[i])) ++ if (iupObjectCheck(ih_array[i])) /* here must be a handle */ + IupDestroy(ih_array[i]); + } +  + free(ih_array); + } +  +-void iupNamesInit(void) +-{ +- inames_strtable = iupTableCreate(IUPTABLE_STRINGINDEXED); +- inames_ihtable = iupTableCreate(IUPTABLE_POINTERINDEXED); +-} +- +-void iupNamesFinish(void) +-{ +- iupTableDestroy(inames_strtable); +- inames_strtable = NULL; +- +- iupTableDestroy(inames_ihtable); +- inames_ihtable = NULL; +-} +- +-void iupRemoveAllNames(Ihandle* ih) ++void iupRemoveNames(Ihandle* ih) + { + char *name; +- Ihandle *cur_ih; +  +- name = iupTableFirst(inames_strtable); +- while (name) +- { +- cur_ih = (Ihandle*)iupTableGetCurr(inames_strtable); +- if (iupObjectCheck(cur_ih) && cur_ih == ih) +- iupTableRemoveCurr(inames_strtable); ++ /* clear the cache */ ++ name = iupAttribGet(ih, "_IUP_LASTHANDLENAME"); ++ if (name) ++ iupTableRemove(inames_strtable, name); +  +- name = iupTableNext(inames_strtable); +- } ++ /* check for an internal name */ ++ name = iupAttribGetHandleName(ih); ++ if (name) ++ iupTableRemove(inames_strtable, name); +  +- iupTableRemove(inames_ihtable, (char*)ih); ++ /* Do NOT search for other names */ + } +  + Ihandle *IupGetHandle(const char *name) +@@ -104,22 +122,24 @@ Ihandle* IupSetHandle(const char *name, Ihandle *ih) + return NULL; +  + old_ih = iupTableGet(inames_strtable, name); ++ + if (ih != NULL) + { + iupTableSet(inames_strtable, name, ih, IUPTABLE_POINTER); +- iupTableSet(inames_ihtable, (char*)ih, (char*)name, IUPTABLE_STRING); /* keep only the last name set */ ++ ++ /* save the name in the cache if it is a valid handle */ ++ if (iupObjectCheck(ih)) ++ iupAttribStoreStr(ih, "_IUP_LASTHANDLENAME", name); + } + else + { +- ih = iupTableGet(inames_strtable, name); + iupTableRemove(inames_strtable, name); +- if (ih)  +- { +- char* cur_name = iupTableGet(inames_ihtable, (char*)ih); +- if (iupStrEqualNoCase(cur_name, name)) +- iupTableRemove(inames_ihtable, (char*)ih); +- } ++ ++ /* clear the name from the cache if it is a valid handle */ ++ if (iupObjectCheck(old_ih)) ++ iupAttribSetStr(old_ih, "_IUP_LASTHANDLENAME", NULL); + } ++ + return old_ih; + } +  +@@ -151,7 +171,8 @@ static int iNamesCountDialogs(void) + while (name) + { + Ihandle* dlg = (Ihandle*)iupTableGetCurr(inames_strtable); +- if (iupObjectCheck(dlg) && dlg->iclass->nativetype == IUP_TYPEDIALOG) ++ if (iupObjectCheck(dlg) && /* here must be a handle */ ++ dlg->iclass->nativetype == IUP_TYPEDIALOG) + i++; +  + name = iupTableNext(inames_strtable); +@@ -171,7 +192,8 @@ int IupGetAllDialogs(char** names, int n) + while (name) + { + Ihandle* dlg = (Ihandle*)iupTableGetCurr(inames_strtable); +- if (iupObjectCheck(dlg) && dlg->iclass->nativetype == IUP_TYPEDIALOG) ++ if (iupObjectCheck(dlg) && /* here must be a handle */ ++ dlg->iclass->nativetype == IUP_TYPEDIALOG) + { + names[i] = name; + i++; +@@ -186,8 +208,32 @@ int IupGetAllDialogs(char** names, int n) +  + char* IupGetName(Ihandle* ih) + { +- iupASSERT(iupObjectCheck(ih)); +- if (!iupObjectCheck(ih)) ++ char *name; ++ if (!ih) /* no iupASSERT needed here */ + return NULL; +- return iupTableGet(inames_ihtable, (char*)ih); ++ ++ if (iupObjectCheck(ih)) ++ { ++ /* check the cache first, but must be a handle */ ++ name = iupAttribGet(ih, "_IUP_LASTHANDLENAME"); ++ if (name) ++ return name; ++ } ++ ++ /* check for an internal name */ ++ name = iupAttribGetHandleName(ih); ++ if (name) ++ return name; ++  ++ /* search for the name */ ++ name = iupTableFirst(inames_strtable); ++ while (name) ++ { ++ if ((Ihandle*)iupTableGetCurr(inames_strtable) == ih) ++ return name; ++ ++ name = iupTableNext(inames_strtable); ++ } ++ ++ return NULL; + } +diff --git a/iup/src/iup_names.h b/iup/src/iup_names.h +index 9d3adc7..d652594 100755 +--- a/iup/src/iup_names.h ++++ b/iup/src/iup_names.h +@@ -17,7 +17,7 @@ void iupNamesFinish(void); + void iupNamesDestroyHandles(void); +  + /* called from IupDestroy */ +-void iupRemoveAllNames(Ihandle* ih); ++void iupRemoveNames(Ihandle* ih); +  + /* Other functions declared in and implemented here. + IupGetName +diff --git a/iup/src/iup_object.c b/iup/src/iup_object.c +index 7f4ce23..f0d5dc9 100755 +--- a/iup/src/iup_object.c ++++ b/iup/src/iup_object.c +@@ -148,6 +148,8 @@ Ihandle* IupCreate(const char *name) +  + void IupDestroy(Ihandle *ih) + { ++ Icallback cb; ++ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; +@@ -156,6 +158,9 @@ void IupDestroy(Ihandle *ih) + if (ih->iclass->nativetype == IUP_TYPEDIALOG) + IupHide(ih); +  ++ cb = IupGetCallback(ih, "DESTROY_CB"); ++ if (cb) cb(ih); ++ + /* Destroy all its children. + Just need to remove the first child, + IupDetach will update firstchild. */ +@@ -165,6 +170,9 @@ void IupDestroy(Ihandle *ih) + /* unmap if mapped and remove from its parent child list */ + IupDetach(ih); +  ++ /* removes names associated with the element */ ++ iupRemoveNames(ih); ++ + /* destroy the element */ + iupClassObjectDestroy(ih); +  +@@ -172,9 +180,6 @@ void IupDestroy(Ihandle *ih) + if (ih->data) + free(ih->data); +  +- /* removes all the names associated with the element */ +- iupRemoveAllNames(ih); +- + /* destroy the base handle structure */ + iHandleDestroy(ih); + } +diff --git a/iup/src/iup_object.h b/iup/src/iup_object.h +index 6f6b668..a69edc0 100755 +--- a/iup/src/iup_object.h ++++ b/iup/src/iup_object.h +@@ -113,6 +113,7 @@ Ihandle* iupObjectCreate(Iclass* ic, void** params); + void** iupObjectGetParamList(void* first, va_list arglist); +  + /** Checks if the handle is still valid based on the signature. ++ * But if the handle was destroyed still can access invalid memory. + * \ingroup object */ + int iupObjectCheck(Ihandle* ih); +  +diff --git a/iup/src/iup_open.c b/iup/src/iup_open.c +index e02561e..bce5c5c 100755 +--- a/iup/src/iup_open.c ++++ b/iup/src/iup_open.c +@@ -101,8 +101,8 @@ void IupClose(void) +  + iupdrvSetIdleFunction(NULL); /* stop any idle */ +  +- iupDlgListDestroyAll(); /* destroy all dialogs */ +- iupNamesDestroyHandles(); /* destroy everything else that have names */ ++ iupDlgListDestroyAll(); /* destroy all dialogs and their children */ ++ iupNamesDestroyHandles(); /* destroy everything that do not belong to a dialog */ + iupImageStockFinish(); /* release stock images hash table and the images */ +  + iupRegisterFinish(); /* release native classes */ +diff --git a/iup/src/iup_register.c b/iup/src/iup_register.c +index 4c58038..2e9954a 100755 +--- a/iup/src/iup_register.c ++++ b/iup/src/iup_register.c +@@ -99,6 +99,7 @@ void iupRegisterInternalClasses(void) + iupRegisterClass(iupCboxGetClass()); + iupRegisterClass(iupSboxGetClass()); + iupRegisterClass(iupNormalizerGetClass()); ++ iupRegisterClass(iupSplitGetClass()); +  + iupRegisterClass(iupMenuGetClass()); + iupRegisterClass(iupItemGetClass()); +diff --git a/iup/src/iup_sbox.c b/iup/src/iup_sbox.c +index 5a71d33..9998481 100755 +--- a/iup/src/iup_sbox.c ++++ b/iup/src/iup_sbox.c +@@ -57,6 +57,7 @@ static void iSboxSaveDimension(Ihandle* ih, int w, int h) + { + ih->data->w = w; + ih->data->h = h; ++ iupLayoutSetMinMaxSize(ih, &(ih->data->w), &(ih->data->h)); + } +  + static void iSboxAddDecorOffset(Ihandle* ih, int *x, int *y) +diff --git a/iup/src/iup_show.c b/iup/src/iup_show.c +index 9ea1408..b42975e 100755 +--- a/iup/src/iup_show.c ++++ b/iup/src/iup_show.c +@@ -53,35 +53,6 @@ void IupUnmap(Ihandle *ih) + ih->handle = NULL; + } +  +-static char* iShowGetVisible(Ihandle* ih) +-{ +- char* value = iupAttribGet(ih, "VISIBLE"); /* Check on the element first */ +- while (!value) +- { +- ih = ih->parent; /* iheritance here independs on the attribute */ +- if (!ih) +- return NULL; +- +- value = iupAttribGet(ih, "VISIBLE"); +- +- /* only recursive up to the native parent */  +- if (ih->iclass->nativetype != IUP_TYPEVOID) +- return value; /* can be NULL */ +- } +- +- return value; +-} +- +-static void iShowUpdateVisible(Ihandle* ih) +-{ +- int inherit; +- /* although default is VISIBLE=YES,  +- when mapped the element is still hidden.  +- So we must manually update the visible state. */ +- char* value = iShowGetVisible(ih); +- iupClassObjectSetAttribute(ih, "VISIBLE", value, &inherit); +-} +- + int IupMap(Ihandle* ih) + { + iupASSERT(iupObjectCheck(ih)); +@@ -108,7 +79,7 @@ int IupMap(Ihandle* ih) + return IUP_ERROR; + } +  +- /* update FONT, must be the before several others */ ++ /* update FONT, must be the before several others, so we do it here */ + if (ih->iclass->nativetype != IUP_TYPEVOID && + ih->iclass->nativetype != IUP_TYPEIMAGE && + ih->iclass->nativetype != IUP_TYPEMENU) +@@ -117,18 +88,13 @@ int IupMap(Ihandle* ih) + /* ensure attributes default values, at this time only the ones that need to be set after map */ + iupClassObjectEnsureDefaultAttributes(ih); +  +- /* check visible state if not a dialog */ +- if (ih->iclass->nativetype == IUP_TYPECANVAS ||  +- ih->iclass->nativetype == IUP_TYPECONTROL) +- iShowUpdateVisible(ih); +- +- /* updates the defined attributes in the native system. */ ++ /* updates the defined attributes from the hash table to the native system. */ + iupAttribUpdate(ih);  +  +- /* updates attributes defined in the parent tree */ ++ /* updates inheritable attributes defined in the parent tree */ + iupAttribUpdateFromParent(ih); +  +- /* map children */ ++ /* map children independent from childtype */ + { + Ihandle* child = ih->firstchild; + while (child) +@@ -140,6 +106,10 @@ int IupMap(Ihandle* ih) + } + } +  ++ /* updates the defined attributes from the hash table to the native system. */ ++ if (ih->iclass->childtype!=IUP_CHILDNONE) ++ iupAttribUpdateChildren(ih); ++ + /* moves and resizes the elements to reflect the layout computation */ + /* if the dialog is visible will be reflected in the user interface */ + if (ih->iclass->nativetype == IUP_TYPEDIALOG) +diff --git a/iup/src/iup_spin.c b/iup/src/iup_spin.c +index 6fadab4..514703f 100755 +--- a/iup/src/iup_spin.c ++++ b/iup/src/iup_spin.c +@@ -175,7 +175,7 @@ static int iSpinCreateMethod(Ihandle* ih, void** params) +  + static int iSpinboxCreateMethod(Ihandle* ih, void** params) + { +- Ihandle *spin, *ctrl; ++ Ihandle *spin; +  + if (!params || !(params[0])) + return IUP_ERROR; +@@ -184,8 +184,7 @@ static int iSpinboxCreateMethod(Ihandle* ih, void** params) + IupSetAttribute(ih, "MARGIN", "0x0"); + IupSetAttribute(ih, "ALIGNMENT", "ACENTER"); +  +- ctrl = (Ihandle*)(params[0]); +- iupChildTreeAppend(ih, ctrl); ++ /* IupText is already a child of Spinbox because of the IupHbox Create method */ +  + spin = IupSpin(); + iupChildTreeAppend(ih, spin); +@@ -249,7 +248,7 @@ Iclass* iupSpinboxGetClass(void) + ic->name = "spinbox"; + ic->format = "h"; /* one Ihandle */ + ic->nativetype = IUP_TYPEVOID; +- ic->childtype = IUP_CHILDNONE; ++ ic->childtype = IUP_CHILD_ONE; /* fake value to define it as a container */ + ic->is_interactive = 0; +  + iupClassRegisterCallback(ic, "SPIN_CB", "i"); +@@ -267,7 +266,7 @@ Iclass* iupSpinGetClass(void) + ic->name = "spin"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPEVOID; +- ic->childtype = IUP_CHILDNONE; ++ ic->childtype = IUP_CHILD_ONE; /* fake value to define it as a container */ + ic->is_interactive = 0; +  + /* Class functions */ +diff --git a/iup/src/iup_stdcontrols.h b/iup/src/iup_stdcontrols.h +index 11499ae..0f3deb9 100755 +--- a/iup/src/iup_stdcontrols.h ++++ b/iup/src/iup_stdcontrols.h +@@ -46,6 +46,7 @@ Iclass* iupZboxGetClass(void); + Iclass* iupCboxGetClass(void); + Iclass* iupSboxGetClass(void); + Iclass* iupNormalizerGetClass(void); ++Iclass* iupSplitGetClass(void); +  + Iclass* iupTimerGetClass(void); + Iclass* iupImageGetClass(void); +diff --git a/iup/src/iup_str.c b/iup/src/iup_str.c +index 68976f1..5f5b85d 100755 +--- a/iup/src/iup_str.c ++++ b/iup/src/iup_str.c +@@ -147,8 +147,9 @@ char *iupStrCopyUntil(char **str, int c) + return NULL; +  + p_str=strchr(*str,c); +- if (!p_str) return NULL; +- ++ if (!p_str)  ++ return NULL; ++ else + { + int i; + int sl=(int)(p_str - (*str)); +@@ -160,10 +161,10 @@ char *iupStrCopyUntil(char **str, int c) + new_str[i] = (*str)[i]; +  + new_str[sl] = 0; +- } +  +- *str = p_str+1; +- return new_str; ++ *str = p_str+1; ++ return new_str; ++ } + } +  + char *iupStrCopyUntilNoCase(char **str, int c) +@@ -174,11 +175,12 @@ char *iupStrCopyUntilNoCase(char **str, int c) +  + p_str=strchr(*str,c); /* usually the lower case is enough */ + if (!p_str && isalpha(c))  +- { + p_str=strchr(*str, toupper(c)); /* but check also for upper case */ +- if (!p_str) return NULL; +- } +  ++ /* if both fail, then abort */ ++ if (!p_str)  ++ return NULL; ++ else + { + int i; + int sl=(int)(p_str - (*str)); +@@ -190,10 +192,10 @@ char *iupStrCopyUntilNoCase(char **str, int c) + new_str[i] = (*str)[i]; +  + new_str[sl] = 0; +- } +  +- *str = p_str+1; +- return new_str; ++ *str = p_str+1; ++ return new_str; ++ } + } +  + char *iupStrGetMemory(int size) +diff --git a/iup/src/iup_table.c b/iup/src/iup_table.c +index 9e97ff5..a873191 100755 +--- a/iup/src/iup_table.c ++++ b/iup/src/iup_table.c +@@ -19,12 +19,12 @@ + /* Adjust these parameters for optimal performance and memory usage */ + static const unsigned int itable_maxTableSizeIndex = 8; + static const unsigned int itable_hashTableSize[] = { 31, 101, 401, 1601, 4001, 8009, 16001, 32003, 64007 }; +-static const float itable_resizeLimit = 2; ++static const unsigned int itable_resizeLimit = 2; + static const unsigned int itable_itemGrow = 5; +  + /* Iteration context. + */ +-typedef struct ItableContext ++typedef struct _ItableContext + { + unsigned int entryIndex; /* index at the Itable::entries array */ + unsigned int itemIndex; /* index at the ItableEntry::items array */ +@@ -41,7 +41,7 @@ typedef struct ItableContext + * this is simply the pointer (in this case keyIndex + * and keyStr are equal). + */ +-typedef struct ItableKey ++typedef struct _ItableKey + { + unsigned long keyIndex; /* the secondary hash number */ + const char *keyStr; +@@ -52,11 +52,11 @@ ItableKey; + * Such an item is stored in the item list of + * an entry. + */ +-typedef struct ItableItem ++typedef struct _ItableItem + { + Itable_Types itemType; +- ItableKey key; +- void *value; ++ ItableKey key; ++ void* value; + } + ItableItem; +  +@@ -67,29 +67,28 @@ ItableItem; + * in nextItemIndex. + * size is the current size of the items array. + */ +-typedef struct ItableEntry ++typedef struct _ItableEntry + { + unsigned int nextItemIndex; +- unsigned int size; +- ItableItem *items; ++ unsigned int itemsSize; ++ ItableItem* items; + } + ItableEntry; +  +  + /* A hash table. +- * indexType is the type of the index. + * entries is an array of entries. Select an + * entry by its index. + * size is the number of entries in the hash table... + */ +-struct Itable ++struct _Itable + { +- unsigned int size; +- unsigned int numberOfEntries; +- unsigned int tableSizeIndex; /* index into itable_hashTableSize array */ +- Itable_IndexTypes indexType; +- ItableEntry *entries; +- ItableContext context; ++ unsigned int entriesSize; ++ unsigned int numberOfEntries; ++ unsigned int tableSizeIndex; /* index into itable_hashTableSize array */ ++ Itable_IndexTypes indexType; /* type of the index: string or pointer. */ ++ ItableEntry *entries; ++ ItableContext context; + }; +  +  +@@ -121,8 +120,7 @@ Itable *iupTableCreate(Itable_IndexTypes indexType) +  + Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSizeIndex) + { +- Itable *it = (Itable *)malloc(sizeof(struct Itable)); +- ++ Itable *it = (Itable *)malloc(sizeof(Itable)); + iupASSERT(it!=NULL); + if (!it) + return 0; +@@ -130,12 +128,12 @@ Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSiz + if (initialSizeIndex > itable_maxTableSizeIndex) + initialSizeIndex = itable_maxTableSizeIndex; +  +- it->size = itable_hashTableSize[initialSizeIndex]; ++ it->entriesSize = itable_hashTableSize[initialSizeIndex]; + it->tableSizeIndex = initialSizeIndex; + it->numberOfEntries = 0; + it->indexType = indexType; +  +- it->entries = (ItableEntry *)malloc(it->size * sizeof(ItableEntry)); ++ it->entries = (ItableEntry *)malloc(it->entriesSize * sizeof(ItableEntry)); + iupASSERT(it->entries!=NULL); + if (!it->entries) + { +@@ -143,7 +141,7 @@ Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSiz + return 0; + } +  +- memset(it->entries, 0, it->size * sizeof(ItableEntry)); ++ memset(it->entries, 0, it->entriesSize * sizeof(ItableEntry)); +  + it->context.entryIndex = (unsigned int)-1; + it->context.itemIndex = (unsigned int)-1; +@@ -158,16 +156,19 @@ void iupTableClear(Itable *it) + if (!it) + return; +  +- for (i = 0; i < it->size; i++) ++ for (i = 0; i < it->entriesSize; i++) + { + ItableEntry *entry = &(it->entries[i]); + if (entry->items) ++ { + iTableFreeItemArray(it->indexType, entry->nextItemIndex, entry->items); ++ entry->items = NULL; ++ } + } +  + it->numberOfEntries = 0; +  +- memset(it->entries, 0, it->size * sizeof(ItableEntry)); ++ memset(it->entries, 0, it->entriesSize * sizeof(ItableEntry)); +  + it->context.entryIndex = (unsigned int)-1; + it->context.itemIndex = (unsigned int)-1; +@@ -185,7 +186,10 @@ void iupTableDestroy(Itable *it) + iupTableClear(it); +  + if (it->entries) ++ { + free(it->entries); ++ it->entries = NULL; ++ } +  + free(it); + } +@@ -288,17 +292,23 @@ static void iTableRemoveItem(Itable *it, ItableEntry *entry, unsigned int itemIn + item = &(entry->items[itemIndex]); +  + if (it->indexType == IUPTABLE_STRINGINDEXED) ++ { + free((void *)item->key.keyStr); ++ item->key.keyStr = NULL; ++ } +  + if (item->itemType == IUPTABLE_STRING) ++ { + free(item->value); ++ item->value = NULL; ++ } +  +- /* order the remaining items */ ++ /* re-order the remaining items */ + for (i = itemIndex; i < entry->nextItemIndex-1; i++) + entry->items[i] = entry->items[i+1]; +  +- /* clear the non used item */ +- memset(entry->items + entry->nextItemIndex, 0, sizeof (ItableItem)); ++ /* clear the released item */ ++ memset(entry->items + entry->nextItemIndex-1, 0, sizeof (ItableItem)); +  + entry->nextItemIndex--; + it->numberOfEntries--; +@@ -398,7 +408,7 @@ char *iupTableFirst(Itable *it) + it->context.itemIndex = (unsigned int)-1; +  + /* find the first used entry */ +- for (entryIndex = 0; entryIndex < it->size; entryIndex++) ++ for (entryIndex = 0; entryIndex < it->entriesSize; entryIndex++) + { + if (it->entries[entryIndex].nextItemIndex > 0) + { +@@ -430,7 +440,7 @@ char *iupTableNext(Itable *it) + else + { + /* find the next used entry */ +- for (entryIndex = it->context.entryIndex+1; entryIndex < it->size; entryIndex++) ++ for (entryIndex = it->context.entryIndex+1; entryIndex < it->entriesSize; entryIndex++) + { + if (it->entries[entryIndex].nextItemIndex > 0) + { +@@ -471,7 +481,7 @@ char *iupTableRemoveCurr(Itable *it) + else + { + /* find the next used entry */ +- for (entryIndex = it->context.entryIndex+1; entryIndex < it->size; entryIndex++) ++ for (entryIndex = it->context.entryIndex+1; entryIndex < it->entriesSize; entryIndex++) + { + if (it->entries[entryIndex].nextItemIndex > 0) + { +@@ -498,6 +508,8 @@ static void iTableFreeItemArray(Itable_IndexTypes indexType, unsigned int nextFr + { + unsigned int i; +  ++ /* Used only in iupTableClear */ ++ + iupASSERT(items!=NULL); + if (!items) + return; +@@ -505,13 +517,19 @@ static void iTableFreeItemArray(Itable_IndexTypes indexType, unsigned int nextFr + if (indexType == IUPTABLE_STRINGINDEXED) + { + for (i = 0; i < nextFreeIndex; i++) ++ { + free((void *)(items[i].key.keyStr)); ++ items[i].key.keyStr = NULL; ++ } + } +  + for (i = 0; i < nextFreeIndex; i++) + { + if (items[i].itemType == IUPTABLE_STRING) ++ { + free(items[i].value); ++ items[i].value = NULL; ++ } + } +  + free(items); +@@ -545,7 +563,7 @@ static unsigned int iTableGetEntryIndex(Itable *it, const char *key, unsigned lo + *keyIndex = (unsigned long)key; /* this could NOT be dependent from table size */ + } +  +- return (unsigned int)((*keyIndex) % it->size); ++ return (unsigned int)((*keyIndex) % it->entriesSize); + } +  + #ifdef DEBUGTABLE +@@ -603,25 +621,24 @@ static unsigned int iTableFindItem(Itable *it, const char *key, ItableEntry **en +  + static void iTableUpdateArraySize(ItableEntry *entry) + { +- if (entry->nextItemIndex >= entry->size) ++ if (entry->nextItemIndex >= entry->itemsSize) + { + /* we have to expand the item array */ + unsigned int newSize; +  +- newSize = entry->size + itable_itemGrow; ++ newSize = entry->itemsSize + itable_itemGrow; +  + entry->items = (ItableItem *)realloc(entry->items, newSize * sizeof(ItableItem)); + iupASSERT(entry->items!=NULL); + if (!entry->items) + return; +  +- memset(entry->items + entry->size, 0, itable_itemGrow * sizeof(ItableItem)); ++ memset(entry->items + entry->itemsSize, 0, itable_itemGrow * sizeof(ItableItem)); +  +- entry->size = newSize; ++ entry->itemsSize = newSize; + } + } +  +- + static void iTableAdd(Itable *it, ItableKey *key, void *value, Itable_Types itemType) + { + unsigned int entryIndex; +@@ -657,7 +674,7 @@ static unsigned int iTableResize(Itable *it) + /* check if we do not need to resize the hash table */ + if (it->numberOfEntries == 0 || + it->tableSizeIndex >= itable_maxTableSizeIndex || +- it->size / it->numberOfEntries >= itable_resizeLimit) ++ it->entriesSize / it->numberOfEntries >= itable_resizeLimit) + return 0; +  + /* create a new hash table and copy the contents of +@@ -666,7 +683,7 @@ static unsigned int iTableResize(Itable *it) + newSizeIndex = it->tableSizeIndex + 1; + newTable = iupTableCreateSized(it->indexType, newSizeIndex); +  +- for (entryIndex = 0; entryIndex < it->size; entryIndex++) ++ for (entryIndex = 0; entryIndex < it->entriesSize; entryIndex++) + { + entry = &(it->entries[entryIndex]); +  +@@ -680,12 +697,13 @@ static unsigned int iTableResize(Itable *it) + }  +  + free(entry->items); ++ entry->items = NULL; + } + } +  + free(it->entries); +  +- it->size = newTable->size; ++ it->entriesSize = newTable->entriesSize; + it->tableSizeIndex = newTable->tableSizeIndex; + it->numberOfEntries = newTable->numberOfEntries; + it->entries = newTable->entries; +@@ -712,11 +730,11 @@ static void iTableShowStatistics(Itable *it) + return; + } +  +- nofSlots = it->size; ++ nofSlots = it->entriesSize; + nofKeys = it->numberOfEntries; + optimalNofKeysPerSlot = (double)nofKeys / (double)nofSlots; +  +- for (entryIndex = 0; entryIndex < it->size; entryIndex++) ++ for (entryIndex = 0; entryIndex < it->entriesSize; entryIndex++) + { + ItableEntry *entry = &(it->entries[entryIndex]); +  +diff --git a/iup/src/iup_table.h b/iup/src/iup_table.h +index 5222160..f2ff2c7 100755 +--- a/iup/src/iup_table.h ++++ b/iup/src/iup_table.h +@@ -42,8 +42,8 @@ typedef enum _Itable_Types +  + typedef void (*Ifunc)(void); +  +-struct Itable; +-typedef struct Itable Itable; ++struct _Itable; ++typedef struct _Itable Itable; +  +  + /** Creates a hash table with an initial default size. +@@ -63,7 +63,7 @@ Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSiz + /** Destroys the Itable. + * Calls \ref iupTableClear. + * \ingroup table */ +-void iupTableDestroy(Itable *n); ++void iupTableDestroy(Itable *it); +  + /** Removes all items in the table. + * This function does also free the memory of strings contained in the table!!!! +@@ -76,33 +76,33 @@ int iupTableCount(Itable *it); +  + /** Store an element in the table. + * \ingroup table */ +-void iupTableSet(Itable *n, const char *key, void *value, Itable_Types itemType); ++void iupTableSet(Itable *it, const char *key, void *value, Itable_Types itemType); +  + /** Store a function pointer in the table. + * Type is set to IUPTABLE_FUNCPOINTER. + * \ingroup table */ +-void iupTableSetFunc(Itable *n, const char *key, Ifunc func); ++void iupTableSetFunc(Itable *it, const char *key, Ifunc func); +  + /** Retrieves an element from the table. + * Returns NULL if not found. + * \ingroup table */ +-void *iupTableGet(Itable *n, const char *key); ++void *iupTableGet(Itable *it, const char *key); +  + /** Retrieves a function pointer from the table.  + * If not a function or not found returns NULL. + * value always contains the element pointer. + * \ingroup table */ +-Ifunc iupTableGetFunc(Itable *n, const char *key, void **value); ++Ifunc iupTableGetFunc(Itable *it, const char *key, void **value); +  + /** Retrieves an element from the table and its type. + * \ingroup table */ +-void *iupTableGetTyped(Itable *n, const char *key, Itable_Types *itemType); ++void *iupTableGetTyped(Itable *it, const char *key, Itable_Types *itemType); +  + /** Removes the entry at the specified key from the + * hash table and frees the memory used by it if + * it is a string... + * \ingroup table */ +-void iupTableRemove(Itable *n, const char *key); ++void iupTableRemove(Itable *it, const char *key); +  + /** Key iteration function. Returns a key. + * To iterate over all keys call iupTableFirst at the first +diff --git a/iup/src/iup_tabs.c b/iup/src/iup_tabs.c +index 77b2cf5..2907371 100755 +--- a/iup/src/iup_tabs.c ++++ b/iup/src/iup_tabs.c +@@ -307,6 +307,25 @@ static char* iTabsGetClientSizeAttrib(Ihandle* ih) + return str; + } +  ++void iupTabsTestRemoveTab(Ihandle* ih, int pos) ++{ ++ int cur_pos = iupdrvTabsGetCurrentTab(ih); ++ if (cur_pos == pos) ++ { ++ if (cur_pos == 0) ++ { ++ Ihandle* child = IupGetChild(ih, 1); ++ if (!child) /* not found child, means only one child, do nothing */ ++ return; ++ ++ cur_pos = 1; ++ } ++ else ++ cur_pos--; ++ ++ iupdrvTabsSetCurrentTab(ih, cur_pos); ++ } ++} +  + /* ------------------------------------------------------------------------- */ + /* TABS - Methods */ +diff --git a/iup/src/iup_tabs.h b/iup/src/iup_tabs.h +index 7f5df2e..fd0edf4 100755 +--- a/iup/src/iup_tabs.h ++++ b/iup/src/iup_tabs.h +@@ -16,6 +16,7 @@ char* iupTabsGetTabOrientationAttrib(Ihandle* ih); + char* iupTabsGetTabTypeAttrib(Ihandle* ih); + char* iupTabsAttribGetStrId(Ihandle* ih, const char* name, int pos); + char* iupTabsGetPaddingAttrib(Ihandle* ih); ++void iupTabsTestRemoveTab(Ihandle* ih, int pos); +  + int iupdrvTabsExtraDecor(Ihandle* ih); + int iupdrvTabsGetLineCountAttrib(Ihandle* ih); +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; + } +diff --git a/iup/src/iup_tree.h b/iup/src/iup_tree.h +index f96a698..44acc83 100755 +--- a/iup/src/iup_tree.h ++++ b/iup/src/iup_tree.h +@@ -29,6 +29,36 @@ void iupdrvTreeUpdateMarkMode(Ihandle *ih); +  + char* iupTreeGetSpacingAttrib(Ihandle* ih); +  ++#if defined(GTK_MAJOR_VERSION) ++typedef void InodeHandle; ++#elif defined(XmVERSION) ++typedef struct _WidgetRec InodeHandle; ++#elif defined(WINVER) ++typedef struct _TREEITEM InodeHandle; ++#else ++typedef struct _InodeData InodeHandle; ++#endif ++ ++typedef struct _InodeData ++{ ++ InodeHandle* node_handle; ++ void* userdata; ++} InodeData; ++ ++typedef int (*iupTreeNodeFunc)(Ihandle* ih, InodeHandle* node_handle, int id, void* userdata); ++int iupTreeForEach(Ihandle* ih, iupTreeNodeFunc func, void* userdata); ++InodeHandle* iupTreeGetNode(Ihandle* ih, int id); ++InodeHandle* iupTreeGetNodeFromString(Ihandle* ih, const char* name_id); ++int iupTreeFindNodeId(Ihandle* ih, InodeHandle* node_handle); ++ ++InodeHandle* iupdrvTreeGetFocusNode(Ihandle* ih); ++int iupdrvTreeTotalChildCount(Ihandle* ih, InodeHandle* node_handle); ++void iupTreeSelectLastCollapsedBranch(Ihandle* ih, int *last_id); ++ ++void iupTreeDelFromCache(Ihandle* ih, int id, int count); ++void iupTreeAddToCache(Ihandle* ih, int add, int kindPrev, InodeHandle* prevNode, InodeHandle* node_handle); ++void iupTreeCopyMoveCache(Ihandle* ih, int id_src, int id_dst, int count, int is_copy); ++ + /* Structure of the tree */ + struct _IcontrolData + { +@@ -36,6 +66,7 @@ struct _IcontrolData + add_expanded, + show_dragdrop, + show_rename, ++ stamp, /* GTK only */ + spacing; +  + void* def_image_leaf; /* Default image leaf */ +@@ -44,9 +75,10 @@ struct _IcontrolData +  + void* def_image_leaf_mask; /* Motif Only */ + void* def_image_collapsed_mask;  +- void* def_image_expanded_mask;  ++ void* def_image_expanded_mask;  +  +- int id_control; /* auxiliary variable for computing or finding the id of a node */ ++ InodeData *node_cache; ++ int node_cache_max, node_count; + }; +  +  +diff --git a/iup/src/iup_vbox.c b/iup/src/iup_vbox.c +index f71aa51..23e8e3a 100755 +--- a/iup/src/iup_vbox.c ++++ b/iup/src/iup_vbox.c +@@ -215,6 +215,13 @@ static void iVboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) + else + { + int empty = (child->expand & IUP_EXPAND_H1)? empty_h1: ((child->expand & IUP_EXPAND_H0)? empty_h0: 0); ++ char* weigth_str = iupAttribGet(child, "EXPANDWEIGTH"); ++ if (weigth_str) ++ { ++ float weigth;  ++ if (iupStrToFloat(weigth_str, &weigth)) ++ empty = iupROUND(empty * weigth); ++ } + iupBaseSetCurrentSize(child, client_width, child->naturalheight+empty, shrink); + } +  +diff --git a/iup/src/iup_zbox.c b/iup/src/iup_zbox.c +index 3f79892..dd4a0e4 100755 +--- a/iup/src/iup_zbox.c ++++ b/iup/src/iup_zbox.c +@@ -210,7 +210,7 @@ static int iZboxSetVisibleAttrib(Ihandle* ih, const char* value) + { + if (iupObjectCheck(ih->data->value_handle)) + IupSetAttribute(ih->data->value_handle, "VISIBLE", (char*)value); +- return 0; ++ return 1; /* must be 1 to mark when set at the element */ + } +  + static void iZboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +@@ -368,8 +368,8 @@ Iclass* iupZboxGetClass(void) + iupClassRegisterAttribute(ic, "VALUEPOS", iZboxGetValuePosAttrib, iZboxSetValuePosAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE_HANDLE", NULL, iZboxSetValueHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); +  +- /* Intercept VISIBLE since ZBOX works showing and hidding its children */ +- iupClassRegisterAttribute(ic, "VISIBLE", NULL, iZboxSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); ++ /* Intercept VISIBLE since ZBOX works by showing and hidding its children */ ++ iupClassRegisterAttribute(ic, "VISIBLE", NULL, iZboxSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED); +  + return ic; + } +diff --git a/iup/src/make_uname b/iup/src/make_uname +index 7fec9f8..6542234 100755 +--- a/iup/src/make_uname ++++ b/iup/src/make_uname +@@ -1,4 +1,4 @@ + #This builds all the libraries of the folder for 1 uname +  +-tecmake $1 $2 $3 $4 $5 $6 $7 ++tecmake USE_MOTIF=Yes $1 $2 $3 $4 $5 $6 $7 + tecmake USE_GTK=Yes $1 $2 $3 $4 $5 $6 $7 +diff --git a/iup/src/mot/iupmot_button.c b/iup/src/mot/iupmot_button.c +index 2d93588..f6e383f 100755 +--- a/iup/src/mot/iupmot_button.c ++++ b/iup/src/mot/iupmot_button.c +@@ -112,8 +112,10 @@ static int motButtonSetPaddingAttrib(Ihandle* ih, const char* value) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); ++ return 0; + } +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int motButtonSetBgColorAttrib(Ihandle* ih, const char* value) +@@ -189,43 +191,43 @@ static int motButtonMapMethod(Ihandle* ih) + if (value) + { + ih->data->type = IUP_BUTTON_IMAGE; +- iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP); ++ iupMOT_SETARG(args, num_args, XmNlabelType, XmPIXMAP); + } + else + { + ih->data->type = IUP_BUTTON_TEXT; +- iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); ++ iupMOT_SETARG(args, num_args, XmNlabelType, XmSTRING); + } +  + /* Core */ +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Label */ +- iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ +- iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); +- iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ +- iupmotSetArg(args, num_args, XmNmarginLeft, 0); +- iupmotSetArg(args, num_args, XmNmarginBottom, 0); +- iupmotSetArg(args, num_args, XmNmarginRight, 0); ++ iupMOT_SETARG(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginTop, 0); /* no extra margins */ ++ iupMOT_SETARG(args, num_args, XmNmarginLeft, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginBottom, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginRight, 0); + /* PushButton */ +- iupmotSetArg(args, num_args, XmNfillOnArm, False); ++ iupMOT_SETARG(args, num_args, XmNfillOnArm, False); +  + /* Primitive */ + if (iupAttribGetBoolean(ih, "FOCUSONCLICK")) + { + if (iupAttribGetBoolean(ih, "CANFOCUS")) +- iupmotSetArg(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); + else +- iupmotSetArg(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); + } + else +- iupmotSetArg(args, num_args, XmNtraversalOn, False); +- iupmotSetArg(args, num_args, XmNhighlightThickness, 2); +- iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); +  + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ +diff --git a/iup/src/mot/iupmot_canvas.c b/iup/src/mot/iupmot_canvas.c +index 7777cf3..299bbcd 100755 +--- a/iup/src/mot/iupmot_canvas.c ++++ b/iup/src/mot/iupmot_canvas.c +@@ -434,6 +434,10 @@ static void motCanvasLayoutUpdateMethod(Ihandle *ih) +  + XtVaGetValues(sb_win, XmNborderWidth, &border, NULL); +  ++ /* avoid abort in X */ ++ if (ih->currentwidth <= 2*border) ih->currentwidth = 2*border+1; ++ if (ih->currentheight <= 2*border) ih->currentheight = 2*border+1; ++ + XtVaSetValues(sb_win, + XmNx, (XtArgVal)ih->x, + XmNy, (XtArgVal)ih->y, +@@ -458,19 +462,19 @@ static int motCanvasMapMethod(Ihandle* ih) + /* Create the scrolled window */ + /******************************/ +  +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); +- iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); +- iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and draw area */ +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); ++ iupMOT_SETARG(args, num_args, XmNvisualPolicy, XmVARIABLE); ++ iupMOT_SETARG(args, num_args, XmNspacing, 0); /* no space between scrollbars and draw area */ ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); +  + if (iupAttribGetBoolean(ih, "BORDER")) + { +- iupmotSetArg(args, num_args, XmNborderWidth, 1); +- iupmotSetArg(args, num_args, XmNborderColor, iupmotColorGetPixelStr("0 0 0")); ++ iupMOT_SETARG(args, num_args, XmNborderWidth, 1); ++ iupMOT_SETARG(args, num_args, XmNborderColor, iupmotColorGetPixelStr("0 0 0")); + } + else +- iupmotSetArg(args, num_args, XmNborderWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNborderWidth, 0); +  + sb_win = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ +@@ -488,36 +492,36 @@ static int motCanvasMapMethod(Ihandle* ih) + /****************************/ +  + num_args = 0; +- iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); +- iupmotSetArg(args, num_args, XmNresizePolicy, XmRESIZE_NONE); /* no automatic resize of children */ ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNresizePolicy, XmRESIZE_NONE); /* no automatic resize of children */ + if (ih->iclass->is_interactive) + { +- iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); /* include in navigation */ ++ iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); /* include in navigation */ +  + if (iupAttribGetBoolean(ih, "CANFOCUS")) +- iupmotSetArg(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); + else +- iupmotSetArg(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); + } + else + { +- iupmotSetArg(args, num_args, XmNnavigationType, XmNONE); +- iupmotSetArg(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNnavigationType, XmNONE); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); + } +  +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ +  + visual = IupGetAttribute(ih, "VISUAL"); /* defined by the OpenGL Canvas or NULL */ + if (visual) + { + Colormap colormap = (Colormap)iupAttribGet(ih, "COLORMAP"); + if (colormap) +- iupmotSetArg(args, num_args, XmNcolormap,colormap); ++ iupMOT_SETARG(args, num_args, XmNcolormap,colormap); +  + iupmotDialogSetVisual(ih, visual); + } +diff --git a/iup/src/mot/iupmot_common.c b/iup/src/mot/iupmot_common.c +index 7b3f8b7..286e075 100755 +--- a/iup/src/mot/iupmot_common.c ++++ b/iup/src/mot/iupmot_common.c +@@ -167,6 +167,10 @@ void iupdrvBaseLayoutUpdateMethod(Ihandle *ih) + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; +  ++ /* avoid abort in X */ ++ if (ih->currentwidth == 0) ih->currentwidth = 1; ++ if (ih->currentheight == 0) ih->currentheight = 1; ++ + XtVaSetValues(widget, + XmNx, (XtArgVal)ih->x, + XmNy, (XtArgVal)ih->y, +@@ -184,7 +188,7 @@ void iupdrvBaseUnMapMethod(Ihandle* ih) + XtDestroyWidget(widget); /* To match the call to XtCreateManagedWidget */ + } +  +-void iupdrvDisplayUpdate(Ihandle *ih) ++void iupdrvPostRedraw(Ihandle *ih) + { + XExposeEvent evt; + Dimension w, h; +@@ -209,12 +213,12 @@ void iupdrvDisplayUpdate(Ihandle *ih) + XSendEvent(iupmot_display, XtWindow(ih->handle), False, ExposureMask, (XEvent*)&evt); + } +  +-void iupdrvDisplayRedraw(Ihandle *ih) ++void iupdrvRedrawNow(Ihandle *ih) + { + Widget w; +  + /* POST a Redraw */ +- iupdrvDisplayUpdate(ih); ++ iupdrvPostRedraw(ih); +  + /* if this element has an inner native parent (like IupTabs),  + then redraw that native parent if different from the element. */ +@@ -223,7 +227,7 @@ void iupdrvDisplayRedraw(Ihandle *ih) + { + Widget handle = ih->handle; + ih->handle = w; +- iupdrvDisplayUpdate(ih); ++ iupdrvPostRedraw(ih); + ih->handle = handle; + } +  +@@ -276,10 +280,11 @@ int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value) + { + if (iupdrvIsVisible(ih)) + { ++ Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (iupStrEqualNoCase(value, "TOP")) +- XRaiseWindow(iupmot_display, XtWindow(ih->handle)); ++ XRaiseWindow(iupmot_display, XtWindow(widget)); + else +- XLowerWindow(iupmot_display, XtWindow(ih->handle)); ++ XLowerWindow(iupmot_display, XtWindow(widget)); + } +  + return 0; +@@ -455,9 +460,11 @@ static Cursor motGetCursor(Ihandle* ih, const char* name) + { "RESIZE_N", XC_top_side}, + { "RESIZE_S", XC_bottom_side}, + { "RESIZE_NS", XC_sb_v_double_arrow}, ++ { "SPLITTER_HORIZ", XC_sb_v_double_arrow}, + { "RESIZE_W", XC_left_side}, + { "RESIZE_E", XC_right_side}, + { "RESIZE_WE", XC_sb_h_double_arrow}, ++ { "SPLITTER_VERT", XC_sb_h_double_arrow}, + { "RESIZE_NE", XC_top_right_corner}, + { "RESIZE_SE", XC_bottom_right_corner}, + { "RESIZE_NW", XC_top_left_corner}, +diff --git a/iup/src/mot/iupmot_dialog.c b/iup/src/mot/iupmot_dialog.c +index 4eeb834..7a27d74 100755 +--- a/iup/src/mot/iupmot_dialog.c ++++ b/iup/src/mot/iupmot_dialog.c +@@ -134,12 +134,13 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu + static int native_border = 0; + static int native_caption = 0; +  +- int has_caption = iupAttribGetBoolean(ih, "MAXBOX") || +- iupAttribGetBoolean(ih, "MINBOX") || +- iupAttribGetBoolean(ih, "MENUBOX") ||  +- IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ ++ int has_titlebar = iupAttribGetBoolean(ih, "RESIZE") || /* GTK and Motif only */ ++ iupAttribGetBoolean(ih, "MAXBOX") || ++ iupAttribGetBoolean(ih, "MINBOX") || ++ iupAttribGetBoolean(ih, "MENUBOX") ||  ++ IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ +  +- int has_border = has_caption || ++ int has_border = has_titlebar || + iupAttribGetBoolean(ih, "RESIZE") || + iupAttribGetBoolean(ih, "BORDER"); +  +@@ -155,7 +156,7 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu + *border = win_border; +  + *caption = 0; +- if (has_caption) ++ if (has_titlebar) + *caption = win_caption; +  + if (!native_border && *border) +@@ -181,7 +182,7 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu + } +  + *caption = 0; +- if (has_caption) ++ if (has_titlebar) + { + if (native_caption) + *caption = native_caption; +@@ -853,6 +854,7 @@ static int motDialogMapMethod(Ihandle* ih) + InativeHandle* parent; + int mwm_decor = 0; + int num_args = 0; ++ int has_titlebar = 0; + Arg args[20]; +  + if (iupAttribGetBoolean(ih, "DIALOGFRAME"))  +@@ -867,32 +869,46 @@ static int motDialogMapMethod(Ihandle* ih) + /****************************/ +  + if (iupAttribGet(ih, "TITLE")) +- mwm_decor |= MWM_DECOR_TITLE; ++ has_titlebar = 1; + if (iupAttribGetBoolean(ih, "MENUBOX")) +- mwm_decor |= MWM_DECOR_MENU; ++ { ++ mwm_decor |= MWM_DECOR_MENU; ++ has_titlebar = 1; ++ } + if (iupAttribGetBoolean(ih, "MINBOX")) +- mwm_decor |= MWM_DECOR_MINIMIZE; ++ { ++ mwm_decor |= MWM_DECOR_MINIMIZE; ++ has_titlebar = 1; ++ } + if (iupAttribGetBoolean(ih, "MAXBOX")) +- mwm_decor |= MWM_DECOR_MAXIMIZE; ++ { ++ mwm_decor |= MWM_DECOR_MAXIMIZE; ++ has_titlebar = 1; ++ } + if (iupAttribGetBoolean(ih, "RESIZE")) +- mwm_decor |= MWM_DECOR_RESIZEH; +- if (iupAttribGetBoolean(ih, "BORDER")) +- mwm_decor |= MWM_DECOR_BORDER; +- +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* so XtRealizeWidget will not show the dialog */ +- iupmotSetArg(args, num_args, XmNdeleteResponse, XmDO_NOTHING); +- iupmotSetArg(args, num_args, XmNallowShellResize, True); /* Used so the BulletinBoard can control the shell size */ +- iupmotSetArg(args, num_args, XmNtitle, ""); +- iupmotSetArg(args, num_args, XmNvisual, iupmot_visual); ++ { ++ mwm_decor |= MWM_DECOR_RESIZEH; ++ mwm_decor |= MWM_DECOR_BORDER; /* has_border */ ++ } ++ if (has_titlebar) ++ mwm_decor |= MWM_DECOR_TITLE; ++ if (iupAttribGetBoolean(ih, "BORDER") || has_titlebar)  ++ mwm_decor |= MWM_DECOR_BORDER; /* has_border */ ++ ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* so XtRealizeWidget will not show the dialog */ ++ iupMOT_SETARG(args, num_args, XmNdeleteResponse, XmDO_NOTHING); ++ iupMOT_SETARG(args, num_args, XmNallowShellResize, True); /* Used so the BulletinBoard can control the shell size */ ++ iupMOT_SETARG(args, num_args, XmNtitle, ""); ++ iupMOT_SETARG(args, num_args, XmNvisual, iupmot_visual); +  + if (iupmotColorMap())  +- iupmotSetArg(args, num_args, XmNcolormap, iupmotColorMap()); ++ iupMOT_SETARG(args, num_args, XmNcolormap, iupmotColorMap()); +  + if (mwm_decor != 0x7E)  +- iupmotSetArg(args, num_args, XmNmwmDecorations, mwm_decor); ++ iupMOT_SETARG(args, num_args, XmNmwmDecorations, mwm_decor); +  + if (iupAttribGetBoolean(ih, "SAVEUNDER")) +- iupmotSetArg(args, num_args, XmNsaveUnder, True); ++ iupMOT_SETARG(args, num_args, XmNsaveUnder, True); +  + parent = iupDialogGetNativeParent(ih); + if (parent) +diff --git a/iup/src/mot/iupmot_drv.h b/iup/src/mot/iupmot_drv.h +index 8a536ef..424ae9f 100755 +--- a/iup/src/mot/iupmot_drv.h ++++ b/iup/src/mot/iupmot_drv.h +@@ -65,7 +65,7 @@ void iupmotGetWindowSize(Ihandle *ih, int *width, int *height); +  + char* iupmotGetXWindowAttrib(Ihandle *ih); +  +-#define iupmotSetArg(_a, _i, _n, _d) ((_a)[(_i)].name = (_n), (_a)[(_i)].value = (XtArgVal)(_d), (_i)++) ++#define iupMOT_SETARG(_a, _i, _n, _d) ((_a)[(_i)].name = (_n), (_a)[(_i)].value = (XtArgVal)(_d), (_i)++) +  +  + #ifdef __cplusplus +diff --git a/iup/src/mot/iupmot_filedlg.c b/iup/src/mot/iupmot_filedlg.c +index 768dd2b..0be6319 100755 +--- a/iup/src/mot/iupmot_filedlg.c ++++ b/iup/src/mot/iupmot_filedlg.c +@@ -17,6 +17,7 @@ + #include  + #include  + #include  ++#include  +  + #include "iup.h" + #include "iupcbs.h" +@@ -28,6 +29,7 @@ + #include "iup_dialog.h" + #include "iup_strmessage.h" + #include "iup_drvinfo.h" ++#include "iup_array.h" +  + #include "iupmot_drv.h" +  +@@ -87,14 +89,14 @@ static int motFileDlgCheckValue(Ihandle* ih, Widget w) + return 0; + } + } +- else ++ else if (!iupAttribGetBoolean(ih, "MULTIPLEFILES")) + { + if (iupdrvIsDirectory(value)) /* selected a directory */ + { + iupStrMessageShowError(ih, "IUP_INVALIDDIR"); + return 0; + } +- else if (!iupdrvIsFile(value)) /* new file */ ++ else if (!iupdrvIsFile(value)) /* not a file == new file */ + { + value = iupAttribGet(ih, "ALLOWNEW"); + if (!value) +@@ -132,6 +134,51 @@ static void motFileDlgCBclose(Widget w, XtPointer client_data, XtPointer call_da + iupAttribSetStr(ih, "_IUP_WM_DELETE", "1"); + } +  ++static int motFileDlgGetMultipleFiles(Ihandle* ih, const char* dir, Widget wList) ++{ ++ int *pos, sel_count, dir_len; ++ int i, len, cur_len; ++ char *filename, *all_names; ++ Iarray* names_array; ++ XmString* items; ++ ++ if (!XmListGetSelectedPos(wList, &pos, &sel_count)) ++ return 0; ++ ++ names_array = iupArrayCreate(1024, 1); /* just set an initial size, but count is 0 */ ++ XtVaGetValues(wList, XmNitems, &items, NULL); ++ ++ cur_len = strlen(dir); ++ ++ all_names = iupArrayAdd(names_array, cur_len+1); ++ memcpy(all_names, dir, cur_len); ++ all_names[cur_len] = '|'; ++ dir_len = cur_len; ++ cur_len++; /* skip separator */ ++ ++ for (i = 0; iitem, XmSTRING_DEFAULT_CHARSET, &filename); +  ++ cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (iupdrvIsFile(filename)) +- { +- IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + cb(ih, filename, "SELECT"); +- } ++ else ++ cb(ih, filename, "OTHER"); +  + XtFree(filename); + (void)w; +@@ -417,6 +488,13 @@ static int motFileDlgPopup(Ihandle* ih, int x, int y) + if (dialogtype == IUP_DIALOGDIR) + XtVaSetValues(filebox, XmNfileTypeMask, XmFILE_DIRECTORY, NULL); +  ++ if (iupAttribGetBoolean(ih, "MULTIPLEFILES")) ++ { ++ Widget wList = XmFileSelectionBoxGetChild(filebox, XmDIALOG_LIST); ++ XtVaSetValues(wList, XmNselectionPolicy, XmEXTENDED_SELECT, NULL); ++ XtAddCallback(wList, XmNextendedSelectionCallback, (XtCallbackProc)motFileDlgBrowseSelectionCallback, (XtPointer)ih); ++ } ++ + /* just check for the path inside FILE */ + value = iupAttribGet(ih, "FILE"); + if (value && value[0] == '/') +@@ -501,8 +579,10 @@ static int motFileDlgPopup(Ihandle* ih, int x, int y) + file_cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (file_cb) + { +- Widget file_list = XmFileSelectionBoxGetChild(filebox, XmDIALOG_LIST); +- XtAddCallback(file_list, XmNbrowseSelectionCallback, (XtCallbackProc)motFileDlgBrowseSelectionCallback, (XtPointer)ih); ++ Widget list = XmFileSelectionBoxGetChild(filebox, XmDIALOG_LIST); ++ XtAddCallback(list, XmNbrowseSelectionCallback, (XtCallbackProc)motFileDlgBrowseSelectionCallback, (XtPointer)ih); ++ list = XmFileSelectionBoxGetChild(filebox, XmDIALOG_DIR_LIST); ++ XtAddCallback(list, XmNbrowseSelectionCallback, (XtCallbackProc)motFileDlgBrowseSelectionCallback, (XtPointer)ih); +  + if (iupAttribGetBoolean(ih, "SHOWPREVIEW")) + { +@@ -575,4 +655,6 @@ static int motFileDlgPopup(Ihandle* ih, int x, int y) + void iupdrvFileDlgInitClass(Iclass* ic) + { + ic->DlgPopup = motFileDlgPopup; ++ ++ iupClassRegisterAttribute(ic, "MULTIPLEFILES", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + } +diff --git a/iup/src/mot/iupmot_font.c b/iup/src/mot/iupmot_font.c +index 8da06dd..42154b6 100755 +--- a/iup/src/mot/iupmot_font.c ++++ b/iup/src/mot/iupmot_font.c +@@ -135,19 +135,19 @@ static XmFontList motFontCreateRenderTable(XFontStruct* fontstruct, int is_under + Arg args[10]; + int num_args = 0; +  +- iupmotSetArg(args, num_args, XmNfontType, XmFONT_IS_FONT); +- iupmotSetArg(args, num_args, XmNfont, (XtPointer)fontstruct); +- iupmotSetArg(args, num_args, XmNloadModel, XmLOAD_IMMEDIATE); ++ iupMOT_SETARG(args, num_args, XmNfontType, XmFONT_IS_FONT); ++ iupMOT_SETARG(args, num_args, XmNfont, (XtPointer)fontstruct); ++ iupMOT_SETARG(args, num_args, XmNloadModel, XmLOAD_IMMEDIATE); +  + if (is_underline) +- iupmotSetArg(args, num_args, XmNunderlineType, XmSINGLE_LINE); ++ iupMOT_SETARG(args, num_args, XmNunderlineType, XmSINGLE_LINE); + else +- iupmotSetArg(args, num_args, XmNunderlineType, XmNO_LINE); ++ iupMOT_SETARG(args, num_args, XmNunderlineType, XmNO_LINE); +  + if (is_strikeout) +- iupmotSetArg(args, num_args, XmNstrikethruType, XmSINGLE_LINE); ++ iupMOT_SETARG(args, num_args, XmNstrikethruType, XmSINGLE_LINE); + else +- iupmotSetArg(args, num_args, XmNstrikethruType, XmNO_LINE); ++ iupMOT_SETARG(args, num_args, XmNstrikethruType, XmNO_LINE); +  + rendition = XmRenditionCreate(NULL, "", args, num_args); +  +diff --git a/iup/src/mot/iupmot_frame.c b/iup/src/mot/iupmot_frame.c +index 39de5d8..cfda44f 100755 +--- a/iup/src/mot/iupmot_frame.c ++++ b/iup/src/mot/iupmot_frame.c +@@ -42,22 +42,33 @@ static int motFrameSetBgColorAttrib(Ihandle* ih, const char* value) + { + Pixel color; +  +- /* ignore given value, must use only from parent */ +- value = iupBaseNativeParentGetBgColor(ih); ++ if (!iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) ++ { ++ /* ignore given value, must use only from parent */ ++ value = iupBaseNativeParentGetBgColor(ih); ++ } +  + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget title_label, child_manager; +  +- iupmotSetBgColor(ih->handle, color); ++ if (!iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) ++ { ++ iupmotSetBgColor(ih->handle, color); +  +- child_manager = XtNameToWidget(ih->handle, "*child_manager"); +- iupmotSetBgColor(child_manager, color); ++ child_manager = XtNameToWidget(ih->handle, "*child_manager"); ++ iupmotSetBgColor(child_manager, color); +  +- title_label = XtNameToWidget(ih->handle, "*title_label"); +- if (!title_label) return 1; +- iupmotSetBgColor(title_label, color); ++ title_label = XtNameToWidget(ih->handle, "*title_label"); ++ if (!title_label) return 1; ++ iupmotSetBgColor(title_label, color); ++ } ++ else ++ { ++ child_manager = XtNameToWidget(ih->handle, "*child_manager"); ++ iupmotSetBgColor(child_manager, color); ++ } +  + return 1; + } +@@ -171,22 +182,25 @@ static int motFrameMapMethod(Ihandle* ih) + { + char* value = iupAttribGetStr(ih, "SUNKEN"); + if (iupStrBoolean(value)) +- iupmotSetArg(args, num_args, XmNshadowType, XmSHADOW_IN);  ++ iupMOT_SETARG(args, num_args, XmNshadowType, XmSHADOW_IN);  + else +- iupmotSetArg(args, num_args, XmNshadowType, XmSHADOW_ETCHED_IN);  ++ iupMOT_SETARG(args, num_args, XmNshadowType, XmSHADOW_ETCHED_IN);  ++ ++ if (iupAttribGet(ih, "BGCOLOR")) ++ iupAttribSetStr(ih, "_IUPFRAME_HAS_BGCOLOR", "1"); + } +  + /* Core */ +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Manager */ +- iupmotSetArg(args, num_args, XmNshadowThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); + /* Frame */ +- iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ +  + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ +@@ -204,11 +218,11 @@ static int motFrameMapMethod(Ihandle* ih) + Widget title_label; + num_args = 0; + /* Label */ +- iupmotSetArg(args, num_args, XmNlabelType, XmSTRING);  +- iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNlabelType, XmSTRING);  ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); + /* Frame Constraint */ +- iupmotSetArg(args, num_args, XmNchildType, XmFRAME_TITLE_CHILD); ++ iupMOT_SETARG(args, num_args, XmNchildType, XmFRAME_TITLE_CHILD); + title_label = XtCreateManagedWidget("title_label", xmLabelWidgetClass, ih->handle, args, num_args); + iupmotSetString(title_label, XmNlabelString, title); + } +diff --git a/iup/src/mot/iupmot_key.c b/iup/src/mot/iupmot_key.c +index 835b5d7..9897741 100755 +--- a/iup/src/mot/iupmot_key.c ++++ b/iup/src/mot/iupmot_key.c +@@ -393,33 +393,33 @@ void iupmotKeyPressEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) + void iupmotButtonKeySetStatus(unsigned int state, unsigned int but, char* status, int doubleclick) + { + if (state & ShiftMask) +- iupKEYSETSHIFT(status); ++ iupKEY_SETSHIFT(status); +  + if (state & ControlMask) +- iupKEYSETCONTROL(status);  ++ iupKEY_SETCONTROL(status);  +  + if ((state & Button1Mask) || but==Button1) +- iupKEYSETBUTTON1(status); ++ iupKEY_SETBUTTON1(status); +  + if ((state & Button2Mask) || but==Button2) +- iupKEYSETBUTTON2(status); ++ iupKEY_SETBUTTON2(status); +  + if ((state & Button3Mask) || but==Button3) +- iupKEYSETBUTTON3(status); ++ iupKEY_SETBUTTON3(status); +  + if ((state & Button4Mask) || but==Button4) +- iupKEYSETBUTTON4(status); ++ iupKEY_SETBUTTON4(status); +  + if ((state & Button5Mask) || but==Button5) +- iupKEYSETBUTTON5(status); ++ iupKEY_SETBUTTON5(status); +  + if (state & Mod1Mask || state & Mod5Mask) /* Alt */ +- iupKEYSETALT(status); ++ iupKEY_SETALT(status); +  + if (state & Mod4Mask) /* Apple/Win */ +- iupKEYSETSYS(status); ++ iupKEY_SETSYS(status); +  + if (doubleclick) +- iupKEYSETDOUBLE(status); ++ iupKEY_SETDOUBLE(status); + } +  +diff --git a/iup/src/mot/iupmot_label.c b/iup/src/mot/iupmot_label.c +index 52dfc9a..afff3c3 100755 +--- a/iup/src/mot/iupmot_label.c ++++ b/iup/src/mot/iupmot_label.c +@@ -147,8 +147,10 @@ static int motLabelSetPaddingAttrib(Ihandle* ih, const char* value) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); ++ return 0; + } +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int motLabelMapMethod(Ihandle* ih) +@@ -165,12 +167,12 @@ static int motLabelMapMethod(Ihandle* ih) + if (iupStrEqualNoCase(value, "HORIZONTAL")) + { + ih->data->type = IUP_LABEL_SEP_HORIZ; +- iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); ++ iupMOT_SETARG(args, num_args, XmNorientation, XmHORIZONTAL); + } + else /* "VERTICAL" */ + { + ih->data->type = IUP_LABEL_SEP_VERT; +- iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); ++ iupMOT_SETARG(args, num_args, XmNorientation, XmVERTICAL); + } + } + else +@@ -180,32 +182,32 @@ static int motLabelMapMethod(Ihandle* ih) + if (value) + { + ih->data->type = IUP_LABEL_IMAGE; +- iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP);  ++ iupMOT_SETARG(args, num_args, XmNlabelType, XmPIXMAP);  + } + else + { + ih->data->type = IUP_LABEL_TEXT; +- iupmotSetArg(args, num_args, XmNlabelType, XmSTRING);  ++ iupMOT_SETARG(args, num_args, XmNlabelType, XmSTRING);  + } + } +  + /* Core */ +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ +- iupmotSetArg(args, num_args, XmNtraversalOn, False); +- iupmotSetArg(args, num_args, XmNhighlightThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNhighlightThickness, 0); + /* Label */ +- iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ +- iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); +- iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ +- iupmotSetArg(args, num_args, XmNmarginLeft, 0); +- iupmotSetArg(args, num_args, XmNmarginBottom, 0); +- iupmotSetArg(args, num_args, XmNmarginRight, 0); ++ iupMOT_SETARG(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginTop, 0); /* no extra margins */ ++ iupMOT_SETARG(args, num_args, XmNmarginLeft, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginBottom, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginRight, 0); +  + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ +diff --git a/iup/src/mot/iupmot_list.c b/iup/src/mot/iupmot_list.c +index f8e73ed..800e6e9 100755 +--- a/iup/src/mot/iupmot_list.c ++++ b/iup/src/mot/iupmot_list.c +@@ -143,15 +143,36 @@ void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value) + motListAddSortedItem(ih, value); + else + motListAddItem(ih, pos, value); ++ ++ iupListUpdateOldValue(ih, pos, 0); + } +  + void iupdrvListRemoveItem(Ihandle* ih, int pos) + { + /* The utility functions use 0=last 1=first */ + if (ih->data->is_dropdown || ih->data->has_editbox) ++ { ++ if (ih->data->is_dropdown && !ih->data->has_editbox) ++ { ++ /* must check if removing the current item */ ++ int curpos; ++ XtVaGetValues(ih->handle, XmNselectedPosition, &curpos, NULL); ++ if (pos == curpos && iupdrvListGetCount(ih)>1) ++ { ++ if (curpos > 0) curpos--; ++ else curpos++; ++ ++ XtRemoveCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih); ++ XtVaSetValues(ih->handle, XmNselectedPosition, curpos, NULL);  ++ XtAddCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih); ++ } ++ } + XmComboBoxDeletePos(ih->handle, pos+1); ++ } + else + XmListDeletePos(ih->handle, pos+1); ++ ++ iupListUpdateOldValue(ih, pos, 1); + } +  + void iupdrvListRemoveAllItems(Ihandle* ih) +@@ -174,7 +195,7 @@ void iupdrvListRemoveAllItems(Ihandle* ih) + static char* motListGetIdValueAttrib(Ihandle* ih, const char* name_id) + { + int pos = iupListGetPos(ih, name_id); +- if (pos != -1) ++ if (pos >= 0) + { + XmString* items; + XtVaGetValues(ih->handle, XmNitems, &items, NULL); +@@ -852,8 +873,10 @@ static int motListSetNCAttrib(Ihandle* ih, const char* value) + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XtVaSetValues(cbedit, XmNmaxLength, ih->data->nc, NULL); ++ return 0; + } +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int motListSetClipboardAttrib(Ihandle *ih, const char *value) +@@ -1181,32 +1204,32 @@ static int motListMapMethod(Ihandle* ih) + if (ih->data->is_dropdown || ih->data->has_editbox) + { + /* could not set XmNmappedWhenManaged to False because the list and the edit box where not displayed */ +- /* iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); */ +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ +- iupmotSetArg(args, num_args, XmNmarginHeight, 0); +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); ++ /* iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); +  + if (iupAttribGetBoolean(ih, "CANFOCUS")) +- iupmotSetArg(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); + else +- iupmotSetArg(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); +  +- iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); +- iupmotSetArg(args, num_args, XmNhighlightThickness, 2); +- iupmotSetArg(args, num_args, XmNshadowThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); ++ iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); +  + if (ih->data->has_editbox) + { + if (ih->data->is_dropdown) +- iupmotSetArg(args, num_args, XmNcomboBoxType, XmDROP_DOWN_COMBO_BOX); /* hidden-list+edit */ ++ iupMOT_SETARG(args, num_args, XmNcomboBoxType, XmDROP_DOWN_COMBO_BOX); /* hidden-list+edit */ + else +- iupmotSetArg(args, num_args, XmNcomboBoxType, XmCOMBO_BOX); /* visible-list+edit */ ++ iupMOT_SETARG(args, num_args, XmNcomboBoxType, XmCOMBO_BOX); /* visible-list+edit */ + } + else +- iupmotSetArg(args, num_args, XmNcomboBoxType, XmDROP_DOWN_LIST); /* hidden-list */ ++ iupMOT_SETARG(args, num_args, XmNcomboBoxType, XmDROP_DOWN_LIST); /* hidden-list */ +  + ih->handle = XtCreateManagedWidget( + child_id, /* child identifier */ +@@ -1220,13 +1243,13 @@ static int motListMapMethod(Ihandle* ih) +  + /* Create the scrolled window */ +  +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); +- iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); +- iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ +- iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ +- iupmotSetArg(args, num_args, XmNborderWidth, 0); +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); ++ iupMOT_SETARG(args, num_args, XmNvisualPolicy, XmVARIABLE); ++ iupMOT_SETARG(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ ++ iupMOT_SETARG(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ ++ iupMOT_SETARG(args, num_args, XmNborderWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); +  + sb_win = XtCreateManagedWidget( + child_id, /* child identifier */ +@@ -1243,34 +1266,34 @@ static int motListMapMethod(Ihandle* ih) + /* Create the list */ +  + num_args = 0; +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ +  + if (iupAttribGetBoolean(ih, "CANFOCUS")) +- iupmotSetArg(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); + else +- iupmotSetArg(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); +  +- iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); +- iupmotSetArg(args, num_args, XmNhighlightThickness, 2); +- iupmotSetArg(args, num_args, XmNshadowThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); ++ iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); +  +- iupmotSetArg(args, num_args, XmNlistMarginHeight, 0); /* default padding */ +- iupmotSetArg(args, num_args, XmNlistMarginWidth, 0); +- iupmotSetArg(args, num_args, XmNlistSpacing, 0); +- iupmotSetArg(args, num_args, XmNlistSizePolicy, XmCONSTANT); /* don't grow to fit, add scrollbar */ ++ iupMOT_SETARG(args, num_args, XmNlistMarginHeight, 0); /* default padding */ ++ iupMOT_SETARG(args, num_args, XmNlistMarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNlistSpacing, 0); ++ iupMOT_SETARG(args, num_args, XmNlistSizePolicy, XmCONSTANT); /* don't grow to fit, add scrollbar */ +  + if (ih->data->is_multiple) +- iupmotSetArg(args, num_args, XmNselectionPolicy, XmEXTENDED_SELECT); ++ iupMOT_SETARG(args, num_args, XmNselectionPolicy, XmEXTENDED_SELECT); + else +- iupmotSetArg(args, num_args, XmNselectionPolicy, XmBROWSE_SELECT); ++ iupMOT_SETARG(args, num_args, XmNselectionPolicy, XmBROWSE_SELECT); +  + if (iupAttribGetBoolean(ih, "AUTOHIDE")) +- iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); ++ iupMOT_SETARG(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); + else +- iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); ++ iupMOT_SETARG(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); +  + ih->handle = XtCreateManagedWidget( + child_id, /* child identifier */ +diff --git a/iup/src/mot/iupmot_loop.c b/iup/src/mot/iupmot_loop.c +index 828ddcd..c1f92ec 100755 +--- a/iup/src/mot/iupmot_loop.c ++++ b/iup/src/mot/iupmot_loop.c +@@ -56,7 +56,7 @@ void iupdrvSetIdleFunction(Icallback f) + mot_idle_id = XtAppAddWorkProc(iupmot_appcontext, motIdlecbWorkProc, NULL); + } +  +-static int motLoopStep(void) ++static int motLoopProcessEvent(void) + { + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + return (mot_exitmainloop)? IUP_CLOSE : IUP_DEFAULT; +@@ -79,7 +79,7 @@ int IupMainLoop(void) +  + while (!mot_exitmainloop) + { +- if (motLoopStep() == IUP_CLOSE) ++ if (motLoopProcessEvent() == IUP_CLOSE) + break; + } +  +@@ -88,19 +88,26 @@ int IupMainLoop(void) + return IUP_NOERROR; + } +  ++int IupLoopStepWait(void) ++{ ++ while(!XtAppPending(iupmot_appcontext)); ++ ++ return motLoopProcessEvent(); ++} ++ + int IupLoopStep(void) + { + if (!XtAppPending(iupmot_appcontext))  + return IUP_DEFAULT; +  +- return motLoopStep(); ++ return motLoopProcessEvent(); + } +  + void IupFlush(void) + { + while (XPending(iupmot_display) != 0) + { +- if (motLoopStep() == IUP_CLOSE) ++ if (motLoopProcessEvent() == IUP_CLOSE) + break; + } +  +diff --git a/iup/src/mot/iupmot_menu.c b/iup/src/mot/iupmot_menu.c +index be9b953..8f51334 100755 +--- a/iup/src/mot/iupmot_menu.c ++++ b/iup/src/mot/iupmot_menu.c +@@ -125,7 +125,10 @@ static void motPopupMenuUnmapCallback(Widget w, Ihandle* ih, XtPointer call_data + static void motMenuUnMapMethod(Ihandle* ih) + { + if (iupMenuIsMenuBar(ih)) ++ { + XtDestroyWidget(ih->handle); ++ ih->parent = NULL; ++ } + else + XtDestroyWidget(XtParent(ih->handle)); /* in this case the RowColumn widget is a child of a MenuShell. */ + } +@@ -146,7 +149,6 @@ static int motMenuMapMethod(Ihandle* ih) + XmNrowColumnType, XmMENU_BAR, + XmNmarginHeight, 0, + XmNmarginWidth, 0, +- XmNresizeWidth, False, + NULL); + if (!ih->handle) + return IUP_ERROR; +@@ -161,8 +163,8 @@ static int motMenuMapMethod(Ihandle* ih) +  + if (iupAttribGetBoolean(ih, "RADIO")) + { +- iupmotSetArg(args, num_args, XmNpacking, XmPACK_COLUMN); +- iupmotSetArg(args, num_args, XmNradioBehavior, TRUE); ++ iupMOT_SETARG(args, num_args, XmNpacking, XmPACK_COLUMN); ++ iupMOT_SETARG(args, num_args, XmNradioBehavior, TRUE); + } +  + ih->handle = XmCreatePulldownMenu( +@@ -183,7 +185,7 @@ static int motMenuMapMethod(Ihandle* ih) + { + /* top level menu used for IupPopup */ +  +- iupmotSetArg(args, num_args, XmNpopupEnabled, XmPOPUP_AUTOMATIC); ++ iupMOT_SETARG(args, num_args, XmNpopupEnabled, XmPOPUP_AUTOMATIC); +  + ih->handle = XmCreatePopupMenu( + iupmot_appshell,  +@@ -307,19 +309,19 @@ static int motItemMapMethod(Ihandle* ih) +  + if (iupAttribGetBoolean(ih->parent, "RADIO")) + { +- iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); +- iupmotSetArg(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); +- iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); +- iupmotSetArg(args, num_args, XmNindicatorSize, 13); +- iupmotSetArg(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); ++ iupMOT_SETARG(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); ++ iupMOT_SETARG(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); ++ iupMOT_SETARG(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); ++ iupMOT_SETARG(args, num_args, XmNindicatorSize, 13); ++ iupMOT_SETARG(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); + } + else + { + if (iupAttribGetBoolean(ih, "HIDEMARK")) +- iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); ++ iupMOT_SETARG(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); + else +- iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK); +- iupmotSetArg(args, num_args, XmNlabelType, iupAttribGet(ih, "TITLEIMAGE")? XmPIXMAP: XmSTRING); ++ iupMOT_SETARG(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK); ++ iupMOT_SETARG(args, num_args, XmNlabelType, iupAttribGet(ih, "TITLEIMAGE")? XmPIXMAP: XmSTRING); + } +  + ih->handle = XtCreateManagedWidget( +diff --git a/iup/src/mot/iupmot_progressbar.c b/iup/src/mot/iupmot_progressbar.c +index 7266d38..82fa178 100755 +--- a/iup/src/mot/iupmot_progressbar.c ++++ b/iup/src/mot/iupmot_progressbar.c +@@ -98,25 +98,25 @@ static int motProgressBarMapMethod(Ihandle* ih) + Arg args[30]; +  + /* Core */ +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ +- iupmotSetArg(args, num_args, XmNtraversalOn, False); +- iupmotSetArg(args, num_args, XmNhighlightThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNhighlightThickness, 0); + /* Scale */ +- iupmotSetArg(args, num_args, XmNminimum, 0); +- iupmotSetArg(args, num_args, XmNmaximum, SHRT_MAX); +- iupmotSetArg(args, num_args, XmNslidingMode, XmTHERMOMETER); /* thermometer effect */ +- iupmotSetArg(args, num_args, XmNsliderMark, XmNONE); +- iupmotSetArg(args, num_args, XmNeditable, False); +- iupmotSetArg(args, num_args, XmNshowValue, XmNONE); ++ iupMOT_SETARG(args, num_args, XmNminimum, 0); ++ iupMOT_SETARG(args, num_args, XmNmaximum, SHRT_MAX); ++ iupMOT_SETARG(args, num_args, XmNslidingMode, XmTHERMOMETER); /* thermometer effect */ ++ iupMOT_SETARG(args, num_args, XmNsliderMark, XmNONE); ++ iupMOT_SETARG(args, num_args, XmNeditable, False); ++ iupMOT_SETARG(args, num_args, XmNshowValue, XmNONE); +  + if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL")) + { +- iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); ++ iupMOT_SETARG(args, num_args, XmNorientation, XmVERTICAL); +  + if (ih->currentheight < ih->currentwidth) + { +@@ -126,7 +126,7 @@ static int motProgressBarMapMethod(Ihandle* ih) + } + } + else +- iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); ++ iupMOT_SETARG(args, num_args, XmNorientation, XmHORIZONTAL); +  + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ +diff --git a/iup/src/mot/iupmot_tabs.c b/iup/src/mot/iupmot_tabs.c +index 7c8a6b5..cafc41d 100755 +--- a/iup/src/mot/iupmot_tabs.c ++++ b/iup/src/mot/iupmot_tabs.c +@@ -52,8 +52,10 @@ void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos) + { + Ihandle* child = IupGetChild(ih, pos); + Ihandle* prev_child = IupGetChild(ih, iupdrvTabsGetCurrentTab(ih)); +- IupSetAttribute(child, "VISIBLE", "YES"); +- IupSetAttribute(prev_child, "VISIBLE", "NO"); ++ Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); ++ Widget prev_child_manager = (Widget)iupAttribGet(prev_child, "_IUPTAB_CONTAINER"); ++ XtMapWidget(child_manager); ++ if (prev_child_manager) XtUnmapWidget(prev_child_manager); +  + XtVaSetValues(ih->handle, XmNcurrentPageNumber, pos, NULL); + } +@@ -200,7 +202,7 @@ static int motTabsSetTabTypeAttrib(Ihandle* ih, const char* value) + ih->data->type = ITABS_TOP; +  + if (ih->handle) +- motTabsUpdateTabType(ih); ++ motTabsUpdateTabType(ih); /* for this to work must be updated in map */ +  + return 0; + } +@@ -313,8 +315,10 @@ void motTabsPageChangedCallback(Widget w, Ihandle* ih, XmNotebookCallbackStruct + IFnnn cb; + Ihandle* child = IupGetChild(ih, nptr->page_number); + Ihandle* prev_child = IupGetChild(ih, nptr->prev_page_number); +- IupSetAttribute(child, "VISIBLE", "YES"); +- IupSetAttribute(prev_child, "VISIBLE", "NO"); ++ Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); ++ Widget prev_child_manager = (Widget)iupAttribGet(prev_child, "_IUPTAB_CONTAINER"); ++ XtMapWidget(child_manager); ++ if (prev_child_manager) XtUnmapWidget(prev_child_manager); +  + cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB"); + if (cb) +@@ -397,12 +401,12 @@ static void motTabsChildAddedMethod(Ihandle* ih, Ihandle* child) +  + /* Create tabs */ + /* Label */ +- iupmotSetArg(args, num_args, XmNlabelType, tabtitle? XmSTRING: XmPIXMAP); +- iupmotSetArg(args, num_args, XmNmarginHeight, 0); +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNlabelType, tabtitle? XmSTRING: XmPIXMAP); ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); + /* Notebook Constraint */ +- iupmotSetArg(args, num_args, XmNnotebookChildType, XmMAJOR_TAB); +- iupmotSetArg(args, num_args, XmNpageNumber, pos); ++ iupMOT_SETARG(args, num_args, XmNnotebookChildType, XmMAJOR_TAB); ++ iupMOT_SETARG(args, num_args, XmNpageNumber, pos); + tab_button = XtCreateManagedWidget("tab_button", xmPushButtonWidgetClass, ih->handle, args, num_args); +  + /* Disable Drag Source */ +@@ -450,10 +454,8 @@ static void motTabsChildAddedMethod(Ihandle* ih, Ihandle* child) + iupAttribSetStr(child, "_IUPMOT_TABBUTTON", (char*)tab_button); + iupAttribSetInt(child, "_IUPMOT_TABNUMBER", pos); +  +- if (pos == iupdrvTabsGetCurrentTab(ih)) +- IupSetAttribute(child, "VISIBLE", "YES"); +- else +- IupSetAttribute(child, "VISIBLE", "NO"); ++ if (pos != iupdrvTabsGetCurrentTab(ih)) ++ XtUnmapWidget(child_manager); + } + } +  +@@ -464,20 +466,11 @@ static void motTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) + Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (child_manager) + { +- int cur_pos, pos; ++ int pos; + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); +  +- cur_pos = iupdrvTabsGetCurrentTab(ih); + pos = iupAttribGetInt(child, "_IUPMOT_TABNUMBER"); /* did not work when using XtVaGetValues(child_manager, XmNpageNumber) */ +- if (cur_pos == pos) +- { +- if (cur_pos == 0) +- cur_pos = 1; +- else +- cur_pos--; +- +- iupdrvTabsSetCurrentTab(ih, cur_pos); +- } ++ iupTabsTestRemoveTab(ih, pos); +  + XtDestroyWidget(tab_button); + XtDestroyWidget(child_manager); +@@ -501,22 +494,22 @@ static int motTabsMapMethod(Ihandle* ih) + return IUP_ERROR; +  + /* Core */ +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Manager */ +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); +- iupmotSetArg(args, num_args, XmNtraversalOn, True); +- iupmotSetArg(args, num_args, XmNhighlightThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNhighlightThickness, 0); + /* Notebook */ +- iupmotSetArg(args, num_args, XmNbindingType, XmNONE); +- iupmotSetArg(args, num_args, XmNbindingWidth, 0); +- iupmotSetArg(args, num_args, XmNfirstPageNumber, 0); /* IupTabs index always starts with zero */ +- iupmotSetArg(args, num_args, XmNbackPageSize, 0); +- iupmotSetArg(args, num_args, XmNbackPageNumber, 1); +- iupmotSetArg(args, num_args, XmNframeShadowThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNbindingType, XmNONE); ++ iupMOT_SETARG(args, num_args, XmNbindingWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNfirstPageNumber, 0); /* IupTabs index always starts with zero */ ++ iupMOT_SETARG(args, num_args, XmNbackPageSize, 0); ++ iupMOT_SETARG(args, num_args, XmNbackPageNumber, 1); ++ iupMOT_SETARG(args, num_args, XmNframeShadowThickness, 2); +  + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ +@@ -589,5 +582,5 @@ void iupdrvTabsInitClass(Iclass* ic) + iupClassRegisterAttribute(ic, "TABORIENTATION", iupTabsGetTabOrientationAttrib, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* can not be set, always HORIZONTAL in Motif */ + iupClassRegisterAttributeId(ic, "TABTITLE", NULL, motTabsSetTabTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, motTabsSetTabImageAttrib, IUPAF_NO_INHERIT); +- iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, motTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); ++ iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, motTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + } +diff --git a/iup/src/mot/iupmot_text.c b/iup/src/mot/iupmot_text.c +index 4a8f936..d9d2c74 100755 +--- a/iup/src/mot/iupmot_text.c ++++ b/iup/src/mot/iupmot_text.c +@@ -142,8 +142,10 @@ static int motTextSetPaddingAttrib(Ihandle* ih, const char* value) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); ++ return 0; + } +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int motTextSetReadOnlyAttrib(Ihandle* ih, const char* value) +@@ -164,7 +166,7 @@ static char* motTextGetReadOnlyAttrib(Ihandle* ih) +  + static int motTextSetInsertAttrib(Ihandle* ih, 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; + if (!value) + return 0; +@@ -207,12 +209,12 @@ static char* motTextGetSelectedTextAttrib(Ihandle* ih) + static int motTextSetAppendAttrib(Ihandle* ih, const char* value) + { + XmTextPosition pos; +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; + pos = XmTextGetLastPosition(ih->handle); + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); +- if (ih->data->is_multiline && ih->data->append_newline) ++ if (ih->data->is_multiline && ih->data->append_newline && pos!=0) + XmTextInsert(ih->handle, pos, "\n"); + if (value) + XmTextInsert(ih->handle, pos+1, (char*)value); +@@ -482,8 +484,12 @@ static int motTextSetNCAttrib(Ihandle* ih, const char* value) + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = INT_MAX; + if (ih->handle) ++ { + XtVaSetValues(ih->handle, XmNmaxLength, ih->data->nc, NULL); +- return 0; ++ return 0; ++ } ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int motTextSetClipboardAttrib(Ihandle *ih, const char *value) +@@ -911,6 +917,10 @@ static void motTextLayoutUpdateMethod(Ihandle* ih) + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { ++ /* avoid abort in X */ ++ if (ih->currentwidth == 0) ih->currentwidth = 1; ++ if (ih->currentheight == 0) ih->currentheight = 1; ++ + XtVaSetValues(ih->handle, + XmNwidth, (XtArgVal)ih->currentwidth-ih->currentheight/2, + XmNheight, (XtArgVal)ih->currentheight, +@@ -952,13 +962,13 @@ static int motTextMapMethod(Ihandle* ih) + /* Create the scrolled window */ + /******************************/ +  +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); +- iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); +- iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ +- iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ +- iupmotSetArg(args, num_args, XmNborderWidth, 0); +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); ++ iupMOT_SETARG(args, num_args, XmNvisualPolicy, XmVARIABLE); ++ iupMOT_SETARG(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ ++ iupMOT_SETARG(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ ++ iupMOT_SETARG(args, num_args, XmNborderWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); +  + sb_win = XtCreateManagedWidget( + child_id, /* child identifier */ +@@ -973,9 +983,9 @@ static int motTextMapMethod(Ihandle* ih) + child_id = "text"; +  + num_args = 0; +- iupmotSetArg(args, num_args, XmNeditMode, XmMULTI_LINE_EDIT); ++ iupMOT_SETARG(args, num_args, XmNeditMode, XmMULTI_LINE_EDIT); + if (wordwrap) +- iupmotSetArg(args, num_args, XmNwordWrap, True); ++ iupMOT_SETARG(args, num_args, XmNwordWrap, True); + } + else + { +@@ -986,18 +996,18 @@ static int motTextMapMethod(Ihandle* ih) + Widget spinbox; +  + num_args = 0; +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between spin and text */ +- iupmotSetArg(args, num_args, XmNborderWidth, 0); +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); +- iupmotSetArg(args, num_args, XmNmarginHeight, 0); +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); +- iupmotSetArg(args, num_args, XmNarrowSize, 8); ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNspacing, 0); /* no space between spin and text */ ++ iupMOT_SETARG(args, num_args, XmNborderWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNarrowSize, 8); +  + if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT")) +- iupmotSetArg(args, num_args, XmNarrowLayout, XmARROWS_BEGINNING); ++ iupMOT_SETARG(args, num_args, XmNarrowLayout, XmARROWS_BEGINNING); + else +- iupmotSetArg(args, num_args, XmNarrowLayout, XmARROWS_END); ++ iupMOT_SETARG(args, num_args, XmNarrowLayout, XmARROWS_END); +  + spinbox = XtCreateManagedWidget( + child_id, /* child identifier */ +@@ -1019,61 +1029,61 @@ static int motTextMapMethod(Ihandle* ih) + } +  + num_args = 0; +- iupmotSetArg(args, num_args, XmNeditMode, XmSINGLE_LINE_EDIT); ++ iupMOT_SETARG(args, num_args, XmNeditMode, XmSINGLE_LINE_EDIT); +  + if (spin) + { + /* Spin Constraints */ +- iupmotSetArg(args, num_args, XmNspinBoxChildType, XmNUMERIC); +- iupmotSetArg(args, num_args, XmNminimumValue, 0); +- iupmotSetArg(args, num_args, XmNmaximumValue, 100); +- iupmotSetArg(args, num_args, XmNposition, 0); ++ iupMOT_SETARG(args, num_args, XmNspinBoxChildType, XmNUMERIC); ++ iupMOT_SETARG(args, num_args, XmNminimumValue, 0); ++ iupMOT_SETARG(args, num_args, XmNmaximumValue, 100); ++ iupMOT_SETARG(args, num_args, XmNposition, 0); +  + if (iupAttribGetBoolean(ih, "SPINWRAP")) +- iupmotSetArg(args, num_args, XmNwrap, TRUE); ++ iupMOT_SETARG(args, num_args, XmNwrap, TRUE); + else +- iupmotSetArg(args, num_args, XmNwrap, FALSE); ++ iupMOT_SETARG(args, num_args, XmNwrap, FALSE); + } + else + { +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + } + } +  +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ +  +- iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); +  + if (iupAttribGetBoolean(ih, "CANFOCUS")) +- iupmotSetArg(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); + else +- iupmotSetArg(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); +  +- iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); +- iupmotSetArg(args, num_args, XmNhighlightThickness, 2); +- iupmotSetArg(args, num_args, XmNverifyBell, False); +- iupmotSetArg(args, num_args, XmNspacing, 0); ++ iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); ++ iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNverifyBell, False); ++ iupMOT_SETARG(args, num_args, XmNspacing, 0); +  + if (iupAttribGetBoolean(ih, "BORDER")) +- iupmotSetArg(args, num_args, XmNshadowThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); + else +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); +  + if (ih->data->is_multiline) + { + if (ih->data->sb & IUP_SB_HORIZ) +- iupmotSetArg(args, num_args, XmNscrollHorizontal, True); ++ iupMOT_SETARG(args, num_args, XmNscrollHorizontal, True); + else +- iupmotSetArg(args, num_args, XmNscrollHorizontal, False); ++ iupMOT_SETARG(args, num_args, XmNscrollHorizontal, False); +  + if (ih->data->sb & IUP_SB_VERT) +- iupmotSetArg(args, num_args, XmNscrollVertical, True); ++ iupMOT_SETARG(args, num_args, XmNscrollVertical, True); + else +- iupmotSetArg(args, num_args, XmNscrollVertical, False); ++ iupMOT_SETARG(args, num_args, XmNscrollVertical, False); + } +  + ih->handle = XtCreateManagedWidget( +diff --git a/iup/src/mot/iupmot_toggle.c b/iup/src/mot/iupmot_toggle.c +index b18f24d..1fda258 100755 +--- a/iup/src/mot/iupmot_toggle.c ++++ b/iup/src/mot/iupmot_toggle.c +@@ -236,8 +236,10 @@ static int motToggleSetPaddingAttrib(Ihandle* ih, const char* value) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); ++ return 0; + } +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static char* motToggleGetSelectColorAttrib(Ihandle* ih) +@@ -336,40 +338,40 @@ static int motToggleMapMethod(Ihandle* ih) + if (value) + { + ih->data->type = IUP_TOGGLE_IMAGE; +- iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP);  ++ iupMOT_SETARG(args, num_args, XmNlabelType, XmPIXMAP);  + } + else + { + ih->data->type = IUP_TOGGLE_TEXT; +- iupmotSetArg(args, num_args, XmNlabelType, XmSTRING);  ++ iupMOT_SETARG(args, num_args, XmNlabelType, XmSTRING);  + } +  + /* Core */ +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ + if (iupAttribGetBoolean(ih, "CANFOCUS")) +- iupmotSetArg(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); + else +- iupmotSetArg(args, num_args, XmNtraversalOn, False); +- iupmotSetArg(args, num_args, XmNhighlightThickness, 2); +- iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); + /* Label */ +- iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ +- iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); +- iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ +- iupmotSetArg(args, num_args, XmNmarginLeft, 0); +- iupmotSetArg(args, num_args, XmNmarginBottom, 0); +- iupmotSetArg(args, num_args, XmNmarginRight, 0); ++ iupMOT_SETARG(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginTop, 0); /* no extra margins */ ++ iupMOT_SETARG(args, num_args, XmNmarginLeft, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginBottom, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginRight, 0); +  + if (radio) + { +- iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); +- iupmotSetArg(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); ++ iupMOT_SETARG(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); ++ iupMOT_SETARG(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); +  + if (!iupAttribGet(radio, "_IUPMOT_LASTTOGGLE")) + { +@@ -380,33 +382,33 @@ static int motToggleMapMethod(Ihandle* ih) + else + { + if (ih->data->type == IUP_TOGGLE_TEXT && iupAttribGetBoolean(ih, "3STATE")) +- iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_INDETERMINATE); ++ iupMOT_SETARG(args, num_args, XmNtoggleMode, XmTOGGLE_INDETERMINATE); + else +- iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); +- iupmotSetArg(args, num_args, XmNindicatorType, XmN_OF_MANY); ++ iupMOT_SETARG(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); ++ iupMOT_SETARG(args, num_args, XmNindicatorType, XmN_OF_MANY); + } +  + if (ih->data->type == IUP_TOGGLE_IMAGE) + { +- iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); +- iupmotSetArg(args, num_args, XmNalignment, XmALIGNMENT_CENTER); +- iupmotSetArg(args, num_args, XmNshadowThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); ++ iupMOT_SETARG(args, num_args, XmNalignment, XmALIGNMENT_CENTER); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); + } + else + { +- iupmotSetArg(args, num_args, XmNspacing, 3); +- iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); +- iupmotSetArg(args, num_args, XmNalignment, XmALIGNMENT_BEGINNING); ++ iupMOT_SETARG(args, num_args, XmNspacing, 3); ++ iupMOT_SETARG(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); ++ iupMOT_SETARG(args, num_args, XmNalignment, XmALIGNMENT_BEGINNING); + if (radio) + { +- iupmotSetArg(args, num_args, XmNindicatorSize, 13); +- iupmotSetArg(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); ++ iupMOT_SETARG(args, num_args, XmNindicatorSize, 13); ++ iupMOT_SETARG(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); + } + else +- iupmotSetArg(args, num_args, XmNindicatorSize, 15); ++ iupMOT_SETARG(args, num_args, XmNindicatorSize, 15); +  +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); +- iupmotSetArg(args, num_args, XmNdetailShadowThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNdetailShadowThickness, 2); + } +  + ih->handle = XtCreateManagedWidget( +diff --git a/iup/src/mot/iupmot_tree.c b/iup/src/mot/iupmot_tree.c +index eb230af..fa5ef09 100755 +--- a/iup/src/mot/iupmot_tree.c ++++ b/iup/src/mot/iupmot_tree.c +@@ -46,48 +46,20 @@ typedef struct _motTreeItemData + Pixmap image, image_mask; + Pixmap image_expanded, image_expanded_mask; + unsigned char kind; +- void* userdata; + } motTreeItemData; +  +  + static void motTreeShowEditField(Ihandle* ih, Widget wItem); +-static int motTreeGetNodeId(Ihandle* ih, Widget wItem); ++static void motTreeRemoveNode(Ihandle* ih, Widget wItem, int del_data, int call_cb); +  +-typedef int (*motTreeNodeFunc)(Ihandle* ih, Widget wItem, void* userdata); +- +-static int motTreeForEach(Ihandle* ih, Widget wItem, motTreeNodeFunc func, void* userdata) +-{ +- WidgetList wItemChildList = NULL; +- int i, numChild; +- +- if (!wItem) +- wItem = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); +- +- if (!func(ih, wItem, userdata)) +- return 0; +- +- numChild = XmContainerGetItemChildren(ih->handle, wItem, &wItemChildList); +- for (i=0; idata->spacing); +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); +- iupmotSetArg(args, num_args, XmNviewType, XmSMALL_ICON); +- iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); +- iupmotSetArg(args, num_args, XmNtraversalOn, True); +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNentryParent, wParent); ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, ih->data->spacing); ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNviewType, XmSMALL_ICON); ++ iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); +  + /* Get values to copy */ + XtVaGetValues(wItem, XmNlabelString, &title, +@@ -113,49 +85,73 @@ static Widget motTreeCopyItem(Ihandle* ih, Widget wItem, Widget wParent, int pos + XmNoutlineState, &state, + NULL); +  +- if (full_copy) /* during a full copy the userdata reference is not copied */ ++ if (is_copy) /* during a copy the itemdata reference is not reused */ + { + /* create a new one */ + motTreeItemData* itemDataNew = malloc(sizeof(motTreeItemData)); + memcpy(itemDataNew, itemData, sizeof(motTreeItemData)); +- itemDataNew->userdata = NULL; + itemData = itemDataNew; + } +  +- iupmotSetArg(args, num_args, XmNlabelString, title); +- iupmotSetArg(args, num_args, XmNuserData, itemData); +- iupmotSetArg(args, num_args, XmNforeground, fgcolor); +- iupmotSetArg(args, num_args, XmNsmallIconPixmap, image); +- iupmotSetArg(args, num_args, XmNsmallIconMask, mask); +- iupmotSetArg(args, num_args, XmNoutlineState, state); ++ iupMOT_SETARG(args, num_args, XmNlabelString, title); ++ iupMOT_SETARG(args, num_args, XmNuserData, itemData); ++ iupMOT_SETARG(args, num_args, XmNforeground, fgcolor); ++ iupMOT_SETARG(args, num_args, XmNsmallIconPixmap, image); ++ iupMOT_SETARG(args, num_args, XmNsmallIconMask, mask); ++ iupMOT_SETARG(args, num_args, XmNoutlineState, state); +  +- iupmotSetArg(args, num_args, XmNentryParent, wParent); +- iupmotSetArg(args, num_args, XmNpositionIndex, pos); ++ iupMOT_SETARG(args, num_args, XmNentryParent, wParent); ++ iupMOT_SETARG(args, num_args, XmNpositionIndex, pos); +  + XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); +- iupmotSetArg(args, num_args, XmNbackground, bgcolor); ++ iupMOT_SETARG(args, num_args, XmNbackground, bgcolor); ++ ++ /* Add the new node */ ++ wItemNew = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); ++ ih->data->node_count++; ++ ++ XtRealizeWidget(wItemNew); ++ ++ return wItemNew; ++} ++ ++static void motTreeChildRebuildCacheRec(Ihandle* ih, Widget wItem, int *id) ++{ ++ WidgetList itemChildList = NULL; ++ int i, numChild; +  +- wNewItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); ++ /* Check whether we have child items */ ++ numChild = XmContainerGetItemChildren(ih->handle, wItem, &itemChildList); ++ ++ for (i = 0; i < numChild; i++) ++ { ++ (*id)++; ++ ih->data->node_cache[*id].node_handle = itemChildList[i]; +  +- /* Root always expanded */ +- XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); ++ /* go recursive to children */ ++ motTreeChildRebuildCacheRec(ih, itemChildList[i], id); ++ } +  +- XtRealizeWidget(wNewItem); ++ if (itemChildList) XtFree((char*)itemChildList); ++} +  +- return wNewItem; ++static void motTreeRebuildNodeCache(Ihandle* ih, int id, Widget wItem) ++{ ++ ih->data->node_cache[id].node_handle = wItem; ++ motTreeChildRebuildCacheRec(ih, wItem, &id); + } +  +-static void motTreeCopyChildren(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int full_copy) ++static void motTreeCopyChildren(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int is_copy) + { + WidgetList wItemChildList = NULL; + int i = 0; + int numChild = XmContainerGetItemChildren(ih->handle, wItemSrc, &wItemChildList); + while(i != numChild) + { +- Widget wNewItem = motTreeCopyItem(ih, wItemChildList[i], wItemDst, i, full_copy); /* Use the same order they where enumerated */ ++ Widget wItemNew = motTreeCopyItem(ih, wItemChildList[i], wItemDst, i, is_copy); /* Use the same order they where enumerated */ +  + /* Recursively transfer all the items */ +- motTreeCopyChildren(ih, wItemChildList[i], wNewItem, full_copy);  ++ motTreeCopyChildren(ih, wItemChildList[i], wItemNew, is_copy);  +  + /* Go to next sibling item */ + i++; +@@ -165,12 +161,18 @@ static void motTreeCopyChildren(Ihandle* ih, Widget wItemSrc, Widget wItemDst, i + } +  + /* Copies all items in a branch to a new location. Returns the new branch node. */ +-static Widget motTreeCopyNode(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int full_copy) ++static Widget motTreeCopyMoveNode(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int is_copy) + { +- Widget wNewItem, wParent; ++ Widget wItemNew, wParent; + motTreeItemData *itemDataDst; + unsigned char stateDst; +- int pos; ++ int pos, id_new, count, id_src, id_dst; ++ ++ int old_count = ih->data->node_count; ++ ++ id_src = iupTreeFindNodeId(ih, wItemSrc); ++ id_dst = iupTreeFindNodeId(ih, wItemDst); ++ id_new = id_dst+1; /* contains the position for a copy operation */ +  + XtVaGetValues(wItemDst, XmNoutlineState, &stateDst,  + XmNuserData, &itemDataDst,  +@@ -184,17 +186,46 @@ static Widget motTreeCopyNode(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int + } + else + { ++ if (itemDataDst->kind == ITREE_BRANCH) ++ { ++ int child_count = iupdrvTreeTotalChildCount(ih, wItemDst); ++ id_new += child_count; ++ } ++ + /* copy as next brother of item or collapsed branch */ + XtVaGetValues(wItemDst, XmNentryParent, &wParent, NULL); + XtVaGetValues(wItemDst, XmNpositionIndex, &pos, NULL); + pos++; + } +  +- wNewItem = motTreeCopyItem(ih, wItemSrc, wParent, pos, full_copy); ++ /* move to the same place does nothing */ ++ if (!is_copy && id_new == id_src) ++ return NULL; ++ ++ wItemNew = motTreeCopyItem(ih, wItemSrc, wParent, pos, is_copy); ++ ++ motTreeCopyChildren(ih, wItemSrc, wItemNew, is_copy); ++ ++ count = ih->data->node_count - old_count; ++ iupTreeCopyMoveCache(ih, id_src, id_new, count, is_copy); +  +- motTreeCopyChildren(ih, wItemSrc, wNewItem, full_copy); ++ if (!is_copy) ++ { ++ /* Deleting the node (and its children) from the old position */ ++ /* do not delete the itemdata, we reuse the references in CopyNode */ ++ motTreeRemoveNode(ih, wItemSrc, 0, 0); ++ ++ /* restore count, because we remove src */ ++ ih->data->node_count = old_count; ++ ++ /* compensate position for a move */ ++ if (id_new > id_src) ++ id_new -= count; ++ } +  +- return wNewItem; ++ motTreeRebuildNodeCache(ih, id_new, wItemNew); ++ ++ return wItemNew; + } +  + static void motTreeContainerDeselectAll(Ihandle *ih) +@@ -233,229 +264,181 @@ static void motTreeContainerSelectAll(Ihandle *ih) + XtCallActionProc(ih->handle, "ContainerSelectAll", (XEvent*)&ev, 0, 0); + } +  +-static Widget motTreeGetLastVisibleNode(Ihandle* ih, Widget wItem) ++static int motTreeIsNodeVisible(Widget wItem, Widget *wLastItemParent) + { +- unsigned char itemState; +- +- XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); +- +- if (itemState == XmEXPANDED) ++ unsigned char itemParentState; ++ Widget wItemParent = NULL; ++ XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL); ++ if (!wItemParent || wItemParent == *wLastItemParent) ++ return 1; ++ while(wItemParent) + { +- WidgetList wChildrenTree = NULL; +- int numChildren = XmContainerGetItemChildren(ih->handle, wItem, &wChildrenTree); +- if(numChildren) +- wItem = motTreeGetLastVisibleNode(ih, wChildrenTree[numChildren - 1]); +- if (wChildrenTree) XtFree((char*)wChildrenTree); ++ XtVaGetValues(wItemParent, XmNoutlineState, &itemParentState, NULL); ++ if (itemParentState != XmEXPANDED) ++ return 0; ++ ++ XtVaGetValues(wItemParent, XmNentryParent, &wItemParent, NULL); + } +  +- return wItem; ++ /* save last parent */ ++ XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL); ++ *wLastItemParent = wItemParent; ++ return 1; + } +  +-static Widget motTreeFindVisibleNodeId(Ihandle* ih, WidgetList itemList, int numItems, Widget itemNode) ++static Widget motTreeGetLastVisibleNode(Ihandle* ih) + { +- Widget itemChild; +- WidgetList itemChildList; +- int i = 0; +- int numChild; +- unsigned char itemState; ++ int i; ++ Widget wLastItemParent = NULL; +  +- while(i != numItems) ++ for (i = ih->data->node_count-1; i >= 0; i--) + { +- /* ID control to traverse items */ +- ih->data->id_control++; /* not the real id since it counts only the visible ones */ +- +- /* StateID founded! */ +- if(itemList[i] == itemNode) +- return itemList[i]; +- +- /* Check whether we have child items */ +- itemChildList = NULL; +- numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); +- XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); +- +- /* The itemWidget has child and it is expanded (visible) */ +- if (numChild && itemState == XmEXPANDED) +- { +- /* pass the list of children of this item */ +- itemChild = motTreeFindVisibleNodeId(ih, itemChildList, numChild, itemNode); +- +- /* StateID founded! */ +- if(itemChild) +- { +- XtFree((char*)itemChildList); +- return itemChild; +- } +- } +- +- if (itemChildList) XtFree((char*)itemChildList); +- /* Go to next sibling item */ +- i++; ++ if (motTreeIsNodeVisible(ih->data->node_cache[i].node_handle, &wLastItemParent)) ++ return ih->data->node_cache[i].node_handle; + } +  +- return NULL; ++ return ih->data->node_cache[0].node_handle; /* root is always visible */ + } +  +-static Widget motTreeFindVisibleNodeFromId(Ihandle* ih, WidgetList itemList, int numItems) ++static Widget motTreeGetNextVisibleNode(Ihandle* ih, Widget wItem, int count) + { +- Widget itemChild; +- WidgetList itemChildList; +- int i = 0; +- int numChild; +- unsigned char itemState; ++ int i, id; ++ Widget wLastItemParent = NULL; +  +- while(i != numItems) +- { +- /* ID control to traverse items */ +- ih->data->id_control--; /* not the real id since it counts only the visible ones */ ++ id = iupTreeFindNodeId(ih, wItem); ++ id += count; +  +- /* StateID founded! */ +- if(ih->data->id_control < 0) +- return itemList[i]; ++ for (i = id; i < ih->data->node_count; i++) ++ { ++ if (motTreeIsNodeVisible(ih->data->node_cache[i].node_handle, &wLastItemParent)) ++ return ih->data->node_cache[i].node_handle; ++ } +  +- /* Check whether we have child items */ +- itemChildList = NULL; +- numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); +- XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); ++ return ih->data->node_cache[0].node_handle; /* root is always visible */ ++} +  +- /* The itemWidget has child and it is expanded (visible) */ +- if (numChild && itemState == XmEXPANDED) +- { +- /* pass the list of children of this item */ +- itemChild = motTreeFindVisibleNodeFromId(ih, itemChildList, numChild); ++static Widget motTreeGetPreviousVisibleNode(Ihandle* ih, Widget wItem, int count) ++{ ++ int i, id; ++ Widget wLastItemParent = NULL; +  +- /* StateID founded! */ +- if(ih->data->id_control < 0) +- { +- if (itemChildList) XtFree((char*)itemChildList); +- return itemChild; +- } +- } ++ id = iupTreeFindNodeId(ih, wItem); ++ id -= count; +  +- if (itemChildList) XtFree((char*)itemChildList); +- /* Go to next sibling item */ +- i++; ++ for (i = id; i >= 0; i--) ++ { ++ if (motTreeIsNodeVisible(ih->data->node_cache[i].node_handle, &wLastItemParent)) ++ return ih->data->node_cache[i].node_handle; + } +  +- return NULL; ++ return motTreeGetLastVisibleNode(ih); + } +  +-static Widget motTreeGetNextVisibleNode(Ihandle* ih, Widget wRoot, Widget wItem) ++static void motTreeChildCountRec(Ihandle* ih, Widget wItem, int *count) + { +- Widget wNext; ++ WidgetList itemChildList = NULL; ++ int i, numChild; +  +- ih->data->id_control = -1; +- motTreeFindVisibleNodeId(ih, &wRoot, 1, wItem); +- ih->data->id_control++; /* more 1 visible node */ ++ /* Check whether we have child items */ ++ numChild = XmContainerGetItemChildren(ih->handle, wItem, &itemChildList); +  +- wNext = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); ++ for (i = 0; i < numChild; i++) ++ { ++ (*count)++; +  +- if (ih->data->id_control >= 0) +- wNext = motTreeGetLastVisibleNode(ih, wRoot); ++ /* go recursive to children */ ++ motTreeChildCountRec(ih, itemChildList[i], count); ++ } +  +- return wNext; ++ if (itemChildList) XtFree((char*)itemChildList); + } +  +-static Widget motTreeGetPreviousVisibleNode(Ihandle* ih, Widget wRoot, Widget wItem) ++int iupdrvTreeTotalChildCount(Ihandle* ih, Widget wItem) + { +- ih->data->id_control = -1; +- motTreeFindVisibleNodeId(ih, &wRoot, 1, wItem); +- ih->data->id_control--; /* less 1 visible node */ +- +- if (ih->data->id_control < 0) +- ih->data->id_control = 0; /* Begin of tree = Root id */ +- +- return motTreeFindVisibleNodeFromId(ih, &wRoot, 1); ++ int count = 0; ++ motTreeChildCountRec(ih, wItem, &count); ++ return count; + } +  +-static void motTreeUpdateBgColor(Ihandle* ih, WidgetList itemList, int numItems, Pixel bgcolor) ++static void motTreeUpdateBgColor(Ihandle* ih, Pixel bgcolor) + { +- WidgetList itemChildList; +- int i = 0; +- int numChild; +- +- while(i != numItems) ++ int i; ++ for (i = 0; i < ih->data->node_count; i++) + { +- XtVaSetValues(itemList[i], XmNbackground, bgcolor, NULL); +- +- /* Check whether we have child items */ +- itemChildList = NULL; +- numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); +- if(numChild) +- motTreeUpdateBgColor(ih, itemChildList, numChild, bgcolor); +- if (itemChildList) XtFree((char*)itemChildList); +- +- /* Go to next sibling item */ +- i++; ++ XtVaSetValues(ih->data->node_cache[i].node_handle, XmNbackground, bgcolor, NULL); + } + } +  +-static void motTreeUpdateImages(Ihandle* ih, WidgetList itemList, int numItems, int mode) ++static void motTreeUpdateImages(Ihandle* ih, int mode) + { +- motTreeItemData *itemData; +- int i = 0; +- ++ int i; + /* called when one of the default images is changed */ +- +- while(i != numItems) ++ for (i = 0; i < ih->data->node_count; i++) + { +- /* Get node attributes */ +- XtVaGetValues(itemList[i], XmNuserData, &itemData, NULL); +-  ++ motTreeItemData *itemData; ++ Widget wItem = ih->data->node_cache[i].node_handle; ++ ++ XtVaGetValues(wItem, XmNuserData, &itemData, NULL); ++ + if (itemData->kind == ITREE_BRANCH) + { + unsigned char itemState; +- XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); ++ XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); +  + if (itemState == XmEXPANDED) + { + if (mode == ITREE_UPDATEIMAGE_EXPANDED) + { +- XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image_expanded!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded: (Pixmap)ih->data->def_image_expanded, NULL); +- XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_expanded_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded_mask: (Pixmap)ih->data->def_image_expanded_mask, NULL); ++ XtVaSetValues(wItem, XmNsmallIconPixmap, (itemData->image_expanded!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded: (Pixmap)ih->data->def_image_expanded, NULL); ++ XtVaSetValues(wItem, XmNsmallIconMask, (itemData->image_expanded_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded_mask: (Pixmap)ih->data->def_image_expanded_mask, NULL); + } + } + else  + { + if (mode == ITREE_UPDATEIMAGE_COLLAPSED) + { +- XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_collapsed, NULL); +- XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_collapsed_mask, NULL); ++ XtVaSetValues(wItem, XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_collapsed, NULL); ++ XtVaSetValues(wItem, XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_collapsed_mask, NULL); + } + } +- +- /* Recursively traverse child items */ +- { +- WidgetList itemChildList; +- int numChild; +- itemChildList = NULL; +- numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); +- motTreeUpdateImages(ih, itemChildList, numChild, mode); +- if (itemChildList) XtFree((char*)itemChildList); +- } + } + else  + { + if (mode == ITREE_UPDATEIMAGE_LEAF) + { +- XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_leaf, NULL); +- XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_leaf_mask, NULL); ++ XtVaSetValues(wItem, XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_leaf, NULL); ++ XtVaSetValues(wItem, XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_leaf_mask, NULL); + } + } +- +- /* Go to next sibling node */ +- i++; + } + } +  +-static int motTreeSelectFunc(Ihandle* ih, Widget wItem, int *select) ++static int motTreeIsNodeSelected(Widget wItem) ++{ ++ unsigned char isSelected; ++ XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); ++ if(isSelected == XmSELECTED) ++ return 1; ++ else ++ return 0; ++} ++ ++static void motTreeSelectNode(Widget wItem, int select) ++{ ++ if (select == -1) ++ select = !motTreeIsNodeSelected(wItem); /* toggle */ ++ ++ if (select) ++ XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); ++ else ++ XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); ++} ++ ++static int motTreeSelectFunc(Ihandle* ih, Widget wItem, int id, int *select) + { + int do_select = *select; + if (do_select == -1) +- { +- unsigned char isSelected; +- XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); +- do_select = (isSelected == XmSELECTED)? 0: 1; /* toggle */ +- } ++ do_select = !motTreeIsNodeSelected(wItem); /* toggle */ +  + if (do_select) + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); +@@ -463,272 +446,111 @@ static int motTreeSelectFunc(Ihandle* ih, Widget wItem, int *select) + XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); +  + (void)ih; ++ (void)id; + return 1; + } +  + static void motTreeInvertAllNodeMarking(Ihandle* ih) + { + int select = -1; +- motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSelectFunc, &select); ++ iupTreeForEach(ih, (iupTreeNodeFunc)motTreeSelectFunc, &select); + } +  +-typedef struct _motTreeRange{ +- Widget wItem1, wItem2; +- char inside, clear; +-}motTreeRange; +- +-static int motTreeSelectRangeFunc(Ihandle* ih, Widget wItem, motTreeRange* range) ++static void motTreeSelectRange(Ihandle* ih, Widget wItem1, Widget wItem2, int clear) + { +- int end_range = 0; +- +- if (range->inside == 0) /* detect the range start */ +- { +- if (range->wItem1 == wItem) range->inside=1; +- else if (range->wItem2 == wItem) range->inside=1; +- } +- else if (range->inside == 1) /* detect the range end */ ++ int i; ++ int id1 = iupTreeFindNodeId(ih, wItem1); ++ int id2 = iupTreeFindNodeId(ih, wItem2); ++ if (id1 > id2) + { +- if (range->wItem1 == wItem) end_range=1; +- else if (range->wItem2 == wItem) end_range=1; ++ int tmp = id1; ++ id1 = id2; ++ id2 = tmp; + } +  +- if (range->inside == 1) /* if inside, select */ +- XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); +- else if (range->clear) /* if outside and clear, unselect */ +- XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); +- +- if (end_range || (range->inside && range->wItem1==range->wItem2)) +- range->inside=-1; /* update after selecting the node */ +- +- (void)ih; +- return 1; +-} +- +-static void motTreeSelectRange(Ihandle* ih, Widget wItem1, Widget wItem2, int clear) +-{ +- motTreeRange range; +- range.wItem1 = wItem1; +- range.wItem2 = wItem2; +- range.inside = 0; +- range.clear = (char)clear; +- motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSelectRangeFunc, &range); +-} +- +-void motTreeExpandCollapseAllNodes(Ihandle* ih, WidgetList itemList, int numItems, unsigned char itemState) +-{ +- WidgetList itemChildList; +- int numChild; +- int i = 0; +- +- while(i != numItems) ++ for (i = 0; i < ih->data->node_count; i++) + { +- /* Check whether we have child items */ +- itemChildList = NULL; +- numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); +- +- if(numChild) ++ if (i < id1 || i > id2) + { +- XtVaSetValues(itemList[i], XmNoutlineState, itemState, NULL); +- motTreeExpandCollapseAllNodes(ih, itemChildList, numChild, itemState); ++ if (clear) ++ XtVaSetValues(ih->data->node_cache[i].node_handle, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + } +- +- if (itemChildList) XtFree((char*)itemChildList); +- /* Go to next sibling item */ +- i++; ++ else ++ XtVaSetValues(ih->data->node_cache[i].node_handle, XmNvisualEmphasis, XmSELECTED, NULL); + } + } +  +-static void motTreeDestroyItemData(Ihandle* ih, Widget wItem) ++void motTreeExpandCollapseAllNodes(Ihandle* ih, unsigned char itemState) + { +- motTreeItemData *itemData = NULL; +- XtVaGetValues(wItem, XmNuserData, &itemData, NULL); +- if (itemData) ++ int i; ++ /* called when one of the default images is changed */ ++ for (i = 0; i < ih->data->node_count; i++) + { +- IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB"); +- if (cb) cb(ih, motTreeGetNodeId(ih, wItem), (char*)itemData->userdata); +- free(itemData); +- XtVaSetValues(wItem, XmNuserData, NULL, NULL); +- } +-} +- +-static void motTreeRemoveChildren(Ihandle* ih, WidgetList itemList, int numItems, int del_userdata) +-{ +- WidgetList itemChildList; +- int numChild; +- int i = 0; ++ motTreeItemData *itemData; ++ Widget wItem = ih->data->node_cache[i].node_handle; +  +- while(i != numItems) +- {  ++ XtVaGetValues(wItem, XmNuserData, &itemData, NULL); ++  + /* Check whether we have child items */ +- itemChildList = NULL; +- numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); +- if (numChild) +- motTreeRemoveChildren(ih, itemChildList, numChild, del_userdata); +- +- if (del_userdata) +- motTreeDestroyItemData(ih, itemList[i]); +- +- XtDestroyWidget(itemList[i]); +- +- if (itemChildList) XtFree((char*)itemChildList); +- /* Go to next sibling item */ +- i++; ++ if (itemData->kind == ITREE_BRANCH) ++ XtVaSetValues(wItem, XmNoutlineState, itemState, NULL); + } + } +  +-static void motTreeRemoveNode(Ihandle* ih, Widget wItem, int del_userdata) ++static void motTreeDestroyItemData(Ihandle* ih, Widget wItem, int del_data, IFns cb, int id) + { +- WidgetList wChildList = NULL; +- int numChild = XmContainerGetItemChildren(ih->handle, wItem, &wChildList); +- if (numChild) +- motTreeRemoveChildren(ih, wChildList, numChild, del_userdata); +- if (del_userdata) +- motTreeDestroyItemData(ih, wItem); +- XtDestroyWidget(wItem); +- if (wChildList) XtFree((char*)wChildList); +-} +- +-static Widget motTreeFindNodeID(Ihandle* ih, WidgetList itemList, int numItems, Widget itemNode) +-{ +- Widget itemChild; +- WidgetList itemChildList; +- int i = 0; +- int numChild; +- +- while(i != numItems) ++ motTreeItemData *itemData = NULL; ++ XtVaGetValues(wItem, XmNuserData, &itemData, NULL); ++ if (itemData) + { +- /* ID control to traverse items */ +- ih->data->id_control++; ++ if (cb)  ++ cb(ih, (char*)ih->data->node_cache[id].userdata); +  +- /* StateID founded! */ +- if(itemList[i] == itemNode) +- return itemList[i]; +- +- /* Check whether we have child items */ +- itemChildList = NULL; +- numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); +- if(numChild) ++ if (del_data) + { +- /* pass the list of children of this item */ +- itemChild = motTreeFindNodeID(ih, itemChildList, numChild, itemNode); +- +- /* StateID founded! */ +- if(itemChild) +- { +- if (itemChildList) XtFree((char*)itemChildList); +- return itemChild; +- } ++ free(itemData); ++ XtVaSetValues(wItem, XmNuserData, NULL, NULL); + } +- +- if (itemChildList) XtFree((char*)itemChildList); +- /* Go to next sibling item */ +- i++; + } +- +- return NULL; + } +  +-static Widget motTreeFindNodeFromID(Ihandle* ih, WidgetList itemList, int numItems) ++static void motTreeRemoveNodeRec(Ihandle* ih, Widget wItem, int del_data, IFns cb, int *id) + { +- Widget itemChild; +- WidgetList itemChildList; +- int i = 0; +- int numChild; ++ WidgetList itemChildList = NULL; ++ int i, numChild; ++ int old_id = *id; +  +- while(i != numItems) ++ /* Check whether we have child items */ ++ /* remove from children first */ ++ numChild = XmContainerGetItemChildren(ih->handle, wItem, &itemChildList); ++ for (i = 0; i < numChild; i++) + { +- /* ID control to traverse items */ +- ih->data->id_control--; +- +- /* StateID founded! */ +- if(ih->data->id_control < 0) +- return itemList[i]; +- +- /* Check whether we have child items */ +- itemChildList = NULL; +- numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); +- if(numChild) +- { +- /* pass the list of children of this item */ +- itemChild = motTreeFindNodeFromID(ih, itemChildList, numChild); +- +- /* StateID founded! */ +- if(ih->data->id_control < 0) +- { +- if (itemChildList) XtFree((char*)itemChildList); +- return itemChild; +- } +- } +- +- if (itemChildList) XtFree((char*)itemChildList); +- /* Go to next sibling item */ +- i++; ++ /* go recursive to children */ ++ motTreeRemoveNodeRec(ih, itemChildList[i], del_data, cb, id); + } ++ if (itemChildList) XtFree((char*)itemChildList); +  +- return NULL; +-} ++ /* actually do it for the node */ ++ ih->data->node_count--; ++ (*id)++; +  +-static int motTreeGetNodeId(Ihandle* ih, Widget wItem) +-{ +- Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); +- ih->data->id_control = -1; +- if (motTreeFindNodeID(ih, &wRoot, 1, wItem)) +- return ih->data->id_control; +- else +- return -1; ++ if (del_data || cb) ++ motTreeDestroyItemData(ih, wItem, del_data, cb, old_id); ++ ++ XtDestroyWidget(wItem); /* must manually destroy each node, this is NOT recursive */ + } +  +-static Widget motTreeFindUserDataID(Ihandle* ih, WidgetList itemList, int numItems, void* userdata) ++static void motTreeRemoveNode(Ihandle* ih, Widget wItem, int del_data, int call_cb) + { +- Widget itemChild; +- WidgetList itemChildList; +- motTreeItemData *itemData; +- int i = 0; +- int numChild; +- +- while(i != numItems) +- { +- /* ID control to traverse items */ +- ih->data->id_control++; +- +- XtVaGetValues(itemList[i], XmNuserData, &itemData, NULL); +- +- /* StateID founded! */ +- if(itemData->userdata == userdata) +- return itemList[i]; ++ IFns cb = call_cb? (IFns)IupGetCallback(ih, "NODEREMOVED_CB"): NULL; ++ int old_count = ih->data->node_count; ++ int id = iupTreeFindNodeId(ih, wItem); ++ int old_id = id; +  +- /* Check whether we have child items */ +- itemChildList = NULL; +- numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); +- if(numChild) +- { +- /* pass the list of children of this item */ +- itemChild = motTreeFindUserDataID(ih, itemChildList, numChild, userdata); +- +- /* StateID founded! */ +- if (itemChild) +- { +- if (itemChildList) XtFree((char*)itemChildList); +- return itemChild; +- } +- } ++ motTreeRemoveNodeRec(ih, wItem, del_data, cb, &id); +  +- if (itemChildList) XtFree((char*)itemChildList); +- /* Go to next sibling item */ +- i++; +- } +- +- return NULL; +-} +- +-static int motTreeGetUserDataId(Ihandle* ih, void* userdata) +-{ +- Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); +- ih->data->id_control = -1; +- if (motTreeFindUserDataID(ih, &wRoot, 1, userdata)) +- return ih->data->id_control; +- else +- return -1; ++ if (call_cb) ++ iupTreeDelFromCache(ih, old_id, old_count-ih->data->node_count); + } +  + static void motTreeSetFocusNode(Ihandle* ih, Widget wItem) +@@ -737,7 +559,7 @@ static void motTreeSetFocusNode(Ihandle* ih, Widget wItem) + XmProcessTraversal(wItem, XmTRAVERSE_CURRENT); + } +  +-static Widget motTreeGetFocusNode(Ihandle* ih) ++Widget iupdrvTreeGetFocusNode(Ihandle* ih) + { + Widget wItem = XmGetFocusWidget(ih->handle); /* returns the focus in the dialog */ + if (wItem && XtParent(wItem) == ih->handle) /* is a node */ +@@ -746,18 +568,6 @@ static Widget motTreeGetFocusNode(Ihandle* ih) + return (Widget)iupAttribGet(ih, "_IUPTREE_LAST_FOCUS"); + } +  +-static Widget motTreeFindNodeFromString(Ihandle* ih, const char* name_id) +-{ +- if (name_id[0]) +- { +- Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); +- iupStrToInt(name_id, &ih->data->id_control); +- return motTreeFindNodeFromID(ih, &wRoot, 1); +- } +- else +- return motTreeGetFocusNode(ih); +-} +- + static void motTreeEnterLeaveWindowEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) + { + if (iupAttribGet(ih, "_IUPTREE_EDITFIELD")) +@@ -812,16 +622,24 @@ static void motTreeFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean +  + void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add) + { +- Widget wItemPrev = motTreeFindNodeFromString(ih, name_id); +- Widget wNewItem; ++ Widget wItemPrev = iupTreeGetNodeFromString(ih, name_id); ++ Widget wItemNew; + XmString itemTitle; +- motTreeItemData *itemData, *itemDataPrev; ++ motTreeItemData *itemData; + Pixel bgcolor, fgcolor; +- int kindPrev, num_args = 0; ++ int kindPrev = 0, num_args = 0; + Arg args[30]; +  + if (!wItemPrev) +- return; ++ { ++ /* check if the root was really specified */ ++ int id = 0; ++ if (!iupStrToInt(name_id, &id) || id != -1) ++ return; ++ } ++ ++ if (!title) ++ title = ""; +  + itemData = calloc(1, sizeof(motTreeItemData)); + itemData->image = XmUNSPECIFIED_PIXMAP; +@@ -836,138 +654,103 @@ void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* t + XtVaGetValues(ih->handle, XmNforeground, &fgcolor, NULL); + XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); +  +- /* Get the kind of previous item */ +- XtVaGetValues(wItemPrev, XmNuserData, &itemDataPrev, NULL); +- kindPrev = itemDataPrev->kind; +- +- if (kindPrev == ITREE_BRANCH && add) ++ if (wItemPrev) + { +- /* wItemPrev is parent of the new item (firstchild of it) */ +- iupmotSetArg(args, num_args, XmNentryParent, wItemPrev); +- iupmotSetArg(args, num_args, XmNpositionIndex, 0); +- } +- else +- { +- /* wItemPrev is sibling of the new item (set its parent to the new item) */ +- Widget wItemParent; +- int pos; ++ motTreeItemData *itemDataPrev; +  +- XtVaGetValues(wItemPrev, XmNentryParent, &wItemParent, NULL); +- XtVaGetValues(wItemPrev, XmNpositionIndex, &pos, NULL); ++ /* Get the kind of previous item */ ++ XtVaGetValues(wItemPrev, XmNuserData, &itemDataPrev, NULL); ++ kindPrev = itemDataPrev->kind; ++ ++ if (kindPrev == ITREE_BRANCH && add) ++ { ++ /* wItemPrev is parent of the new item (firstchild of it) */ ++ iupMOT_SETARG(args, num_args, XmNentryParent, wItemPrev); ++ iupMOT_SETARG(args, num_args, XmNpositionIndex, 0); ++ } ++ else ++ { ++ /* wItemPrev is sibling of the new item (set its parent to the new item) */ ++ Widget wItemParent; ++ int pos; +  +- iupmotSetArg(args, num_args, XmNentryParent, wItemParent); +- iupmotSetArg(args, num_args, XmNpositionIndex, pos+1); ++ XtVaGetValues(wItemPrev, XmNentryParent, &wItemParent, NULL); ++ XtVaGetValues(wItemPrev, XmNpositionIndex, &pos, NULL); ++ ++ iupMOT_SETARG(args, num_args, XmNentryParent, wItemParent); ++ iupMOT_SETARG(args, num_args, XmNpositionIndex, pos+1); ++ } + } +  +- iupmotSetArg(args, num_args, XmNuserData, itemData); +- iupmotSetArg(args, num_args, XmNforeground, fgcolor); +- iupmotSetArg(args, num_args, XmNbackground, bgcolor); +- iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); +- iupmotSetArg(args, num_args, XmNviewType, XmSMALL_ICON); +- iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); +- iupmotSetArg(args, num_args, XmNtraversalOn, True); +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); +- iupmotSetArg(args, num_args, XmNlabelString, itemTitle); ++ iupMOT_SETARG(args, num_args, XmNuserData, itemData); ++ iupMOT_SETARG(args, num_args, XmNforeground, fgcolor); ++ iupMOT_SETARG(args, num_args, XmNbackground, bgcolor); ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, ih->data->spacing); ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNviewType, XmSMALL_ICON); ++ iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNlabelString, itemTitle); +  + if (kind == ITREE_BRANCH) + { + if (ih->data->add_expanded) + { +- iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_expanded); +- iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_expanded_mask); ++ iupMOT_SETARG(args, num_args, XmNsmallIconPixmap, ih->data->def_image_expanded); ++ iupMOT_SETARG(args, num_args, XmNsmallIconMask, ih->data->def_image_expanded_mask); + } + else + { +- iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_collapsed); +- iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_collapsed_mask); ++ iupMOT_SETARG(args, num_args, XmNsmallIconPixmap, ih->data->def_image_collapsed); ++ iupMOT_SETARG(args, num_args, XmNsmallIconMask, ih->data->def_image_collapsed_mask); + } + } + else + { +- iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_leaf); +- iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_leaf_mask); ++ iupMOT_SETARG(args, num_args, XmNsmallIconPixmap, ih->data->def_image_leaf); ++ iupMOT_SETARG(args, num_args, XmNsmallIconMask, ih->data->def_image_leaf_mask); + } +  ++ /* Add the new node */ ++ wItemNew = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); ++ if (wItemPrev) ++ iupTreeAddToCache(ih, add, kindPrev, wItemPrev, wItemNew); ++ else ++ { ++ iupTreeAddToCache(ih, 0, 0, NULL, wItemNew); ++ ++ if (ih->data->node_count == 1) ++ { ++ /* MarkStart node */ ++ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)wItemNew); +  +- wNewItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); ++ /* Set the default VALUE */ ++ motTreeSetFocusNode(ih, wItemNew); ++ } ++ } +  + if (kind == ITREE_BRANCH) + { ++ iupAttribSetStr(ih, "_IUP_IGNORE_BRANCH_CB", "1"); + if (ih->data->add_expanded) +- { +- iupAttribSetStr(ih, "_IUP_IGNORE_BRANCHOPEN", "1"); +- XtVaSetValues(wNewItem, XmNoutlineState, XmEXPANDED, NULL); +- } ++ XtVaSetValues(wItemNew, XmNoutlineState, XmEXPANDED, NULL); + else +- XtVaSetValues(wNewItem, XmNoutlineState, XmCOLLAPSED, NULL); ++ XtVaSetValues(wItemNew, XmNoutlineState, XmCOLLAPSED, NULL); ++ iupAttribSetStr(ih, "_IUP_IGNORE_BRANCH_CB", NULL); + } +  +- /* Root always expanded */ +- XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); +- +- XtRealizeWidget(wNewItem); ++ XtRealizeWidget(wItemNew); + XmStringFree(itemTitle); + } +  +-static void motTreeAddRootNode(Ihandle* ih) +-{ +- Widget wRootItem; +- motTreeItemData *itemData; +- Pixel bgcolor, fgcolor; +- int num_args = 0; +- Arg args[30]; +- +- itemData = calloc(1, sizeof(motTreeItemData)); +- itemData->image = XmUNSPECIFIED_PIXMAP; +- itemData->image_expanded = XmUNSPECIFIED_PIXMAP; +- itemData->image_mask = XmUNSPECIFIED_PIXMAP; +- itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP; +- itemData->kind = ITREE_BRANCH; +- +- /* Get default foreground color */ +- XtVaGetValues(ih->handle, XmNforeground, &fgcolor, NULL); +- XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); +- +- iupmotSetArg(args, num_args, XmNentryParent, NULL); +- iupmotSetArg(args, num_args, XmNuserData, itemData); +- iupmotSetArg(args, num_args, XmNforeground, fgcolor); +- iupmotSetArg(args, num_args, XmNbackground, bgcolor); +- iupmotSetArg(args, num_args, XmNoutlineState, XmEXPANDED); +- iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); +- iupmotSetArg(args, num_args, XmNviewType, XmSMALL_ICON); +- iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); +- iupmotSetArg(args, num_args, XmNtraversalOn, True); +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); +- iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_expanded); +- iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_expanded_mask); +- +- wRootItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); +- +- /* Select the new item */ +- XtVaSetValues(wRootItem, XmNvisualEmphasis, XmSELECTED, NULL); +- +- XtRealizeWidget(wRootItem); +- +- /* Save the root node for later use */ +- iupAttribSetStr(ih, "_IUPTREE_ROOTITEM", (char*)wRootItem); +- +- /* MarkStart node */ +- iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)wRootItem); +- +- /* Set the default VALUE */ +- /* In Motif this will set also the current focus */ +- motTreeSetFocusNode(ih, wRootItem); +-} +- + /*****************************************************************************/ +  + static int motTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const char* value) + { + motTreeItemData *itemData; + unsigned char itemState; +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem) + return 0; +  +@@ -1003,7 +786,7 @@ static int motTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const + static int motTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* value) + { + motTreeItemData *itemData; +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem)  + return 0; +  +@@ -1053,7 +836,6 @@ static int motTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* v +  + static int motTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) + { +- Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->def_image_expanded = iupImageGetImage(value, ih, 0); + if (!ih->data->def_image_expanded)  + { +@@ -1067,14 +849,13 @@ static int motTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) + } +  + /* Update all images, starting at root node */ +- motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_EXPANDED); ++ motTreeUpdateImages(ih, ITREE_UPDATEIMAGE_EXPANDED); +  + return 1; + } +  + static int motTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) + { +- Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->def_image_collapsed = iupImageGetImage(value, ih, 0); + if (!ih->data->def_image_collapsed)  + { +@@ -1088,14 +869,13 @@ static int motTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) + } +  + /* Update all images, starting at root node */ +- motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_COLLAPSED); ++ motTreeUpdateImages(ih, ITREE_UPDATEIMAGE_COLLAPSED); +  + return 1; + } +  + static int motTreeSetImageLeafAttrib(Ihandle* ih, const char* value) + { +- Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->def_image_leaf = iupImageGetImage(value, ih, 0); + if (!ih->data->def_image_leaf)  + { +@@ -1109,7 +889,7 @@ static int motTreeSetImageLeafAttrib(Ihandle* ih, const char* value) + } +  + /* Update all images, starting at root node */ +- motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_LEAF); ++ motTreeUpdateImages(ih, ITREE_UPDATEIMAGE_LEAF); +  + return 1; + } +@@ -1118,7 +898,7 @@ static char* motTreeGetStateAttrib(Ihandle* ih, const char* name_id) + { + int hasChildren; + unsigned char itemState; +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem)  + return 0; +  +@@ -1138,14 +918,21 @@ static char* motTreeGetStateAttrib(Ihandle* ih, const char* name_id) +  + static int motTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value) + { +- Widget wItem = motTreeFindNodeFromString(ih, name_id); +- if (!wItem)  ++ motTreeItemData *itemData; ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); ++ if (!wItem) + return 0; +  +- if (iupStrEqualNoCase(value, "EXPANDED")) +- XtVaSetValues(wItem, XmNoutlineState, XmEXPANDED, NULL); +- else  +- XtVaSetValues(wItem, XmNoutlineState, XmCOLLAPSED, NULL); ++ XtVaGetValues(wItem, XmNuserData, &itemData, NULL); ++ if (itemData->kind == ITREE_BRANCH) ++ { ++ iupAttribSetStr(ih, "_IUP_IGNORE_BRANCH_CB", "1"); ++ if (iupStrEqualNoCase(value, "EXPANDED")) ++ XtVaSetValues(wItem, XmNoutlineState, XmEXPANDED, NULL); ++ else  ++ XtVaSetValues(wItem, XmNoutlineState, XmCOLLAPSED, NULL); ++ iupAttribSetStr(ih, "_IUP_IGNORE_BRANCH_CB", NULL); ++ } +  + return 0; + } +@@ -1155,7 +942,7 @@ static char* motTreeGetColorAttrib(Ihandle* ih, const char* name_id) + unsigned char r, g, b; + Pixel color; + char* str; +- Widget wItem = motTreeFindNodeFromString(ih, name_id);  ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id);  + if (!wItem)  + return NULL; +  +@@ -1170,7 +957,7 @@ static char* motTreeGetColorAttrib(Ihandle* ih, const char* name_id) + static int motTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* value) + { + Pixel color; +- Widget wItem = motTreeFindNodeFromString(ih, name_id);  ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id);  + if (!wItem)  + return 0; +  +@@ -1182,36 +969,33 @@ static int motTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* v +  + static char* motTreeGetDepthAttrib(Ihandle* ih, const char* name_id) + { +- Widget wRoot; +- int dep = 0; +- char* depth; +- Widget wItem = motTreeFindNodeFromString(ih, name_id);  ++ int depth = -1; ++ char* str; ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id);  + if (!wItem)  + return NULL; +  +- wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); +- +- while((wRoot != wItem) && (wItem != NULL)) ++ while(wItem != NULL) + { + XtVaGetValues(wItem, XmNentryParent, &wItem, NULL); +- dep++; ++ depth++; + } +  +- depth = iupStrGetMemory(10); +- sprintf(depth, "%d", dep); +- return depth; ++ str = iupStrGetMemory(10); ++ sprintf(str, "%d", depth); ++ return str; + } +  + static int motTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value) + { + Widget wItemDst, wParent, wItemSrc; +  +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; +- wItemSrc = motTreeFindNodeFromString(ih, name_id); ++ wItemSrc = iupTreeGetNodeFromString(ih, name_id); + if (!wItemSrc) + return 0; +- wItemDst = motTreeFindNodeFromString(ih, value); ++ wItemDst = iupTreeGetNodeFromString(ih, value); + if (!wItemDst) + return 0; +  +@@ -1224,11 +1008,8 @@ static int motTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char + return 0; + } +  +- /* Copying the node and its children to the new position */ +- motTreeCopyNode(ih, wItemSrc, wItemDst, 0); /* not a full copy, preserve user data */ +- +- /* Deleting the node (and its children) inserted into the old position */ +- motTreeRemoveNode(ih, wItemSrc, 0); /* do not delete the user data, we copy the references in CopyNode */ ++ /* Move the node and its children to the new position */ ++ motTreeCopyMoveNode(ih, wItemSrc, wItemDst, 0); +  + return 0; + } +@@ -1237,12 +1018,12 @@ static int motTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char + { + Widget wItemDst, wParent, wItemSrc; +  +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; +- wItemSrc = motTreeFindNodeFromString(ih, name_id); ++ wItemSrc = iupTreeGetNodeFromString(ih, name_id); + if (!wItemSrc) + return 0; +- wItemDst = motTreeFindNodeFromString(ih, value); ++ wItemDst = iupTreeGetNodeFromString(ih, value); + if (!wItemDst) + return 0; +  +@@ -1255,8 +1036,8 @@ static int motTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char + return 0; + } +  +- /* Copying the node and its children to the new position */ +- motTreeCopyNode(ih, wItemSrc, wItemDst, 1); ++ /* Copy the node and its children to the new position */ ++ motTreeCopyMoveNode(ih, wItemSrc, wItemDst, 1); +  + return 0; + } +@@ -1265,7 +1046,7 @@ static char* motTreeGetParentAttrib(Ihandle* ih, const char* name_id) + { + Widget wItemParent; + char* str; +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem)  + return NULL; +  +@@ -1275,7 +1056,7 @@ static char* motTreeGetParentAttrib(Ihandle* ih, const char* name_id) + return NULL; +  + str = iupStrGetMemory(10); +- sprintf(str, "%d", motTreeGetNodeId(ih, wItemParent)); ++ sprintf(str, "%d", iupTreeFindNodeId(ih, wItemParent)); + return str; + } +  +@@ -1283,7 +1064,7 @@ static char* motTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) + { + char* str; + WidgetList wList = NULL; +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem)  + return NULL; +  +@@ -1293,30 +1074,10 @@ static char* motTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) + return str; + } +  +-static int motTreeCount(Ihandle* ih, Widget wItem) +-{ +- WidgetList wList = NULL; +- int i, count = 0; +- int childCount = XmContainerGetItemChildren(ih->handle, wItem, &wList); +- count++; +- for (i=0; idata->node_count) ++ return "0"; /* default VALUE is root */ ++ else ++ return "-1"; ++ } +  + str = iupStrGetMemory(10); +- sprintf(str, "%d", motTreeGetNodeId(ih, wItem)); ++ sprintf(str, "%d", iupTreeFindNodeId(ih, wItem)); ++ return str; ++} ++ ++static char* motTreeGetMarkedNodesAttrib(Ihandle* ih) ++{ ++ char* str; ++ int i; ++ ++ if (ih->data->mark_mode==ITREE_MARK_SINGLE) ++ return NULL; ++ ++ str = iupStrGetMemory(ih->data->node_count+1); ++ ++ for (i=0; idata->node_count; i++) ++ { ++ if (motTreeIsNodeSelected(ih->data->node_cache[i].node_handle)) ++ str[i] = '+'; ++ else ++ str[i] = '-'; ++ } ++ ++ str[ih->data->node_count] = 0; + return str; + } +  ++static int motTreeSetMarkedNodesAttrib(Ihandle* ih, const char* value) ++{ ++ int count, i; ++ ++ if (ih->data->mark_mode==ITREE_MARK_SINGLE || !value) ++ return 0; ++ ++ count = strlen(value); ++ if (count > ih->data->node_count) ++ count = ih->data->node_count; ++ ++ for (i=0; idata->node_cache[i].node_handle, XmNvisualEmphasis, XmSELECTED, NULL); ++ else ++ XtVaSetValues(ih->data->node_cache[i].node_handle, XmNvisualEmphasis, XmNOT_SELECTED, NULL); ++ } ++ ++ return 0; ++} ++ + static int motTreeSetMarkAttrib(Ihandle* ih, const char* value) + { + if (ih->data->mark_mode==ITREE_MARK_SINGLE) +@@ -1353,21 +1163,16 @@ static int motTreeSetMarkAttrib(Ihandle* ih, const char* value) + motTreeInvertAllNodeMarking(ih); + else if(iupStrEqualPartial(value, "INVERT")) + { +- unsigned char isSelected; +- Widget wItem = motTreeFindNodeFromString(ih, &value[strlen("INVERT")]); ++ Widget wItem = iupTreeGetNodeFromString(ih, &value[strlen("INVERT")]); + if (!wItem)  + return 0; +  +- XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); +- if (isSelected == XmSELECTED) +- XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); +- else +- XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); ++ motTreeSelectNode(wItem, -1); + } + else if(iupStrEqualNoCase(value, "BLOCK")) + { + Widget wItem = (Widget)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"); +- Widget wFocusItem = motTreeGetFocusNode(ih); ++ Widget wFocusItem = iupdrvTreeGetFocusNode(ih); + if(!wFocusItem || !wItem) + return 0; + motTreeSelectRange(ih, wFocusItem, wItem, 0); +@@ -1379,10 +1184,10 @@ static int motTreeSetMarkAttrib(Ihandle* ih, const char* value) + if (iupStrToStrStr(value, str1, str2, '-')!=2) + return 0; +  +- wItem1 = motTreeFindNodeFromString(ih, str1); ++ wItem1 = iupTreeGetNodeFromString(ih, str1); + if (!wItem1)  + return 0; +- wItem2 = motTreeFindNodeFromString(ih, str2); ++ wItem2 = iupTreeGetNodeFromString(ih, str2); + if (!wItem2)  + return 0; +  +@@ -1394,69 +1199,49 @@ static int motTreeSetMarkAttrib(Ihandle* ih, const char* value) +  + static int motTreeSetValueAttrib(Ihandle* ih, const char* value) + { +- Widget wRoot, wItem; ++ Widget wItem, wItemParent; +  + if (motTreeSetMarkAttrib(ih, value)) + return 0; +  +- wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); +- +- if (iupStrEqualNoCase(value, "ROOT")) +- wItem = wRoot; ++ if (iupStrEqualNoCase(value, "ROOT") || iupStrEqualNoCase(value, "FIRST")) ++ wItem = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + else if(iupStrEqualNoCase(value, "LAST")) +- wItem = motTreeGetLastVisibleNode(ih, wRoot); ++ wItem = motTreeGetLastVisibleNode(ih); + else if(iupStrEqualNoCase(value, "PGUP")) + { +- Widget wItemFocus = motTreeGetFocusNode(ih); ++ Widget wItemFocus = iupdrvTreeGetFocusNode(ih); + if(!wItemFocus) + return 0; +  +- ih->data->id_control = -1; +- motTreeFindVisibleNodeId(ih, &wRoot, 1, wItemFocus); +- ih->data->id_control -= 10; /* less 10 visible nodes */ +- +- if(ih->data->id_control < 0) +- ih->data->id_control = 0; /* Begin of tree = Root id */ +- +- wItem = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); ++ wItem = motTreeGetPreviousVisibleNode(ih, wItemFocus, 10); + } + else if(iupStrEqualNoCase(value, "PGDN")) + { +- Widget wNext, wItemFocus; +- +- wItemFocus = motTreeGetFocusNode(ih); ++ Widget wItemFocus = iupdrvTreeGetFocusNode(ih); + if(!wItemFocus) + return 0; +  +- ih->data->id_control = -1; +- motTreeFindVisibleNodeId(ih, &wRoot, 1, wItemFocus); +- ih->data->id_control += 10; /* more 10 visible nodes */ +- +- wNext = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); +- +- if (ih->data->id_control >= 0) +- wNext = motTreeGetLastVisibleNode(ih, wRoot); +-  +- wItem = wNext; ++ wItem = motTreeGetNextVisibleNode(ih, wItemFocus, 10); + } + else if(iupStrEqualNoCase(value, "NEXT")) + { +- Widget wItemFocus = motTreeGetFocusNode(ih); ++ Widget wItemFocus = iupdrvTreeGetFocusNode(ih); + if (!wItemFocus) + return 0; +  +- wItem = motTreeGetNextVisibleNode(ih, wRoot, wItemFocus); ++ wItem = motTreeGetNextVisibleNode(ih, wItemFocus, 1); + } + else if(iupStrEqualNoCase(value, "PREVIOUS")) + { +- Widget wItemFocus = motTreeGetFocusNode(ih); ++ Widget wItemFocus = iupdrvTreeGetFocusNode(ih); + if(!wItemFocus) + return 0; +  +- wItem = motTreeGetPreviousVisibleNode(ih, wRoot, wItemFocus); ++ wItem = motTreeGetPreviousVisibleNode(ih, wItemFocus, 1); + } + else +- wItem = motTreeFindNodeFromString(ih, value); ++ wItem = iupTreeGetNodeFromString(ih, value); +  + if (!wItem)  + return 0; +@@ -1471,17 +1256,26 @@ static int motTreeSetValueAttrib(Ihandle* ih, const char* value) + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + } +  ++ ++ /* expand all parents */ ++ XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL); ++ while(wItemParent) ++ { ++ XtVaSetValues(wItemParent, XmNoutlineState, XmEXPANDED, NULL); ++ XtVaGetValues(wItemParent, XmNentryParent, &wItemParent, NULL); ++ } ++ + /* set focus (will scroll to visible) */ + motTreeSetFocusNode(ih, wItem); +  +- iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", motTreeGetNodeId(ih, wItem)); ++ iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", iupTreeFindNodeId(ih, wItem)); +  + return 0; + }  +  + static int motTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) + { +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem)  + return 0; +  +@@ -1492,14 +1286,11 @@ static int motTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) +  + static char* motTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) + { +- unsigned char isSelected; +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem)  + return NULL; +  +- XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); +- +- if(isSelected == XmSELECTED) ++ if (motTreeIsNodeSelected(wItem)) + return "YES"; + else + return "NO"; +@@ -1507,7 +1298,7 @@ static char* motTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) +  + static int motTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value) + { +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem)  + return 0; +  +@@ -1531,7 +1322,7 @@ static char* motTreeGetTitle(Widget wItem) +  + static char* motTreeGetTitleAttrib(Ihandle* ih, const char* name_id) + { +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem)  + return NULL; + return motTreeGetTitle(wItem); +@@ -1539,10 +1330,13 @@ static char* motTreeGetTitleAttrib(Ihandle* ih, const char* name_id) +  + static int motTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value) + { +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem)  + return 0; +  ++ if (!value) ++ value = ""; ++ + iupmotSetString(wItem, XmNlabelString, value); +  + return 0; +@@ -1551,7 +1345,7 @@ static int motTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* v + static int motTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const char* value) + { + XmFontList fontlist = NULL; +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem)  + return 0; +  +@@ -1569,7 +1363,7 @@ static int motTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const cha + static char* motTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) + { + XmFontList fontlist; +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem)  + return NULL; +  +@@ -1577,118 +1371,81 @@ static char* motTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) + return iupmotFindFontList(fontlist); + } +  +-static char* motTreeGetFindUserDataAttrib(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 = motTreeGetUserDataId(ih, userdata); +- if (id == -1) +- return NULL; +- str = iupStrGetMemory(16); +- sprintf(str, "%d", id); +- return str; +-} +- +-static char* motTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) +-{ +- motTreeItemData *itemData; +- Widget wItem = motTreeFindNodeFromString(ih, name_id); +- if (!wItem)  +- return NULL; +- +- XtVaGetValues(wItem, XmNuserData, &itemData, NULL); +- +- return itemData->userdata; +-} +- +-static int motTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) +-{ +- motTreeItemData *itemData; +- Widget wItem = motTreeFindNodeFromString(ih, name_id); +- if (!wItem)  +- return 0; +- +- XtVaGetValues(wItem, XmNuserData, &itemData, NULL); +- itemData->userdata = (void*)value; +- +- return 0; +-} +- + static int motTreeSetRenameAttrib(Ihandle* ih, const char* value) + {  + if (ih->data->show_rename) + { +- IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); +- Widget wItemFocus = motTreeGetFocusNode(ih); +- if (cbShowRename) +- cbShowRename(ih, motTreeGetNodeId(ih, wItemFocus)); ++ Widget wItemFocus = iupdrvTreeGetFocusNode(ih); + motTreeShowEditField(ih, wItemFocus); + } +- else +- { +- IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB"); +- if (cbRenameNode) +- { +- Widget wItemFocus = motTreeGetFocusNode(ih); +- cbRenameNode(ih, motTreeGetNodeId(ih, wItemFocus), motTreeGetTitle(wItemFocus));  +- } +- } +  + (void)value; + return 0; + } +  ++static void motTreeRemoveAllNodes(Ihandle* ih, int call_cb) ++{ ++ IFns cb = call_cb? (IFns)IupGetCallback(ih, "NODEREMOVED_CB"): NULL; ++ int i, old_count = ih->data->node_count; ++ Widget wItem; ++ ++ for (i = 0; i < ih->data->node_count; i++) ++ { ++ wItem = ih->data->node_cache[i].node_handle; ++ ++ motTreeDestroyItemData(ih, wItem, 1, cb, i); ++ ++ XtDestroyWidget(wItem); /* must manually destroy each node, this is NOT recursive */ ++ } ++ ++ ih->data->node_count = 0; ++ ++ if (call_cb) ++ iupTreeDelFromCache(ih, 0, old_count); ++} ++ + static int motTreeSetDelNodeAttrib(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; +- if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */ ++ if (iupStrEqualNoCase(value, "ALL")) + { +- Widget wItem = motTreeFindNodeFromString(ih, name_id); +- Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); +- +- /* the root node can't be deleted */ +- if(!wItem || wItem == wRoot) /* root is the unique child */ ++ motTreeRemoveAllNodes(ih, 1); ++ return 0; ++ } ++ if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the reference node */ ++ { ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); ++ if(!wItem) + return 0; +  +- /* deleting the specified node (and it's children) */ +- motTreeRemoveNode(ih, wItem, 1); ++ /* deleting the reference node (and it's children) */ ++ motTreeRemoveNode(ih, wItem, 1, 1); + } +- else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */ ++ else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the reference node */ + { +- Widget wItem = motTreeFindNodeFromString(ih, name_id); ++ int numChild, i; ++ WidgetList wItemList = NULL; ++ Widget wItem = iupTreeGetNodeFromString(ih, name_id); +  + if(!wItem) + return 0; +  +- { +- /* deleting the selected node's children only */ +- WidgetList wItemList = NULL; +- int numChild = XmContainerGetItemChildren(ih->handle, wItem, &wItemList); +- if(numChild) +- motTreeRemoveChildren(ih, wItemList, numChild, 1); +- if (wItemList) XtFree((char*)wItemList); +- } ++ /* deleting the reference node children only */ ++ numChild = XmContainerGetItemChildren(ih->handle, wItem, &wItemList); ++ for(i = 0; i < numChild; i++) ++ motTreeRemoveNode(ih, wItemList[i], 1, 1); ++ if (wItemList) XtFree((char*)wItemList); + } + else if(iupStrEqualNoCase(value, "MARKED")) /* Delete the array of marked nodes */ + { +- WidgetList wSelectedItemList = NULL; +- Widget wRoot; +- int countItems, i; +- +- XtVaGetValues(ih->handle, XmNselectedObjects, &wSelectedItemList, +- XmNselectedObjectCount, &countItems, NULL); +- +- wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); +- +- for(i = 0; i < countItems; i++) ++ int i; ++ for(i = 1; i < ih->data->node_count; /* increment only if not removed */) + { +- int ok = XmIsIconGadget(wSelectedItemList[i]); +- if ((wSelectedItemList[i] != wRoot) && ok) /* the root node can't be deleted */ +- motTreeRemoveNode(ih, wSelectedItemList[i], 1); ++ if (motTreeIsNodeSelected(ih->data->node_cache[i].node_handle)) ++ motTreeRemoveNode(ih, ih->data->node_cache[i].node_handle, 1, 1); ++ else ++ i++; + } + } +  +@@ -1714,7 +1471,7 @@ static int motTreeSetIndentationAttrib(Ihandle* ih, const char* value) +  + static int motTreeSetTopItemAttrib(Ihandle* ih, const char* value) + { +- Widget wItem = motTreeFindNodeFromString(ih, value); ++ Widget wItem = iupTreeGetNodeFromString(ih, value); + Widget sb_win; + Widget wItemParent; +  +@@ -1735,10 +1492,11 @@ static int motTreeSetTopItemAttrib(Ihandle* ih, const char* value) + return 0; + } +  +-static int motTreeSpacingFunc(Ihandle* ih, Widget wItem, void *data) ++static int motTreeSpacingFunc(Ihandle* ih, Widget wItem, int id, void *data) + { + XtVaSetValues(wItem, XmNmarginHeight, ih->data->spacing, NULL); + (void)data; ++ (void)id; + return 1; + } +  +@@ -1752,7 +1510,7 @@ static int motTreeSetSpacingAttrib(Ihandle* ih, const char* value) +  + if (ih->handle) + { +- motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSpacingFunc, 0); ++ iupTreeForEach(ih, (iupTreeNodeFunc)motTreeSpacingFunc, 0); + return 0; + } + else +@@ -1761,17 +1519,10 @@ static int motTreeSetSpacingAttrib(Ihandle* ih, const char* value) +  + static int motTreeSetExpandAllAttrib(Ihandle* ih, const char* value) + { +- Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); +- + if (iupStrBoolean(value)) +- motTreeExpandCollapseAllNodes(ih, &wRoot, 1, XmEXPANDED); ++ motTreeExpandCollapseAllNodes(ih, XmEXPANDED); + else +- { +- motTreeExpandCollapseAllNodes(ih, &wRoot, 1, XmCOLLAPSED); +- +- /* The root node is always expanded */ +- XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); +- } ++ motTreeExpandCollapseAllNodes(ih, XmCOLLAPSED); +  + return 0; + } +@@ -1801,16 +1552,13 @@ static int motTreeSetBgColorAttrib(Ihandle* ih, const char* value) + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { +- Widget wRoot; + Widget clipwin = NULL; +  + XtVaGetValues(sb_win, XmNclipWindow, &clipwin, NULL); + if (clipwin) iupmotSetBgColor(clipwin, color); +  +- wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); +-  + /* Update all children, starting at root node */ +- motTreeUpdateBgColor(ih, &wRoot, 1, color); ++ motTreeUpdateBgColor(ih, color); + } +  + iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */ +@@ -1871,10 +1619,14 @@ static void motTreeSetRenameSelectionPos(Widget cbEdit, const char* value) +  + static int motTreeCallBranchCloseCb(Ihandle* ih, Widget wItem) + { +- IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); ++ IFni cbBranchClose; ++ ++ if (iupAttribGet(ih, "_IUP_IGNORE_BRANCH_CB")) ++ return IUP_DEFAULT; +  +- if(cbBranchClose) +- return cbBranchClose(ih, motTreeGetNodeId(ih, wItem)); ++ cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); ++ if (cbBranchClose) ++ return cbBranchClose(ih, iupTreeFindNodeId(ih, wItem)); +  + return IUP_DEFAULT; + } +@@ -1883,59 +1635,136 @@ static int motTreeCallBranchOpenCb(Ihandle* ih, Widget wItem) + { + IFni cbBranchOpen; +  +- if (iupAttribGet(ih, "_IUP_IGNORE_BRANCHOPEN")) +- { +- iupAttribSetStr(ih, "_IUP_IGNORE_BRANCHOPEN", NULL); ++ if (iupAttribGet(ih, "_IUP_IGNORE_BRANCH_CB")) + return IUP_DEFAULT; +- } +  + cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB"); + if (cbBranchOpen) +- return cbBranchOpen(ih, motTreeGetNodeId(ih, wItem)); ++ return cbBranchOpen(ih, iupTreeFindNodeId(ih, wItem)); +  + return IUP_DEFAULT; + } +  ++static void motTreeFindRange(Ihandle* ih, WidgetList wSelectedItemList, int countItems, int *id1, int *id2) ++{ ++ int i = 0, id; ++ ++ *id1 = ih->data->node_count; ++ *id2 = -1; ++ ++ for(i = 0; i < countItems; i++) ++ { ++ int is_icon = XmIsIconGadget(wSelectedItemList[i]); /* this line generates a warning in some compilers */ ++ if (is_icon) ++ { ++ id = iupTreeFindNodeId(ih, wSelectedItemList[i]); ++ if (id < *id1) ++ *id1 = id; ++ if (id > *id2) ++ *id2 = id; ++ } ++ } ++ ++ /* interactive selection of several nodes will NOT select hidden nodes, ++ so make sure that they are selected. */ ++ for(i = *id1; i <= *id2; i++) ++ { ++ if (!motTreeIsNodeSelected(ih->data->node_cache[i].node_handle)) ++ XtVaSetValues(ih->data->node_cache[i].node_handle, XmNvisualEmphasis, XmSELECTED, NULL); ++ } ++ ++ /* if last selected item is a branch, then select its children */ ++ iupTreeSelectLastCollapsedBranch(ih, id2); ++} ++ ++static Iarray* motTreeGetSelectedArrayId(Ihandle* ih, WidgetList wSelectedItemList, int countItems) ++{ ++ Iarray* selarray = iupArrayCreate(1, sizeof(int)); ++ int i; ++ ++ for(i = 0; i < countItems; i++) ++ { ++ int is_icon = XmIsIconGadget(wSelectedItemList[i]); /* this line generates a warning in some compilers */ ++ if (is_icon) ++ { ++ int* id_hitem = (int*)iupArrayInc(selarray); ++ int j = iupArrayCount(selarray); ++ id_hitem[j-1] = iupTreeFindNodeId(ih, wSelectedItemList[i]); ++ } ++ } ++ ++ return selarray; ++} ++ ++static void motTreeCallMultiUnSelectionCb(Ihandle* ih) ++{ ++ IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTIUNSELECTION_CB"); ++ IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); ++ if (cbSelec || cbMulti) ++ { ++ WidgetList wSelectedItemList = NULL; ++ int countItems = 0; ++ ++ XtVaGetValues(ih->handle, XmNselectedObjects, &wSelectedItemList, ++ XmNselectedObjectCount, &countItems, NULL); ++ if (countItems > 1) ++ { ++ Iarray* markedArray = motTreeGetSelectedArrayId(ih, wSelectedItemList, countItems); ++ int* id_hitem = (int*)iupArrayGetData(markedArray); ++ int i, count = iupArrayCount(markedArray); ++ ++ if (cbMulti) ++ cbMulti(ih, id_hitem, iupArrayCount(markedArray)); ++ else ++ { ++ for (i=0; ihandle, XmNselectedObjects, &wSelectedItemList, + XmNselectedObjectCount, &countItems, NULL); + if (countItems == 0) + return; +  +- if (cbMulti || cbSelec) ++ /* Must be a continuous range of selection ids */ ++ motTreeFindRange(ih, wSelectedItemList, countItems, &id1, &id2); ++ countItems = id2-id1+1; ++ ++ if (cbMulti) + { + int* id_rowItem = malloc(sizeof(int) * countItems); +- int i = 0; +  + for(i = 0; i < countItems; i++) +- id_rowItem[i] = motTreeGetNodeId(ih, wSelectedItemList[i]); ++ id_rowItem[i] = id1+i; +  +- if (cbMulti) +- cbMulti(ih, id_rowItem, countItems); +- else +- { +- for (i=0; ihandle, (Position)x, (Position)y); + if (wItem) +- return motTreeGetNodeId(ih, wItem); ++ return iupTreeFindNodeId(ih, wItem); + return -1; + } +  +@@ -1965,7 +1794,7 @@ static void motTreeCallRenameCb(Ihandle* ih) + cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); + if (cbRename) + { +- if (cbRename(ih, motTreeGetNodeId(ih, wItem), title) == IUP_IGNORE) ++ if (cbRename(ih, iupTreeFindNodeId(ih, wItem), title) == IUP_IGNORE) + ignore = 1; + } +  +@@ -1993,8 +1822,8 @@ static int motTreeCallDragDropCb(Ihandle* ih, Widget wItemDrag, Widget wItemDrop +  + if (cbDragDrop) + { +- int drag_id = motTreeGetNodeId(ih, wItemDrag); +- int drop_id = motTreeGetNodeId(ih, wItemDrop); ++ int drag_id = iupTreeFindNodeId(ih, wItemDrag); ++ int drop_id = iupTreeFindNodeId(ih, wItemDrop); + return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl); + } +  +@@ -2069,6 +1898,10 @@ static void motTreeShowEditField(Ihandle* ih, Widget wItem) + XmFontList fontlist; + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); +  ++ IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); ++ if (cbShowRename && cbShowRename(ih, iupTreeFindNodeId(ih, wItem))==IUP_IGNORE) ++ return; ++ + XtVaGetValues(wItem, XmNx, &x,  + XmNy, &y, + XmNwidth, &w,  +@@ -2083,16 +1916,16 @@ static void motTreeShowEditField(Ihandle* ih, Widget wItem) + iupdrvImageGetInfo((void*)image, &w_img, NULL, NULL); + w_img += 3; /* add some room for borders */ +  +- iupmotSetArg(args, num_args, XmNx, x+w_img); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, y); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, w-w_img); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, h); /* default height to avoid 0 */ +- iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); /* default padding */ +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); +- iupmotSetArg(args, num_args, XmNforeground, color); +- iupmotSetArg(args, num_args, XmNrenderTable, fontlist); +- iupmotSetArg(args, num_args, XmNvalue, iupmotConvertString(title)); +- iupmotSetArg(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNx, x+w_img); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, y); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, w-w_img); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, h); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, ih->data->spacing); /* default padding */ ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNforeground, color); ++ iupMOT_SETARG(args, num_args, XmNrenderTable, fontlist); ++ iupMOT_SETARG(args, num_args, XmNvalue, iupmotConvertString(title)); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); +  + cbEdit = XtCreateManagedWidget( + child_id, /* child identifier */ +@@ -2134,8 +1967,6 @@ static void motTreeSelectionCallback(Widget w, Ihandle* ih, XmContainerSelectCal + (void)w; + (void)nptr; +  +-printf("SelectionCallback(%d)\n", nptr->selected_item_count); +- + if (ih->data->mark_mode == ITREE_MARK_MULTIPLE) + { + char key[5]; +@@ -2149,11 +1980,13 @@ printf("SelectionCallback(%d)\n", nptr->selected_item_count); + { + if (IupGetCallback(ih, "MULTISELECTION_CB")) + { ++ /* current selection same as the initial selection */ + if (nptr->auto_selection_type==XmAUTO_NO_CHANGE) + motTreeCallMultiSelectionCb(ih); + } + else + { ++ /* current selection is caused by button drag */ + if (nptr->auto_selection_type==XmAUTO_MOTION) + motTreeCallMultiSelectionCb(ih); + } +@@ -2164,14 +1997,10 @@ printf("SelectionCallback(%d)\n", nptr->selected_item_count); + cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbSelec) + { +- Widget wItemFocus = motTreeGetFocusNode(ih); +- int curpos = motTreeGetNodeId(ih, wItemFocus); ++ Widget wItemFocus = iupdrvTreeGetFocusNode(ih); ++ int curpos = iupTreeFindNodeId(ih, wItemFocus); + if (is_ctrl)  +- { +- unsigned char isSelected; +- XtVaGetValues(wItemFocus, XmNvisualEmphasis, &isSelected, NULL); +- cbSelec(ih, curpos, isSelected == XmSELECTED? 1: 0); +- } ++ cbSelec(ih, curpos, motTreeIsNodeSelected(wItemFocus)); + else + { + int oldpos = iupAttribGetInt(ih, "_IUPTREE_OLDVALUE"); +@@ -2218,7 +2047,7 @@ static void motTreeDefaultActionCallback(Widget w, Ihandle* ih, XmContainerSelec + { + IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); + if (cbExecuteLeaf) +- cbExecuteLeaf(ih, motTreeGetNodeId(ih, wItem)); ++ cbExecuteLeaf(ih, iupTreeFindNodeId(ih, wItem)); + } + } +  +@@ -2295,15 +2124,14 @@ static void motTreeKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean + iupmotHelpCallback(w, ih, NULL); + else if ((motcode == XK_Down || motcode == XK_Up) && (evt->state & ControlMask)) + { +- Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + Widget wItem; +- Widget wItemFocus = motTreeGetFocusNode(ih); ++ Widget wItemFocus = iupdrvTreeGetFocusNode(ih); +  + /* Ctrl+Arrows move only focus */ + if (motcode == XK_Down) +- wItem = motTreeGetNextVisibleNode(ih, wRoot, wItemFocus); ++ wItem = motTreeGetNextVisibleNode(ih, wItemFocus, 1); + else +- wItem = motTreeGetPreviousVisibleNode(ih, wRoot, wItemFocus); ++ wItem = motTreeGetPreviousVisibleNode(ih, wItemFocus, 1); +  + motTreeSetFocusNode(ih, wItem); + *cont = False; +@@ -2317,8 +2145,8 @@ static void motTreeKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean +  + if (motcode == XK_Home) + wItem = wRoot; +- else +- wItem = motTreeGetLastVisibleNode(ih, wRoot); ++ else /* motcode == XK_End */ ++ wItem = motTreeGetLastVisibleNode(ih); +  + /* Ctrl+Arrows move only focus */ + if (!(evt->state & ControlMask)) +@@ -2326,7 +2154,7 @@ static void motTreeKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean + /* Shift+Arrows select block */ + if (evt->state & ShiftMask) + { +- Widget wItemFocus = motTreeGetFocusNode(ih); ++ Widget wItemFocus = iupdrvTreeGetFocusNode(ih); + if (!wItemFocus) + return; + motTreeSelectRange(ih, wItemFocus, wItem, 1); +@@ -2346,16 +2174,9 @@ static void motTreeKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean + } + else if(motcode == XK_space && (evt->state & ControlMask)) + { +- Widget wItemFocus = motTreeGetFocusNode(ih); ++ Widget wItemFocus = iupdrvTreeGetFocusNode(ih); + if (wItemFocus) +- { +- unsigned char isSelected; +- XtVaGetValues(wItemFocus, XmNvisualEmphasis, &isSelected, NULL); +- if (isSelected == XmSELECTED) +- XtVaSetValues(wItemFocus, XmNvisualEmphasis, XmNOT_SELECTED, NULL); +- else +- XtVaSetValues(wItemFocus, XmNvisualEmphasis, XmSELECTED, NULL); +- } ++ motTreeSelectNode(wItemFocus, -1); + } + } +  +@@ -2378,7 +2199,7 @@ static void motTreeButtonEvent(Widget w, Ihandle* ih, XButtonEvent* evt, Boolean +  + if (evt->button==Button1) + { +- Widget wItemFocus = motTreeGetFocusNode(ih); ++ Widget wItemFocus = iupdrvTreeGetFocusNode(ih); + static Widget wLastItem = NULL; + static Time last = 0; + int clicktwice = 0, doubleclicktime = XtGetMultiClickTime(iupmot_display); +@@ -2395,6 +2216,11 @@ static void motTreeButtonEvent(Widget w, Ihandle* ih, XButtonEvent* evt, Boolean + *cont = False; + } + wLastItem = wItemFocus; ++ ++ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE &&  ++ !(evt->state & ShiftMask) && ++ !(evt->state & ControlMask)) ++ motTreeCallMultiUnSelectionCb(ih); + } + else if (evt->button==Button3) + motTreeCallRightClickCb(ih, evt->x, evt->y); +@@ -2436,21 +2262,18 @@ static void motTreeTransferProc(Widget drop_context, XtPointer client_data, Atom +  + if (motTreeCallDragDropCb(ih, wItemDrag, wItemDrop, &is_ctrl) == IUP_CONTINUE) + { +- /* Copy the dragged item to the new position. */ +- Widget wNewItem = motTreeCopyNode(ih, wItemDrag, wItemDrop, is_ctrl); ++ /* Copy or move the dragged item to the new position. */ ++ Widget wItemNew = motTreeCopyMoveNode(ih, wItemDrag, wItemDrop, is_ctrl); +  +- if (!is_ctrl) ++ /* Set focus and selection */ ++ if (wItemNew) + { +- /* do not delete the user data, we copy the references in CopyNode */ +- motTreeRemoveNode(ih, wItemDrag, 0); +- } +- +- /* Select the dragged item */ +- XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); +- XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); +- XtVaSetValues(wNewItem, XmNvisualEmphasis, XmSELECTED, NULL); ++ XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); ++ XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); ++ XtVaSetValues(wItemNew, XmNvisualEmphasis, XmSELECTED, NULL); +  +- motTreeSetFocusNode(ih, wNewItem); ++ motTreeSetFocusNode(ih, wItemNew); ++ } + } + } +  +@@ -2475,8 +2298,8 @@ static void motTreeDropProc(Widget w, XtPointer client_data, XmDropProcCallbackS + drop_context = drop_data->dragContext; +  + /* retrieve the data targets */ +- iupmotSetArg(args, num_args, XmNexportTargets, &exportTargets); +- iupmotSetArg(args, num_args, XmNnumExportTargets, &numExportTargets); ++ iupMOT_SETARG(args, num_args, XmNexportTargets, &exportTargets); ++ iupMOT_SETARG(args, num_args, XmNnumExportTargets, &numExportTargets); + XtGetValues(drop_context, args, num_args); +  + for (i = 0; i < (int)numExportTargets; i++)  +@@ -2495,17 +2318,17 @@ static void motTreeDropProc(Widget w, XtPointer client_data, XmDropProcCallbackS + num_args = 0; + if ((!found) || (drop_data->dropAction != XmDROP) || (drop_data->operation != XmDROP_COPY && drop_data->operation != XmDROP_MOVE))  + { +- iupmotSetArg(args, num_args, XmNtransferStatus, XmTRANSFER_FAILURE); +- iupmotSetArg(args, num_args, XmNnumDropTransfers, 0); ++ iupMOT_SETARG(args, num_args, XmNtransferStatus, XmTRANSFER_FAILURE); ++ iupMOT_SETARG(args, num_args, XmNnumDropTransfers, 0); + } + else  + { + /* set up transfer requests for drop site */ + transferList[0].target = atomTreeItem; + transferList[0].client_data = (XtPointer)wItemDrop; +- iupmotSetArg(args, num_args, XmNdropTransfers, transferList); +- iupmotSetArg(args, num_args, XmNnumDropTransfers, 1); +- iupmotSetArg(args, num_args, XmNtransferProc, motTreeTransferProc); ++ iupMOT_SETARG(args, num_args, XmNdropTransfers, transferList); ++ iupMOT_SETARG(args, num_args, XmNnumDropTransfers, 1); ++ iupMOT_SETARG(args, num_args, XmNtransferProc, motTreeTransferProc); + } +  + XmDropTransferStart(drop_context, args, num_args); +@@ -2584,23 +2407,23 @@ static void motTreeStartDrag(Widget w, XButtonEvent* evt, String* params, Cardin + XmNforeground, &fg, + NULL); +  +- iupmotSetArg(args, num_args, XmNpixmap, pixmap); +- iupmotSetArg(args, num_args, XmNmask, mask); ++ iupMOT_SETARG(args, num_args, XmNpixmap, pixmap); ++ iupMOT_SETARG(args, num_args, XmNmask, mask); + drag_icon = XmCreateDragIcon(w, "drag_icon", args, num_args); +  + exportList[0] = atomTreeItem; +  + /* specify resources for DragContext for the transfer */ + num_args = 0; +- iupmotSetArg(args, num_args, XmNcursorBackground, bg); +- iupmotSetArg(args, num_args, XmNcursorForeground, fg); +- /* iupmotSetArg(args, num_args, XmNsourcePixmapIcon, drag_icon); works, but only outside the dialog, inside disapears */ +- iupmotSetArg(args, num_args, XmNsourceCursorIcon, drag_icon); /* does not work, shows the default cursor */ +- iupmotSetArg(args, num_args, XmNexportTargets, exportList); +- iupmotSetArg(args, num_args, XmNnumExportTargets, 1); +- iupmotSetArg(args, num_args, XmNdragOperations, XmDROP_MOVE|XmDROP_COPY); +- iupmotSetArg(args, num_args, XmNconvertProc, motTreeConvertProc); +- iupmotSetArg(args, num_args, XmNclientData, wItemDrag); ++ iupMOT_SETARG(args, num_args, XmNcursorBackground, bg); ++ iupMOT_SETARG(args, num_args, XmNcursorForeground, fg); ++ /* iupMOT_SETARG(args, num_args, XmNsourcePixmapIcon, drag_icon); works, but only outside the dialog, inside disapears */ ++ iupMOT_SETARG(args, num_args, XmNsourceCursorIcon, drag_icon); /* does not work, shows the default cursor */ ++ iupMOT_SETARG(args, num_args, XmNexportTargets, exportList); ++ iupMOT_SETARG(args, num_args, XmNnumExportTargets, 1); ++ iupMOT_SETARG(args, num_args, XmNdragOperations, XmDROP_MOVE|XmDROP_COPY); ++ iupMOT_SETARG(args, num_args, XmNconvertProc, motTreeConvertProc); ++ iupMOT_SETARG(args, num_args, XmNclientData, wItemDrag); +  + /* start the drag and register a callback to clean up when done */ + drop_context = XmDragStart(w, (XEvent*)evt, args, num_args); +@@ -2628,10 +2451,10 @@ static void motTreeEnableDragDrop(Widget w) + XtOverrideTranslations(w, XtParseTranslationTable(dragTranslations)); +  + importList[0] = atomTreeItem; +- iupmotSetArg(args, num_args, XmNimportTargets, importList); +- iupmotSetArg(args, num_args, XmNnumImportTargets, 1); +- iupmotSetArg(args, num_args, XmNdropSiteOperations, XmDROP_MOVE|XmDROP_COPY); +- iupmotSetArg(args, num_args, XmNdropProc, motTreeDropProc); ++ iupMOT_SETARG(args, num_args, XmNimportTargets, importList); ++ iupMOT_SETARG(args, num_args, XmNnumImportTargets, 1); ++ iupMOT_SETARG(args, num_args, XmNdropSiteOperations, XmDROP_MOVE|XmDROP_COPY); ++ iupMOT_SETARG(args, num_args, XmNdropProc, motTreeDropProc); + XmDropSiteUpdate(w, args, num_args); +  + XtVaSetValues(XmGetXmDisplay(iupmot_display), XmNenableDragIcon, True, NULL); +@@ -2648,13 +2471,13 @@ static int motTreeMapMethod(Ihandle* ih) + /******************************/ + /* Create the scrolled window */ + /******************************/ +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAUTOMATIC); +- iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE);  +- iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); +- iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ +- iupmotSetArg(args, num_args, XmNborderWidth, 0); +- iupmotSetArg(args, num_args, XmNshadowThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNscrollingPolicy, XmAUTOMATIC); ++ iupMOT_SETARG(args, num_args, XmNvisualPolicy, XmVARIABLE);  ++ iupMOT_SETARG(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); ++ iupMOT_SETARG(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ ++ iupMOT_SETARG(args, num_args, XmNborderWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); +  + sb_win = XtCreateManagedWidget( + child_id, /* child identifier */ +@@ -2672,37 +2495,37 @@ static int motTreeMapMethod(Ihandle* ih) +  + num_args = 0; +  +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ +  +- iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ +- iupmotSetArg(args, num_args, XmNmarginWidth, 0); ++ iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ ++ iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); +  + if (iupAttribGetBoolean(ih, "CANFOCUS")) +- iupmotSetArg(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); + else +- iupmotSetArg(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); +  +- iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); +- iupmotSetArg(args, num_args, XmNhighlightThickness, 2); +- iupmotSetArg(args, num_args, XmNshadowThickness, 0); ++ iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); ++ iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); +  +- iupmotSetArg(args, num_args, XmNlayoutType, XmOUTLINE); +- iupmotSetArg(args, num_args, XmNentryViewType, XmSMALL_ICON); +- iupmotSetArg(args, num_args, XmNselectionPolicy, XmSINGLE_SELECT); +- iupmotSetArg(args, num_args, XmNoutlineIndentation, 20); ++ iupMOT_SETARG(args, num_args, XmNlayoutType, XmOUTLINE); ++ iupMOT_SETARG(args, num_args, XmNentryViewType, XmSMALL_ICON); ++ iupMOT_SETARG(args, num_args, XmNselectionPolicy, XmSINGLE_SELECT); ++ iupMOT_SETARG(args, num_args, XmNoutlineIndentation, 20); +  + if (iupAttribGetBoolean(ih, "HIDELINES")) +- iupmotSetArg(args, num_args, XmNoutlineLineStyle, XmNO_LINE); ++ iupMOT_SETARG(args, num_args, XmNoutlineLineStyle, XmNO_LINE); + else +- iupmotSetArg(args, num_args, XmNoutlineLineStyle, XmSINGLE); ++ iupMOT_SETARG(args, num_args, XmNoutlineLineStyle, XmSINGLE); +  + if (iupAttribGetBoolean(ih, "HIDEBUTTONS")) +- iupmotSetArg(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_ABSENT); ++ iupMOT_SETARG(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_ABSENT); + else +- iupmotSetArg(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_PRESENT); ++ iupMOT_SETARG(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_PRESENT); +  + ih->handle = XtCreateManagedWidget( + child_id, /* child identifier */ +@@ -2788,17 +2611,30 @@ static int motTreeMapMethod(Ihandle* ih) + if (!ih->data->def_image_expanded_mask) ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP; + } +  +- motTreeAddRootNode(ih); ++ if (iupAttribGetInt(ih, "ADDROOT")) ++ iupdrvTreeAddNode(ih, "-1", ITREE_BRANCH, "", 0); +  + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)motTreeConvertXYToPos); +  ++ iupdrvTreeUpdateMarkMode(ih); ++ + return IUP_NOERROR; + } +  ++static void motTreeUnMapMethod(Ihandle* ih) ++{ ++ motTreeRemoveAllNodes(ih, 0); ++ ++ ih->data->node_count = 0; ++ ++ iupdrvBaseUnMapMethod(ih); ++} ++ + void iupdrvTreeInitClass(Iclass* ic) + { + /* Driver Dependent Class functions */ + ic->Map = motTreeMapMethod; ++ ic->UnMap = motTreeUnMapMethod; +  + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motTreeSetBgColorAttrib, "TXTBGCOLOR", NULL, IUPAF_DEFAULT); +@@ -2807,7 +2643,6 @@ void iupdrvTreeInitClass(Iclass* ic) + /* IupTree Attributes - GENERAL */ + iupClassRegisterAttribute(ic, "EXPANDALL", NULL, motTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY||IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INDENTATION", motTreeGetIndentationAttrib, motTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT); +- iupClassRegisterAttribute(ic, "COUNT", motTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, motTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, motTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); +  +@@ -2827,7 +2662,6 @@ void iupdrvTreeInitClass(Iclass* ic) + iupClassRegisterAttributeId(ic, "COLOR", motTreeGetColorAttrib, motTreeSetColorAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "NAME", motTreeGetTitleAttrib, motTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLE", motTreeGetTitleAttrib, motTreeSetTitleAttrib, IUPAF_NO_INHERIT); +- iupClassRegisterAttributeId(ic, "USERDATA", motTreeGetUserDataAttrib, motTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "CHILDCOUNT", motTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLEFONT", motTreeGetTitleFontAttrib, motTreeSetTitleFontAttrib, IUPAF_NO_INHERIT); +  +@@ -2836,6 +2670,7 @@ void iupdrvTreeInitClass(Iclass* ic) + iupClassRegisterAttribute (ic, "MARK", NULL, motTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "STARTING", NULL, motTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARKSTART", NULL, motTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); ++ iupClassRegisterAttribute (ic, "MARKEDNODES", motTreeGetMarkedNodesAttrib, motTreeSetMarkedNodesAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +  + iupClassRegisterAttribute (ic, "VALUE", motTreeGetValueAttrib, motTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +  +@@ -2844,5 +2679,4 @@ void iupdrvTreeInitClass(Iclass* ic) + iupClassRegisterAttribute(ic, "RENAME", NULL, motTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "MOVENODE", NULL, motTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COPYNODE", NULL, motTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); +- iupClassRegisterAttributeId(ic, "FINDUSERDATA", motTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + } +diff --git a/iup/src/mot/iupmot_val.c b/iup/src/mot/iupmot_val.c +index 200d2b4..ce9eba7 100755 +--- a/iup/src/mot/iupmot_val.c ++++ b/iup/src/mot/iupmot_val.c +@@ -383,41 +383,41 @@ static int motValMapMethod(Ihandle* ih) + int show_ticks; +  + /* Core */ +- iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ +- iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ +- iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ +- iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ +- iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ ++ iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ ++ iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ ++ iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ ++ iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ + if (iupAttribGetBoolean(ih, "CANFOCUS")) +- iupmotSetArg(args, num_args, XmNtraversalOn, True); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, True); + else +- iupmotSetArg(args, num_args, XmNtraversalOn, False); +- iupmotSetArg(args, num_args, XmNhighlightThickness, 2); +- iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); ++ iupMOT_SETARG(args, num_args, XmNtraversalOn, False); ++ iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); ++ iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); + /* Scale */ +- iupmotSetArg(args, num_args, XmNminimum, 0); +- iupmotSetArg(args, num_args, XmNmaximum, SHRT_MAX); +- iupmotSetArg(args, num_args, XmNslidingMode, XmSLIDER); +- iupmotSetArg(args, num_args, XmNsliderMark, XmETCHED_LINE); +- iupmotSetArg(args, num_args, XmNsliderSize, 16); +- iupmotSetArg(args, num_args, XmNshowValue, XmNONE); ++ iupMOT_SETARG(args, num_args, XmNminimum, 0); ++ iupMOT_SETARG(args, num_args, XmNmaximum, SHRT_MAX); ++ iupMOT_SETARG(args, num_args, XmNslidingMode, XmSLIDER); ++ iupMOT_SETARG(args, num_args, XmNsliderMark, XmETCHED_LINE); ++ iupMOT_SETARG(args, num_args, XmNsliderSize, 16); ++ iupMOT_SETARG(args, num_args, XmNshowValue, XmNONE); +  + if (ih->data->type == IVAL_HORIZONTAL) + { +- iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); ++ iupMOT_SETARG(args, num_args, XmNorientation, XmHORIZONTAL); + if (ih->data->inverted) +- iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_LEFT); ++ iupMOT_SETARG(args, num_args, XmNprocessingDirection, XmMAX_ON_LEFT); + else +- iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_RIGHT); ++ iupMOT_SETARG(args, num_args, XmNprocessingDirection, XmMAX_ON_RIGHT); + } + else + { +- iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); ++ iupMOT_SETARG(args, num_args, XmNorientation, XmVERTICAL); + if (ih->data->inverted) +- iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_TOP); ++ iupMOT_SETARG(args, num_args, XmNprocessingDirection, XmMAX_ON_TOP); + else +- iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_BOTTOM); ++ iupMOT_SETARG(args, num_args, XmNprocessingDirection, XmMAX_ON_BOTTOM); + } +  + ih->handle = XtCreateManagedWidget( +diff --git a/iup/src/mot/iupunix_info.c b/iup/src/mot/iupunix_info.c +index b522638..f09573c 100755 +--- a/iup/src/mot/iupunix_info.c ++++ b/iup/src/mot/iupunix_info.c +@@ -282,7 +282,7 @@ char *iupdrvGetSystemName(void) + char *iupdrvGetSystemVersion(void) + { + struct utsname un; +- char *str = iupStrGetMemory(60);  ++ char *str = iupStrGetMemory(100);  +  + uname(&un); + strcpy(str, un.release); +diff --git a/iup/src/win/iupwin_button.c b/iup/src/win/iupwin_button.c +index 7f780e3..3b05ba7 100755 +--- a/iup/src/win/iupwin_button.c ++++ b/iup/src/win/iupwin_button.c +@@ -27,6 +27,7 @@ + #include "iupwin_drv.h" + #include "iupwin_handle.h" + #include "iupwin_draw.h" ++#include "iupwin_info.h" +  +  + #ifndef CDIS_SHOWKEYBOARDCUES +@@ -308,18 +309,22 @@ static void winButtonDrawText(Ihandle* ih, HDC hDC, int rect_width, int rect_hei +  + static void winButtonDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem) + {  ++ HDC hDC; + iupwinBitmapDC bmpDC; + int border, draw_border; + int width = drawitem->rcItem.right - drawitem->rcItem.left; + int height = drawitem->rcItem.bottom - drawitem->rcItem.top; +  +- HDC hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height); ++ hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height); +  + iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem); +  + if ((drawitem->itemState & ODS_FOCUS) && !(drawitem->itemState & ODS_HOTLIGHT)) + drawitem->itemState |= ODS_DEFAULT; +  ++ if (iupAttribGet(ih, "_IUPWINBUT_SELECTED")) ++ drawitem->itemState |= ODS_SELECTED; ++ + border = winButtonGetBorder(); +  + if (ih->data->type & IUP_BUTTON_IMAGE && iupAttribGet(ih, "IMPRESS") && !iupAttribGetStr(ih, "IMPRESSBORDER")) +@@ -365,7 +370,7 @@ static int winButtonSetImageAttrib(Ihandle* ih, const char* value) + (void)value; + if (ih->data->type != IUP_BUTTON_TEXT) + { +- iupdrvDisplayUpdate(ih); ++ iupdrvPostRedraw(ih); + return 1; + } + else +@@ -377,7 +382,7 @@ static int winButtonSetImInactiveAttrib(Ihandle* ih, const char* value) + (void)value; + if (ih->data->type != IUP_BUTTON_TEXT) + { +- iupdrvDisplayUpdate(ih); ++ iupdrvPostRedraw(ih); + return 1; + } + else +@@ -389,7 +394,7 @@ static int winButtonSetImPressAttrib(Ihandle* ih, const char* value) + (void)value; + if (ih->data->type != IUP_BUTTON_TEXT) + { +- iupdrvDisplayUpdate(ih); ++ iupdrvPostRedraw(ih); + return 1; + } + else +@@ -400,7 +405,7 @@ static int winButtonSetActiveAttrib(Ihandle* ih, const char* value) + { + /* redraw IMINACTIVE image if any */ + if (ih->data->type != IUP_BUTTON_TEXT) +- iupdrvDisplayUpdate(ih); ++ iupdrvPostRedraw(ih); +  + return iupBaseSetActiveAttrib(ih, value); + } +@@ -425,7 +430,7 @@ static int winButtonSetAlignmentAttrib(Ihandle* ih, const char* value) + else /* "ACENTER" */ + ih->data->vert_alignment = IUP_ALIGN_ACENTER; +  +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); +  + return 1; + } +@@ -443,7 +448,7 @@ static int winButtonSetPaddingAttrib(Ihandle* ih, const char* value) + { + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + return 0; + } +  +@@ -454,7 +459,7 @@ static int winButtonSetBgColorAttrib(Ihandle* ih, const char* value) + { + iupAttribSetStr(ih, "BGCOLOR", value); + iupImageUpdateParent(ih); +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + } + return 1; + } +@@ -486,7 +491,9 @@ static int winButtonSetFgColorAttrib(Ihandle* ih, const char* value) + if (iupStrToRGB(value, &r, &g, &b)) + { + ih->data->fgcolor = RGB(r,g,b); +- iupdrvDisplayRedraw(ih); ++ ++ if (ih->handle) ++ iupdrvRedrawNow(ih); + } + return 1; + } +@@ -499,7 +506,7 @@ static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r + { + /* redraw IMPRESS image if any */ + if ((msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) && iupAttribGet(ih, "IMPRESS")) +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + } +  + switch (msg) +@@ -514,6 +521,13 @@ static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r + case WM_RBUTTONDOWN: + { + iupwinButtonDown(ih, msg, wp, lp); ++ ++ /* Feedback will NOT be done when not receiving the focus */ ++ if (msg==WM_LBUTTONDOWN && !iupAttribGetBoolean(ih, "FOCUSONCLICK")) ++ { ++ iupAttribSetStr(ih, "_IUPWINBUT_SELECTED", "1"); ++ iupdrvRedrawNow(ih); ++ } + break; + } + case WM_XBUTTONUP: +@@ -526,11 +540,24 @@ static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r + /* BN_CLICKED will NOT be notified when not receiving the focus */ + if (msg==WM_LBUTTONUP && !iupAttribGetBoolean(ih, "FOCUSONCLICK")) + { +- Icallback cb = IupGetCallback(ih, "ACTION"); ++ Icallback cb; ++ ++ iupAttribSetStr(ih, "_IUPWINBUT_SELECTED", NULL); ++ iupdrvRedrawNow(ih); ++ ++ cb = IupGetCallback(ih, "ACTION"); + if (cb && cb(ih) == IUP_CLOSE) + IupExitLoop(); + } +  ++ if (!iupwinIsVistaOrNew()) ++ { ++ /* TIPs desapear forever after a button click in XP, ++ so we force an update. */ ++ char* tip = iupAttribGet(ih, "TIP"); ++ if (tip) ++ iupdrvBaseSetTipAttrib(ih, tip); ++ } + break; + } + case WM_KEYDOWN: +@@ -549,7 +576,12 @@ static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r + if (!iupwin_comctl32ver6) + { + iupAttribSetStr(ih, "_IUPWINBUT_ENTERWIN", NULL); +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); ++ } ++ if (!iupAttribGetBoolean(ih, "FOCUSONCLICK")) ++ { ++ iupAttribSetStr(ih, "_IUPWINBUT_SELECTED", NULL); ++ iupdrvRedrawNow(ih); + } + break; + case WM_MOUSEMOVE: +@@ -558,7 +590,7 @@ static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r + if (!iupAttribGet(ih, "_IUPWINBUT_ENTERWIN")) + { + iupAttribSetStr(ih, "_IUPWINBUT_ENTERWIN", "1"); +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + } + } + break; +@@ -635,7 +667,7 @@ static int winButtonWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp) + static int winButtonMapMethod(Ihandle* ih) + { + char* value; +- DWORD dwStyle = WS_CHILD |  ++ DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | + BS_NOTIFY; /* necessary because of the base messages */ +  + if (!ih->parent) +@@ -661,7 +693,7 @@ static int winButtonMapMethod(Ihandle* ih) + ih->data->type = IUP_BUTTON_IMAGE; +  + value = iupAttribGet(ih, "TITLE"); +- if (value) ++ if (value && *value!=0) + ih->data->type |= IUP_BUTTON_TEXT; + } + else +diff --git a/iup/src/win/iupwin_canvas.c b/iup/src/win/iupwin_canvas.c +index bb88b8a..b865160 100755 +--- a/iup/src/win/iupwin_canvas.c ++++ b/iup/src/win/iupwin_canvas.c +@@ -45,7 +45,7 @@ static void winCanvasSetScrollInfo(HWND hWnd, int imin, int imax, int ipos, int + static int winCanvasSetBgColorAttrib(Ihandle *ih, const char *value) + { + (void)value; +- iupdrvDisplayUpdate(ih); ++ iupdrvPostRedraw(ih); + return 1; + } +  +@@ -220,7 +220,7 @@ static void winCanvasUpdateHorScroll(Ihandle* ih, WORD winop) + xmax = iupAttribGetFloat(ih,"XMAX"); + xmin = iupAttribGetFloat(ih,"XMIN"); +  +- winCanvasGetScrollInfo(ih->handle, &iposx, &ipagex, SB_HORZ, winop==SB_THUMBTRACK? 1: 0); ++ winCanvasGetScrollInfo(ih->handle, &iposx, &ipagex, SB_HORZ, winop==SB_THUMBTRACK||winop==SB_THUMBPOSITION? 1: 0); +  + if (!iupAttribGet(ih,"LINEX")) + { +@@ -296,7 +296,7 @@ static void winCanvasUpdateVerScroll(Ihandle* ih, WORD winop) + ymax = iupAttribGetFloat(ih,"YMAX"); + ymin = iupAttribGetFloat(ih,"YMIN"); +  +- winCanvasGetScrollInfo(ih->handle, &iposy, &ipagey, SB_VERT, winop==SB_THUMBTRACK? 1: 0); ++ winCanvasGetScrollInfo(ih->handle, &iposy, &ipagey, SB_VERT, winop==SB_THUMBTRACK||winop==SB_THUMBPOSITION? 1: 0); +  + if (!iupAttribGet(ih, "LINEY")) + { +@@ -372,6 +372,10 @@ static int winCanvasProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r + GetClientRect(ih->handle, &rect);  + FillRect(hdc, &rect, iupwinBrushGet(color));  + } ++ else ++ InvalidateRect(ih->handle,NULL,FALSE); /* This will invalidate all area.  ++ Necessary in XP, or overlapping windows will have the effect of partial redrawing. */ ++ + /* always return non zero value */ + *result = 1; + return 1;  +@@ -382,7 +386,7 @@ static int winCanvasProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(ih->handle, &ps); +- iupAttribSetStr(ih, "HDC_WMPAINT", (char*)&hdc); ++ iupAttribSetStr(ih, "HDC_WMPAINT", (char*)hdc); + iupAttribSetStrf(ih, "CLIPRECT", "%d %d %d %d", ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top); +  + cb(ih, ih->data->posx, ih->data->posy); +@@ -542,27 +546,13 @@ static int winCanvasProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r + return iupwinBaseProc(ih, msg, wp, lp, result); + } +  +-static void winCanvasRegisterClass(void) +-{ +- WNDCLASS wndclass; +- ZeroMemory(&wndclass, sizeof(WNDCLASS)); +-  +- wndclass.hInstance = iupwin_hinstance; +- wndclass.lpszClassName = "IupCanvas"; +- wndclass.lpfnWndProc = (WNDPROC)iupwinBaseWinProc; +- wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); +- wndclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; /* using CS_OWNDC will minimize the work of cdActivate in the CD library */ +- wndclass.hbrBackground = NULL; /* remove the background to optimize redraw */ +-  +- RegisterClass(&wndclass); +-} +- + static int winCanvasMapMethod(Ihandle* ih) + { + CLIENTCREATESTRUCT clientstruct; + void *clientdata = NULL; + char *classname; +- DWORD dwStyle = WS_CHILD, dwExStyle = 0; ++ DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS,  ++ dwExStyle = 0; +  + if (!ih->parent) + return IUP_ERROR; +@@ -574,14 +564,7 @@ static int winCanvasMapMethod(Ihandle* ih) + } +  + if (ih->firstchild) /* can be a container */ +- { +- dwStyle |= WS_CLIPSIBLINGS; +- +- if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) +- dwExStyle |= WS_EX_COMPOSITED; +- else +- dwStyle |= WS_CLIPCHILDREN; +- } ++ iupwinGetNativeParentStyle(ih, &dwExStyle, &dwStyle); +  + if (iupAttribGetBoolean(ih, "MDICLIENT"))  + { +@@ -693,6 +676,21 @@ static void winCanvasReleaseMethod(Iclass* ic) + UnregisterClass("IupCanvas", iupwin_hinstance); + } +  ++static void winCanvasRegisterClass(void) ++{ ++ WNDCLASS wndclass; ++ ZeroMemory(&wndclass, sizeof(WNDCLASS)); ++  ++ wndclass.hInstance = iupwin_hinstance; ++ wndclass.lpszClassName = "IupCanvas"; ++ wndclass.lpfnWndProc = (WNDPROC)iupwinBaseWinProc; ++ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); ++ wndclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; /* using CS_OWNDC will minimize the work of cdActivate in the CD library */ ++ wndclass.hbrBackground = NULL; /* remove the background to optimize redraw */ ++  ++ RegisterClass(&wndclass); ++} ++ + void iupdrvCanvasInitClass(Iclass* ic) + { + if (!iupwinClassExist("IupCanvas")) +diff --git a/iup/src/win/iupwin_common.c b/iup/src/win/iupwin_common.c +index a1a7c0f..ba68b78 100755 +--- a/iup/src/win/iupwin_common.c ++++ b/iup/src/win/iupwin_common.c +@@ -94,16 +94,17 @@ void iupdrvBaseLayoutUpdateMethod(Ihandle *ih) + SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER); + } +  +-void iupdrvDisplayRedraw(Ihandle *ih) ++void iupdrvRedrawNow(Ihandle *ih) + { + /* REDRAW Now */ +- RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_NOCHILDREN|RDW_UPDATENOW); ++ RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_UPDATENOW); + } +  +-void iupdrvDisplayUpdate(Ihandle *ih) ++void iupdrvPostRedraw(Ihandle *ih) + { + /* Post a REDRAW */ +- RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_NOCHILDREN); ++ /* can NOT use RDW_NOCHILDREN because IupList has internal children that needs to be redraw */ ++ RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT);  + } +  + void iupdrvScreenToClient(Ihandle* ih, int *x, int *y) +@@ -534,6 +535,8 @@ int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value) +  + void iupdrvSetVisible(Ihandle* ih, int visible) + { ++ if (iupStrEqual(ih->iclass->name, "colorbar")) ++ ih=ih; + ShowWindow(ih->handle, visible? SW_SHOWNORMAL: SW_HIDE); + } +  +@@ -618,6 +621,18 @@ char* iupdrvBaseGetClientSizeAttrib(Ihandle* ih) + #define IDC_HELP MAKEINTRESOURCE(32651) + #endif +  ++static HCURSOR winLoadComCtlCursor(LPCTSTR lpCursorName) ++{ ++ HCURSOR cur = NULL; ++ HINSTANCE hinstDll = LoadLibrary("comctl32.dll"); ++ if (hinstDll) ++ { ++ cur = LoadCursor(hinstDll, lpCursorName); ++ FreeLibrary(hinstDll); ++ } ++ return cur; ++} ++ + static HCURSOR winGetCursor(Ihandle* ih, const char* name) + { + static struct { +@@ -649,7 +664,7 @@ static HCURSOR winGetCursor(Ihandle* ih, const char* name) + {"APPSTARTING", IDC_APPSTARTING} + }; +  +- HCURSOR cur; ++ HCURSOR cur = NULL; + char str[50]; + int i, count = sizeof(table)/sizeof(table[0]); +  +@@ -676,14 +691,22 @@ static HCURSOR winGetCursor(Ihandle* ih, const char* name) + if (i == count) + { + /* check other system cursors */ +- /* cursor PEN is handled here */ ++ + if (iupStrEqualNoCase(name, "PEN")) +- name = "CURSOR_PEN"; ++ name = "CURSOR_PEN"; /* name in "iup.rc" */ +  + /* check for an name defined cursor */ + cur = iupImageGetCursor(name); + } +  ++ if (!cur) ++ { ++ if (iupStrEqualNoCase(name, "SPLITTER_VERT")) ++ cur = winLoadComCtlCursor(MAKEINTRESOURCE(107)); ++ else if (iupStrEqualNoCase(name, "SPLITTER_HORIZ")) ++ cur = winLoadComCtlCursor(MAKEINTRESOURCE(135)); ++ } ++ + iupAttribSetStr(ih, str, (char*)cur); + return cur; + } +@@ -758,29 +781,29 @@ int iupwinButtonUp(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp) + if (msg==WM_LBUTTONUP) + { + b = IUP_BUTTON1; +- iupKEYSETBUTTON1(status);  ++ iupKEY_SETBUTTON1(status);  + } + else if (msg==WM_MBUTTONUP) + { + b = IUP_BUTTON2; +- iupKEYSETBUTTON2(status); ++ iupKEY_SETBUTTON2(status); + } + else if (msg==WM_RBUTTONUP) + { + b = IUP_BUTTON3; +- iupKEYSETBUTTON3(status); ++ iupKEY_SETBUTTON3(status); + } + else if (msg==WM_XBUTTONUP) + { + if (HIWORD(wp) == XBUTTON1) + { + b = IUP_BUTTON4; +- iupKEYSETBUTTON4(status); ++ iupKEY_SETBUTTON4(status); + } + else + { + b = IUP_BUTTON5; +- iupKEYSETBUTTON5(status); ++ iupKEY_SETBUTTON5(status); + } + } +  +@@ -807,6 +830,14 @@ int iupwinMouseMove(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp) + return 0; + } +  ++void iupwinGetNativeParentStyle(Ihandle* ih, DWORD *dwExStyle, DWORD *dwStyle) ++{ ++ *dwStyle |= WS_CLIPCHILDREN; ++ ++ if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) ++ *dwExStyle |= WS_EX_COMPOSITED; ++} ++ + int iupwinCreateWindowEx(Ihandle* ih, LPCSTR lpClassName, DWORD dwExStyle, DWORD dwStyle) + { + ih->serial = iupDialogGetChildId(ih); +diff --git a/iup/src/win/iupwin_dialog.c b/iup/src/win/iupwin_dialog.c +index 39fdc0c..c13b88d 100755 +--- a/iup/src/win/iupwin_dialog.c ++++ b/iup/src/win/iupwin_dialog.c +@@ -102,9 +102,9 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu + else + { + int has_titlebar = iupAttribGetBoolean(ih, "MAXBOX") || +- iupAttribGetBoolean(ih, "MINBOX") || +- iupAttribGetBoolean(ih, "MENUBOX") ||  +- IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ ++ iupAttribGetBoolean(ih, "MINBOX") || ++ iupAttribGetBoolean(ih, "MENUBOX") ||  ++ IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ +  + *caption = 0; + if (has_titlebar) +@@ -118,14 +118,17 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu + *border = 0; + if (iupAttribGetBoolean(ih, "RESIZE")) + { ++ /* has_border */ + *border = GetSystemMetrics(SM_CXFRAME); /* Thickness of the sizing border around the perimeter of a window */ + } /* that can be resized, in pixels. */ + else if (has_titlebar) + { ++ /* has_border */ + *border = GetSystemMetrics(SM_CXFIXEDFRAME); /* Thickness of the frame around the perimeter of a window */ + } /* that has a caption but is not sizable, in pixels. */ + else if (iupAttribGetBoolean(ih, "BORDER")) + { ++ /* has_border */ + *border = GetSystemMetrics(SM_CXBORDER); + } + } +@@ -712,28 +715,27 @@ static int winDialogMapMethod(Ihandle* ih) + } +  + if (iupAttribGetBoolean(ih, "RESIZE")) ++ { + dwStyle |= WS_THICKFRAME; ++ has_border = 1; ++ } + else + iupAttribSetStr(ih, "MAXBOX", "NO"); /* Must also remove this to RESIZE=NO work */ +- + if (iupAttribGetBoolean(ih, "MAXBOX")) + { + dwStyle |= WS_MAXIMIZEBOX; + has_titlebar = 1; + } +- + if (iupAttribGetBoolean(ih, "MINBOX")) + { + dwStyle |= WS_MINIMIZEBOX; + has_titlebar = 1; + } +- + if (iupAttribGetBoolean(ih, "MENUBOX")) + { + dwStyle |= WS_SYSMENU; + has_titlebar = 1; + } +- + if (iupAttribGetBoolean(ih, "BORDER") || has_titlebar) + has_border = 1; +  +@@ -815,10 +817,7 @@ static int winDialogMapMethod(Ihandle* ih) + if (iupAttribGetBoolean(ih, "DIALOGFRAME") && native_parent) + dwExStyle |= WS_EX_DLGMODALFRAME; /* this will hide the MENUBOX but not the close button */ +  +- if (iupAttribGetBoolean(ih, "COMPOSITED")) +- dwExStyle |= WS_EX_COMPOSITED; +- else +- dwStyle |= WS_CLIPCHILDREN; ++ iupwinGetNativeParentStyle(ih, &dwExStyle, &dwStyle); +  + if (iupAttribGetBoolean(ih, "HELPBUTTON")) + dwExStyle |= WS_EX_CONTEXTHELP; +@@ -878,7 +877,6 @@ static int winDialogMapMethod(Ihandle* ih) + /* Reset attributes handled during creation that */ + /* also can be changed later, and can be consulted from the native system. */ + iupAttribSetStr(ih, "TITLE", NULL);  +- iupAttribSetStr(ih, "BORDER", NULL); +  + /* Ignore VISIBLE before mapping */ + iupAttribSetStr(ih, "VISIBLE", NULL); +@@ -956,7 +954,7 @@ static int winDialogSetBgColorAttrib(Ihandle* ih, const char* value) + { + iupAttribStoreStr(ih, "_IUPWIN_BACKGROUND_COLOR", value); + iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_BITMAP", NULL); +- RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_ERASENOW); /* force a WM_ERASEBKGND now */ ++ RedrawWindow(ih->handle, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN); /* post WM_ERASEBKGND and WM_PAINT */ + return 1; + } + return 0; +@@ -973,7 +971,7 @@ static int winDialogSetBackgroundAttrib(Ihandle* ih, const char* value) + { + iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_COLOR", NULL); + iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_BITMAP", (char*)hBitmap); +- RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_ERASENOW); /* force a WM_ERASEBKGND now */ ++ RedrawWindow(ih->handle, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN); /* post WM_ERASEBKGND and WM_PAINT */ + return 1; + } + } +diff --git a/iup/src/win/iupwin_draw.c b/iup/src/win/iupwin_draw.c +index 4a810e6..f663d20 100755 +--- a/iup/src/win/iupwin_draw.c ++++ b/iup/src/win/iupwin_draw.c +@@ -14,12 +14,16 @@ + #include  + #include  + #include  ++#include  +  + #include "iup.h" +  + #include "iup_attrib.h" + #include "iup_class.h" + #include "iup_str.h" ++#include "iup_object.h" ++#include "iup_image.h" ++#include "iup_draw.h" +  + #include "iupwin_drv.h" + #include "iupwin_info.h" +@@ -38,6 +42,11 @@ + #endif +  +  ++/****************************************************************************** ++ Themes ++*******************************************************************************/ ++ ++ + typedef HTHEME (STDAPICALLTYPE *_winThemeOpenData)(HWND hwnd, LPCWSTR pszClassList); + typedef HRESULT (STDAPICALLTYPE *_winThemeCloseData)(HTHEME hTheme); + typedef HRESULT (STDAPICALLTYPE *_winThemeDrawBackground)(HTHEME hTheme, HDC hDC, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect); +@@ -61,58 +70,6 @@ static int winDrawThemeEnabled(void) + return winThemeOpenData? 1: 0; + } +  +-void iupwinDrawText(HDC hDC, const char* text, int x, int y, int width, int height, HFONT hFont, COLORREF fgcolor, int style) +-{ +- COLORREF oldcolor; +- RECT rect; +- HFONT hOldFont = SelectObject(hDC, hFont); +- +- rect.left = x; +- rect.top = y; +- rect.right = x+width; +- rect.bottom = y+height; +- +- SetTextAlign(hDC, TA_TOP|TA_LEFT); +- SetBkMode(hDC, TRANSPARENT); +- oldcolor = SetTextColor(hDC, fgcolor); +- +- DrawText(hDC, text, -1, &rect, style|DT_NOCLIP); +- +- SelectObject(hDC, hOldFont); +- SetTextColor(hDC, oldcolor); +- SetBkMode(hDC, OPAQUE); +-} +- +-void iupwinDrawBitmap(HDC hDC, HBITMAP hBitmap, HBITMAP hMask, int x, int y, int width, int height, int bpp) +-{ +- HDC hMemDC = CreateCompatibleDC(hDC); +- SelectObject(hMemDC, hBitmap); +- +- if (bpp == 32 && winAlphaBlend) +- { +- BLENDFUNCTION blendfunc; +- blendfunc.BlendOp = AC_SRC_OVER; +- blendfunc.BlendFlags = 0; +- blendfunc.SourceConstantAlpha = 0xFF; +- blendfunc.AlphaFormat = AC_SRC_ALPHA; +- +- winAlphaBlend(hDC, x, y, width, height,  +- hMemDC, 0, 0, width, height,  +- blendfunc); +- } +- else if (bpp == 8 && hMask) +- MaskBlt(hDC, x, y, width, height,  +- hMemDC, 0, 0,  +- hMask, 0, 0, MAKEROP4(SRCCOPY, 0xAA0000)); +- else +- BitBlt(hDC, x, y, width, height,  +- hMemDC, 0, 0,  +- SRCCOPY); +- +- +- DeleteDC(hMemDC); +-} +- + void iupwinDrawInit(void) + { + if (!winAlphaBlend) +@@ -201,7 +158,7 @@ int iupwinDrawGetThemeTabsBgColor(HWND hWnd, COLORREF *color) + if (!hTheme)  + return 0; +  +- if (iupwinIsVista()) ++ if (iupwinIsVistaOrNew()) + ret = winThemeGetColor(hTheme, TABP_AEROWIZARDBODY, TIS_NORMAL, TMT_FILLCOLORHINT, color); + else + ret = winThemeGetColor(hTheme, TABP_BODY, TIS_NORMAL, TMT_FILLCOLORHINT, color); +@@ -246,6 +203,79 @@ int iupwinDrawGetThemeFrameFgColor(HWND hWnd, COLORREF *color) + return (ret == S_OK)? 1: 0; + } +  ++void iupwinDrawRemoveTheme(HWND hwnd) ++{ ++ typedef HRESULT (STDAPICALLTYPE *winSetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList); ++ static winSetWindowTheme mySetWindowTheme = NULL; ++ if (!mySetWindowTheme) ++ { ++ HMODULE hinstDll = LoadLibrary("uxtheme.dll"); ++ if (hinstDll) ++ mySetWindowTheme = (winSetWindowTheme)GetProcAddress(hinstDll, "SetWindowTheme"); ++ } ++ ++ if (mySetWindowTheme) ++ mySetWindowTheme(hwnd, L"", L""); ++} ++ ++ ++/****************************************************************************** ++ Utilities ++*******************************************************************************/ ++ ++ ++void iupwinDrawText(HDC hDC, const char* text, int x, int y, int width, int height, HFONT hFont, COLORREF fgcolor, int style) ++{ ++ COLORREF oldcolor; ++ RECT rect; ++ HFONT hOldFont = SelectObject(hDC, hFont); ++ ++ rect.left = x; ++ rect.top = y; ++ rect.right = x+width; ++ rect.bottom = y+height; ++ ++ SetTextAlign(hDC, TA_TOP|TA_LEFT); ++ SetBkMode(hDC, TRANSPARENT); ++ oldcolor = SetTextColor(hDC, fgcolor); ++ ++ DrawText(hDC, text, -1, &rect, style|DT_NOCLIP); ++ ++ SelectObject(hDC, hOldFont); ++ SetTextColor(hDC, oldcolor); ++ SetBkMode(hDC, OPAQUE); ++} ++ ++void iupwinDrawBitmap(HDC hDC, HBITMAP hBitmap, HBITMAP hMask, int x, int y, int width, int height, int bpp) ++{ ++ HDC hMemDC = CreateCompatibleDC(hDC); ++ SelectObject(hMemDC, hBitmap); ++ ++ if (bpp == 32 && winAlphaBlend) ++ { ++ BLENDFUNCTION blendfunc; ++ blendfunc.BlendOp = AC_SRC_OVER; ++ blendfunc.BlendFlags = 0; ++ blendfunc.SourceConstantAlpha = 0xFF; ++ blendfunc.AlphaFormat = AC_SRC_ALPHA; ++ ++ winAlphaBlend(hDC, x, y, width, height,  ++ hMemDC, 0, 0, width, height,  ++ blendfunc); ++ } ++ else if (bpp == 8 && hMask) ++ MaskBlt(hDC, x, y, width, height,  ++ hMemDC, 0, 0,  ++ hMask, 0, 0, MAKEROP4(SRCCOPY, 0xAA0000)); ++ else ++ BitBlt(hDC, x, y, width, height,  ++ hMemDC, 0, 0,  ++ SRCCOPY); ++ ++ ++ DeleteDC(hMemDC); ++} ++ + static int winDrawGetStateId(int itemState) + { + if (itemState & ODS_DISABLED) +@@ -282,21 +312,6 @@ void iupdrvDrawFocusRect(Ihandle* ih, void* gc, int x, int y, int w, int h) + DrawFocusRect(hDC, &rect); + } +  +-void iupwinDrawRemoveTheme(HWND hwnd) +-{ +- typedef HRESULT (STDAPICALLTYPE *winSetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList); +- static winSetWindowTheme mySetWindowTheme = NULL; +- if (!mySetWindowTheme) +- { +- HMODULE hinstDll = LoadLibrary("uxtheme.dll"); +- if (hinstDll) +- mySetWindowTheme = (winSetWindowTheme)GetProcAddress(hinstDll, "SetWindowTheme"); +- } +- +- if (mySetWindowTheme) +- mySetWindowTheme(hwnd, L"", L""); +-} +- + void iupwinDrawParentBackground(Ihandle* ih, HDC hDC, RECT* rect) + { + unsigned char r=0, g=0, b=0; +@@ -326,3 +341,226 @@ void iupwinDrawDestroyBitmapDC(iupwinBitmapDC *bmpDC) + DeleteDC(bmpDC->hBitmapDC); + } +  ++ ++/****************************************************************************** ++ Simple Draw ++*******************************************************************************/ ++ ++struct _IdrawCanvas{ ++ Ihandle* ih; ++ int w, h; ++ ++ int release_dc; ++ HBITMAP hBitmap, hOldBitmap; ++ HDC hBitmapDC, hDC; ++}; ++ ++IdrawCanvas* iupDrawCreateCanvas(Ihandle* ih) ++{ ++ IdrawCanvas* dc = calloc(1, sizeof(IdrawCanvas)); ++ RECT rect; ++ ++ /* valid only inside the ACTION callback of an IupCanvas */ ++ dc->hDC = (HDC)IupGetAttribute(ih, "HDC_WMPAINT"); ++ if (!dc->hDC) ++ { ++ dc->hDC = GetDC(ih->handle); ++ dc->release_dc = 1; ++ } ++ ++ GetClientRect(ih->handle, &rect); ++ dc->w = rect.right - rect.left; ++ dc->h = rect.bottom - rect.top; ++ ++ dc->hBitmap = CreateCompatibleBitmap(dc->hDC, dc->w, dc->h); ++ dc->hBitmapDC = CreateCompatibleDC(dc->hDC); ++ dc->hOldBitmap = SelectObject(dc->hBitmapDC, dc->hBitmap); ++ ++ SetBkMode(dc->hBitmapDC, TRANSPARENT); ++ SetTextAlign(dc->hBitmapDC, TA_TOP|TA_LEFT); ++ ++ return dc; ++} ++ ++void iupDrawKillCanvas(IdrawCanvas* dc) ++{ ++ SelectObject(dc->hBitmapDC, dc->hOldBitmap); ++ DeleteObject(dc->hBitmap); ++ DeleteDC(dc->hBitmapDC); ++ if (dc->release_dc) ++ DeleteDC(dc->hDC); ++ ++ free(dc); ++} ++ ++void iupDrawUpdateSize(IdrawCanvas* dc) ++{ ++ int w, h; ++ RECT rect; ++ GetClientRect(dc->ih->handle, &rect); ++ w = rect.right - rect.left; ++ h = rect.bottom - rect.top; ++ ++ if (w != dc->w || h != dc->h) ++ { ++ SelectObject(dc->hBitmapDC, dc->hOldBitmap); ++ DeleteObject(dc->hBitmap); ++ DeleteDC(dc->hBitmapDC); ++ ++ dc->hBitmap = CreateCompatibleBitmap(dc->hDC, dc->w, dc->h); ++ dc->hBitmapDC = CreateCompatibleDC(dc->hDC); ++ dc->hOldBitmap = SelectObject(dc->hBitmapDC, dc->hBitmap); ++ ++ SetBkMode(dc->hBitmapDC, TRANSPARENT); ++ SetTextAlign(dc->hBitmapDC, TA_TOP|TA_LEFT); ++ } ++} ++ ++void iupDrawFlush(IdrawCanvas* dc) ++{ ++ BitBlt(dc->hDC, 0, 0, dc->w, dc->h, dc->hBitmapDC, 0, 0, SRCCOPY); ++} ++ ++void iupDrawGetSize(IdrawCanvas* dc, int *w, int *h) ++{ ++ if (w) *w = dc->w; ++ if (h) *h = dc->h; ++} ++ ++void iupDrawParentBackground(IdrawCanvas* dc) ++{ ++ unsigned char r=0, g=0, b=0; ++ char* color = iupBaseNativeParentGetBgColorAttrib(dc->ih); ++ iupStrToRGB(color, &r, &g, &b); ++ iupDrawRectangle(dc, 0, 0, dc->w-1, dc->h-1, r, g, b, 1); ++} ++ ++void iupDrawRectangle(IdrawCanvas* dc, int x1, int y1, int x2, int y2, unsigned char r, unsigned char g, unsigned char b, int filled) ++{ ++ RECT rect; ++ rect.left = x1; rect.top = y1; rect.right = x2+1; rect.bottom = y2+1; ++ SetDCBrushColor(dc->hBitmapDC, RGB(r,g,b)); ++ if (filled) ++ FillRect(dc->hBitmapDC, &rect, (HBRUSH)GetStockObject(DC_BRUSH)); ++ else ++ FrameRect(dc->hBitmapDC, &rect, (HBRUSH)GetStockObject(DC_BRUSH)); ++} ++ ++void iupDrawLine(IdrawCanvas* dc, int x1, int y1, int x2, int y2, unsigned char r, unsigned char g, unsigned char b) ++{ ++ POINT line_poly[2]; ++ HPEN hPen = CreatePen(PS_SOLID, 1, RGB(r, g, b)); ++ HPEN hPenOld = SelectObject(dc->hBitmapDC, hPen); ++ line_poly[0].x = x1; ++ line_poly[0].y = y1; ++ line_poly[1].x = x2; ++ line_poly[1].y = y2; ++ Polyline(dc->hBitmapDC, line_poly, 2); ++ SelectObject(dc->hBitmapDC, hPenOld); ++ DeleteObject(hPen); ++} ++ ++#define IUP_DEG2RAD 0.01745329252 /* degrees to radians (rad = CD_DEG2RAD * deg) */ ++ ++static int winDrawCalcArc(int c1, int c2, double a, int start) ++{ ++ double proj, off; ++ if (start) ++ proj = cos(IUP_DEG2RAD * a); ++ else ++ proj = sin(IUP_DEG2RAD * a); ++ off = (c2+c1)/2.0 + (c2-c1+1)*proj/2.0; ++ return iupROUND(off); ++} ++ ++void iupDrawArc(IdrawCanvas* dc, int x1, int y1, int x2, int y2, double a1, double a2, unsigned char r, unsigned char g, unsigned char b, int filled) ++{ ++ int XStartArc = winDrawCalcArc(x1, x2, a1, 1); ++ int XEndArc = winDrawCalcArc(x1, x2, a2, 0); ++ int YStartArc = winDrawCalcArc(y1, y2, a1, 1); ++ int YEndArc = winDrawCalcArc(y1, y2, a2, 0); ++ ++ if (filled) ++ { ++ HBRUSH hBrush = CreateSolidBrush(RGB(r,g,b)); ++ HPEN hBrushOld = SelectObject(dc->hBitmapDC, hBrush);  ++ BeginPath(dc->hBitmapDC);  ++ Pie(dc->hBitmapDC, x1, y1, x2+1, y2+1, XStartArc, YStartArc, XEndArc, YEndArc); ++ EndPath(dc->hBitmapDC); ++ FillPath(dc->hBitmapDC); ++ SelectObject(dc->hBitmapDC, hBrushOld); ++ DeleteObject(hBrush); ++ } ++ else ++ { ++ HPEN hPen = CreatePen(PS_SOLID, 1, RGB(r, g, b)); ++ HPEN hPenOld = SelectObject(dc->hBitmapDC, hPen); ++ Arc(dc->hBitmapDC, x1, y1, x2+1, y2+1, XStartArc, YStartArc, XEndArc, YEndArc); ++ SelectObject(dc->hBitmapDC, hPenOld); ++ DeleteObject(hPen); ++ } ++} ++ ++void iupDrawPolygon(IdrawCanvas* dc, int* points, int count, unsigned char r, unsigned char g, unsigned char b, int filled) ++{ ++ if (filled) ++ { ++ HBRUSH hBrush = CreateSolidBrush(RGB(r,g,b)); ++ HPEN hBrushOld = SelectObject(dc->hBitmapDC, hBrush);  ++ BeginPath(dc->hBitmapDC);  ++ Polygon(dc->hBitmapDC, (POINT*)points, count); ++ EndPath(dc->hBitmapDC); ++ FillPath(dc->hBitmapDC); ++ SelectObject(dc->hBitmapDC, hBrushOld); ++ DeleteObject(hBrush); ++ } ++ else ++ { ++ HPEN hPen = CreatePen(PS_SOLID, 1, RGB(r, g, b)); ++ HPEN hPenOld = SelectObject(dc->hBitmapDC, hPen); ++ Polyline(dc->hBitmapDC, (POINT*)points, count); ++ SelectObject(dc->hBitmapDC, hPenOld); ++ DeleteObject(hPen); ++ } ++} ++ ++void iupDrawSetClipRect(IdrawCanvas* dc, int x1, int y1, int x2, int y2) ++{ ++ HRGN clip_hrgn = CreateRectRgn(x1, y1, x2, y2); ++ SelectClipRgn(dc->hBitmapDC, clip_hrgn); ++ DeleteObject(clip_hrgn); ++} ++ ++void iupDrawResetClip(IdrawCanvas* dc) ++{ ++ SelectClipRgn(dc->hBitmapDC, NULL); ++} ++ ++void iupDrawText(IdrawCanvas* dc, const char* text, int len, int x, int y, unsigned char r, unsigned char g, unsigned char b) ++{ ++ HFONT hOldFont, hFont = (HFONT)IupGetAttribute(dc->ih, "HFONT"); ++ SetTextColor(dc->hBitmapDC, RGB(r, g, b)); ++ hOldFont = SelectObject(dc->hBitmapDC, hFont); ++ TextOut(dc->hBitmapDC, x, y, text, len); ++ SelectObject(dc->hBitmapDC, hOldFont); ++} ++ ++void iupDrawImage(IdrawCanvas* dc, const char* name, int make_inactive, int x, int y) ++{ ++ int img_w, img_h, bpp; ++ HBITMAP hMask = NULL; ++ HBITMAP hBitmap = iupImageGetImage(name, dc->ih, make_inactive); ++ if (!hBitmap) ++ return; ++ ++ /* must use this info, since image can be a driver image loaded from resources */ ++ iupdrvImageGetInfo(hBitmap, &img_w, &img_h, &bpp); ++ ++ if (bpp == 8) ++ hMask = iupdrvImageCreateMask(IupGetHandle(name)); ++ ++ iupwinDrawBitmap(dc->hBitmapDC, hBitmap, hMask, x, y, img_w, img_h, bpp); ++ ++ if (hMask) ++ DeleteObject(hMask); ++} +diff --git a/iup/src/win/iupwin_drv.h b/iup/src/win/iupwin_drv.h +index 3372c1a..7407a7a 100755 +--- a/iup/src/win/iupwin_drv.h ++++ b/iup/src/win/iupwin_drv.h +@@ -77,6 +77,7 @@ int iupwinBaseContainerProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT + /* Creates the Window with native parent and child ID, associate HWND with Ihandle*,  + and replace the WinProc by iupwinBaseWinProc */ + int iupwinCreateWindowEx(Ihandle* ih, LPCSTR lpClassName, DWORD dwExStyle, DWORD dwStyle); ++void iupwinGetNativeParentStyle(Ihandle* ih, DWORD *dwExStyle, DWORD *dwStyle); +  + int iupwinClassExist(const char* name); + int iupwinGetColorRef(Ihandle *ih, char *name, COLORREF *color); +@@ -97,8 +98,8 @@ char* iupwinGetClipboardText(Ihandle* ih); + int iupwinGetScreenRes(void); + /* 1 point = 1/72 inch */ + /* pixel = (point/72)*(pixel/inch) */ +-#define IUPWIN_PT2PIXEL(_pt, _res) MulDiv(_pt, _res, 72) /* (((_pt)*(_res))/72) */ +-#define IUPWIN_PIXEL2PT(_pixel, _res) MulDiv(_pixel, 72, _res) /* (((_pixel)*72)/(_res)) */ ++#define iupWIN_PT2PIXEL(_pt, _res) MulDiv(_pt, _res, 72) /* (((_pt)*(_res))/72) */ ++#define iupWIN_PIXEL2PT(_pixel, _res) MulDiv(_pixel, 72, _res) /* (((_pixel)*72)/(_res)) */ +  +  + /* child window identifier of the first MDI child window created, +diff --git a/iup/src/win/iupwin_filedlg.c b/iup/src/win/iupwin_filedlg.c +index da66b4b..26994e5 100755 +--- a/iup/src/win/iupwin_filedlg.c ++++ b/iup/src/win/iupwin_filedlg.c +@@ -63,7 +63,7 @@ static INT CALLBACK winFileDlgBrowseCallback(HWND hWnd, UINT uMsg, LPARAM lParam + } + else if (uMsg == BFFM_SELCHANGED) + { +- char* buffer = iupStrGetMemory(MAX_FILENAME_SIZE); ++ char buffer[MAX_FILENAME_SIZE]; + ITEMIDLIST* selecteditem = (ITEMIDLIST*)lParam; + buffer[0] = 0; + SHGetPathFromIDList(selecteditem, buffer); +@@ -90,7 +90,7 @@ static void winFileDlgGetFolder(Ihandle *ih) + browseinfo.pszDisplayName = buffer;  + browseinfo.lpfn = winFileDlgBrowseCallback; + browseinfo.lParam = (LPARAM)ih; +- browseinfo.ulFlags = BIF_NEWDIALOGSTYLE; ++ browseinfo.ulFlags = IupGetGlobal("_IUPWIN_COINIT_MULTITHREADED")? 0: BIF_NEWDIALOGSTYLE; + browseinfo.hwndOwner = parent; +  + selecteditem = SHBrowseForFolder(&browseinfo); +@@ -112,6 +112,37 @@ static void winFileDlgGetFolder(Ihandle *ih) +  + /************************************************************************************************/ +  ++static int winFileDlgGetSelectedFile(Ihandle* ih, HWND hWnd, char* filename) ++{ ++ int ret = CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE); ++ if (ret < 0) ++ return 0; ++ ++ if (iupAttribGetBoolean(ih, "MULTIPLEFILES")) ++ { ++ /* check if there are more than 1 files and return only the first one */ ++ int found = 0; ++ while(*filename != 0) ++ {  ++ if (*filename == '"') ++ { ++ if (!found) ++ found = 1; ++ else ++ { ++ *(filename-1) = 0; ++ return 1; ++ } ++ } ++ if (found) ++ *filename = *(filename+1); ++ filename++; ++ } ++ } ++ ++ return 1; ++} ++ + static UINT_PTR CALLBACK winFileDlgSimpleHook(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) + { + (void)wParam; +@@ -152,16 +183,15 @@ static UINT_PTR CALLBACK winFileDlgSimpleHook(HWND hWnd, UINT uiMsg, WPARAM wPar + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (cb) + { +- char* filename = iupStrGetMemory(MAX_FILENAME_SIZE); +- if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE) ++ char filename[MAX_FILENAME_SIZE]; ++ if (winFileDlgGetSelectedFile(ih, hWnd, filename)) + { + int ret; + char* file_msg; +  + if (!iupdrvIsFile(filename)) +- break; +- +- if (pofn->hdr.code == CDN_FILEOK) ++ file_msg = "OTHER"; ++ else if (pofn->hdr.code == CDN_FILEOK) + file_msg = "OK"; + else  + file_msg = "SELECT"; +@@ -267,9 +297,9 @@ static UINT_PTR CALLBACK winFileDlgPreviewHook(HWND hWnd, UINT uiMsg, WPARAM wPa + LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam; + Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER); + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); +- char* filename = iupStrGetMemory(MAX_FILENAME_SIZE); ++ char filename[MAX_FILENAME_SIZE]; + iupAttribSetStr(ih, "PREVIEWDC", (char*)lpDrawItem->hDC); +- if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE) ++ if (winFileDlgGetSelectedFile(ih, hWnd, filename)) + { + if (iupdrvIsFile(filename)) + cb(ih, filename, "PAINT"); +@@ -324,16 +354,15 @@ static UINT_PTR CALLBACK winFileDlgPreviewHook(HWND hWnd, UINT uiMsg, WPARAM wPa + case CDN_SELCHANGE: + { + HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS); +- char* filename = iupStrGetMemory(MAX_FILENAME_SIZE); +- if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE) ++ char filename[MAX_FILENAME_SIZE]; ++ if (winFileDlgGetSelectedFile(ih, hWnd, filename)) + { + int ret; + char* file_msg; +  + if (!iupdrvIsFile(filename)) +- break; +- +- if (pofn->hdr.code == CDN_FILEOK) ++ file_msg = "OTHER"; ++ else if (pofn->hdr.code == CDN_FILEOK) + file_msg = "OK"; + else + file_msg = "SELECT"; +@@ -520,9 +549,14 @@ static int winFileDlgPopup(Ihandle *ih, int x, int y) + if (iupAttribGetBoolean(ih, "MULTIPLEFILES")) + { + int i = 0; +-  ++ ++ char* dir = iupStrFileGetPath(openfilename.lpstrFile); /* the first part is the directory already */ ++ iupAttribStoreStr(ih, "DIRECTORY", dir); ++ free(dir); ++  + /* If there is more than one file, replace terminator by the separator */ +- if (openfilename.lpstrFile && openfilename.lpstrFile[openfilename.nFileOffset-1] == 0 && openfilename.nFileOffset>0)  ++ if (openfilename.lpstrFile[openfilename.nFileOffset-1] == 0 &&  ++ openfilename.nFileOffset>0)  + { + while (openfilename.lpstrFile[i] != 0 || openfilename.lpstrFile[i+1] != 0) + { +@@ -534,12 +568,16 @@ static int winFileDlgPopup(Ihandle *ih, int x, int y) + } +  + iupAttribSetStr(ih, "STATUS", "0"); +- iupAttribSetStr(ih, "FILEEXIST", NULL); ++ iupAttribSetStr(ih, "FILEEXIST", "YES"); + } + else + { + if (iupdrvIsFile(openfilename.lpstrFile)) /* check if file exists */ + { ++ char* dir = iupStrFileGetPath(openfilename.lpstrFile); ++ iupAttribStoreStr(ih, "DIRECTORY", dir); ++ free(dir); ++ + iupAttribSetStr(ih, "FILEEXIST", "YES"); + iupAttribSetStr(ih, "STATUS", "0"); + } +diff --git a/iup/src/win/iupwin_focus.c b/iup/src/win/iupwin_focus.c +index 63da02d..2328dea 100755 +--- a/iup/src/win/iupwin_focus.c ++++ b/iup/src/win/iupwin_focus.c +@@ -32,7 +32,7 @@ +  + /* Since Windows XP, the focus feedback only appears after the user press a key. + Except for the IupText where the feedback is the caret. +- Before that if you click in a control the focus feedback will be hidden. ++ Before a key is pressed if you click in a control the focus feedback will be hidden. +  + We manually send WM_CHANGEUISTATE because we do not use IsDialogMessage anymore, + and the focus feedback was not shown even after the used press a key. +@@ -43,19 +43,28 @@ + void iupdrvSetFocus(Ihandle *ih) + { + SetFocus(ih->handle); +- SendMessage(ih->handle, WM_CHANGEUISTATE, UIS_CLEAR|UISF_HIDEFOCUS, 0); ++ ++ /* See comments above */ ++ SendMessage(ih->handle, WM_CHANGEUISTATE, UIS_CLEAR|UISF_HIDEFOCUS, 0); /* clear+hidefocus=showfocus */ + } +  + void iupwinWmSetFocus(Ihandle *ih) + { + Ihandle* dialog = IupGetDialog(ih); + if (ih != dialog) +- iupAttribSetStr(dialog, "_IUPWIN_LASTFOCUS", (char*)ih); /* used by IupMenu */ ++ iupAttribSetStr(dialog, "_IUPWIN_LASTFOCUS", (char*)ih); /* used by IupMenu and here. */ + else + { + /* if a control inside that dialog had the focus, then reset to it when the dialog gets the focus */ + Ihandle* lastfocus = (Ihandle*)iupAttribGet(dialog, "_IUPWIN_LASTFOCUS"); +- if (lastfocus) IupSetFocus(lastfocus); ++ if (lastfocus) ++ { ++ /* call the callback and update current focus before changing it again */ ++ iupCallGetFocusCb(ih); ++ ++ IupSetFocus(lastfocus); ++ return; ++ } + } +  + iupCallGetFocusCb(ih); +diff --git a/iup/src/win/iupwin_font.c b/iup/src/win/iupwin_font.c +index 659e2d9..c10befb 100755 +--- a/iup/src/win/iupwin_font.c ++++ b/iup/src/win/iupwin_font.c +@@ -70,7 +70,7 @@ static IwinFont* winFindFont(const char *standardfont) + if (height < 0)  + height_pixels = height; /* already in pixels */ + else +- height_pixels = -IUPWIN_PT2PIXEL(height, res); ++ height_pixels = -iupWIN_PT2PIXEL(height, res); +  + if (height_pixels == 0) + return NULL; +@@ -119,7 +119,7 @@ static void winFontFromLogFont(LOGFONT* logfont, char * font) + int is_strikeout = logfont->lfStrikeOut; + int height_pixels = logfont->lfHeight; /* negative value */ + int res = iupwinGetScreenRes(); +- int height = IUPWIN_PIXEL2PT(-height_pixels, res); /* return in points */ ++ int height = iupWIN_PIXEL2PT(-height_pixels, res); /* return in points */ +  + sprintf(font, "%s, %s%s%s%s %d", logfont->lfFaceName,  + is_bold?"Bold ":"",  +diff --git a/iup/src/win/iupwin_fontdlg.c b/iup/src/win/iupwin_fontdlg.c +index 0602441..ce27cf2 100755 +--- a/iup/src/win/iupwin_fontdlg.c ++++ b/iup/src/win/iupwin_fontdlg.c +@@ -68,7 +68,7 @@ static int winFontDlgPopup(Ihandle* ih, int x, int y) +  + standardfont = iupAttribGet(ih, "VALUE"); + if (!standardfont) +- return IUP_ERROR; ++ standardfont = IupGetGlobal("DEFAULTFONT"); +  + /* parse the old format first */ + if (!iupFontParseWin(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout)) +@@ -81,7 +81,7 @@ static int winFontDlgPopup(Ihandle* ih, int x, int y) + if (height < 0) + height_pixels = height; /* already in pixels */ + else +- height_pixels = -IUPWIN_PT2PIXEL(height, res); ++ height_pixels = -iupWIN_PT2PIXEL(height, res); +  + if (height_pixels == 0) + return IUP_ERROR; +@@ -134,7 +134,7 @@ static int winFontDlgPopup(Ihandle* ih, int x, int y) + if (height < 0) /* not an error, use old value as a reference for the units */ + height = height_pixels; /* return in pixels */ + else +- height = IUPWIN_PIXEL2PT(-height_pixels, res); /* return in points */ ++ height = iupWIN_PIXEL2PT(-height_pixels, res); /* return in points */ +  + iupAttribSetStrf(ih, "VALUE", "%s, %s%s%s%s %d", logfont.lfFaceName,  + is_bold?"Bold ":"",  +diff --git a/iup/src/win/iupwin_frame.c b/iup/src/win/iupwin_frame.c +index 0949b5d..3f56aed 100755 +--- a/iup/src/win/iupwin_frame.c ++++ b/iup/src/win/iupwin_frame.c +@@ -47,6 +47,27 @@ void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y) + } + } +  ++static char* winFrameGetBgColorAttrib(Ihandle* ih) ++{ ++ if (iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) ++ return NULL; ++ else ++ return iupBaseNativeParentGetBgColorAttrib(ih); ++} ++ ++static int winFrameSetBgColorAttrib(Ihandle* ih, const char* value) ++{ ++ (void)value; ++ ++ if (iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) ++ { ++ IupUpdate(ih); /* post a redraw */ ++ return 1; ++ } ++ else ++ return 0; ++} ++ + static void winFrameDrawText(HDC hDC, const char* text, int x, int y, COLORREF fgcolor) + { + COLORREF oldcolor; +@@ -126,6 +147,16 @@ static void winFrameDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem) + DrawEdge(hDC, &drawitem->rcItem, EDGE_SUNKEN, BF_RECT); + else + DrawEdge(hDC, &drawitem->rcItem, EDGE_ETCHED, BF_RECT); ++ ++ if (iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) ++ { ++ unsigned char r=0, g=0, b=0; ++ char* color = iupAttribGetStr(ih, "BGCOLOR"); ++ iupStrToRGB(color, &r, &g, &b); ++ SetDCBrushColor(hDC, RGB(r,g,b)); ++ InflateRect(&drawitem->rcItem, -2, -2); ++ FillRect(hDC, &drawitem->rcItem, (HBRUSH)GetStockObject(DC_BRUSH)); ++ } + } +  + iupwinDrawDestroyBitmapDC(&bmpDC); +@@ -169,11 +200,13 @@ static int winFrameMapMethod(Ihandle* ih) + title = iupAttribGet(ih, "TITLE"); + if (title) + iupAttribSetStr(ih, "_IUPFRAME_HAS_TITLE", "1"); +- +- if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) +- dwExStyle |= WS_EX_COMPOSITED; + else +- dwStyle |= WS_CLIPCHILDREN; ++ { ++ if (iupAttribGet(ih, "BGCOLOR")) ++ iupAttribSetStr(ih, "_IUPFRAME_HAS_BGCOLOR", "1"); ++ } ++ ++ iupwinGetNativeParentStyle(ih, &dwExStyle, &dwStyle); +  + if (!iupwinCreateWindowEx(ih, "BUTTON", dwExStyle, dwStyle)) + return IUP_ERROR; +@@ -195,7 +228,7 @@ void iupdrvFrameInitClass(Iclass* ic) + /* Driver Dependent Attribute functions */ +  + /* Visual */ +- iupClassRegisterAttribute(ic, "BGCOLOR", iupBaseNativeParentGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);  ++ iupClassRegisterAttribute(ic, "BGCOLOR", winFrameGetBgColorAttrib, winFrameSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);  +  + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_NOT_MAPPED); +diff --git a/iup/src/win/iupwin_globalattrib.c b/iup/src/win/iupwin_globalattrib.c +index a176925..bcd6355 100755 +--- a/iup/src/win/iupwin_globalattrib.c ++++ b/iup/src/win/iupwin_globalattrib.c +@@ -148,6 +148,11 @@ int iupdrvSetGlobal(const char *name, const char *value) + winGlobalSendKey(key, 0x03); + return 0; + } ++ if (iupStrEqual(name, "DLL_HINSTANCE")) ++ { ++ iupwin_dll_hinstance = (HINSTANCE)value; ++ return 0; ++ } + return 1; + } +  +@@ -239,5 +244,7 @@ char *iupdrvGetGlobal(const char *name) + return "YES"; + return "NO"; + } ++ if (iupStrEqual(name, "DLL_HINSTANCE")) ++ return (char*)iupwin_dll_hinstance; + return NULL; + } +diff --git a/iup/src/win/iupwin_info.c b/iup/src/win/iupwin_info.c +index 8ea7dd4..4d57289 100755 +--- a/iup/src/win/iupwin_info.c ++++ b/iup/src/win/iupwin_info.c +@@ -18,7 +18,7 @@ + #include "iupwin_info.h" +  +  +-int iupwinIsVista(void) ++int iupwinIsVistaOrNew(void) + { + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); +diff --git a/iup/src/win/iupwin_info.h b/iup/src/win/iupwin_info.h +index d39bae0..8d461fb 100755 +--- a/iup/src/win/iupwin_info.h ++++ b/iup/src/win/iupwin_info.h +@@ -16,7 +16,7 @@ int iupwinGetSystemMajorVersion(void); + int iupwinGetComCtl32Version(void); + char* iupwinGetSystemLanguage(void); + int iupwinIsAppThemed(void); +-int iupwinIsVista(void); ++int iupwinIsVistaOrNew(void); +  + /* color */ + void iupwinGetSysColor(char* color, int wincolor); +diff --git a/iup/src/win/iupwin_key.c b/iup/src/win/iupwin_key.c +index 921ed94..899e837 100755 +--- a/iup/src/win/iupwin_key.c ++++ b/iup/src/win/iupwin_key.c +@@ -317,32 +317,32 @@ int iupwinKeyEvent(Ihandle* ih, int wincode, int press) + void iupwinButtonKeySetStatus(WORD keys, char* status, int doubleclick) + { + if (keys & MK_SHIFT) +- iupKEYSETSHIFT(status); ++ iupKEY_SETSHIFT(status); +  + if (keys & MK_CONTROL) +- iupKEYSETCONTROL(status);  ++ iupKEY_SETCONTROL(status);  +  + if (keys & MK_LBUTTON) +- iupKEYSETBUTTON1(status); ++ iupKEY_SETBUTTON1(status); +  + if (keys & MK_MBUTTON) +- iupKEYSETBUTTON2(status); ++ iupKEY_SETBUTTON2(status); +  + if (keys & MK_RBUTTON) +- iupKEYSETBUTTON3(status); ++ iupKEY_SETBUTTON3(status); +  + if (doubleclick) +- iupKEYSETDOUBLE(status); ++ iupKEY_SETDOUBLE(status); +  + if (GetKeyState(VK_MENU) & 0x8000) +- iupKEYSETALT(status); ++ iupKEY_SETALT(status); +  + if ((GetKeyState(VK_LWIN) & 0x8000) || (GetKeyState(VK_RWIN) & 0x8000)) +- iupKEYSETSYS(status); ++ iupKEY_SETSYS(status); +  + if (keys & MK_XBUTTON1) +- iupKEYSETBUTTON4(status); ++ iupKEY_SETBUTTON4(status); +  + if (keys & MK_XBUTTON2) +- iupKEYSETBUTTON5(status); ++ iupKEY_SETBUTTON5(status); + } +diff --git a/iup/src/win/iupwin_label.c b/iup/src/win/iupwin_label.c +index d5a1f53..95dd10c 100755 +--- a/iup/src/win/iupwin_label.c ++++ b/iup/src/win/iupwin_label.c +@@ -173,7 +173,7 @@ static int winLabelSetAlignmentAttrib(Ihandle* ih, const char* value) + else /* "ATOP" */ + ih->data->vert_alignment = IUP_ALIGN_ATOP; +  +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + } + return 0; + } +@@ -197,7 +197,7 @@ static int winLabelSetPaddingAttrib(Ihandle* ih, const char* value) + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); +  + if (ih->handle && ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); +  + return 0; + } +@@ -211,7 +211,7 @@ static int winLabelSetWordWrapAttrib(Ihandle* ih, const char* value) + else + ih->data->text_style &= ~DT_WORDBREAK; +  +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + } +  + return 1; +@@ -226,7 +226,7 @@ static int winLabelSetEllipsisAttrib(Ihandle* ih, const char* value) + else + ih->data->text_style &= ~DT_END_ELLIPSIS; +  +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + } +  + return 1; +@@ -240,12 +240,24 @@ static int winLabelSetFgColorAttrib(Ihandle* ih, const char* value) + if (iupStrToRGB(value, &r, &g, &b)) + { + ih->data->fgcolor = RGB(r,g,b); +- iupdrvDisplayRedraw(ih); ++ ++ if (ih->handle) ++ iupdrvRedrawNow(ih); + } + } + return 1; + } +  ++static int winLabelSetUpdateAttrib(Ihandle* ih, const char* value) ++{ ++ (void)value; ++ ++ if (ih->handle) ++ iupdrvPostRedraw(ih); /* Post a redraw */ ++ ++ return 1; ++} ++ + static int winLabelProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) + { + switch (msg) +@@ -257,6 +269,7 @@ static int winLabelProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *re + *result = WVR_HREDRAW|WVR_VREDRAW; + return 1; + } ++ break; + } + } +  +@@ -266,7 +279,7 @@ static int winLabelProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *re + static int winLabelMapMethod(Ihandle* ih) + { + char* value; +- DWORD dwStyle = WS_CHILD | ++ DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | + SS_NOTIFY; /* SS_NOTIFY is necessary because of the base messages */ +  + if (!ih->parent) +@@ -330,7 +343,7 @@ void iupdrvLabelInitClass(Iclass* ic) +  + /* IupLabel only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", winLabelGetAlignmentAttrib, winLabelSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT:ACENTER", IUPAF_NO_INHERIT); +- iupClassRegisterAttribute(ic, "IMAGE", NULL, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); ++ iupClassRegisterAttribute(ic, "IMAGE", NULL, winLabelSetUpdateAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PADDING", iupLabelGetPaddingAttrib, winLabelSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); +  + /* IupLabel Windows and GTK only */ +diff --git a/iup/src/win/iupwin_list.c b/iup/src/win/iupwin_list.c +index 8fdadb6..cb510b5 100755 +--- a/iup/src/win/iupwin_list.c ++++ b/iup/src/win/iupwin_list.c +@@ -154,6 +154,8 @@ void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value) + SendMessage(ih->handle, WIN_INSERTSTRING(ih), pos, (LPARAM)value); + SendMessage(ih->handle, WIN_SETITEMDATA(ih), pos, (LPARAM)iupdrvFontGetStringWidth(ih, value)); + winListUpdateScrollWidth(ih); ++ ++ iupListUpdateOldValue(ih, pos, 0); + } +  + void iupdrvListRemoveItem(Ihandle* ih, int pos) +@@ -164,8 +166,14 @@ void iupdrvListRemoveItem(Ihandle* ih, int pos) + int curpos = SendMessage(ih->handle, WIN_GETCURSEL(ih), 0, 0); + if (pos == curpos) + { +- if (curpos > 0) curpos--; +- else curpos++; ++ if (curpos > 0)  ++ curpos--; ++ else  ++ { ++ curpos=1; ++ if (iupdrvListGetCount(ih)==1) ++ curpos = -1; /* remove the selection */ ++ } +  + SendMessage(ih->handle, WIN_SETCURSEL(ih), curpos, 0); + } +@@ -173,6 +181,8 @@ void iupdrvListRemoveItem(Ihandle* ih, int pos) +  + SendMessage(ih->handle, WIN_DELETESTRING(ih), pos, 0L); + winListUpdateScrollWidth(ih); ++ ++ iupListUpdateOldValue(ih, pos, 1); + } +  + void iupdrvListRemoveAllItems(Ihandle* ih) +@@ -220,18 +230,29 @@ static void winListUpdateItemWidth(Ihandle* ih) + } + } +  ++static int winListSetBgColorAttrib(Ihandle *ih, const char *value) ++{ ++ (void)value; ++ if (ih->handle) ++ iupdrvPostRedraw(ih); ++ return 1; ++} ++ + static int winListSetStandardFontAttrib(Ihandle* ih, const char* value) + { + iupdrvSetStandardFontAttrib(ih, value); +- winListUpdateItemWidth(ih); +- winListUpdateScrollWidth(ih); ++ if (ih->handle) ++ { ++ winListUpdateItemWidth(ih); ++ winListUpdateScrollWidth(ih); ++ } + return 1; + } +  + static char* winListGetIdValueAttrib(Ihandle* ih, const char* name_id) + { + int pos = iupListGetPos(ih, name_id); +- if (pos != -1) ++ if (pos >= 0) + { + int len = SendMessage(ih->handle, WIN_GETTEXTLEN(ih), (WPARAM)pos, 0); + char* str = iupStrGetMemory(len+1); +@@ -514,8 +535,10 @@ static int winListSetNCAttrib(Ihandle* ih, const char* value) + { + HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_LIMITTEXT, ih->data->nc, 0L); ++ return 0; + } +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int winListSetSelectionAttrib(Ihandle* ih, const char* value) +@@ -995,13 +1018,27 @@ static int winListEditProc(Ihandle* ih, HWND cbedit, UINT msg, WPARAM wp, LPARAM + if (msg==WM_KEYDOWN) /* process K_ANY before text callbacks */ + { + ret = iupwinBaseProc(ih, msg, wp, lp, result); +- if (ret) return 1; ++ if (ret)  ++ { ++ iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", "1"); ++ *result = 0; ++ return 1; ++ } ++ else ++ iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", NULL); + } +  + switch (msg) + { + case WM_CHAR: + { ++ if (iupAttribGet(ih, "_IUPWIN_IGNORE_CHAR")) ++ { ++ iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", NULL); ++ *result = 0; ++ return 1; ++ } ++ + if ((char)wp == '\b') + {  + if (!winListCallEditCb(ih, cbedit, NULL, 0, -1)) +@@ -1301,7 +1338,7 @@ static void winListLayoutUpdateMethod(Ihandle *ih) + static int winListMapMethod(Ihandle* ih) + { + char* class_name; +- DWORD dwStyle = WS_CHILD, ++ DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS, + dwExStyle = WS_EX_CLIENTEDGE; +  + if (!ih->parent) +@@ -1426,7 +1463,7 @@ void iupdrvListInitClass(Iclass* ic) + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, winListSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); +  + /* Visual */ +- iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED);  ++ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winListSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED); +  + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED); +diff --git a/iup/src/win/iupwin_loop.c b/iup/src/win/iupwin_loop.c +index 7c5dbe7..fd25537 100755 +--- a/iup/src/win/iupwin_loop.c ++++ b/iup/src/win/iupwin_loop.c +@@ -106,6 +106,18 @@ int IupMainLoop(void) + return IUP_NOERROR; + } +  ++int IupLoopStepWait(void) ++{ ++ MSG msg; ++ int ret = GetMessage(&msg, NULL, 0, 0); ++ if (ret == -1) /* error */ ++ return IUP_ERROR; ++ if (ret == 0 || /* WM_QUIT */ ++ winLoopProcessMessage(&msg) == IUP_CLOSE) /* ret != 0 */ ++ return IUP_CLOSE; ++ return IUP_DEFAULT; ++} ++ + int IupLoopStep(void) + { + MSG msg; +diff --git a/iup/src/win/iupwin_menu.c b/iup/src/win/iupwin_menu.c +index 74a8b52..06ad93e 100755 +--- a/iup/src/win/iupwin_menu.c ++++ b/iup/src/win/iupwin_menu.c +@@ -385,7 +385,10 @@ static int winMenuMapMethod(Ihandle* ih) + static void winMenuUnMapMethod(Ihandle* ih) + { + if (iupMenuIsMenuBar(ih)) ++ { + SetMenu(ih->parent->handle, NULL); ++ ih->parent = NULL; ++ } +  + DestroyMenu((HMENU)ih->handle); /* DestroyMenu is recursive */ + } +diff --git a/iup/src/win/iupwin_open.c b/iup/src/win/iupwin_open.c +index 7357cde..3629ce4 100755 +--- a/iup/src/win/iupwin_open.c ++++ b/iup/src/win/iupwin_open.c +@@ -76,8 +76,9 @@ int iupdrvOpen(int *argc, char ***argv) + iupwin_hinstance = GetModuleHandle(NULL); + IupSetGlobal("HINSTANCE", (char*)iupwin_hinstance); + } +- +- CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); ++  ++ if (CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)==RPC_E_CHANGED_MODE) ++ IupSetGlobal("_IUPWIN_COINIT_MULTITHREADED", "1"); +  + { + INITCOMMONCONTROLSEX InitCtrls; +diff --git a/iup/src/win/iupwin_progressbar.c b/iup/src/win/iupwin_progressbar.c +index 9038d79..4a52cc4 100755 +--- a/iup/src/win/iupwin_progressbar.c ++++ b/iup/src/win/iupwin_progressbar.c +@@ -106,7 +106,7 @@ static int winProgressBarSetFgColorAttrib(Ihandle* ih, const char* value) +  + static int winProgressBarMapMethod(Ihandle* ih) + { +- DWORD dwStyle = WS_CHILD; ++ DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS; +  + if (!ih->parent) + return IUP_ERROR; +diff --git a/iup/src/win/iupwin_tabs.c b/iup/src/win/iupwin_tabs.c +index 682f451..b39f7fe 100755 +--- a/iup/src/win/iupwin_tabs.c ++++ b/iup/src/win/iupwin_tabs.c +@@ -232,10 +232,7 @@ static HWND winTabCreatePageWindow(Ihandle* ih) + DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS,  + dwExStyle = 0; +  +- if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) +- dwExStyle |= WS_EX_COMPOSITED; +- else +- dwStyle |= WS_CLIPCHILDREN; ++ iupwinGetNativeParentStyle(ih, &dwExStyle, &dwStyle); +  + hWnd = CreateWindowEx(dwExStyle, "IupTabsPage", NULL, dwStyle,  + 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,  +@@ -255,9 +252,12 @@ static int winTabsSetPaddingAttrib(Ihandle* ih, const char* value) + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); +  + if (ih->handle) ++ { + SendMessage(ih->handle, TCM_SETPADDING, 0, MAKELPARAM(ih->data->horiz_padding, ih->data->vert_padding)); +- +- return 0; ++ return 0; ++ } ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int winTabsSetMultilineAttrib(Ihandle* ih, const char* value) +@@ -368,6 +368,13 @@ static char* winTabsGetBgColorAttrib(Ihandle* ih) + return IupGetGlobal("DLGBGCOLOR"); + } +  ++static int winTabsSetBgColorAttrib(Ihandle *ih, const char *value) ++{ ++ (void)value; ++ iupdrvPostRedraw(ih); ++ return 1; ++} ++ +  + /* ------------------------------------------------------------------------- */ + /* winTabs - Calls the user callback to change of tab */ +@@ -397,6 +404,7 @@ static int winTabsWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) + int prev_pos = SendMessage(ih->handle, TCM_GETCURSEL, 0, 0); + iupAttribSetInt(ih, "_IUPTABS_PREV_CHILD_POS", prev_pos); +  ++ /* save the previous handle if callback exists */ + if (cb) + { + Ihandle* prev_child = IupGetChild(ih, prev_pos); +@@ -420,7 +428,9 @@ static int winTabsWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) + Ihandle* prev_child = (Ihandle*)iupAttribGet(ih, "_IUPTABS_PREV_CHILD"); + iupAttribSetStr(ih, "_IUPTABS_PREV_CHILD", NULL); +  +- cb(ih, child, prev_child); ++ /* avoid duplicate calls when a Tab is inside another Tab. */ ++ if (prev_child) ++ cb(ih, child, prev_child); + } + } +  +@@ -522,7 +532,7 @@ static void winTabsChildAddedMethod(Ihandle* ih, Ihandle* child) + } + } +  +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + } + } + } +@@ -535,12 +545,11 @@ static void winTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) + if (tab_page) + { + int pos = winTabsGetPageWindowPos(ih, tab_page); ++ iupTabsTestRemoveTab(ih, pos); ++ + SendMessage(ih->handle, TCM_DELETEITEM, pos, 0); + DestroyWindow(tab_page); +  +- if (pos==0) pos++; +- iupdrvTabsSetCurrentTab(ih, pos-1); +- + iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL); + } + } +@@ -564,19 +573,14 @@ static int winTabsMapMethod(Ihandle* ih) + if (ih->data->is_multiline) + dwStyle |= TCS_MULTILINE; +  +- if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) +- { +- dwExStyle |= WS_EX_COMPOSITED; ++ iupwinGetNativeParentStyle(ih, &dwExStyle, &dwStyle); +  +- if (!ih->data->is_multiline && iupwinIsVista()) +- { +- /* workaround for composite bug in Vista */ +- ih->data->is_multiline = 1;  +- dwStyle |= TCS_MULTILINE; +- } ++ if (dwExStyle & WS_EX_COMPOSITED && !ih->data->is_multiline && iupwinIsVistaOrNew()) ++ { ++ /* workaround for composite bug in Vista */ ++ ih->data->is_multiline = 1;  ++ dwStyle |= TCS_MULTILINE; + } +- else +- dwStyle |= WS_CLIPCHILDREN; +  + if (!iupwinCreateWindowEx(ih, WC_TABCONTROL, dwExStyle, dwStyle)) + return IUP_ERROR; +@@ -665,7 +669,7 @@ void iupdrvTabsInitClass(Iclass* ic) + /* Driver Dependent Attribute functions */ +  + /* Visual */ +- iupClassRegisterAttribute(ic, "BGCOLOR", winTabsGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);  ++ iupClassRegisterAttribute(ic, "BGCOLOR", winTabsGetBgColorAttrib, winTabsSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); +  + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_NOT_MAPPED); +@@ -676,5 +680,9 @@ void iupdrvTabsInitClass(Iclass* ic) + iupClassRegisterAttribute(ic, "MULTILINE", winTabsGetMultilineAttrib, winTabsSetMultilineAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TABTITLE", NULL, winTabsSetTabTitleAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, winTabsSetTabImageAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +- iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, winTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); ++ iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, winTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); ++ ++ /* necessary because transparent background does not work when not using visual styles */ ++ if (!iupwin_comctl32ver6) /* Used by iupdrvImageCreateImage */ ++ iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + } +diff --git a/iup/src/win/iupwin_text.c b/iup/src/win/iupwin_text.c +index dfe489a..2a61724 100755 +--- a/iup/src/win/iupwin_text.c ++++ b/iup/src/win/iupwin_text.c +@@ -432,8 +432,8 @@ static int winTextSetLinColToPosition(Ihandle *ih, int lin, int col) + col--; +  + linmax = SendMessage(ih->handle, EM_GETLINECOUNT, 0, 0L); +- if (lin > linmax) +- lin = linmax; ++ if (lin > linmax-1) ++ lin = linmax-1; +  + lineindex = SendMessage(ih->handle, EM_LINEINDEX, (WPARAM)lin, 0L); +  +@@ -639,8 +639,12 @@ static int winTextSetPaddingAttrib(Ihandle* ih, const char* value) + iupStrToIntInt(value, &(ih->data->horiz_padding), &(ih->data->vert_padding), 'x'); + ih->data->vert_padding = 0; + if (ih->handle) ++ { + SendMessage(ih->handle, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELPARAM(ih->data->horiz_padding, ih->data->horiz_padding)); +- return 0; ++ return 0; ++ } ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int winTextSetSelectedTextAttrib(Ihandle* ih, const char* value) +@@ -713,8 +717,11 @@ static int winTextSetNCAttrib(Ihandle* ih, const char* value) + SendMessage(ih->handle, EM_EXLIMITTEXT, 0, ih->data->nc); /* so it can be larger than 64k */ + else + SendMessage(ih->handle, EM_LIMITTEXT, ih->data->nc, 0L); ++ ++ return 0; + } +- return 0; ++ else ++ return 1; /* store until not mapped, when mapped will be set again */ + } +  + static int winTextSetSelectionAttrib(Ihandle* ih, const char* value) +@@ -845,7 +852,7 @@ static char* winTextGetSelectionPosAttrib(Ihandle* ih) +  + static int winTextSetInsertAttrib(Ihandle* ih, 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; + if (value) + { +@@ -867,9 +874,9 @@ static int winTextSetInsertAttrib(Ihandle* ih, const char* value) +  + static int winTextSetAppendAttrib(Ihandle* ih, const char* value) + { +- int len; ++ int pos; + char* str; +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; + if (!value) value = ""; + str = (char*)value; +@@ -881,9 +888,9 @@ static int winTextSetAppendAttrib(Ihandle* ih, const char* value) + str = iupStrToDos(str); + } +  +- len = GetWindowTextLength(ih->handle)+1; +- SendMessage(ih->handle, EM_SETSEL, (WPARAM)len, (LPARAM)len); +- if (ih->data->is_multiline && ih->data->append_newline) ++ pos = GetWindowTextLength(ih->handle)+1; ++ SendMessage(ih->handle, EM_SETSEL, (WPARAM)pos, (LPARAM)pos); ++ if (ih->data->is_multiline && ih->data->append_newline && pos!=1) + { + if (ih->data->has_formatting) + SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\r"); +@@ -920,7 +927,7 @@ static int winTextSetTabSizeAttrib(Ihandle* ih, const char* value) + iupStrToInt(value, &tabsize); + tabsize *= 4; + SendMessage(ih->handle, EM_SETTABSTOPS, (WPARAM)1L, (LPARAM)&tabsize); +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + return 1; + } +  +@@ -1120,6 +1127,7 @@ static int winTextSetBgColorAttrib(Ihandle *ih, const char *value) + SendMessage(ih->handle, EM_SETBKGNDCOLOR, 0, (LPARAM)color); + } + } ++ iupdrvPostRedraw(ih); + return 1; + } +  +@@ -1529,15 +1537,27 @@ static int winTextProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res + ret = iupwinBaseProc(ih, msg, wp, lp, result); + if (ret)  + { ++ iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", "1"); + *result = 0; + return 1; + } ++ else ++ iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", NULL); + } +  + switch (msg) + { + case WM_CHAR: + { ++ /* even aborting WM_KEYDOWN, a WM_CHAR will be sent, so ignore it also */ ++ /* if a dialog was shown, the loop will be processed, so ignore out of focus WM_CHAR messages */ ++ if (GetFocus() != ih->handle || iupAttribGet(ih, "_IUPWIN_IGNORE_CHAR")) ++ { ++ iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", NULL); ++ *result = 0; ++ return 1; ++ } ++ + if ((char)wp == '\b') + {  + if (!winTextCallActionCb(ih, NULL, 0, -1)) +@@ -1736,7 +1756,7 @@ static int winTextProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res + static void winTextCreateSpin(Ihandle* ih) + { + HWND hSpin; +- DWORD dwStyle = WS_CHILD|UDS_ARROWKEYS|UDS_HOTTRACK|UDS_NOTHOUSANDS; ++ DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS|UDS_ARROWKEYS|UDS_HOTTRACK|UDS_NOTHOUSANDS; + int serial = iupDialogGetChildId(ih); +  + if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT")) +@@ -1826,7 +1846,7 @@ static void winTextLayoutUpdateMethod(Ihandle* ih) +  + static int winTextMapMethod(Ihandle* ih) + { +- DWORD dwStyle = WS_CHILD,  ++ DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS,  + dwExStyle = 0; + char* winclass = "EDIT", *value; +  +@@ -1873,7 +1893,7 @@ static int winTextMapMethod(Ihandle* ih) + } + else + { +- dwStyle |= ES_AUTOHSCROLL|ES_NOHIDESEL; ++ dwStyle |= ES_AUTOHSCROLL; +  + if (iupAttribGetBoolean(ih, "PASSWORD")) + dwStyle |= ES_PASSWORD; +@@ -1950,8 +1970,8 @@ void iupdrvTextInitClass(Iclass* ic) + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, winTextSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); +  + /* Overwrite Visual */ +- iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED);  +- iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, winTextSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); ++ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT);  ++ iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, winTextSetVisibleAttrib, "YES", "NO", IUPAF_DEFAULT); +  + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED); /* usually black */  +diff --git a/iup/src/win/iupwin_toggle.c b/iup/src/win/iupwin_toggle.c +index fcaa438..c17f594 100755 +--- a/iup/src/win/iupwin_toggle.c ++++ b/iup/src/win/iupwin_toggle.c +@@ -35,7 +35,9 @@ +  + void iupdrvToggleAddCheckBox(int *x, int *y) + { +- (*x) += 16+6; ++ (*x) += 16+8; ++ if (!iupwin_comctl32ver6) ++ (*x) += 4; + if ((*y) < 16) (*y) = 16; /* minimum height */ + } +  +@@ -229,7 +231,7 @@ static int winToggleSetImageAttrib(Ihandle* ih, const char* value) + iupAttribSetStr(ih, "IMAGE", (char*)value); +  + if (iupwin_comctl32ver6) +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + else + { + int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L); +@@ -249,7 +251,7 @@ static int winToggleSetImInactiveAttrib(Ihandle* ih, const char* value) + iupAttribSetStr(ih, "IMINACTIVE", (char*)value); +  + if (iupwin_comctl32ver6) +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + else + { + int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L); +@@ -269,7 +271,7 @@ static int winToggleSetImPressAttrib(Ihandle* ih, const char* value) + iupAttribSetStr(ih, "IMPRESS", (char*)value); +  + if (iupwin_comctl32ver6) +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + else + { + int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L); +@@ -339,7 +341,7 @@ static int winToggleSetActiveAttrib(Ihandle* ih, const char* value) + if (iupwin_comctl32ver6) + { + iupBaseSetActiveAttrib(ih, value); +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + return 0; + } + else +@@ -382,11 +384,21 @@ static int winToggleSetPaddingAttrib(Ihandle* ih, const char* value) + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); +  + if (ih->handle && iupwin_comctl32ver6 && ih->data->type == IUP_TOGGLE_IMAGE) +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); +  + return 0; + } +  ++static int winToggleSetUpdateAttrib(Ihandle* ih, const char* value) ++{ ++ (void)value; ++ ++ if (ih->handle) ++ iupdrvPostRedraw(ih); /* Post a redraw */ ++ ++ return 1; ++} ++ + static int winToggleSetBgColorAttrib(Ihandle* ih, const char* value) + { + (void)value; +@@ -395,7 +407,7 @@ static int winToggleSetBgColorAttrib(Ihandle* ih, const char* value) + /* update internal image cache for controls that have the IMAGE attribute */ + iupAttribSetStr(ih, "BGCOLOR", value); + iupImageUpdateParent(ih); +- iupdrvDisplayRedraw(ih); ++ iupdrvRedrawNow(ih); + } + return 1; + } +@@ -591,7 +603,7 @@ static int winToggleMapMethod(Ihandle* ih) + { + Ihandle* radio = iupRadioFindToggleParent(ih); + char* value; +- DWORD dwStyle = WS_CHILD |  ++ DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | + BS_NOTIFY; /* necessary because of the base messages */ +  + if (!ih->parent) +@@ -673,11 +685,11 @@ void iupdrvToggleInitClass(Iclass* ic) + iupClassRegisterAttribute(ic, "BGCOLOR", winToggleGetBgColorAttrib, winToggleSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);  +  + /* Special */ +- iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force the new default value */  ++ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winToggleSetUpdateAttrib, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force the new default value */  + iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, winToggleSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +  + /* IupToggle only */ +- iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, NULL, IUPAF_SAMEASSYSTEM, "ACENTER:ACENTER", IUPAF_NO_INHERIT); ++ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, winToggleSetUpdateAttrib, IUPAF_SAMEASSYSTEM, "ACENTER:ACENTER", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, winToggleSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, winToggleSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESS", NULL, winToggleSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +diff --git a/iup/src/win/iupwin_tree.c b/iup/src/win/iupwin_tree.c +index e6877dc..4a5f8be 100755 +--- a/iup/src/win/iupwin_tree.c ++++ b/iup/src/win/iupwin_tree.c +@@ -31,17 +31,19 @@ + #include "iupwin_draw.h" + #include "iupwin_info.h" +  ++ + typedef struct _winTreeItemData + { + COLORREF color; + unsigned char kind; +- void* userdata; + HFONT hFont; + short image; + short image_expanded; + } winTreeItemData; +  +-#ifndef TVN_ITEMCHANGING /* Vista Only */ ++/* Vista Only */ ++ ++#ifndef TVN_ITEMCHANGING  + typedef struct tagNMTVITEMCHANGE { + NMHDR hdr; + UINT uChanged; +@@ -54,257 +56,125 @@ typedef struct tagNMTVITEMCHANGE { + #define TVN_ITEMCHANGINGW (TVN_FIRST-17)  + #endif +  +-static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem); +-typedef int (*winTreeNodeFunc)(Ihandle* ih, HTREEITEM hItem, void* userdata); +- +-static int winTreeForEach(Ihandle* ih, HTREEITEM hItem, winTreeNodeFunc func, void* userdata) +-{ +- HTREEITEM hItemChild; +- +- if (!hItem) +- hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); ++#ifndef TVS_EX_DOUBLEBUFFER ++#define TVS_EX_DOUBLEBUFFER 0x0004 ++#endif +  +- while(hItem != NULL) +- { +- if (!func(ih, hItem, userdata)) +- return 0; ++#ifndef TVM_SETEXTENDEDSTYLE ++#define TVM_SETEXTENDEDSTYLE (TV_FIRST + 44) ++#endif +  +- hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); +- if (hItemChild) +- { +- /* Recursively traverse child items */ +- if (!winTreeForEach(ih, hItemChild, func, userdata)) +- return 0; +- } +  +- /* Go to next sibling item */ +- hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); +- } ++static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem); +  +- return 1; +-} +  + /*****************************************************************************/ + /* FINDING ITEMS */ + /*****************************************************************************/ +-static HTREEITEM winTreeFindNodeID(Ihandle* ih, HTREEITEM hItem, HTREEITEM hNode) +-{ +- TVITEM item; +- winTreeItemData* itemData; +- +- while(hItem != NULL) +- { +- /* ID control to traverse items */ +- ih->data->id_control++; +- +- /* StateID founded! */ +- if(hItem == hNode) +- return hItem; +  +- /* Get hItem attributes */ +- item.hItem = hItem; +- item.mask = TVIF_HANDLE|TVIF_PARAM; +- SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); +- itemData = (winTreeItemData*)item.lParam; +- +- /* Check whether we have child items */ +- if (itemData->kind == ITREE_BRANCH) +- { +- /* Recursively traverse child items */ +- HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); +- hItemChild = winTreeFindNodeID(ih, hItemChild, hNode); +- +- /* StateID founded! */ +- if(hItemChild) +- return hItemChild; +- } +- /* Go to next sibling item */ +- hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); +- } +- +- return NULL; ++InodeHandle* iupdrvTreeGetFocusNode(Ihandle* ih) ++{ ++ return (InodeHandle*)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CARET, 0); + } +  +-static int winTreeGetNodeId(Ihandle* ih, HTREEITEM hItem) ++static HTREEITEM winTreeFindNodeXY(Ihandle* ih, int x, int y) + { +- HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); +- ih->data->id_control = -1; +- if (winTreeFindNodeID(ih, hItemRoot, hItem)) +- return ih->data->id_control; +- else +- return -1; ++ TVHITTESTINFO info; ++ info.pt.x = x; ++ info.pt.y = y; ++ return (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)(LPTVHITTESTINFO)&info); + } +  +-static HTREEITEM winTreeFindUserDataID(Ihandle* ih, HTREEITEM hItem, void* userdata) ++static HTREEITEM winTreeFindNodePointed(Ihandle* ih) + { +- TVITEM item; +- winTreeItemData* itemData; +- +- while(hItem != NULL) +- { +- /* ID control to traverse items */ +- ih->data->id_control++; +- +- /* Get hItem attributes */ +- item.hItem = hItem; +- item.mask = TVIF_HANDLE|TVIF_PARAM; +- SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); +- itemData = (winTreeItemData*)item.lParam; +- +- /* userdata founded! */ +- if(itemData->userdata == userdata) +- return hItem; +- +- /* Check whether we have child items */ +- if (itemData->kind == ITREE_BRANCH) +- { +- /* Recursively traverse child items */ +- HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); +- hItemChild = winTreeFindUserDataID(ih, hItemChild, userdata); +- +- /* userdata founded! */ +- if (hItemChild) +- return hItemChild; +- } +- +- /* Go to next sibling item */ +- hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); +- } +- +- return NULL; ++ TVHITTESTINFO info; ++ DWORD pos = GetMessagePos(); ++ info.pt.x = LOWORD(pos); ++ info.pt.y = HIWORD(pos); ++ ScreenToClient(ih->handle, &info.pt); ++ return (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)(LPTVHITTESTINFO)&info); + } +  +-static int winTreeGetUserDataId(Ihandle* ih, void* userdata) ++int iupwinGetColor(const char* value, COLORREF *color) + { +- HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); +- ih->data->id_control = -1; +- if (winTreeFindUserDataID(ih, hItemRoot, userdata)) +- return ih->data->id_control; +- else +- return -1; ++ unsigned char r, g, b; ++ if (iupStrToRGB(value, &r, &g, &b)) ++ { ++ *color = RGB(r,g,b); ++ return 1; ++ } ++ return 0; + } +  +-static HTREEITEM winTreeFindNodeFromID(Ihandle* ih, HTREEITEM hItem) ++static void winTreeChildCountRec(Ihandle* ih, HTREEITEM hItem, int *count) + { +- TVITEM item; +- winTreeItemData* itemData; +- ++ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + while(hItem != NULL) + { +- /* ID control to traverse items */ +- ih->data->id_control--; +- +- /* StateID founded! */ +- if(ih->data->id_control < 0) +- return hItem; +- +- /* Get hItem attributes */ +- item.hItem = hItem; +- item.mask = TVIF_HANDLE|TVIF_PARAM; +- SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); +- itemData = (winTreeItemData*)item.lParam; +- +- /* Check whether we have child items */ +- if (itemData->kind == ITREE_BRANCH) +- { +- /* Recursively traverse child items */ +- HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); +- hItemChild = winTreeFindNodeFromID(ih, hItemChild); ++ (*count)++; +  +- /* StateID founded! */ +- if(ih->data->id_control < 0) +- return hItemChild; +- } ++ /* go recursive to children */ ++ winTreeChildCountRec(ih, hItem, count); +  + /* Go to next sibling item */ + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } +- +- return hItem; + } +  +-static HTREEITEM winTreeFindNodeFromString(Ihandle* ih, const char* name_id) ++int iupdrvTreeTotalChildCount(Ihandle* ih, HTREEITEM hItem) + { +- if (name_id[0]) +- { +- HTREEITEM hRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); +- iupStrToInt(name_id, &ih->data->id_control); +- return winTreeFindNodeFromID(ih, hRoot); +- } +- else +- return (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CARET, 0); ++ int count = 0; ++ winTreeChildCountRec(ih, hItem, &count); ++ return count; + } +  +-/* Recursively, find a new brother for the item +- that will have its depth changed. Returns the new brother. */ +-static HTREEITEM winTreeFindNewBrother(Ihandle* ih, HTREEITEM hBrotherItem) ++static void winTreeChildRebuildCacheRec(Ihandle* ih, HTREEITEM hItem, int *id) + { +- TVITEM item; +- winTreeItemData* itemData; +- +- while(hBrotherItem != NULL) ++ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); ++ while(hItem != NULL) + { +- if(ih->data->id_control < 0) +- return hBrotherItem; +- +- item.hItem = hBrotherItem; +- item.mask = TVIF_HANDLE|TVIF_PARAM; +- SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); +- itemData = (winTreeItemData*)item.lParam; +- +- if (itemData->kind == ITREE_BRANCH) +- { +- HTREEITEM hItemChild; +- +- ih->data->id_control--; +- hItemChild = winTreeFindNewBrother(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hBrotherItem)); ++ (*id)++; ++ ih->data->node_cache[*id].node_handle = hItem; +  +- if(ih->data->id_control < 0) +- return hItemChild; +- } ++ /* go recursive to children */ ++ winTreeChildRebuildCacheRec(ih, hItem, id); +  +- hBrotherItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hBrotherItem); ++ /* Go to next sibling item */ ++ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } +- +- return hBrotherItem; + } +  +-static HTREEITEM winTreeFindNodePointed(Ihandle* ih) ++static void winTreeRebuildNodeCache(Ihandle* ih, int id, HTREEITEM hItem) + { +- TVHITTESTINFO info; +- DWORD pos = GetMessagePos(); +- info.pt.x = LOWORD(pos); +- info.pt.y = HIWORD(pos); +- +- ScreenToClient(ih->handle, &info.pt); +-  +- return (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)(LPTVHITTESTINFO)&info); ++ ih->data->node_cache[id].node_handle = hItem; ++ winTreeChildRebuildCacheRec(ih, hItem, &id); + } +  +-int iupwinGetColor(const char* value, COLORREF *color) +-{ +- unsigned char r, g, b; +- if (iupStrToRGB(value, &r, &g, &b)) +- { +- *color = RGB(r,g,b); +- return 1; +- } +- return 0; +-} +  + /*****************************************************************************/ + /* ADDING ITEMS */ + /*****************************************************************************/ ++ ++static void winTreeExpandItem(Ihandle* ih, HTREEITEM hItem, int expand); ++ + void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add) + { +- TVITEM item, tviPrevItem; ++ TVITEM item; + TVINSERTSTRUCT tvins; +- HTREEITEM hPrevItem = winTreeFindNodeFromString(ih, name_id); +- int kindPrev; ++ HTREEITEM hPrevItem = iupTreeGetNodeFromString(ih, name_id); ++ HTREEITEM hItemNew; + winTreeItemData* itemData; +  + if (!hPrevItem) +- return; ++ { ++ /* check if the root was really specified */ ++ int id = 0; ++ if (!iupStrToInt(name_id, &id) || id != -1) ++ return; ++ } ++ ++ if (!title) ++ title = ""; +  + itemData = calloc(1, sizeof(winTreeItemData)); + itemData->image = -1; +@@ -318,83 +188,71 @@ void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* t + iupwinGetColor(iupAttribGetStr(ih, "FGCOLOR"), &itemData->color); +  + if (kind == ITREE_BRANCH) +- { + item.iSelectedImage = item.iImage = (int)ih->data->def_image_collapsed; +- +- if (ih->data->add_expanded) +- { +- item.mask |= TVIF_STATE; +- item.state = item.stateMask = TVIS_EXPANDED; +- item.iSelectedImage = item.iImage = (int)ih->data->def_image_expanded; +- } +- } + else + item.iSelectedImage = item.iImage = (int)ih->data->def_image_leaf; +  + /* Save the heading level in the node's application-defined data area */ + tvins.item = item; +  +- /* get the KIND attribute of node selected */  +- tviPrevItem.hItem = hPrevItem; +- tviPrevItem.mask = TVIF_PARAM|TVIF_CHILDREN;  +- SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&tviPrevItem); +- kindPrev = ((winTreeItemData*)tviPrevItem.lParam)->kind; +- +- /* Define the parent and the position to the new node inside +- the list, using the KIND attribute of node selected */ +- if (kindPrev == ITREE_BRANCH && add) +- { +- tvins.hParent = hPrevItem; +- tvins.hInsertAfter = TVI_FIRST; /* insert the new node after item selected, as first child */ +- } +- else +- { +- tvins.hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hPrevItem); +- tvins.hInsertAfter = hPrevItem; /* insert the new node after item selected */ +- } +- +- /* Add the node to the tree-view control */ +- SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); +- +- if (kindPrev == ITREE_BRANCH && tviPrevItem.cChildren==0) ++ if (hPrevItem) + { +- /* this is the first child, redraw to update the '+'/'-' buttons */ +- iupdrvDisplayRedraw(ih); +- } +-} ++ int kindPrev; ++ TVITEM tviPrevItem; +  +-static void winTreeAddRootNode(Ihandle* ih) +-{ +- TVITEM item;  +- TVINSERTSTRUCT tvins; +- HTREEITEM hNewItem; +- winTreeItemData* itemData; ++ /* get the KIND attribute of reference node */  ++ tviPrevItem.hItem = hPrevItem; ++ tviPrevItem.mask = TVIF_PARAM|TVIF_CHILDREN;  ++ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&tviPrevItem); ++ kindPrev = ((winTreeItemData*)tviPrevItem.lParam)->kind; +  +- itemData = calloc(1, sizeof(winTreeItemData)); +- itemData->image = -1; +- itemData->image_expanded = -1; +- itemData->kind = ITREE_BRANCH; ++ /* Define the parent and the position to the new node inside ++ the list, using the KIND attribute of reference node */ ++ if (kindPrev == ITREE_BRANCH && add) ++ { ++ /* depth+1 */ ++ tvins.hParent = hPrevItem; ++ tvins.hInsertAfter = TVI_FIRST; /* insert the new node after the reference node, as first child */ ++ } ++ else ++ { ++ /* same depth */ ++ tvins.hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hPrevItem); ++ tvins.hInsertAfter = hPrevItem; /* insert the new node after reference node */ ++ } +  +- item.mask = TVIF_PARAM | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;  +- item.state = item.stateMask = TVIS_EXPANDED; +- item.iSelectedImage = item.iImage = (int)ih->data->def_image_expanded; +- item.lParam = (LPARAM)itemData; ++ /* Add the new node */ ++ hItemNew = (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); ++ iupTreeAddToCache(ih, add, kindPrev, hPrevItem, hItemNew); +  +- iupwinGetColor(iupAttribGetStr(ih, "FGCOLOR"), &itemData->color); ++ if (kindPrev == ITREE_BRANCH && tviPrevItem.cChildren==0) /* was 0, now is 1 */ ++ { ++ /* this is the first child, redraw to update the '+'/'-' buttons */ ++ if (ih->data->add_expanded) ++ winTreeExpandItem(ih, hPrevItem, 1); ++ else ++ winTreeExpandItem(ih, hPrevItem, 0); ++ } +  +- /* Save the heading level in the node's application-defined data area */ +- tvins.item = item;  +- tvins.hInsertAfter = TVI_FIRST; +- tvins.hParent = TVI_ROOT; ++ } ++ else ++ { ++ tvins.hInsertAfter = TVI_FIRST; ++ tvins.hParent = TVI_ROOT; +  +- /* Add the node to the tree-view control */ +- hNewItem = (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); ++ /* Add the new node */ ++ hItemNew = (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); ++ iupTreeAddToCache(ih, 0, 0, NULL, hItemNew); +  +- /* MarkStart node */ +- iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)hNewItem); ++ if (ih->data->node_count == 1) ++ { ++ /* MarkStart node */ ++ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)hItemNew); +  +- /* Set the default VALUE */ +- winTreeSetFocusNode(ih, hNewItem); ++ /* Set the default VALUE */ ++ winTreeSetFocusNode(ih, hItemNew); ++ } ++ } + } +  + static int winTreeIsItemExpanded(Ihandle* ih, HTREEITEM hItem) +@@ -408,13 +266,28 @@ static int winTreeIsItemExpanded(Ihandle* ih, HTREEITEM hItem) +  + static void winTreeExpandItem(Ihandle* ih, HTREEITEM hItem, int expand) + { +- if (expand == -1) +- expand = !winTreeIsItemExpanded(ih, hItem); /* toggle */ ++ TVITEM item; ++ winTreeItemData* itemData; ++ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", "1"); ++ /* it only works if the branch has children */ ++ SendMessage(ih->handle, TVM_EXPAND, expand? TVE_EXPAND: TVE_COLLAPSE, (LPARAM)hItem); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", NULL); ++ ++ /* update image */ ++ item.hItem = hItem; ++ item.mask = TVIF_HANDLE|TVIF_PARAM; ++ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); ++ itemData = (winTreeItemData*)item.lParam; +  + if (expand) +- SendMessage(ih->handle, TVM_EXPAND, TVE_EXPAND, (LPARAM)hItem); ++ item.iSelectedImage = item.iImage = (itemData->image_expanded!=-1)? itemData->image_expanded: (int)ih->data->def_image_expanded; + else +- SendMessage(ih->handle, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hItem); ++ item.iSelectedImage = item.iImage = (itemData->image!=-1)? itemData->image: (int)ih->data->def_image_collapsed; ++ ++ item.hItem = hItem; ++ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; ++ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); + } +  + /*****************************************************************************/ +@@ -445,12 +318,12 @@ static void winTreeExpandTree(Ihandle* ih, HTREEITEM hItem, int expand) + /* SELECTING ITEMS */ + /*****************************************************************************/ +  +-static int winTreeIsItemSelected(Ihandle* ih, HTREEITEM hItem) ++static int winTreeIsNodeSelected(Ihandle* ih, HTREEITEM hItem) + { + return ((SendMessage(ih->handle, TVM_GETITEMSTATE, (WPARAM)hItem, TVIS_SELECTED)) & TVIS_SELECTED)!=0; + } +  +-static void winTreeSelectItem(Ihandle* ih, HTREEITEM hItem, int select) ++static void winTreeSelectNode(Ihandle* ih, HTREEITEM hItem, int select) + { + TV_ITEM item; + item.mask = TVIF_STATE | TVIF_HANDLE; +@@ -458,16 +331,13 @@ static void winTreeSelectItem(Ihandle* ih, HTREEITEM hItem, int select) + item.hItem = hItem; +  + if (select == -1) +- select = !winTreeIsItemSelected(ih, hItem); ++ select = !winTreeIsNodeSelected(ih, hItem); /* toggle */ +  + item.state = select ? TVIS_SELECTED : 0; +  ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)&item); +-} +- +-static HTREEITEM winTreeGetFocusNode(Ihandle* ih) +-{ +- return (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CARET, 0); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + } +  + /* ------------Comment from wxWidgets-------------------- +@@ -475,17 +345,17 @@ static HTREEITEM winTreeGetFocusNode(Ihandle* ih) + item without changing anything else. */ + static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem) + { +- HTREEITEM hItemFocus = winTreeGetFocusNode(ih); ++ HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); + if (hItem != hItemFocus) + { + /* remember the selection state of the item */ +- int wasSelected = winTreeIsItemSelected(ih, hItem); ++ int wasSelected = winTreeIsNodeSelected(ih, hItem); + int wasFocusSelected = 0; +  +- if (iupwinIsVista()) ++ if (iupwinIsVistaOrNew() && iupwin_comctl32ver6) + iupAttribSetStr(ih, "_IUPTREE_ALLOW_CHANGE", (char*)hItem); /* Vista Only */ + else +- wasFocusSelected = hItemFocus && winTreeIsItemSelected(ih, hItemFocus); ++ wasFocusSelected = hItemFocus && winTreeIsNodeSelected(ih, hItemFocus); +  + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); +  +@@ -493,58 +363,42 @@ static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem) + { + /* prevent the tree from unselecting the old focus which it would do by default */ + SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)NULL); /* remove the focus */ +- winTreeSelectItem(ih, hItemFocus, 1); /* select again */ ++ winTreeSelectNode(ih, hItemFocus, 1); /* select again */ + } +  + SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem); /* set focus, selection, and unselect the previous focus */ +  + if (!wasSelected) +- winTreeSelectItem(ih, hItem, 0); /* need to clear the selection if was not selected */ ++ winTreeSelectNode(ih, hItem, 0); /* need to clear the selection if was not selected */ +  + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + iupAttribSetStr(ih, "_IUPTREE_ALLOW_CHANGE", NULL); + } + } +  +-typedef struct _winTreeRange{ +- HTREEITEM hItem1, hItem2; +- char inside, clear; +-}winTreeRange; +- +-static int winTreeSelectRangeFunc(Ihandle* ih, HTREEITEM hItem, winTreeRange* range) ++static void winTreeSelectRange(Ihandle* ih, HTREEITEM hItem1, HTREEITEM hItem2, int clear) + { +- int end_range = 0; +- +- if (range->inside == 0) /* detect the range start */ ++ int i; ++ int id1 = iupTreeFindNodeId(ih, hItem1); ++ int id2 = iupTreeFindNodeId(ih, hItem2); ++ if (id2 == -1) id2 = ih->data->node_count-1; ++ if (id1 > id2) + { +- if (range->hItem1 == hItem) range->inside=1; +- else if (range->hItem2 == hItem) range->inside=1; ++ int tmp = id1; ++ id1 = id2; ++ id2 = tmp; + } +- else if (range->inside == 1) /* detect the range end */ ++ ++ for (i = 0; i < ih->data->node_count; i++) + { +- if (range->hItem1 == hItem) end_range=1; +- else if (range->hItem2 == hItem) end_range=1; ++ if (i < id1 || i > id2) ++ { ++ if (clear) ++ winTreeSelectNode(ih, ih->data->node_cache[i].node_handle, 0); ++ } ++ else ++ winTreeSelectNode(ih, ih->data->node_cache[i].node_handle, 1); + } +- +- if (range->inside == 1) /* if inside, select */ +- winTreeSelectItem(ih, hItem, 1); +- else if (range->clear) /* if outside and clear, unselect */ +- winTreeSelectItem(ih, hItem, 0); +- +- if (end_range || (range->inside && range->hItem1==range->hItem2)) +- range->inside=-1; /* update after selecting the node */ +- +- return 1; +-} +- +-static void winTreeSelectRange(Ihandle* ih, HTREEITEM hItemFrom, HTREEITEM hItemTo, int clear) +-{ +- winTreeRange range; +- range.hItem1 = hItemFrom; +- range.hItem2 = hItemTo; +- range.inside = 0; +- range.clear = (char)clear; +- winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectRangeFunc, &range); + } +  + static void winTreeSelectAll(Ihandle* ih) +@@ -558,9 +412,10 @@ static void winTreeClearSelection(Ihandle* ih, HTREEITEM hItemExcept) + winTreeSelectRange(ih, hItemExcept, hItemExcept, 1); + } +  +-static int winTreeInvertSelectFunc(Ihandle* ih, HTREEITEM hItem, void* userdata) ++static int winTreeInvertSelectFunc(Ihandle* ih, HTREEITEM hItem, int id, void* userdata) + { +- winTreeSelectItem(ih, hItem, -1); ++ (void)id; ++ winTreeSelectNode(ih, hItem, -1); + (void)userdata; + return 1; + } +@@ -568,14 +423,11 @@ static int winTreeInvertSelectFunc(Ihandle* ih, HTREEITEM hItem, void* userdata) + typedef struct _winTreeSelArray{ + Iarray* markedArray; + char is_handle; +- int id_control; + }winTreeSelArray; +  +-static int winTreeSelectedArrayFunc(Ihandle* ih, HTREEITEM hItem, winTreeSelArray* selarray) ++static int winTreeSelectedArrayFunc(Ihandle* ih, HTREEITEM hItem, int id, winTreeSelArray* selarray) + {  +- selarray->id_control++; +- +- if (winTreeIsItemSelected(ih, hItem)) ++ if (winTreeIsNodeSelected(ih, hItem)) + { + if (selarray->is_handle) + { +@@ -587,7 +439,7 @@ static int winTreeSelectedArrayFunc(Ihandle* ih, HTREEITEM hItem, winTreeSelArra + { + int* intArrayData = (int*)iupArrayInc(selarray->markedArray); + int i = iupArrayCount(selarray->markedArray); +- intArrayData[i-1] = selarray->id_control; ++ intArrayData[i-1] = id; + } + } +  +@@ -599,10 +451,9 @@ static Iarray* winTreeGetSelectedArray(Ihandle* ih) + Iarray* markedArray = iupArrayCreate(1, sizeof(HTREEITEM)); + winTreeSelArray selarray; + selarray.markedArray = markedArray; +- selarray.id_control = -1; + selarray.is_handle = 1; +  +- winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectedArrayFunc, &selarray); ++ iupTreeForEach(ih, (iupTreeNodeFunc)winTreeSelectedArrayFunc, &selarray); +  + return markedArray; + } +@@ -612,10 +463,9 @@ static Iarray* winTreeGetSelectedArrayId(Ihandle* ih) + Iarray* markedArray = iupArrayCreate(1, sizeof(int)); + winTreeSelArray selarray; + selarray.markedArray = markedArray; +- selarray.id_control = -1; + selarray.is_handle = 0; +  +- winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectedArrayFunc, &selarray); ++ iupTreeForEach(ih, (iupTreeNodeFunc)winTreeSelectedArrayFunc, &selarray); +  + return markedArray; + } +@@ -625,7 +475,7 @@ static Iarray* winTreeGetSelectedArrayId(Ihandle* ih) + /* COPYING ITEMS (Branches and its children) */ + /*****************************************************************************/ + /* Insert the copied item in a new location. Returns the new item. */ +-static HTREEITEM winTreeCopyItem(Ihandle* ih, HTREEITEM hItem, HTREEITEM hParent, HTREEITEM hPosition, int full_copy) ++static HTREEITEM winTreeCopyItem(Ihandle* ih, HTREEITEM hItem, HTREEITEM hParent, HTREEITEM hPosition, int is_copy) + { + TVITEM item;  + TVINSERTSTRUCT tvins; +@@ -637,34 +487,34 @@ static HTREEITEM winTreeCopyItem(Ihandle* ih, HTREEITEM hItem, HTREEITEM hParent + item.cchTextMax = 255; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); +  +- if (full_copy) /* during a full copy the userdata reference is not copied */ ++ if (is_copy) /* during a copy the itemdata reference is not reused */ + { + /* create a new one */ + winTreeItemData* itemDataNew = malloc(sizeof(winTreeItemData)); + memcpy(itemDataNew, (void*)item.lParam, sizeof(winTreeItemData)); +- itemDataNew->userdata = NULL; + item.lParam = (LPARAM)itemDataNew; + } +  +- /* Copy everything including user data reference */ ++ /* Copy everything including itemdata reference */ + tvins.item = item;  + tvins.hInsertAfter = hPosition; + tvins.hParent = hParent; +  +- /* Add the node to the tree-view control */ ++ /* Add the new node */ ++ ih->data->node_count++; + return (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); + } +  +-static void winTreeCopyChildren(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int full_copy) ++static void winTreeCopyChildren(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int is_copy) + { + HTREEITEM hChildSrc = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItemSrc); +- HTREEITEM hNewItem = TVI_FIRST; ++ HTREEITEM hItemNew = TVI_FIRST; + while (hChildSrc != NULL) + { +- hNewItem = winTreeCopyItem(ih, hChildSrc, hItemDst, hNewItem, full_copy); /* Use the same order they where enumerated */ ++ hItemNew = winTreeCopyItem(ih, hChildSrc, hItemDst, hItemNew, is_copy); /* Use the same order they where enumerated */ +  + /* Recursively transfer all the items */ +- winTreeCopyChildren(ih, hChildSrc, hNewItem, full_copy);  ++ winTreeCopyChildren(ih, hChildSrc, hItemNew, is_copy);  +  + /* Go to next sibling item */ + hChildSrc = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hChildSrc); +@@ -672,11 +522,18 @@ static void winTreeCopyChildren(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItem + } +  + /* Copies all items in a branch to a new location. Returns the new branch node. */ +-static HTREEITEM winTreeCopyNode(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int full_copy) ++static HTREEITEM winTreeCopyMoveNode(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int is_copy) + { +- HTREEITEM hNewItem, hParent; ++ HTREEITEM hItemNew, hParent; + TVITEM item; + winTreeItemData* itemDataDst; ++ int id_new, count, id_src, id_dst; ++ ++ int old_count = ih->data->node_count; ++ ++ id_src = iupTreeFindNodeId(ih, hItemSrc); ++ id_dst = iupTreeFindNodeId(ih, hItemDst); ++ id_new = id_dst+1; /* contains the position for a copy operation */ +  + /* Get DST node attributes */ + item.hItem = hItemDst; +@@ -691,31 +548,64 @@ static HTREEITEM winTreeCopyNode(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hIte + hItemDst = TVI_FIRST; + } + else +- {  ++ {  ++ if (itemDataDst->kind == ITREE_BRANCH) ++ { ++ int child_count = iupdrvTreeTotalChildCount(ih, hItemDst); ++ id_new += child_count; ++ } ++ + /* copy as next brother of item or collapsed branch */ + hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItemDst); + } +  +- hNewItem = winTreeCopyItem(ih, hItemSrc, hParent, hItemDst, full_copy); ++ /* move to the same place does nothing */ ++ if (!is_copy && id_new == id_src) ++ return NULL; ++ ++ hItemNew = winTreeCopyItem(ih, hItemSrc, hParent, hItemDst, is_copy); ++ ++ winTreeCopyChildren(ih, hItemSrc, hItemNew, is_copy); ++ ++ count = ih->data->node_count - old_count; ++ iupTreeCopyMoveCache(ih, id_src, id_new, count, is_copy); ++ ++ if (!is_copy) ++ { ++ /* Deleting the node (and its children) from the old position */ ++ /* do not delete the itemdata, we reuse the references in CopyNode */ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); ++ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemSrc); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); +  +- winTreeCopyChildren(ih, hItemSrc, hNewItem, full_copy); ++ /* restore count, because we remove src */ ++ ih->data->node_count = old_count; +  +- return hNewItem; ++ /* compensate position for a move */ ++ if (id_new > id_src) ++ id_new -= count; ++ } ++ ++ winTreeRebuildNodeCache(ih, id_new, hItemNew); ++ ++ return hItemNew; + } +  + /*****************************************************************************/ + /* MANIPULATING IMAGES */ + /*****************************************************************************/ +-static void winTreeUpdateImages(Ihandle* ih, HTREEITEM hItem, int mode) ++static void winTreeUpdateImages(Ihandle* ih, int mode) + { +- HTREEITEM hItemChild; ++ HTREEITEM hItem; + TVITEM item; + winTreeItemData* itemData; ++ int i; +  + /* called when one of the default images is changed */ +- +- while(hItem != NULL) ++ for (i = 0; i < ih->data->node_count; i++) + { ++ hItem = ih->data->node_cache[i].node_handle; ++ + /* Get node attributes */ + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE; +@@ -742,10 +632,6 @@ static void winTreeUpdateImages(Ihandle* ih, HTREEITEM hItem, int mode) + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); + } + } +- +- /* Recursively traverse child items */ +- hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); +- winTreeUpdateImages(ih, hItemChild, mode); + } + else + { +@@ -756,9 +642,6 @@ static void winTreeUpdateImages(Ihandle* ih, HTREEITEM hItem, int mode) + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); + } + } +- +- /* Go to next sibling node */ +- hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } + } +  +@@ -828,29 +711,57 @@ static int winTreeCallBranchLeafCb(Ihandle* ih, HTREEITEM hItem) +  + if (itemData->kind == ITREE_BRANCH) + { ++ if (iupAttribGet(ih, "_IUPTREE_IGNORE_BRANCH_CB")) ++ return IUP_DEFAULT; ++ + if (item.state & TVIS_EXPANDED) + { + IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); + if (cbBranchClose) +- return cbBranchClose(ih, winTreeGetNodeId(ih, hItem)); ++ return cbBranchClose(ih, iupTreeFindNodeId(ih, hItem)); + } + else + { + IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB"); + if (cbBranchOpen) +- return cbBranchOpen(ih, winTreeGetNodeId(ih, hItem)); ++ return cbBranchOpen(ih, iupTreeFindNodeId(ih, hItem)); + } + } + else + { + IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); + if (cbExecuteLeaf) +- return cbExecuteLeaf(ih, winTreeGetNodeId(ih, hItem)); ++ return cbExecuteLeaf(ih, iupTreeFindNodeId(ih, hItem)); + } +  + return IUP_DEFAULT; + } +  ++static void winTreeCallMultiUnSelectionCb(Ihandle* ih) ++{ ++ IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTIUNSELECTION_CB"); ++ IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); ++ if (cbSelec || cbMulti) ++ { ++ Iarray* markedArray = winTreeGetSelectedArrayId(ih); ++ int* id_hitem = (int*)iupArrayGetData(markedArray); ++ int i, count = iupArrayCount(markedArray); ++ ++ if (count > 1) ++ { ++ if (cbMulti) ++ cbMulti(ih, id_hitem, iupArrayCount(markedArray)); ++ else ++ { ++ for (i=0; idata->mark_mode == ITREE_MARK_MULTIPLE && IupGetCallback(ih,"MULTISELECTION_CB")) + { + if ((GetKeyState(VK_SHIFT) & 0x8000)) +@@ -894,7 +807,9 @@ static void winTreeCallSelectionCb(Ihandle* ih, int status, HTREEITEM hItem) + if (iupAttribGet(ih, "_IUPTREE_IGNORE_SELECTION_CB")) + return; +  +- cbSelec(ih, winTreeGetNodeId(ih, hItem), status); ++ id = iupTreeFindNodeId(ih, hItem); ++ if (id != -1) ++ cbSelec(ih, id, status); + } + } +  +@@ -911,8 +826,8 @@ static int winTreeCallDragDropCb(Ihandle* ih, HTREEITEM hItemDrag, HTREEITEM hIt +  + if (cbDragDrop) + { +- int drag_id = winTreeGetNodeId(ih, hItemDrag); +- int drop_id = winTreeGetNodeId(ih, hItemDrop); ++ int drag_id = iupTreeFindNodeId(ih, hItemDrag); ++ int drop_id = iupTreeFindNodeId(ih, hItemDrop); + return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl); + } +  +@@ -929,8 +844,8 @@ static int winTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) + { + ih->data->def_image_expanded = (void*)winTreeGetImageIndex(ih, value); +  +- /* Update all images, starting at root node */ +- winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_EXPANDED); ++ /* Update all images */ ++ winTreeUpdateImages(ih, ITREE_UPDATEIMAGE_EXPANDED); +  + return 1; + } +@@ -939,8 +854,8 @@ static int winTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) + { + ih->data->def_image_collapsed = (void*)winTreeGetImageIndex(ih, value); +  +- /* Update all images, starting at root node */ +- winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_COLLAPSED); ++ /* Update all images */ ++ winTreeUpdateImages(ih, ITREE_UPDATEIMAGE_COLLAPSED); +  + return 1; + } +@@ -949,8 +864,8 @@ static int winTreeSetImageLeafAttrib(Ihandle* ih, const char* value) + { + ih->data->def_image_leaf = (void*)winTreeGetImageIndex(ih, value); +  +- /* Update all images, starting at root node */ +- winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_LEAF); ++ /* Update all images */ ++ winTreeUpdateImages(ih, ITREE_UPDATEIMAGE_LEAF); +  + return 1; + } +@@ -959,7 +874,7 @@ static int winTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const + { + TVITEM item; + winTreeItemData* itemData; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return 0; +  +@@ -986,7 +901,7 @@ static int winTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* v + { + TVITEM item; + winTreeItemData* itemData; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return 0; +  +@@ -1025,7 +940,7 @@ static int winTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* v +  + static int winTreeSetTopItemAttrib(Ihandle* ih, const char* value) + { +- HTREEITEM hItem = winTreeFindNodeFromString(ih, value); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, value); + if (hItem) + SendMessage(ih->handle, TVM_ENSUREVISIBLE, 0, (LPARAM)hItem); + return 0; +@@ -1056,9 +971,8 @@ static int winTreeSetSpacingAttrib(Ihandle* ih, const char* value) + static int winTreeSetExpandAllAttrib(Ihandle* ih, const char* value) + { + HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); +- HTREEITEM hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItemRoot); /* skip the root node that is always expanded */ + int expand = iupStrBoolean(value); +- winTreeExpandTree(ih, hItem, expand); ++ winTreeExpandTree(ih, hItemRoot, expand); + return 0; + } +  +@@ -1131,7 +1045,7 @@ static char* winTreeGetTitle(Ihandle* ih, HTREEITEM hItem) +  + static char* winTreeGetTitleAttrib(Ihandle* ih, const char* name_id) + { +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return NULL; + return winTreeGetTitle(ih, hItem); +@@ -1140,10 +1054,13 @@ static char* winTreeGetTitleAttrib(Ihandle* ih, const char* name_id) + static int winTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value) + { + TVITEM item;  +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return 0; +  ++ if (!value) ++ value = ""; ++ + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_TEXT;  + item.pszText = (char*)value; +@@ -1151,60 +1068,11 @@ static int winTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* v + return 0; + } +  +-static char* winTreeGetFindUserDataAttrib(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 = winTreeGetUserDataId(ih, userdata); +- if (id == -1) +- return NULL; +- str = iupStrGetMemory(16); +- sprintf(str, "%d", id); +- return str; +-} +- +-static char* winTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) +-{ +- TVITEM item; +- winTreeItemData* itemData; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); +- if (!hItem) +- return NULL; +- +- item.hItem = hItem; +- item.mask = TVIF_HANDLE | TVIF_PARAM; +- SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); +- itemData = (winTreeItemData*)item.lParam; +- +- return itemData->userdata; +-} +- +-static int winTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) +-{ +- TVITEM item;  +- winTreeItemData* itemData; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); +- if (!hItem) +- return 0; +- +- item.hItem = hItem; +- item.mask = TVIF_HANDLE | TVIF_PARAM; +- SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); +- itemData = (winTreeItemData*)item.lParam; +- +- itemData->userdata = (void*)value; +- +- return 0; +-} +- + static char* winTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) + { + TVITEM item; + winTreeItemData* itemData; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return NULL; +  +@@ -1220,7 +1088,7 @@ static int winTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const cha + { + TVITEM item;  + winTreeItemData* itemData; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return 0; +  +@@ -1230,11 +1098,23 @@ static int winTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const cha + itemData = (winTreeItemData*)item.lParam; +  + if (value) ++ { + itemData->hFont = iupwinGetHFont(value); ++ if (itemData->hFont) ++ { ++ TV_ITEM item; ++ item.mask = TVIF_STATE | TVIF_HANDLE | TVIF_TEXT; ++ item.stateMask = TVIS_BOLD; ++ item.hItem = hItem; ++ item.pszText = winTreeGetTitle(ih, hItem); /* reset text to resize item */ ++ item.state = (strstr(value, "Bold")||strstr(value, "BOLD"))? TVIS_BOLD: 0; ++ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)&item); ++ } ++ } + else + itemData->hFont = NULL; +  +- iupdrvDisplayUpdate(ih); ++ iupdrvPostRedraw(ih); +  + return 0; + } +@@ -1259,7 +1139,7 @@ static char* winTreeGetStateAttrib(Ihandle* ih, const char* name_id) + { + TVITEM item; + winTreeItemData* itemData; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return NULL; +  +@@ -1281,25 +1161,34 @@ static char* winTreeGetStateAttrib(Ihandle* ih, const char* name_id) +  + static int winTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value) + { +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ TVITEM item; ++ winTreeItemData* itemData; ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return 0; +  +- winTreeExpandItem(ih, hItem, iupStrEqualNoCase(value, "EXPANDED")); ++ /* Get Children: branch or leaf */ ++ item.mask = TVIF_HANDLE|TVIF_PARAM;  ++ item.hItem = hItem; ++ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); ++ itemData = (winTreeItemData*)item.lParam; ++ ++ if (itemData->kind == ITREE_BRANCH) ++ winTreeExpandItem(ih, hItem, iupStrEqualNoCase(value, "EXPANDED")); ++ + return 0; + } +  + static char* winTreeGetDepthAttrib(Ihandle* ih, const char* name_id) + { +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); +- HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); +- int depth = 0; ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); ++ int depth = -1; + char* str; +  +- if (!hItem) ++ if (!hItem)  + return NULL; +  +- while((hItemRoot != hItem) && (hItem != NULL)) ++ while(hItem != NULL) + { + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); + depth++; +@@ -1314,12 +1203,13 @@ static int winTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char + { + HTREEITEM hItemDst, hParent, hItemSrc; +  +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; +- hItemSrc = winTreeFindNodeFromString(ih, name_id); ++ ++ hItemSrc = iupTreeGetNodeFromString(ih, name_id); + if (!hItemSrc) + return 0; +- hItemDst = winTreeFindNodeFromString(ih, value); ++ hItemDst = iupTreeGetNodeFromString(ih, value); + if (!hItemDst) + return 0; +  +@@ -1332,11 +1222,8 @@ static int winTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char + return 0; + } +  +- /* Copying the node and its children to the new position */ +- winTreeCopyNode(ih, hItemSrc, hItemDst, 0); /* not a full copy, preserve user data */ +- +- /* do not delete the user data, we copy the references in CopyNode */ +- SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemSrc); ++ /* Move the node and its children to the new position */ ++ winTreeCopyMoveNode(ih, hItemSrc, hItemDst, 0); +  + return 0; + } +@@ -1345,12 +1232,13 @@ static int winTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char + { + HTREEITEM hItemDst, hParent, hItemSrc; +  +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; +- hItemSrc = winTreeFindNodeFromString(ih, name_id); ++ ++ hItemSrc = iupTreeGetNodeFromString(ih, name_id); + if (!hItemSrc) + return 0; +- hItemDst = winTreeFindNodeFromString(ih, value); ++ hItemDst = iupTreeGetNodeFromString(ih, value); + if (!hItemDst) + return 0; +  +@@ -1363,8 +1251,8 @@ static int winTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char + return 0; + } +  +- /* Copying the node and its children to the new position */ +- winTreeCopyNode(ih, hItemSrc, hItemDst, 1); ++ /* Copy the node and its children to the new position */ ++ winTreeCopyMoveNode(ih, hItemSrc, hItemDst, 1); +  + return 0; + } +@@ -1375,7 +1263,7 @@ static char* winTreeGetColorAttrib(Ihandle* ih, const char* name_id) + char* str; + TVITEM item; + winTreeItemData* itemData; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return NULL; +  +@@ -1398,7 +1286,7 @@ static int winTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* v + unsigned char r, g, b; + TVITEM item; + winTreeItemData* itemData; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return 0; +  +@@ -1410,7 +1298,7 @@ static int winTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* v + if (iupStrToRGB(value, &r, &g, &b)) + { + itemData->color = RGB(r,g,b); +- iupdrvDisplayUpdate(ih); ++ iupdrvPostRedraw(ih); + } +  + return 0; +@@ -1435,7 +1323,7 @@ static char* winTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) + { + int count; + char* str; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return NULL; +  +@@ -1454,18 +1342,11 @@ static char* winTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) + return str; + } +  +-static char* winTreeGetCountAttrib(Ihandle* ih) +-{ +- char* str = iupStrGetMemory(10); +- sprintf(str, "%d", (int)SendMessage(ih->handle, TVM_GETCOUNT, 0, 0)); +- return str; +-} +- + static char* winTreeGetKindAttrib(Ihandle* ih, const char* name_id) + { + TVITEM item;  + winTreeItemData* itemData; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return NULL; +  +@@ -1483,7 +1364,7 @@ static char* winTreeGetKindAttrib(Ihandle* ih, const char* name_id) + static char* winTreeGetParentAttrib(Ihandle* ih, const char* name_id) + { + char* str; +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return NULL; +  +@@ -1492,15 +1373,13 @@ static char* winTreeGetParentAttrib(Ihandle* ih, const char* name_id) + return NULL; +  + str = iupStrGetMemory(10); +- sprintf(str, "%d", winTreeGetNodeId(ih, hItem)); ++ sprintf(str, "%d", iupTreeFindNodeId(ih, hItem)); + return str; + } +  +-static void winTreeDelNodeData(Ihandle* ih, HTREEITEM hItem) ++static void winTreeRemoveItemData(Ihandle* ih, HTREEITEM hItem, IFns cb, int id) + { + TVITEM item;  +- HTREEITEM hChildItem; +- + item.hItem = hItem; + item.mask = TVIF_HANDLE|TVIF_PARAM;  + if (SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item)) +@@ -1508,81 +1387,153 @@ static void winTreeDelNodeData(Ihandle* ih, HTREEITEM hItem) + winTreeItemData* itemData = (winTreeItemData*)item.lParam; + if (itemData) + { +- IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB"); +- if (cb) cb(ih, winTreeGetNodeId(ih, hItem), (char*)itemData->userdata); ++ if (cb)  ++ cb(ih, (char*)ih->data->node_cache[id].userdata); ++ + free(itemData); + item.lParam = (LPARAM)NULL; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); + } + } ++} ++ ++static void winTreeRemoveNodeDataRec(Ihandle* ih, HTREEITEM hItem, IFns cb, int *id) ++{ ++ int old_id = *id; +  +- hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); ++ /* Check whether we have child items */ ++ /* remove from children first */ ++ HTREEITEM hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + while (hChildItem) + { +- winTreeDelNodeData(ih, hChildItem); ++ /* go recursive to children */ ++ winTreeRemoveNodeDataRec(ih, hChildItem, cb, id); ++ ++ /* Go to next sibling item */ + hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hChildItem); + } ++ ++ /* actually do it for the node */ ++ ih->data->node_count--; ++ (*id)++; ++ ++ winTreeRemoveItemData(ih, hItem, cb, old_id); ++} ++ ++static void winTreeRemoveNodeData(Ihandle* ih, HTREEITEM hItem, int call_cb) ++{ ++ IFns cb = call_cb? (IFns)IupGetCallback(ih, "NODEREMOVED_CB"): NULL; ++ int old_count = ih->data->node_count; ++ int id = iupTreeFindNodeId(ih, hItem); ++ int old_id = id; ++ ++ winTreeRemoveNodeDataRec(ih, hItem, cb, &id); ++ ++ if (call_cb) ++ iupTreeDelFromCache(ih, old_id, old_count-ih->data->node_count); ++} ++ ++static void winTreeRemoveAllNodeData(Ihandle* ih, int call_cb) ++{ ++ IFns cb = call_cb? (IFns)IupGetCallback(ih, "NODEREMOVED_CB"): NULL; ++ int i, old_count = ih->data->node_count; ++ HTREEITEM hItem; ++ ++ for (i = 0; i < ih->data->node_count; i++) ++ { ++ hItem = ih->data->node_cache[i].node_handle; ++ winTreeRemoveItemData(ih, hItem, cb, i); ++ } ++ ++ ih->data->node_count = 0; ++ ++ if (call_cb) ++ iupTreeDelFromCache(ih, 0, old_count); + } +  + static int winTreeSetDelNodeAttrib(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; +- if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */ ++ if (iupStrEqualNoCase(value, "ALL")) + { +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); +- HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); ++ winTreeRemoveAllNodeData(ih, 1); +  +- /* the root node can't be deleted */ +- if(!hItem || hItem == hItemRoot) ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); ++ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); ++ return 0; ++ } ++ if (iupStrEqualNoCase(value, "SELECTED")) /* selected here means the reference one */ ++ { ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); ++ if(!hItem) + return 0; +  +- /* deleting the specified node (and it's children) */ +- winTreeDelNodeData(ih, hItem); ++ /* deleting the reference node (and it's children) */ ++ winTreeRemoveNodeData(ih, hItem, 1); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItem); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); +  + return 0; + } +- else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */ ++ else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the reference node */ + { +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + HTREEITEM hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); +  + if(!hItem) + return 0; +  +- /* deleting the selected node's children */ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); ++ ++ /* deleting the reference node children */ + while (hChildItem) + { +- winTreeDelNodeData(ih, hChildItem); ++ winTreeRemoveNodeData(ih, hChildItem, 1); + SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hChildItem); + hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + } +  ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + return 0; + } + else if(iupStrEqualNoCase(value, "MARKED")) + { +- int i, count; +- Iarray* markedArray; +- HTREEITEM* hItemArrayData; +- HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); ++ int i, del_focus = 0; ++ HTREEITEM hItemFocus; +  +- /* Delete the array of marked nodes */ +- markedArray = winTreeGetSelectedArray(ih); +- hItemArrayData = (HTREEITEM*)iupArrayGetData(markedArray); +- count = iupArrayCount(markedArray); ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); ++ hItemFocus = iupdrvTreeGetFocusNode(ih); +  +- for(i = 0; i < count; i++) ++ for(i = 1; i < ih->data->node_count; /* increment only if not removed */) + { +- if (hItemArrayData[i] != hItemRoot) /* the root node can't be deleted */ ++ if (winTreeIsNodeSelected(ih, ih->data->node_cache[i].node_handle)) + { +- winTreeDelNodeData(ih, hItemArrayData[i]); +- SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemArrayData[i]); ++ HTREEITEM hItem = ih->data->node_cache[i].node_handle; ++ if (hItemFocus == hItem) ++ { ++ del_focus = 1; ++ i++; ++ } ++ else ++ { ++ winTreeRemoveNodeData(ih, hItem, 1); ++ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItem); ++ } + } ++ else ++ i++; + } +  +- iupArrayDestroy(markedArray); ++ if (del_focus) ++ { ++ winTreeRemoveNodeData(ih, hItemFocus, 1); ++ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemFocus); ++ } ++ ++ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); +  + return 0; + } +@@ -1592,22 +1543,13 @@ static int winTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* +  + static int winTreeSetRenameAttrib(Ihandle* ih, const char* value) + {  +- HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + if (ih->data->show_rename) + { +- IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); +- if (cbShowRename) +- cbShowRename(ih, winTreeGetNodeId(ih, hItemFocus)); +- ++ HTREEITEM hItemFocus; + SetFocus(ih->handle); /* the tree must have focus to activate the edit */ ++ hItemFocus = iupdrvTreeGetFocusNode(ih); + SendMessage(ih->handle, TVM_EDITLABEL, 0, (LPARAM)hItemFocus); + } +- else +- { +- IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB"); +- if (cbRenameNode) +- cbRenameNode(ih, winTreeGetNodeId(ih, hItemFocus), winTreeGetTitle(ih, hItemFocus));  +- } +  + (void)value; + return 0; +@@ -1615,11 +1557,11 @@ static int winTreeSetRenameAttrib(Ihandle* ih, const char* value) +  + static char* winTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) + { +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return NULL; +  +- if (winTreeIsItemSelected(ih, hItem)) ++ if (winTreeIsNodeSelected(ih, hItem)) + return "YES"; + else  + return "NO"; +@@ -1627,17 +1569,23 @@ static char* winTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) +  + static int winTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value) + { +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return 0; +  +- winTreeSelectItem(ih, hItem, iupStrBoolean(value)); ++ if (ih->data->mark_mode==ITREE_MARK_SINGLE) ++ { ++ HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); ++ winTreeSelectNode(ih, hItemFocus, 0); ++ } ++ ++ winTreeSelectNode(ih, hItem, iupStrBoolean(value)); + return 0; + } +  + static int winTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) + { +- HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if (!hItem) + return 0; +  +@@ -1649,15 +1597,59 @@ static int winTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) + static char* winTreeGetValueAttrib(Ihandle* ih) + { + char* str; +- HTREEITEM hItemFocus = winTreeGetFocusNode(ih); ++ HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); + if (!hItemFocus) +- return "0"; /* default VALUE is root */ ++ { ++ if (ih->data->node_count) ++ return "0"; /* default VALUE is root */ ++ else ++ return "-1"; ++ } +  + str = iupStrGetMemory(16); +- sprintf(str, "%d", winTreeGetNodeId(ih, hItemFocus)); ++ sprintf(str, "%d", iupTreeFindNodeId(ih, hItemFocus)); ++ return str; ++} ++ ++static char* winTreeGetMarkedNodesAttrib(Ihandle* ih) ++{ ++ char* str = iupStrGetMemory(ih->data->node_count+1); ++ int i; ++ ++ for (i=0; idata->node_count; i++) ++ { ++ if (winTreeIsNodeSelected(ih, ih->data->node_cache[i].node_handle)) ++ str[i] = '+'; ++ else ++ str[i] = '-'; ++ } ++ ++ str[ih->data->node_count] = 0; + return str; + } +  ++static int winTreeSetMarkedNodesAttrib(Ihandle* ih, const char* value) ++{ ++ int count, i; ++ ++ if (ih->data->mark_mode==ITREE_MARK_SINGLE || !value) ++ return 0; ++ ++ count = strlen(value); ++ if (count > ih->data->node_count) ++ count = ih->data->node_count; ++ ++ for (i=0; idata->node_cache[i].node_handle, 1); ++ else ++ winTreeSelectNode(ih, ih->data->node_cache[i].node_handle, 0); ++ } ++ ++ return 0; ++} ++ + static int winTreeSetMarkAttrib(Ihandle* ih, const char* value) + { + if (ih->data->mark_mode==ITREE_MARK_SINGLE) +@@ -1665,7 +1657,7 @@ static int winTreeSetMarkAttrib(Ihandle* ih, const char* value) +  + if(iupStrEqualNoCase(value, "BLOCK")) + { +- HTREEITEM hItemFocus = winTreeGetFocusNode(ih); ++ HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); + winTreeSelectRange(ih, (HTREEITEM)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"), hItemFocus, 0); + } + else if(iupStrEqualNoCase(value, "CLEARALL")) +@@ -1673,14 +1665,14 @@ static int winTreeSetMarkAttrib(Ihandle* ih, const char* value) + else if(iupStrEqualNoCase(value, "MARKALL")) + winTreeSelectAll(ih); + else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */ +- winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeInvertSelectFunc, NULL); ++ iupTreeForEach(ih, (iupTreeNodeFunc)winTreeInvertSelectFunc, NULL); + else if(iupStrEqualPartial(value, "INVERT")) /* iupStrEqualPartial allows the use of "INVERTid" form */ + { +- HTREEITEM hItem = winTreeFindNodeFromString(ih, &value[strlen("INVERT")]); ++ HTREEITEM hItem = iupTreeGetNodeFromString(ih, &value[strlen("INVERT")]); + if (!hItem) + return 0; +  +- winTreeSelectItem(ih, hItem, -1); /* toggle */ ++ winTreeSelectNode(ih, hItem, -1); /* toggle */ + } + else + { +@@ -1690,10 +1682,10 @@ static int winTreeSetMarkAttrib(Ihandle* ih, const char* value) + if (iupStrToStrStr(value, str1, str2, '-')!=2) + return 0; +  +- hItem1 = winTreeFindNodeFromString(ih, str1); ++ hItem1 = iupTreeGetNodeFromString(ih, str1); + if (!hItem1)  + return 0; +- hItem2 = winTreeFindNodeFromString(ih, str2); ++ hItem2 = iupTreeGetNodeFromString(ih, str2); + if (!hItem2)  + return 0; +  +@@ -1711,9 +1703,9 @@ static int winTreeSetValueAttrib(Ihandle* ih, const char* value) + if (winTreeSetMarkAttrib(ih, value)) + return 0; +  +- hItemFocus = winTreeGetFocusNode(ih); ++ hItemFocus = iupdrvTreeGetFocusNode(ih); +  +- if(iupStrEqualNoCase(value, "ROOT")) ++ if(iupStrEqualNoCase(value, "ROOT") || iupStrEqualNoCase(value, "FIRST")) + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + else if(iupStrEqualNoCase(value, "LAST")) + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0); +@@ -1759,15 +1751,14 @@ static int winTreeSetValueAttrib(Ihandle* ih, const char* value) + else if(iupStrEqualNoCase(value, "PREVIOUS")) + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemFocus); + else +- hItem = winTreeFindNodeFromString(ih, value); ++ hItem = iupTreeGetNodeFromString(ih, value); +  + if (hItem) + { + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + { +- iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); +- winTreeSelectItem(ih, hItem, 1); +- iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); ++ winTreeSelectNode(ih, hItemFocus, 0); ++ winTreeSelectNode(ih, hItem, 1); + } + winTreeSetFocusNode(ih, hItem); + } +@@ -1832,27 +1823,60 @@ static LRESULT CALLBACK winTreeEditWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARA + return CallWindowProc(oldProc, hwnd, msg, wp, lp); + } +  +-static void winTreeDrag(Ihandle* ih, int x, int y) ++static void winTreeBeginDrag(Ihandle* ih, int x, int y) + { +- HTREEITEM hItemDrop; ++ HIMAGELIST dragImageList; ++ ++ HTREEITEM hItemDrag = winTreeFindNodeXY(ih, x, y); ++ if (!hItemDrag) ++ return; ++ ++ SendMessage(ih->handle, TVM_ENDEDITLABELNOW, TRUE, 0); ++ ++ /* store the drag-and-drop item */ ++ iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", (char*)hItemDrag); +  ++ /* get the image list for dragging */ ++ dragImageList = (HIMAGELIST)SendMessage(ih->handle, TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItemDrag); ++ if (dragImageList) ++ { ++ POINT pt; ++ ImageList_BeginDrag(dragImageList, 0, 0, 0); ++ ++ pt.x = x; ++ pt.y = y; ++ ++ ClientToScreen(ih->handle, &pt); ++ ImageList_DragEnter(NULL, pt.x, pt.y); ++ ++ iupAttribSetStr(ih, "_IUPTREE_DRAGIMAGELIST", (char*)dragImageList); ++ } ++ ++ ShowCursor(FALSE); ++ SetCapture(ih->handle); /* drag only inside the tree */ ++} ++ ++static void winTreeDrag(Ihandle* ih, int x, int y) ++{ ++ HTREEITEM hItemDrop = winTreeFindNodeXY(ih, x, y); ++ HTREEITEM hItemDrag = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM"); + HIMAGELIST dragImageList = (HIMAGELIST)iupAttribGet(ih, "_IUPTREE_DRAGIMAGELIST"); ++ + if (dragImageList) + { +- POINT pnt; +- pnt.x = x; +- pnt.y = y; +- GetCursorPos(&pnt); +- ClientToScreen(GetDesktopWindow(), &pnt) ; +- ImageList_DragMove(pnt.x, pnt.y); ++ POINT pt; ++ pt.x = x; ++ pt.y = y; ++ ClientToScreen(ih->handle, &pt); ++ ImageList_DragMove(pt.x, pt.y); + } +  +- if ((hItemDrop = winTreeFindNodePointed(ih)) != NULL) ++ if (hItemDrop && hItemDrop!=hItemDrag) + { + if(dragImageList) + ImageList_DragShowNolock(FALSE); +  +- SendMessage(ih->handle, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)hItemDrop); ++ SendMessage(ih->handle, TVM_SETINSERTMARK, TRUE, (LPARAM)hItemDrop); +  + /* store the drop item to be executed */ + iupAttribSetStr(ih, "_IUPTREE_DROPITEM", (char*)hItemDrop); +@@ -1860,6 +1884,8 @@ static void winTreeDrag(Ihandle* ih, int x, int y) + if(dragImageList) + ImageList_DragShowNolock(TRUE); + } ++ else ++ iupAttribSetStr(ih, "_IUPTREE_DROPITEM", NULL); + } +  + static void winTreeDrop(Ihandle* ih) +@@ -1882,7 +1908,7 @@ static void winTreeDrop(Ihandle* ih) + ShowCursor(TRUE); +  + /* Remove drop target highlighting */ +- SendMessage(ih->handle, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)NULL); ++ SendMessage(ih->handle, TVM_SETINSERTMARK, 0, (LPARAM)NULL); +  + iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", NULL); + iupAttribSetStr(ih, "_IUPTREE_DROPITEM", NULL); +@@ -1901,16 +1927,12 @@ static void winTreeDrop(Ihandle* ih) +  + if (winTreeCallDragDropCb(ih, hItemDrag, hItemDrop, &is_ctrl) == IUP_CONTINUE) + { +- /* Copy the dragged item to the new position. */ +- HTREEITEM hItemNew = winTreeCopyNode(ih, hItemDrag, hItemDrop, is_ctrl); +- +- if (!is_ctrl) +- { +- /* do not delete the user data, we copy the references in CopyNode */ +- SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemDrag); +- } ++ /* Copy or move the dragged item to the new position. */ ++ HTREEITEM hItemNew = winTreeCopyMoveNode(ih, hItemDrag, hItemDrop, is_ctrl); +  +- SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItemNew); /* set focus and selection */ ++ /* Set focus and selection */ ++ if (hItemNew) ++ SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItemNew);  + } + }  +  +@@ -1929,9 +1951,7 @@ static void winTreeExtendSelect(Ihandle* ih, int x, int y) + hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM"); + if (hItemFirstSel) + { +- iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + winTreeSelectRange(ih, hItemFirstSel, hItem, 1); +- iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); +  + iupAttribSetStr(ih, "_IUPTREE_LASTSELITEM", (char*)hItem); + winTreeSetFocusNode(ih, hItem); +@@ -1952,10 +1972,10 @@ static int winTreeMouseMultiSelect(Ihandle* ih, int x, int y) + if (GetKeyState(VK_CONTROL) & 0x8000) /* Control key is down */ + { + /* Toggle selection state */ +- winTreeSelectItem(ih, hItem, -1); ++ winTreeSelectNode(ih, hItem, -1); + iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItem); +  +- winTreeCallSelectionCb(ih, winTreeIsItemSelected(ih, hItem), hItem); ++ winTreeCallSelectionCb(ih, winTreeIsNodeSelected(ih, hItem), hItem); + winTreeSetFocusNode(ih, hItem); +  + return 1; +@@ -1965,9 +1985,11 @@ static int winTreeMouseMultiSelect(Ihandle* ih, int x, int y) + HTREEITEM hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM"); + if (hItemFirstSel) + { +- iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); ++ int last_id = iupTreeFindNodeId(ih, hItem); + winTreeSelectRange(ih, hItemFirstSel, hItem, 1); +- iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); ++ ++ /* if last selected item is a branch, then select its children */ ++ iupTreeSelectLastCollapsedBranch(ih, &last_id); +  + winTreeCallMultiSelectionCb(ih); + winTreeSetFocusNode(ih, hItem); +@@ -1975,11 +1997,15 @@ static int winTreeMouseMultiSelect(Ihandle* ih, int x, int y) + } + } +  ++ winTreeCallMultiUnSelectionCb(ih); ++ + /* simple click */ + winTreeClearSelection(ih, hItem); + iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItem); + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1"); +  ++ /* Call SELECT_CB for all unselected nodes */ ++ + return 0; + } +  +@@ -2039,7 +2065,7 @@ static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res +  + if (wp == VK_RETURN) + { +- HTREEITEM hItemFocus = winTreeGetFocusNode(ih); ++ HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); + if (winTreeCallBranchLeafCb(ih, hItemFocus) != IUP_IGNORE) + winTreeExpandItem(ih, hItemFocus, -1); +  +@@ -2056,14 +2082,14 @@ static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res + { + if (GetKeyState(VK_CONTROL) & 0x8000) + { +- HTREEITEM hItemFocus = winTreeGetFocusNode(ih); ++ HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); + /* Toggle selection state */ +- winTreeSelectItem(ih, hItemFocus, -1); ++ winTreeSelectNode(ih, hItemFocus, -1); + } + } + else if (wp == VK_UP || wp == VK_DOWN) + { +- HTREEITEM hItemFocus = winTreeGetFocusNode(ih); ++ HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); + if (wp == VK_UP) + hItemFocus = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemFocus); + else +@@ -2084,9 +2110,7 @@ static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res + HTREEITEM hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM"); + if (hItemFirstSel) + { +- iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + winTreeSelectRange(ih, hItemFirstSel, hItemFocus, 1); +- iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); +  + winTreeCallMultiSelectionCb(ih); + winTreeSetFocusNode(ih, hItemFocus); +@@ -2138,10 +2162,20 @@ static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res + } + break; + case WM_MOUSEMOVE: +- if (ih->data->show_dragdrop && (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM") != NULL) +- winTreeDrag(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); ++ if (ih->data->show_dragdrop && (wp & MK_LBUTTON)) ++ { ++ if (!iupAttribGet(ih, "_IUPTREE_DRAGITEM")) ++ winTreeBeginDrag(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); ++ else  ++ winTreeDrag(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); ++ } + else if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT")) +- winTreeExtendSelect(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); ++ { ++ if (wp & MK_LBUTTON) ++ winTreeExtendSelect(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); ++ else ++ iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", NULL); ++ } +  + iupwinMouseMove(ih, msg, wp, lp); + break; +@@ -2157,6 +2191,7 @@ static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res + if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT")) + { + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", NULL); ++ + if (iupAttribGet(ih, "_IUPTREE_LASTSELITEM")) + { + winTreeCallMultiSelectionCb(ih); +@@ -2205,14 +2240,19 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) + else if (msg_info->code == TVN_SELCHANGED) + { + NMTREEVIEW* info = (NMTREEVIEW*)msg_info; +- winTreeCallSelectionCb(ih, 0, info->itemOld.hItem); /* node unselected */ +- winTreeCallSelectionCb(ih, 1, info->itemNew.hItem); /* node selected */ ++ if (ih->data->mark_mode!=ITREE_MARK_MULTIPLE || /* (NOT) Multiple selection with Control or Shift key is down */ ++ !(GetKeyState(VK_CONTROL) & 0x8000 || GetKeyState(VK_SHIFT) & 0x8000))  ++ { ++ winTreeCallSelectionCb(ih, 0, info->itemOld.hItem); /* node unselected */ ++ winTreeCallSelectionCb(ih, 1, info->itemNew.hItem); /* node selected */ ++ } + } + else if(msg_info->code == TVN_BEGINLABELEDIT) + { + char* value; + HWND hEdit; + NMTVDISPINFO* info = (NMTVDISPINFO*)msg_info; ++ IFni cbShowRename; +  + if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT")) + { +@@ -2220,6 +2260,13 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) + return 1; + } +  ++ cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); ++ if (cbShowRename && cbShowRename(ih, iupTreeFindNodeId(ih, info->item.hItem))==IUP_IGNORE) ++ { ++ *result = TRUE; /* prevent the change */ ++ return 1; ++ } ++ + hEdit = (HWND)SendMessage(ih->handle, TVM_GETEDITCONTROL, 0, 0); +  + /* save the edit box. */ +@@ -2253,57 +2300,30 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) + } + else if(msg_info->code == TVN_ENDLABELEDIT) + { ++ IFnis cbRename; + NMTVDISPINFO* info = (NMTVDISPINFO*)msg_info; +  + iupAttribSetStr(ih, "_IUPWIN_EDITBOX", NULL); +  +- if (info->item.pszText) +- { +- IFnis cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); +- if (cbRename) +- { +- if (cbRename(ih, winTreeGetNodeId(ih, info->item.hItem), info->item.pszText) == IUP_IGNORE) +- { +- *result = FALSE; +- return 1; +- } +- } ++ if (!info->item.pszText) /* cancel, so abort */ ++ return 0; +  +- *result = TRUE; +- return 1; +- } +- } +- else if(msg_info->code == TVN_BEGINDRAG) +- { +- if (ih->data->show_dragdrop) ++ cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); ++ if (cbRename) + { +- NMTREEVIEW* pNMTreeView = (NMTREEVIEW*)msg_info; +- HTREEITEM hItemDrag = pNMTreeView->itemNew.hItem; +- HIMAGELIST dragImageList; +- +- /* store the drag-and-drop item */ +- iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", (char*)hItemDrag); +- +- /* get the image list for dragging */ +- dragImageList = (HIMAGELIST)SendMessage(ih->handle, TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItemDrag); +- if (dragImageList) ++ if (cbRename(ih, iupTreeFindNodeId(ih, info->item.hItem), info->item.pszText) == IUP_IGNORE) + { +- POINT pt = pNMTreeView->ptDrag; +- ImageList_BeginDrag(dragImageList, 0, 0, 0); +- +- ClientToScreen(ih->handle, &pt); +- ImageList_DragEnter(NULL, pt.x, pt.y); +- +- iupAttribSetStr(ih, "_IUPTREE_DRAGIMAGELIST", (char*)dragImageList); ++ *result = FALSE; ++ return 1; + } +- +- ShowCursor(FALSE); +- SetCapture(ih->handle); /* drag only inside the tree */ + } ++ ++ *result = TRUE; ++ return 1; + } + else if(msg_info->code == NM_DBLCLK) + { +- HTREEITEM hItemFocus = winTreeGetFocusNode(ih); ++ HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); + TVITEM item; + winTreeItemData* itemData; +  +@@ -2317,7 +2337,7 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) + { + IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); + if(cbExecuteLeaf) +- cbExecuteLeaf(ih, winTreeGetNodeId(ih, hItemFocus)); ++ cbExecuteLeaf(ih, iupTreeFindNodeId(ih, hItemFocus)); + } + } + else if(msg_info->code == TVN_ITEMEXPANDING) +@@ -2351,7 +2371,7 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) + HTREEITEM hItem = winTreeFindNodePointed(ih); + IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB"); + if (cbRightClick) +- cbRightClick(ih, winTreeGetNodeId(ih, hItem)); ++ cbRightClick(ih, iupTreeFindNodeId(ih, hItem)); + } + else if (msg_info->code == NM_CUSTOMDRAW) + { +@@ -2374,7 +2394,7 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; +  +- if (winTreeIsItemSelected(ih, hItem)) ++ if (GetFocus()==ih->handle && (customdraw->nmcd.uItemState & CDIS_SELECTED)) + customdraw->clrText = winTreeInvertColor(itemData->color); + else + customdraw->clrText = itemData->color; +@@ -2402,47 +2422,34 @@ static int winTreeConvertXYToPos(Ihandle* ih, int x, int y) + info.pt.y = y; + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)&info); + if (hItem) +- return winTreeGetNodeId(ih, hItem); ++ return iupTreeFindNodeId(ih, hItem); + return -1; + } +  +  + /*******************************************************************************************/ +  +-static void winTreeUnMapMethod(Ihandle* ih) +-{ +- Iarray* bmp_array; +- HIMAGELIST image_list; +- +- HTREEITEM itemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); +- winTreeDelNodeData(ih, itemRoot); +- +- image_list = (HIMAGELIST)SendMessage(ih->handle, TVM_GETIMAGELIST, TVSIL_NORMAL, 0); +- if (image_list) +- ImageList_Destroy(image_list); +- +- bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY"); +- if (bmp_array) +- iupArrayDestroy(bmp_array); +- +- iupdrvBaseUnMapMethod(ih); +-} +  + static int winTreeMapMethod(Ihandle* ih) + { +- DWORD dwStyle = WS_CHILD | WS_BORDER | TVS_SHOWSELALWAYS; ++ DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_BORDER | TVS_SHOWSELALWAYS; +  +- /* can be set only on the Tree View creation */ ++ /* styles can be set only on the Tree View creation */ +  +- if (!ih->data->show_dragdrop) +- dwStyle |= TVS_DISABLEDRAGDROP; ++ /* always disable the internal drag&drop, because it affects our selection and drawing */ ++ dwStyle |= TVS_DISABLEDRAGDROP; +  + if (ih->data->show_rename) + dwStyle |= TVS_EDITLABELS; +  + if (!iupAttribGetBoolean(ih, "HIDELINES")) ++ { + dwStyle |= TVS_HASLINES; +  ++ if (!iupAttribGetInt(ih, "ADDROOT")) ++ dwStyle |= TVS_LINESATROOT; ++ } ++ + if (!iupAttribGetBoolean(ih, "HIDEBUTTONS")) + dwStyle |= TVS_HASBUTTONS; +  +@@ -2455,6 +2462,11 @@ static int winTreeMapMethod(Ihandle* ih) + if (!iupwinCreateWindowEx(ih, WC_TREEVIEW, 0, dwStyle)) + return IUP_ERROR; +  ++ if (!iupwin_comctl32ver6) /* To improve drawing of items when TITLEFONT is set */ ++ SendMessage(ih->handle, CCM_SETVERSION, 5, 0);  ++ else ++ SendMessage(ih->handle, TVM_SETEXTENDEDSTYLE, TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER);  ++ + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTreeProc); + IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTreeWmNotify); +  +@@ -2466,7 +2478,7 @@ static int winTreeMapMethod(Ihandle* ih) + winTreeSetBgColorAttrib(ih, value); + iupAttribSetStr(ih, "BGCOLOR", NULL); + } +- else if (iupwinGetSystemMajorVersion()<6) /* force background in XP because of the editbox background */ ++ else if (!iupwin_comctl32ver6 || iupwinGetSystemMajorVersion()<6) /* force background in XP because of the editbox background */ + winTreeSetBgColorAttrib(ih, IupGetGlobal("TXTBGCOLOR")); + } +  +@@ -2475,8 +2487,8 @@ static int winTreeMapMethod(Ihandle* ih) + ih->data->def_image_collapsed = (void*)winTreeGetImageIndex(ih, "IMGCOLLAPSED"); + ih->data->def_image_expanded = (void*)winTreeGetImageIndex(ih, "IMGEXPANDED"); +  +- /* Add the Root Node */ +- winTreeAddRootNode(ih); ++ if (iupAttribGetInt(ih, "ADDROOT")) ++ iupdrvTreeAddNode(ih, "-1", ITREE_BRANCH, "", 0); +  + /* configure for DRAG&DROP of files */ + if (IupGetCallback(ih, "DROPFILES_CB")) +@@ -2484,9 +2496,31 @@ static int winTreeMapMethod(Ihandle* ih) +  + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winTreeConvertXYToPos); +  ++ iupdrvTreeUpdateMarkMode(ih); ++ + return IUP_NOERROR; + } +  ++static void winTreeUnMapMethod(Ihandle* ih) ++{ ++ Iarray* bmp_array; ++ HIMAGELIST image_list; ++ ++ winTreeRemoveAllNodeData(ih, 0); ++ ++ ih->data->node_count = 0; ++ ++ image_list = (HIMAGELIST)SendMessage(ih->handle, TVM_GETIMAGELIST, TVSIL_NORMAL, 0); ++ if (image_list) ++ ImageList_Destroy(image_list); ++ ++ bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY"); ++ if (bmp_array) ++ iupArrayDestroy(bmp_array); ++ ++ iupdrvBaseUnMapMethod(ih); ++} ++ + void iupdrvTreeInitClass(Iclass* ic) + { + /* Driver Dependent Class functions */ +@@ -2500,7 +2534,6 @@ void iupdrvTreeInitClass(Iclass* ic) + /* IupTree Attributes - GENERAL */ + iupClassRegisterAttribute(ic, "EXPANDALL", NULL, winTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INDENTATION", winTreeGetIndentationAttrib, winTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT); +- iupClassRegisterAttribute(ic, "COUNT", winTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, winTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, winTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); +@@ -2521,7 +2554,6 @@ void iupdrvTreeInitClass(Iclass* ic) + iupClassRegisterAttributeId(ic, "NAME", winTreeGetTitleAttrib, winTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLE", winTreeGetTitleAttrib, winTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "CHILDCOUNT", winTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); +- iupClassRegisterAttributeId(ic, "USERDATA", winTreeGetUserDataAttrib, winTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COLOR", winTreeGetColorAttrib, winTreeSetColorAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLEFONT", winTreeGetTitleFontAttrib, winTreeSetTitleFontAttrib, IUPAF_NO_INHERIT); +  +@@ -2530,6 +2562,7 @@ void iupdrvTreeInitClass(Iclass* ic) + iupClassRegisterAttribute (ic, "MARK", NULL, winTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "STARTING", NULL, winTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARKSTART", NULL, winTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); ++ iupClassRegisterAttribute (ic, "MARKEDNODES", winTreeGetMarkedNodesAttrib, winTreeSetMarkedNodesAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +  + iupClassRegisterAttribute (ic, "VALUE", winTreeGetValueAttrib, winTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +  +@@ -2538,5 +2571,8 @@ void iupdrvTreeInitClass(Iclass* ic) + iupClassRegisterAttribute(ic, "RENAME", NULL, winTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "MOVENODE", NULL, winTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COPYNODE", NULL, winTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); +- iupClassRegisterAttributeId(ic, "FINDUSERDATA", winTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); ++ ++ /* necessary because transparent background does not work when not using visual styles */ ++ if (!iupwin_comctl32ver6) /* Used by iupdrvImageCreateImage */ ++ iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + } +diff --git a/iup/src/win/iupwin_val.c b/iup/src/win/iupwin_val.c +index 706c612..5c956d9 100755 +--- a/iup/src/win/iupwin_val.c ++++ b/iup/src/win/iupwin_val.c +@@ -56,6 +56,13 @@ void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h) + } + } +  ++static int winValSetBgColorAttrib(Ihandle *ih, const char *value) ++{ ++ (void)value; ++ iupdrvPostRedraw(ih); ++ return 1; ++} ++ + static int winValSetStepAttrib(Ihandle* ih, const char* value) + { + int linesize; +@@ -110,18 +117,6 @@ static int winValSetValueAttrib(Ihandle* ih, const char* value) + /*********************************************************************************************/ +  +  +-static int winValCtlColor(Ihandle* ih, HDC hdc, LRESULT *result) +-{ +- COLORREF cr; +- if (iupwinGetParentBgColor(ih, &cr)) +- { +- SetDCBrushColor(hdc, cr); +- *result = (LRESULT)GetStockObject(DC_BRUSH); +- return 1; +- } +- return 0; +-} +- + static int winValCustomScroll(Ihandle* ih, int msg) + { + double old_val = ih->data->val; +@@ -190,6 +185,19 @@ static void winValIncPageValue(Ihandle *ih, int dir) + winValCustomScroll(ih, 0); + } +  ++static int winValCtlColor(Ihandle* ih, HDC hdc, LRESULT *result) ++{ ++ COLORREF cr; ++ if (iupwinGetParentBgColor(ih, &cr)) ++ { ++ SetBkColor(hdc, cr); ++ SetDCBrushColor(hdc, cr); ++ *result = (LRESULT)GetStockObject(DC_BRUSH); ++ return 1; ++ } ++ return 0; ++} ++ + static int winValProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) + { + (void)lp; +@@ -240,7 +248,7 @@ static int winValProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *resu +  + static int winValMapMethod(Ihandle* ih) + { +- DWORD dwStyle = WS_CHILD | TBS_AUTOTICKS; ++ DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | TBS_AUTOTICKS; + int show_ticks; +  + if (!ih->parent) +@@ -312,4 +320,7 @@ void iupdrvValInitClass(Iclass* ic) + iupClassRegisterAttribute(ic, "STEP", iupValGetStepAttrib, winValSetStepAttrib, "0.01", NULL, IUPAF_NO_INHERIT); /* force new default value */ +  + iupClassRegisterAttribute(ic, "TICKSPOS", NULL, NULL, "NORMAL", NULL, IUPAF_NOT_MAPPED); ++ ++ /* Visual */ ++ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winValSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + } +diff --git a/iup/srccd/Makefile b/iup/srccd/Makefile +index 43a3f09..8b1d154 100755 +--- a/iup/srccd/Makefile ++++ b/iup/srccd/Makefile +@@ -3,4 +3,4 @@ + do_all: iupcd +  + iupcd: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak  ++ @$(MAKE) --no-print-directory -f ../tecmake.mak  +diff --git a/iup/srccd/iup_cd.c b/iup/srccd/iup_cd.c +index 5998775..619ded7 100755 +--- a/iup/srccd/iup_cd.c ++++ b/iup/srccd/iup_cd.c +@@ -14,7 +14,6 @@ + #include  + #include  +  +- + static void (*cdcreatecanvasNATIVE)(cdCanvas* canvas, void* data) = NULL; +  + static void cdcreatecanvasIUP(cdCanvas* canvas, Ihandle *ih_canvas) +@@ -24,8 +23,12 @@ static void cdcreatecanvasIUP(cdCanvas* canvas, Ihandle *ih_canvas) + #endif + char* data; +  +- if (IupGetInt(ih_canvas, "CD_GDK")) ++ if (cdBaseDriver()==CD_BASE_GDK) ++ { + data = IupGetAttribute(ih_canvas, "DRAWABLE"); /* new IUP 3 attribute, works for GTK only */ ++ if (!data) ++ return; ++ } + else + { + #ifdef WIN32 +diff --git a/iup/srcconsole/Makefile b/iup/srcconsole/Makefile +index 876ca8d..505b103 100755 +--- a/iup/srcconsole/Makefile ++++ b/iup/srcconsole/Makefile +@@ -3,10 +3,10 @@ + do_all: iuplua5 +  + iuplua5: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak  ++ @$(MAKE) --no-print-directory -f ../tecmake.mak  +  + iuplua5gtk: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak USE_GTK=Yes ++ @$(MAKE) --no-print-directory -f ../tecmake.mak USE_GTK=Yes +  + iuplua3: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iuplua3 ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iuplua3 +diff --git a/iup/srcconsole/config.mak b/iup/srcconsole/config.mak +index 612a3ab..568bed6 100755 +--- a/iup/srcconsole/config.mak ++++ b/iup/srcconsole/config.mak +@@ -1,12 +1,23 @@ + PROJNAME = iup + APPNAME = iuplua51 +-APPTYPE = console ++APPTYPE = CONSOLE ++ ++ifdef GTK_DEFAULT ++ ifdef USE_MOTIF ++ # Build Motif version in Linux,Darwin,FreeBSD ++ APPNAME = iuplua51mot ++ endif ++else  ++ ifdef USE_GTK ++ # Build GTK version in IRIX,SunOS,AIX,Win32 ++ APPNAME = iuplua51gtk ++ endif ++endif +  + LOHDIR = loh + SRCLUA = console5.lua + SRC = iup_lua51.c +  +- + # Disable strip + STRIP =  + # Optimize +@@ -35,6 +46,16 @@ ifdef DBG + USE_STATIC = Yes + USE_LUA51 = Yes +  ++ ifdef DBG_DIR ++ IUPLIB = $(IUP)/lib/$(TEC_UNAME)d ++ CDLIB = $(CD)/lib/$(TEC_UNAME)d ++ IMLIB = $(IM)/lib/$(TEC_UNAME)d ++ else ++ IUPLIB = $(IUP)/lib/$(TEC_UNAME) ++ CDLIB = $(CD)/lib/$(TEC_UNAME) ++ IMLIB = $(IM)/lib/$(TEC_UNAME) ++ endif  ++  + DEFINES = USE_STATIC +  + USE_CDLUA = Yes +@@ -42,7 +63,6 @@ ifdef DBG + ifneq ($(findstring Win, $(TEC_SYSNAME)), ) + LIBS += iuplua_pplot$(LIBLUASUFX) iup_pplot + else +- IUPLIB = $(IUP)/lib/$(TEC_UNAME) + SLIB += $(IUPLIB)/libiuplua_pplot$(LIBLUASUFX).a $(IUPLIB)/libiup_pplot.a + endif +  +@@ -50,7 +70,6 @@ ifdef DBG + ifneq ($(findstring Win, $(TEC_SYSNAME)), ) + LIBS += cdluaim$(LIBLUASUFX) + else +- CDLIB = $(CD)/lib/$(TEC_UNAME) + SLIB += $(CDLIB)/libcdluaim$(LIBLUASUFX).a + endif + endif +@@ -65,8 +84,6 @@ ifdef DBG + ifneq ($(findstring Win, $(TEC_SYSNAME)), ) + LIBS += imlua_process$(LIBLUASUFX) iupluaim$(LIBLUASUFX) im_process iupim + else +- IUPLIB = $(IUP)/lib/$(TEC_UNAME) +- IMLIB = $(IM)/lib/$(TEC_UNAME) + SLIB += $(IMLIB)/libimlua_process$(LIBLUASUFX).a $(IUPLIB)/libiupluaim$(LIBLUASUFX).a $(IMLIB)/libim_process.a $(IUPLIB)/libiupim.a + endif +  +@@ -77,20 +94,24 @@ ifdef DBG + ifneq ($(findstring Win, $(TEC_SYSNAME)), ) + LIBS += iupluaimglib$(LIBLUASUFX) iupimglib + else +- IUPLIB = $(IUP)/lib/$(TEC_UNAME) + SLIB += $(IUPLIB)/libiupluaimglib$(LIBLUASUFX).a $(IUPLIB)/libiupimglib.a + endif + endif + else + ifneq ($(findstring Win, $(TEC_SYSNAME)), ) + # Dinamically link in Windows, when not debugging +- # Must call "tecmake dll8" ++ # Must call "tecmake dll8" so USE_* will use the correct TEC_UNAME + USE_LUA51 = Yes + USE_DLL = Yes + GEN_MANIFEST = No + else + # In UNIX Lua is always statically linked, late binding is used. +- USE_STATIC = Yes ++ # Except in Cygwin and MacOSX ++ ifeq ($(findstring cygw, $(TEC_UNAME)), ) ++ ifeq ($(findstring Darwin, $(TEC_UNAME)), ) ++ USE_STATIC = Yes ++ endif ++ endif + USE_LUA51 = Yes + endif + endif +@@ -102,10 +123,13 @@ ifneq ($(findstring Win, $(TEC_SYSNAME)), ) + endif +  + ifneq ($(findstring cygw, $(TEC_UNAME)), ) +- LDFLAGS = -s + LIBS += readline history + endif +  ++ifneq ($(findstring Darwin, $(TEC_UNAME)), ) ++ LIBS += readline ++endif ++ + ifneq ($(findstring Linux, $(TEC_UNAME)), ) + LIBS += dl  + #To allow late binding +@@ -129,10 +153,3 @@ ifneq ($(findstring AIX, $(TEC_UNAME)), ) + LFLAGS = -Xlinker "-bbigtoc" + endif +  +-ifeq ($(TEC_UNAME), vc8) +- ifdef DBG +- #debug info not working for vc8 linker +- define DBG +- endef +- endif +-endif  +diff --git a/iup/srcconsole/console5.lua b/iup/srcconsole/console5.lua +index 20f74b2..0b93641 100755 +--- a/iup/srcconsole/console5.lua ++++ b/iup/srcconsole/console5.lua +@@ -1,67 +1,69 @@ + require"iuplua" +  +-iup.console = {} +- + -- Utilities ++iup_console = {} +  +-function iup.console.printtable(t) +- local n,v = next(t, nil) +- print("--printtable Start--") +- while n do +- print(tostring(n).."="..tostring(v)) +- n,v = next(t, n) +- end +- print("--printtable End--") ++function iup_console.concat(str, info) ++ return str .. info .. "\n" + end +  +-function iup.console.print_version_info() +- if (im) then print("IM " .. im._VERSION .. " " .. im._COPYRIGHT) end ++function iup_console.print_version_info() ++ iup_console.clear() ++ local str = "" ++ if (im) then str = iup_console.concat(str, "IM " .. im._VERSION .. " " .. im._COPYRIGHT) end +  +- if (cd) then print("CD " .. cd._VERSION .. " " .. cd._COPYRIGHT) end ++ if (cd) then str = iup_console.concat(str, "CD " .. cd._VERSION .. " " .. cd._COPYRIGHT) end +  +- print("IUP " .. iup._VERSION .. " " .. iup._COPYRIGHT) +- print("") +- print("IUP Info") +- print(" System: " .. iup.GetGlobal("SYSTEM")) +- print(" System Version: " .. iup.GetGlobal("SYSTEMVERSION")) ++ str = iup_console.concat(str, "IUP " .. iup._VERSION .. " " .. iup._COPYRIGHT) ++ str = iup_console.concat(str, "") ++ str = iup_console.concat(str, "IUP Info") ++ str = iup_console.concat(str, " System: " .. iup.GetGlobal("SYSTEM")) ++ str = iup_console.concat(str, " System Version: " .. iup.GetGlobal("SYSTEMVERSION")) +  + local mot = iup.GetGlobal("MOTIFVERSION") +- if (mot) then print(" Motif Version: ", mot) end ++ if (mot) then str = iup_console.concat(str, " Motif Version: ", mot) end +  +- print(" Screen Size: " .. iup.GetGlobal("SCREENSIZE")) +- print(" Screen Depth: " .. iup.GetGlobal("SCREENDEPTH")) ++ str = iup_console.concat(str, " Screen Size: " .. iup.GetGlobal("SCREENSIZE")) ++ str = iup_console.concat(str, " Screen Depth: " .. iup.GetGlobal("SCREENDEPTH")) +  +- if (iup.GL_VENDOR) then print(" OpenGL Vendor: " .. iup.GL_VENDOR) end +- if (iup.GL_RENDERER) then print(" OpenGL Renderer: " .. iup.GL_RENDERER) end +- if (iup.GL_VERSION) then print(" OpenGL Version: " .. iup.GL_VERSION) end ++ if (iup.GL_VENDOR) then str = iup_console.concat(str, " OpenGL Vendor: " .. iup.GL_VENDOR) end ++ if (iup.GL_RENDERER) then str = iup_console.concat(str, " OpenGL Renderer: " .. iup.GL_RENDERER) end ++ if (iup.GL_VERSION) then str = iup_console.concat(str, " OpenGL Version: " .. iup.GL_VERSION) end ++  ++ iup_console.mlCode.value=str + end +  + -- Console Dialog +  +-iup.console.lastfilename = nil -- Last file open +-iup.console.mlCode = iup.multiline{expand="YES", size="200x120", font="COURIER_NORMAL_10"} +-iup.console.lblPosition = iup.label{title="0:0", size="50x"} +-iup.console.lblFileName = iup.label{title="", size="50x", expand="HORIZONTAL"} ++iup_console.lastfilename = nil -- Last file open ++iup_console.mlCode = iup.multiline{expand="YES", size="200x120", font="COURIER_NORMAL_10"} ++iup_console.lblPosition = iup.label{title="0:0", size="50x"} ++iup_console.lblFileName = iup.label{title="", size="50x", expand="HORIZONTAL"} ++ ++function iup_console.mlCode:caret_cb(lin, col) ++ iup_console.lblPosition.title = lin..":"..col ++end +  +-function iup.console.mlCode:caret_cb(lin, col) +- iup.console.lblPosition.title = lin..":"..col ++function iup_console.clear() ++ iup_console.mlCode.value=''  ++ iup_console.lblFileName.title = ''  ++ iup_console.lastfilename = nil + end +  +-iup.console.butExecute = iup.button{size="50x15", title="Execute", +- action="iup.dostring(iup.console.mlCode.value)"} +-iup.console.butClearCommands = iup.button{size="50x15", title="Clear", +- action="iup.console.mlCode.value='' iup.console.lblFileName.title = '' iup.console.lastfilename = nil"} +-iup.console.butLoadFile = iup.button{size="50x15", title="Load..."} +-iup.console.butSaveasFile = iup.button{size="50x15", title="Save As..."} +-iup.console.butSaveFile = iup.button{size="50x15", title="Save"} +- +-function iup.console.butSaveFile:action() +- if (iup.console.lastfilename == nil) then +- iup.console.butSaveasFile:action() ++iup_console.butExecute = iup.button{size="50x15", title="Execute", ++ action="iup.dostring(iup_console.mlCode.value)"} ++iup_console.butClearCommands = iup.button{size="50x15", title="Clear", action=iup_console.clear} ++iup_console.butLoadFile = iup.button{size="50x15", title="Load..."} ++iup_console.butSaveasFile = iup.button{size="50x15", title="Save As..."} ++iup_console.butSaveFile = iup.button{size="50x15", title="Save"} ++ ++function iup_console.butSaveFile:action() ++ if (iup_console.lastfilename == nil) then ++ iup_console.butSaveasFile:action() + else +- newfile = io.open(iup.console.lastfilename, "w+") ++ newfile = io.open(iup_console.lastfilename, "w+") + if (newfile) then +- newfile:write(iup.console.mlCode.value) ++ newfile:write(iup_console.mlCode.value) + newfile:close() + else + error ("Cannot Save file "..filename) +@@ -69,21 +71,26 @@ function iup.console.butSaveFile:action() + end + end +  +-function iup.console.butSaveasFile:action() +- local fd = iup.filedlg{dialogtype="SAVE", title="Save File", ++function iup_console.butSaveasFile:action() ++ local fd = iup.filedlg{dialogtype="SAVE", title="Save File",  ++ nochangedir="NO", directory=iup_console.last_directory, + filter="*.*", filterinfo="All files",allownew=yes} ++  + fd:popup(iup.LEFT, iup.LEFT) ++  + local status = fd.status +- iup.console.lastfilename = fd.value +- iup.console.lblFileName.title = iup.console.lastfilename ++ iup_console.lastfilename = fd.value ++ iup_console.lblFileName.title = fd.value ++ iup_console.last_directory = fd.directory + fd:destroy() ++  + if status ~= "-1" then +- if (iup.console.lastfilename == nil) then ++ if (iup_console.lastfilename == nil) then + error ("Cannot Save file "..filename) + end +- local newfile=io.open(iup.console.lastfilename, "w+") ++ local newfile=io.open(iup_console.lastfilename, "w+") + if (newfile) then +- newfile:write(iup.console.mlCode.value) ++ newfile:write(iup_console.mlCode.value) + newfile:close(newfile) + else + error ("Cannot Save file") +@@ -91,24 +98,26 @@ function iup.console.butSaveasFile:action() + end + end +  +-function iup.console.LoadFile(filename) ++function iup_console.LoadFile(filename) + local newfile = io.open (filename, "r") + if (newfile == nil) then + error ("Cannot load file "..filename) + else +- iup.console.mlCode.value=newfile:read("*a") ++ iup_console.mlCode.value=newfile:read("*a") + newfile:close (newfile) +- iup.console.lastfilename = filename +- iup.console.lblFileName.title = iup.console.lastfilename ++ iup_console.lastfilename = filename ++ iup_console.lblFileName.title = iup_console.lastfilename + end + end +  +-function iup.console.butLoadFile:action() +- local fd=iup.filedlg{dialogtype="OPEN", title="Load File", ++function iup_console.butLoadFile:action() ++ local fd=iup.filedlg{dialogtype="OPEN", title="Load File",  ++ nochangedir="NO", directory=iup_console.last_directory, + filter="*.*", filterinfo="All Files", allownew="NO"} + fd:popup(iup.CENTER, iup.CENTER) + local status = fd.status + local filename = fd.value ++ iup_console.last_directory = fd.directory + fd:destroy() +  + if (status == "-1") or (status == "1") then +@@ -116,21 +125,21 @@ function iup.console.butLoadFile:action() + error ("Cannot load file "..filename) + end + else +- iup.console.LoadFile(filename) ++ iup_console.LoadFile(filename) + end + end +  +-iup.console.vbxConsole = iup.vbox ++iup_console.vbxConsole = iup.vbox + { +- iup.frame{iup.hbox{iup.vbox{iup.console.butLoadFile, +- iup.console.butSaveFile, +- iup.console.butSaveasFile, +- iup.console.butClearCommands, +- iup.console.butExecute; ++ iup.frame{iup.hbox{iup.vbox{iup_console.butLoadFile, ++ iup_console.butSaveFile, ++ iup_console.butSaveasFile, ++ iup_console.butClearCommands, ++ iup_console.butExecute; + margin="0x0", gap="10"}, +- iup.vbox{iup.console.lblFileName, +- iup.console.mlCode, +- iup.console.lblPosition; ++ iup.vbox{iup_console.lblFileName, ++ iup_console.mlCode, ++ iup_console.lblPosition; + alignment = "ARIGHT"}; + alignment="ATOP"}; title="Commands"} + ;alignment="ACENTER", margin="5x5", gap="5" +@@ -138,7 +147,7 @@ iup.console.vbxConsole = iup.vbox +  + -- Main Menu Definition. +  +-iup.console.mnuMain = iup.menu ++iup_console.mnuMain = iup.menu + { + iup.submenu + { +@@ -149,29 +158,29 @@ iup.console.mnuMain = iup.menu + }, + iup.submenu{iup.menu + { +- iup.item{title="Print Version Info...", action=iup.console.print_version_info}, +- iup.item{title="About...", action="iup.console.dlgAbout:popup(iup.CENTER, iup.CENTER)"} ++ iup.item{title="Print Version Info...", action=iup_console.print_version_info}, ++ iup.item{title="About...", action="iup_console.dlgAbout:popup(iup.CENTER, iup.CENTER)"} + };title="Help"} + } +  + -- Main Dialog Definition. +  +-iup.console.dlgMain = iup.dialog{iup.console.vbxConsole; ++iup_console.dlgMain = iup.dialog{iup_console.vbxConsole; + title="IupLua Console", +- menu=iup.console.mnuMain, ++ menu=iup_console.mnuMain, + dragdrop = "YES", +- defaultenter=iup.console.butExecute, ++ defaultenter=iup_console.butExecute, + close_cb = "return iup.CLOSE"} +  +-function iup.console.dlgMain:dropfiles_cb(filename, num, x, y) ++function iup_console.dlgMain:dropfiles_cb(filename, num, x, y) + if (num == 0) then +- iup.console.LoadFile(filename) ++ iup_console.LoadFile(filename) + end + end +  + -- About Dialog Definition. +  +-iup.console.dlgAbout = iup.dialog ++iup_console.dlgAbout = iup.dialog + { + iup.vbox + { +@@ -195,10 +204,12 @@ iup.console.dlgAbout = iup.dialog +  + -- Displays the Main Dialog +  +-iup.console.dlgMain:show() +-iup.SetFocus(iup.console.mlCode) ++iup_console.dlgMain:show() ++iup.SetFocus(iup_console.mlCode) +  +-iup.MainLoop() ++if (not iup.MainLoopLevel or iup.MainLoopLevel()==0) then ++ iup.MainLoop() ++end +  +-iup.console.dlgMain:destroy() +-iup.console.dlgAbout:destroy() ++iup_console.dlgMain:destroy() ++iup_console.dlgAbout:destroy() +diff --git a/iup/srcconsole/copy_all_so b/iup/srcconsole/copy_all_so +index 52f1fea..ce3c248 100755 +--- a/iup/srcconsole/copy_all_so ++++ b/iup/srcconsole/copy_all_so +@@ -2,10 +2,10 @@ +  + foreach plat ( Linux24 Linux24g3 Linux24g3_64 Linux26 Linux26_64 Linux26g4 Linux26g4_64 Linux26_ia64 SunOS57 SunOS510 SunOS510x86 AIX43 IRIX65 IRIX6465 ) + echo $plat +- cp -f ../lib/$plat/*.so ../bin/$plat +- cp -f ../../cd/lib/$plat/*.so ../bin/$plat +- cp -f ../../im/lib/$plat/*.so ../bin/$plat ++# cp -f ../lib/$plat/*.so ../bin/$plat ++# cp -f ../../cd/lib/$plat/*.so ../bin/$plat ++# cp -f ../../im/lib/$plat/*.so ../bin/$plat + cp -f ../../luagl/lib/$plat/*.so ../bin/$plat + cp -f ../../lfs/lib/$plat/*.so ../bin/$plat +- rm -f ../bin/$plat/*3.so ++# rm -f ../bin/$plat/*3.so + end +diff --git a/iup/srcconsole/copy_so b/iup/srcconsole/copy_so +index 2535766..e345d31 100755 +--- a/iup/srcconsole/copy_so ++++ b/iup/srcconsole/copy_so +@@ -1,4 +1,6 @@ + cp -f ../lib/${TEC_UNAME}/*.so ../bin/$TEC_UNAME + cp -f ../../cd/lib/${TEC_UNAME}/*.so ../bin/$TEC_UNAME + cp -f ../../im/lib/${TEC_UNAME}/*.so ../bin/$TEC_UNAME ++cp -f ../../luagl/lib/${TEC_UNAME}/*.so ../bin/${TEC_UNAME} ++cp -f ../../lfs/lib/${TEC_UNAME}/*.so ../bin/${TEC_UNAME} + rm -f ../bin/${TEC_UNAME}/*3.so +diff --git a/iup/srcconsole/iuplua3.rc b/iup/srcconsole/iuplua3.rc +index e741199..9fcc280 100755 +--- a/iup/srcconsole/iuplua3.rc ++++ b/iup/srcconsole/iuplua3.rc +@@ -13,7 +13,7 @@ BEGIN + VALUE "CompanyName", "Tecgraf/PUC-Rio\0" + VALUE "FileDescription", "Lua Windows Standalone Interpreter with IUP\0" + VALUE "FileVersion", "3.0.0\0" +- VALUE "LegalCopyright", "Copyright © 1994-2009 Tecgraf, PUC-Rio.\0" ++ VALUE "LegalCopyright", "Copyright © 1994-2010 Tecgraf, PUC-Rio.\0" + VALUE "OriginalFilename", "iuplua51.exe\0" + VALUE "ProductName", "IUP for Windows\0" + VALUE "ProductVersion", "3.0.0\0" +diff --git a/iup/srcconsole/iuplua5.rc b/iup/srcconsole/iuplua5.rc +index bc02e07..70e40a4 100755 +--- a/iup/srcconsole/iuplua5.rc ++++ b/iup/srcconsole/iuplua5.rc +@@ -13,7 +13,7 @@ BEGIN + VALUE "CompanyName", "Tecgraf/PUC-Rio\0" + VALUE "FileDescription", "Lua Windows Standalone Interpreter with IUP\0" + VALUE "FileVersion", "3.0.0\0" +- VALUE "LegalCopyright", "Copyright © 1994-2009 Tecgraf, PUC-Rio.\0" ++ VALUE "LegalCopyright", "Copyright © 1994-2010 Tecgraf, PUC-Rio.\0" + VALUE "OriginalFilename", "iuplua51.exe\0" + VALUE "ProductName", "IUP for Windows\0" + VALUE "ProductVersion", "3.0.0\0" +diff --git a/iup/srcconsole/make_uname.bat b/iup/srcconsole/make_uname.bat +index a5b1d9a..a0db110 100755 +--- a/iup/srcconsole/make_uname.bat ++++ b/iup/srcconsole/make_uname.bat +@@ -6,24 +6,26 @@ if "%1"=="vc8_64" goto iupexe64 + if "%1"=="all" goto iupexe + goto end +  ++REM Must use dll8 so USE_* will use the correct TEC_UNAME ++ + :iupexe32 + call tecmake dll8 relink %2 %3 %4 %5 %6 %7 +-REM call tecmake dll8 USE_GTK=Yes relink %2 %3 %4 %5 %6 %7 ++REM call tecmake vc8 USE_GTK=Yes relink %2 %3 %4 %5 %6 %7 + REM call tecmake vc8 "MF=iuplua3" relink %2 %3 %4 %5 %6 %7 + goto end +  + :iupexe64 + call tecmake dll8_64 relink %2 %3 %4 %5 %6 %7 +-REM call tecmake dll8_64 USE_GTK=Yes relink %2 %3 %4 %5 %6 %7 ++REM call tecmake vc8_64 USE_GTK=Yes relink %2 %3 %4 %5 %6 %7 + REM call tecmake vc8_64 "MF=iuplua3" relink %2 %3 %4 %5 %6 %7 + goto end +  + :iupexe + call tecmake dll8 relink %2 %3 %4 %5 %6 %7 +-REM call tecmake dll8 USE_GTK=Yes relink %2 %3 %4 %5 %6 %7 ++REM call tecmake vc8 USE_GTK=Yes relink %2 %3 %4 %5 %6 %7 + REM call tecmake vc8 "MF=iuplua3" relink %2 %3 %4 %5 %6 %7 + call tecmake dll8_64 relink %2 %3 %4 %5 %6 %7 +-REM call tecmake dll8_64 USE_GTK=Yes relink %2 %3 %4 %5 %6 %7 ++REM call tecmake vc8_64 USE_GTK=Yes relink %2 %3 %4 %5 %6 %7 + REM call tecmake vc8_64 "MF=iuplua3" relink %2 %3 %4 %5 %6 %7 + goto end +  +diff --git a/iup/srccontrols/Makefile b/iup/srccontrols/Makefile +index d02bbc3..c928251 100755 +--- a/iup/srccontrols/Makefile ++++ b/iup/srccontrols/Makefile +@@ -3,4 +3,4 @@ + do_all: iupcontrols +  + iupcontrols: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak  ++ @$(MAKE) --no-print-directory -f ../tecmake.mak  +diff --git a/iup/srccontrols/color/iup_colorbrowser.c b/iup/srccontrols/color/iup_colorbrowser.c +index 82b4a88..51f8a30 100755 +--- a/iup/srccontrols/color/iup_colorbrowser.c ++++ b/iup/srccontrols/color/iup_colorbrowser.c +@@ -681,7 +681,7 @@ static int iColorBrowserKeypress_CB(Ihandle* ih, int c, int press) + static char* iColorBrowserGetHSIAttrib(Ihandle* ih) + { + char* buffer = iupStrGetMemory(100); +- sprintf(buffer, "%f %f %f", (double)ih->data->hue, (double)ih->data->saturation, (double)ih->data->intensity); ++ sprintf(buffer, "%g %g %g", (double)ih->data->hue, (double)ih->data->saturation, (double)ih->data->intensity); + return buffer; + } +  +@@ -781,10 +781,16 @@ static int iColorBrowserMapMethod(Ihandle* ih) + static void iColorBrowserUnMapMethod(Ihandle* ih) + { + if (ih->data->cddbuffer) ++ { + cdKillCanvas(ih->data->cddbuffer); ++ ih->data->cddbuffer = NULL; ++ } +  + if (ih->data->cdcanvas) ++ { + cdKillCanvas(ih->data->cdcanvas); ++ ih->data->cdcanvas = NULL; ++ } + } +  + static int iColorBrowserCreateMethod(Ihandle* ih, void **params) +diff --git a/iup/srccontrols/color/iup_colorbrowserdlg.c b/iup/srccontrols/color/iup_colorbrowserdlg.c +index 65e4d37..dc52725 100755 +--- a/iup/srccontrols/color/iup_colorbrowserdlg.c ++++ b/iup/srccontrols/color/iup_colorbrowserdlg.c +@@ -158,7 +158,7 @@ static void iColorBrowserDlgBrowserRGB_Update(IcolorDlgData* colordlg_data) +  + static void iColorBrowserDlgBrowserHSI_Update(IcolorDlgData* colordlg_data) + { +- IupSetfAttribute(colordlg_data->color_browser, "HSI", "%f %f %f", (double)colordlg_data->hue, (double)colordlg_data->saturation, (double)colordlg_data->intensity); ++ IupSetfAttribute(colordlg_data->color_browser, "HSI", "%g %g %g", (double)colordlg_data->hue, (double)colordlg_data->saturation, (double)colordlg_data->intensity); + } +  + /*****************************************\ +@@ -575,10 +575,16 @@ static int iColorBrowserDlgColorCnvUnMap_CB(Ihandle* ih) + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); +  + if (colordlg_data->color_cddbuffer) ++ { + cdKillCanvas(colordlg_data->color_cddbuffer); ++ colordlg_data->color_cddbuffer = NULL; ++ } +  + if (colordlg_data->color_cdcanvas) ++ { + cdKillCanvas(colordlg_data->color_cdcanvas); ++ colordlg_data->color_cdcanvas = NULL; ++ } +  + return IUP_DEFAULT; + } +diff --git a/iup/srccontrols/config.mak b/iup/srccontrols/config.mak +index 394d607..10f11e1 100755 +--- a/iup/srccontrols/config.mak ++++ b/iup/srccontrols/config.mak +@@ -13,7 +13,7 @@ SRCMATRIX = iupmat_key.c iupmat_mark.c iupmat_aux.c iupmat_mem.c iupmat_mouse.c + SRCMATRIX := $(addprefix matrix/, $(SRCMATRIX)) +  + SRC = iup_cdutil.c iup_gauge.c iup_cells.c iup_colorbar.c iup_controls.c \ +- iup_dial.c iup_oldtabs.c iup_oldval.c iup_oldmask.c \ ++ iup_dial.c iup_oldmask.c \ + $(SRCCOLOR) $(SRCMATRIX) +  + LIBS = iup iupcd +diff --git a/iup/srccontrols/iup_cells.c b/iup/srccontrols/iup_cells.c +index d9a7fe4..c771d6e 100755 +--- a/iup/srccontrols/iup_cells.c ++++ b/iup/srccontrols/iup_cells.c +@@ -882,10 +882,16 @@ static int iCellsMapMethod(Ihandle* ih) + static void iCellsUnMapMethod(Ihandle* ih) + { + if (ih->data->cddbuffer) ++ { + cdKillCanvas(ih->data->cddbuffer); ++ ih->data->cddbuffer = NULL; ++ } +  + if (ih->data->cdcanvas) ++ { + cdKillCanvas(ih->data->cdcanvas); ++ ih->data->cdcanvas = NULL; ++ } + } +  + static int iCellsCreateMethod(Ihandle* ih, void **params) +diff --git a/iup/srccontrols/iup_colorbar.c b/iup/srccontrols/iup_colorbar.c +index 72e717c..1cbcd59 100755 +--- a/iup/srccontrols/iup_colorbar.c ++++ b/iup/srccontrols/iup_colorbar.c +@@ -978,10 +978,16 @@ static int iColorbarMapMethod(Ihandle* ih) + static void iColorbarUnMapMethod(Ihandle* ih) + { + if (ih->data->cddbuffer) ++ { + cdKillCanvas(ih->data->cddbuffer); ++ ih->data->cddbuffer = NULL; ++ } +  + if (ih->data->cdcanvas) ++ { + cdKillCanvas(ih->data->cdcanvas); ++ ih->data->cdcanvas = NULL; ++ } + } +  + static int iColorbarCreateMethod(Ihandle* ih, void **params) +diff --git a/iup/srccontrols/iup_dial.c b/iup/srccontrols/iup_dial.c +index 1dd2d0f..c8c5656 100755 +--- a/iup/srccontrols/iup_dial.c ++++ b/iup/srccontrols/iup_dial.c +@@ -640,7 +640,7 @@ static int iDialWheel_CB(Ihandle* ih, float delta) + static char* iDialGetValueAttrib(Ihandle* ih) + { + char* str = iupStrGetMemory(20); +- sprintf(str, "%f", ih->data->angle); ++ sprintf(str, "%g", ih->data->angle); + return str; + } +  +@@ -665,7 +665,7 @@ static int iDialSetDensityAttrib(Ihandle* ih, const char* value) + static char* iDialGetDensityAttrib(Ihandle* ih) + { + char* str = iupStrGetMemory(20); +- sprintf(str, "%f", ih->data->density); ++ sprintf(str, "%g", ih->data->density); + return str; + } +  +@@ -780,10 +780,16 @@ static int iDialMapMethod(Ihandle* ih) + static void iDialUnMapMethod(Ihandle* ih) + { + if (ih->data->cddbuffer) ++ { + cdKillCanvas(ih->data->cddbuffer); ++ ih->data->cddbuffer = NULL; ++ } +  + if (ih->data->cdcanvas) ++ { + cdKillCanvas(ih->data->cdcanvas); ++ ih->data->cdcanvas = NULL; ++ } + } +  + static int iDialCreateMethod(Ihandle* ih, void **params) +diff --git a/iup/srccontrols/iup_gauge.c b/iup/srccontrols/iup_gauge.c +index 8732eee..300b28e 100755 +--- a/iup/srccontrols/iup_gauge.c ++++ b/iup/srccontrols/iup_gauge.c +@@ -347,10 +347,16 @@ static char* iGaugeGetTextAttrib(Ihandle* ih) + static void iGaugeUnMapMethod(Ihandle* ih) + { + if (ih->data->cddbuffer) ++ { + cdKillCanvas(ih->data->cddbuffer); ++ ih->data->cddbuffer = NULL; ++ } +  + if (ih->data->cdcanvas) ++ { + cdKillCanvas(ih->data->cdcanvas); ++ ih->data->cdcanvas = NULL; ++ } + } +  + static int iGaugeMapMethod(Ihandle* ih) +diff --git a/iup/srccontrols/iup_oldmask.c b/iup/srccontrols/iup_oldmask.c +index fec10f3..2ec4012 100755 +--- a/iup/srccontrols/iup_oldmask.c ++++ b/iup/srccontrols/iup_oldmask.c +@@ -42,14 +42,14 @@ int iupmaskMatSetInt(Ihandle *ih, int autofill, int min, int max, int lin, int c + int iupmaskSetFloat(Ihandle* ih, int autofill, float min, float max) + { + (void)autofill; +- IupSetfAttribute(ih,"MASKFLOAT", "%f:%f", min, max); ++ IupSetfAttribute(ih,"MASKFLOAT", "%g:%g", min, max); + return 1; + } +  + int iupmaskMatSetFloat(Ihandle* ih, int autofill, float min, float max, int lin, int col) + { + (void)autofill; +- IupMatSetfAttribute(ih,"MASKFLOAT", lin, col, "%f:%f", min, max); ++ IupMatSetfAttribute(ih,"MASKFLOAT", lin, col, "%g:%g", min, max); + return 0; + } +  +diff --git a/iup/srccontrols/iup_oldtabs.c b/iup/srccontrols/iup_oldtabs.c +index 43b0c57..5ea7f0a 100755 +--- a/iup/srccontrols/iup_oldtabs.c ++++ b/iup/srccontrols/iup_oldtabs.c +@@ -2487,10 +2487,16 @@ static int iTabsMapMethod(Ihandle* ih) + static void iTabsUnMapMethod(Ihandle* ih) + { + if (ih->data->cddbuffer) ++ { + cdKillCanvas(ih->data->cddbuffer); ++ ih->data->cddbuffer = NULL; ++ } +  + if (ih->data->cdcanvas) ++ { + cdKillCanvas(ih->data->cdcanvas); ++ ih->data->cdcanvas = NULL; ++ } + } +  + static void iTabsDestroyMethod(Ihandle* ih) +diff --git a/iup/srccontrols/iup_oldval.c b/iup/srccontrols/iup_oldval.c +index 50dae8a..9c14c90 100755 +--- a/iup/srccontrols/iup_oldval.c ++++ b/iup/srccontrols/iup_oldval.c +@@ -533,7 +533,7 @@ static char* iValGetTypeAttrib(Ihandle* ih) + static char* iValGetValueAttrib(Ihandle* ih) + { + char* str = iupStrGetMemory(20); +- sprintf(str, "%f", ih->data->val); ++ sprintf(str, "%g", ih->data->val); + return str; + } +  +@@ -576,7 +576,7 @@ static int iValSetStepAttrib(Ihandle* ih, const char* step) + static char* iValGetStepAttrib(Ihandle* ih) + { + char* str = iupStrGetMemory(20); +- sprintf(str, "%f", ih->data->step); ++ sprintf(str, "%g", ih->data->step); + return str; + } +  +@@ -590,7 +590,7 @@ static int iValSetPageStepAttrib(Ihandle* ih, const char* pagestep) + static char* iValGetPageStepAttrib(Ihandle* ih) + { + char* str = iupStrGetMemory(20); +- sprintf(str, "%f", ih->data->pagestep); ++ sprintf(str, "%g", ih->data->pagestep); + return str; + } +  +@@ -605,7 +605,7 @@ static int iValSetMaxAttrib(Ihandle* ih, const char* max) + static char* iValGetMaxAttrib(Ihandle* ih) + { + char* str = iupStrGetMemory(20); +- sprintf(str, "%f", ih->data->vmax); ++ sprintf(str, "%g", ih->data->vmax); + return str; + } +  +@@ -620,7 +620,7 @@ static int iValSetMinAttrib(Ihandle* ih, const char* min) + static char* iValGetMinAttrib(Ihandle* ih) + { + char* str = iupStrGetMemory(20); +- sprintf(str, "%f", ih->data->vmin); ++ sprintf(str, "%g", ih->data->vmin); + return str; + } +  +@@ -719,10 +719,16 @@ static int iValMapMethod(Ihandle* ih) + static void iValUnMapMethod(Ihandle* ih) + { + if (ih->data->cddbuffer) ++ { + cdKillCanvas(ih->data->cddbuffer); ++ ih->data->cddbuffer = NULL; ++ } +  + if (ih->data->cdcanvas) ++ { + cdKillCanvas(ih->data->cdcanvas); ++ ih->data->cdcanvas = NULL; ++ } + } +  + static void iValDestroyMethod(Ihandle* ih) +diff --git a/iup/srccontrols/matrix/iupmat_aux.c b/iup/srccontrols/matrix/iupmat_aux.c +index f8b85bb..1a8df57 100755 +--- a/iup/srccontrols/matrix/iupmat_aux.c ++++ b/iup/srccontrols/matrix/iupmat_aux.c +@@ -24,16 +24,11 @@ + #include "iupmat_getset.h" +  +  +-static int iMatrixAuxIsFullVisibleLast(Ihandle* ih, int m) ++int iupMatrixAuxIsFullVisibleLast(ImatLinColData *p) + { + int i, sum = 0; +- ImatLinColData *p; +- +- if (m == IMAT_PROCESS_LIN) +- p = &(ih->data->lines); +- else +- p = &(ih->data->columns); +  ++ sum -= p->first_offset; + for(i = p->first; i <= p->last; i++) + sum += p->sizes[i]; +  +@@ -43,16 +38,20 @@ static int iMatrixAuxIsFullVisibleLast(Ihandle* ih, int m) + return 1; + } +  +-int iupMatrixAuxIsCellFullVisible(Ihandle* ih, int lin, int col) ++int iupMatrixAuxIsCellStartVisible(Ihandle* ih, int lin, int col) + { + if(((lin >= ih->data->lines.first) && + (lin <= ih->data->lines.last) && + (col >= ih->data->columns.first) && + (col <= ih->data->columns.last))) + { +- if (col == ih->data->columns.last && !iMatrixAuxIsFullVisibleLast(ih, IMAT_PROCESS_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 (lin == ih->data->lines.last && !iMatrixAuxIsFullVisibleLast(ih, IMAT_PROCESS_LIN)) ++ 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; +@@ -81,18 +80,98 @@ void iupMatrixAuxGetVisibleCellDim(Ihandle* ih, int lin, int col, int* x, int* y + /* find the position where the column starts */ + *x = ih->data->columns.sizes[0]; + for(i = ih->data->columns.first; i < col; i++) ++ { + *x += ih->data->columns.sizes[i]; +  +- /* find the column size */ ++ if (i == ih->data->columns.first) ++ *x -= ih->data->columns.first_offset; ++ } ++ ++ /* get the column size */ + *w = ih->data->columns.sizes[col] - 1; ++ if (col == ih->data->columns.first) ++ *w -= ih->data->columns.first_offset; +  + /* find the position where the line starts */ + *y = ih->data->lines.sizes[0]; + for(i = ih->data->lines.first; i < lin; i++) ++ { + *y += ih->data->lines.sizes[i]; +  +- /* find the line size */ ++ if (i == ih->data->lines.first) ++ *y -= ih->data->lines.first_offset; ++ } ++ ++ /* get the line size */ + *h = ih->data->lines.sizes[lin] - 1; ++ if (lin == ih->data->lines.first) ++ *h -= ih->data->lines.first_offset; ++} ++ ++void iupMatrixAuxAdjustFirstFromLast(ImatLinColData* p) ++{ ++ int i, sum = 0; ++ ++ /* adjust "first" according to "last" */ ++ ++ i = p->last; ++ sum = p->sizes[i]; ++ while (i>1 && sum < p->visible_size) ++ { ++ i--; ++ sum += p->sizes[i]; ++ } ++ ++ if (i==1 && sum < p->visible_size) ++ { ++ /* if there are room for everyone then position at start */ ++ p->first = 1; ++ 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->visible_size; ++ } ++} ++ ++void iupMatrixAuxAdjustFirstFromScrollPos(ImatLinColData* p, int scroll_pos) ++{ ++ int index, sp, offset = 0; ++ ++ sp = 0; ++ for(index = 1; index < p->num; index++) ++ { ++ sp += p->sizes[index]; ++ if (sp > scroll_pos) ++ { ++ sp -= p->sizes[index]; /* get the previous value */ ++ offset = scroll_pos - sp; ++ break; ++ } ++ } ++ ++ if (index == p->num) ++ { ++ if (p->num == 1) ++ { ++ /* did NOT go trough the "for" above */ ++ offset = scroll_pos; ++ index = 1; ++ } ++ 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, +@@ -101,10 +180,11 @@ void iupMatrixAuxGetVisibleCellDim(Ihandle* ih, int lin, int col, int* x, int* y + Depends on the first visible column/line. + -> m : choose will operate on lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] + */ +-void iupMatrixAuxUpdateVisiblePos(Ihandle* ih, int m) ++void iupMatrixAuxUpdateScrollPos(Ihandle* ih, int m) + { ++ float pos; ++ int i, sb, scroll_pos; + char* POS; +- int i, sb, visible_pos; + ImatLinColData *p; +  + if (m == IMAT_PROCESS_LIN) +@@ -120,33 +200,44 @@ void iupMatrixAuxUpdateVisiblePos(Ihandle* ih, int m) + POS = "POSX"; + } +  +- visible_pos = 0; +- for(i = 1; i < p->first; i++) +- visible_pos += p->sizes[i]; ++ /* "first" was changed, so update "last" and the scroll pos */ +  +- if (ih->data->canvas.sb & sb) ++ if (p->total_size <= p->visible_size) + { +- float pos; ++ /* the matrix is fully visible */ ++ p->first = 1; ++ p->first_offset = 0; ++ p->last = p->num==1? 1: p->num-1; +  +- if (p->total_size) +- { +- while ((visible_pos + p->visible_size > p->total_size) && p->first>1) +- { +- /* invalid position, must recalculate first */ +- p->first--; +- visible_pos -= p->sizes[p->first]; +- } ++ if (ih->data->canvas.sb & sb) ++ IupSetAttribute(ih, POS, "0"); +  +- pos = (float)visible_pos/(float)p->total_size; +- } +- else +- pos = 0; ++ return; ++ } ++ ++ /* must check if it is a valid position */ ++ scroll_pos = 0; ++ for(i = 1; i < p->first; i++) ++ scroll_pos += p->sizes[i]; ++ scroll_pos += p->first_offset; ++ ++ if (scroll_pos + p->visible_size > p->total_size) ++ { ++ /* invalid condition, must recalculate so it is valid */ ++ scroll_pos = p->total_size - p->visible_size; +  +- iupMatrixAuxUpdateLast(p); +- IupSetfAttribute(ih, POS, "%.5f", (double)pos); ++ /* position first and first_offset, according to scroll pos */ ++ iupMatrixAuxAdjustFirstFromScrollPos(p, scroll_pos); + } +- else +- iupMatrixAuxUpdateLast(p); ++ ++ pos = (float)scroll_pos/(float)p->total_size; ++ ++ /* update last */ ++ iupMatrixAuxUpdateLast(p); ++ ++ /* update scroll pos */ ++ if (ih->data->canvas.sb & sb) ++ IupSetfAttribute(ih, POS, "%g", (double)pos); + } +  + /* Calculate which is the last visible column/line of the matrix.  +@@ -157,18 +248,24 @@ void iupMatrixAuxUpdateLast(ImatLinColData *p) +  + if (p->visible_size > 0) + { +- /* Find which is the last column/line ++ /* Find which is the last column/line. + Start in the first visible and continue adding the widths +- up to the visible size */ ++ up to the visible size */ ++ sum -= p->first_offset; + for(i = p->first; i < p->num; i++) + { +- sum += p->sizes[i]; ++ sum += p->sizes[i]; + if(sum >= p->visible_size) + break; + } +  + if (i == p->num) +- p->last = i-1; ++ { ++ if (p->num == 1) ++ p->last = 1; ++ else ++ p->last = p->num-1; ++ } + else + p->last = i; + } +@@ -185,7 +282,7 @@ int iupMatrixAuxGetColumnWidth(Ihandle* ih, int col) + char* str = iupStrGetMemory(100); + char* value; +  +- /* can only be called for valid columns */ ++ /* can be called for invalid columns (col>numcol) */ +  + sprintf(str, "WIDTH%d", col); + value = iupAttribGet(ih, str); +@@ -219,7 +316,7 @@ int iupMatrixAuxGetColumnWidth(Ihandle* ih, int col) + width = max_width; + } + } +- else if (ih->data->use_title_size) ++ else if (ih->data->use_title_size && (col>=0 && coldata->columns.num)) + { + char* title_value = iupMatrixCellGetValue(ih, 0, col); + if (title_value) +@@ -257,7 +354,7 @@ int iupMatrixAuxGetLineHeight(Ihandle* ih, int lin) + char* str = iupStrGetMemory(100); + char* value; +  +- /* can only be called for valid lines */ ++ /* can be called for invalid lines (lin>numlin) */ +  + sprintf(str, "HEIGHT%d", lin); + value = iupAttribGet(ih, str); +@@ -291,7 +388,7 @@ int iupMatrixAuxGetLineHeight(Ihandle* ih, int lin) + height = max_height; + } + } +- else if (ih->data->use_title_size) ++ else if (ih->data->use_title_size && (lin>=0 && lindata->lines.num)) + { + char* title_value = iupMatrixCellGetValue(ih, lin, 0); + if (title_value && title_value[0]) +@@ -374,7 +471,7 @@ static void iMatrixAuxUpdateVisibleSize(Ihandle* ih, int m) + p->visible_size = p->total_size; +  + if (p->total_size) +- IupSetfAttribute(ih, D, "%f", (double)p->visible_size/(double)p->total_size); ++ IupSetfAttribute(ih, D, "%g", (double)p->visible_size/(double)p->total_size); + else + IupSetAttribute(ih, D, "1.0"); + } +@@ -390,6 +487,7 @@ void iupMatrixAuxCalcSizes(Ihandle* ih) + /* 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==1) + ih->data->lines.first = 1; + else +@@ -397,46 +495,50 @@ void iupMatrixAuxCalcSizes(Ihandle* ih) + } + if (ih->data->columns.first > ih->data->columns.num-1)  + { ++ ih->data->columns.first_offset = 0; + if (ih->data->columns.num == 1) + ih->data->columns.first = 1; + else + ih->data->columns.first = ih->data->columns.num-1; + } +  +- iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_COL); +- iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_LIN); ++ /* make sure scroll pos is consistent */ ++ iupMatrixAuxUpdateScrollPos(ih, IMAT_PROCESS_COL); ++ iupMatrixAuxUpdateScrollPos(ih, IMAT_PROCESS_LIN); +  + ih->data->need_calcsize = 0; + } +  + int iupMatrixAuxGetLinColFromXY(Ihandle* ih, int x, int y, int* l, int* c) + { +- int size, lin, col; ++ int x_col, y_col, lin, col; +  +- size = ih->data->columns.sizes[0]; /* always visible when non zero */ +- if (x < size) ++ x_col = ih->data->columns.sizes[0]; /* always visible when non zero */ ++ if (x < x_col) + col = 0; /* It is in the column of titles */ + else + { ++ x_col -= ih->data->columns.first_offset; + for(col = ih->data->columns.first; col <= ih->data->columns.last; col++) /* for all visible columns */ + { +- size += ih->data->columns.sizes[col]; +- if (x < size) ++ x_col += ih->data->columns.sizes[col]; ++ if (x < x_col) + break; + } + if (col > ih->data->columns.last) + col = -1; + } +  +- size = ih->data->lines.sizes[0]; /* always visible when non zero */ +- if (y < size) ++ y_col = ih->data->lines.sizes[0]; /* always visible when non zero */ ++ if (y < y_col) + lin = 0; /* It is in the line of titles */ + else + { ++ y_col -= ih->data->lines.first_offset; + for(lin = ih->data->lines.first; lin <= ih->data->lines.last; lin++) /* for all visible lines */ + { +- size += ih->data->lines.sizes[lin]; +- if (y < size) ++ y_col += ih->data->lines.sizes[lin]; ++ if (y < y_col) + break; + } + if(lin > ih->data->lines.last) +diff --git a/iup/srccontrols/matrix/iupmat_aux.h b/iup/srccontrols/matrix/iupmat_aux.h +index 296c1f5..01c77f1 100755 +--- a/iup/srccontrols/matrix/iupmat_aux.h ++++ b/iup/srccontrols/matrix/iupmat_aux.h +@@ -12,19 +12,22 @@ + extern "C" { + #endif +  +-int iupMatrixAuxIsCellFullVisible(Ihandle* ih, int lin, int col); ++int iupMatrixAuxIsFullVisibleLast(ImatLinColData *p); ++int iupMatrixAuxIsCellStartVisible(Ihandle* ih, int lin, int col); + int iupMatrixAuxIsCellVisible(Ihandle* ih, int lin, int col); + void iupMatrixAuxGetVisibleCellDim (Ihandle* ih, int lin, int col, int* x, int* y, int* w, int* h); +  + void iupMatrixAuxCalcSizes(Ihandle* ih); +  +-void iupMatrixAuxUpdateVisiblePos(Ihandle* ih, int m); ++void iupMatrixAuxAdjustFirstFromLast(ImatLinColData* p); ++void iupMatrixAuxAdjustFirstFromScrollPos(ImatLinColData* p, int scroll_pos); ++void iupMatrixAuxUpdateScrollPos(Ihandle* ih, int m); + void iupMatrixAuxUpdateLast(ImatLinColData *p); +  + int iupMatrixAuxGetColumnWidth(Ihandle* ih, int col); + int iupMatrixAuxGetLineHeight (Ihandle* ih, int lin); +  +-int iupMatrixAuxGetLinColFromXY (Ihandle* ih, int x, int y, int* l, int* c); ++int iupMatrixAuxGetLinColFromXY (Ihandle* ih, int x, int y, int* l, int* c); +  + int iupMatrixAuxCallLeaveCellCb (Ihandle* ih); + void iupMatrixAuxCallEnterCellCb (Ihandle* ih); +diff --git a/iup/srccontrols/matrix/iupmat_cd.h b/iup/srccontrols/matrix/iupmat_cd.h +index 1a10f2b..beb616a 100755 +--- a/iup/srccontrols/matrix/iupmat_cd.h ++++ b/iup/srccontrols/matrix/iupmat_cd.h +@@ -11,12 +11,12 @@ + extern "C" { + #endif +  +-#define IUPMAT_LINE(_ih,_x1,_y1,_x2,_y2) cdCanvasLine((_ih)->data->cddbuffer, (_x1), iupMatrixInvertYAxis(_ih, _y1), (_x2), iupMatrixInvertYAxis(_ih, _y2)) +-#define IUPMAT_VERTEX(_ih,_x,_y) cdCanvasVertex((_ih)->data->cddbuffer, (_x), iupMatrixInvertYAxis(_ih, _y)) +-#define IUPMAT_BOX(_ih,_xmin,_xmax,_ymin,_ymax) cdCanvasBox((_ih)->data->cddbuffer, (_xmin), (_xmax), iupMatrixInvertYAxis(_ih, _ymin), iupMatrixInvertYAxis(_ih, _ymax)) +-#define IUPMAT_RECT(_ih,_xmin,_xmax,_ymin,_ymax) cdCanvasRect((_ih)->data->cddbuffer, (_xmin), (_xmax), iupMatrixInvertYAxis(_ih, _ymin), iupMatrixInvertYAxis(_ih, _ymax)) +-#define IUPMAT_CLIPAREA(_ih,_xmin,_xmax,_ymin,_ymax) cdCanvasClipArea((_ih)->data->cddbuffer, (_xmin), (_xmax), iupMatrixInvertYAxis(_ih, _ymin), iupMatrixInvertYAxis(_ih, _ymax)) +-#define IUPMAT_TEXT(_ih,_x,_y,_text) cdCanvasText((_ih)->data->cddbuffer, (_x), iupMatrixInvertYAxis(_ih, _y), (_text)) ++#define iupMATRIX_LINE(_ih,_x1,_y1,_x2,_y2) cdCanvasLine((_ih)->data->cddbuffer, (_x1), iupMATRIX_INVERTYAXIS(_ih, _y1), (_x2), iupMATRIX_INVERTYAXIS(_ih, _y2)) ++#define iupMATRIX_VERTEX(_ih,_x,_y) cdCanvasVertex((_ih)->data->cddbuffer, (_x), iupMATRIX_INVERTYAXIS(_ih, _y)) ++#define iupMATRIX_BOX(_ih,_xmin,_xmax,_ymin,_ymax) cdCanvasBox((_ih)->data->cddbuffer, (_xmin), (_xmax), iupMATRIX_INVERTYAXIS(_ih, _ymin), iupMATRIX_INVERTYAXIS(_ih, _ymax)) ++#define iupMATRIX_RECT(_ih,_xmin,_xmax,_ymin,_ymax) cdCanvasRect((_ih)->data->cddbuffer, (_xmin), (_xmax), iupMATRIX_INVERTYAXIS(_ih, _ymin), iupMATRIX_INVERTYAXIS(_ih, _ymax)) ++#define iupMATRIX_CLIPAREA(_ih,_xmin,_xmax,_ymin,_ymax) cdCanvasClipArea((_ih)->data->cddbuffer, (_xmin), (_xmax), iupMATRIX_INVERTYAXIS(_ih, _ymin), iupMATRIX_INVERTYAXIS(_ih, _ymax)) ++#define iupMATRIX_TEXT(_ih,_x,_y,_text) cdCanvasText((_ih)->data->cddbuffer, (_x), iupMATRIX_INVERTYAXIS(_ih, _y), (_text)) +  + #ifdef __cplusplus + } +diff --git a/iup/srccontrols/matrix/iupmat_colres.c b/iup/srccontrols/matrix/iupmat_colres.c +index d44b7df..79f389e 100755 +--- a/iup/srccontrols/matrix/iupmat_colres.c ++++ b/iup/srccontrols/matrix/iupmat_colres.c +@@ -34,15 +34,17 @@ + if so the resize is started */ + int iupMatrixColResStart(Ihandle* ih, int x, int y) + { +- if (ih->data->lines.sizes[0] && y < ih->data->lines.sizes[0] && iupAttribGetBoolean(ih, "RESIZEMATRIX")) ++ if (ih->data->lines.sizes[0] &&  ++ y < ih->data->lines.sizes[0] &&  ++ iupAttribGetBoolean(ih, "RESIZEMATRIX")) + { +- int size, col; ++ int x_col, col; +  + /* Check if is the column of titles */ +- size = ih->data->columns.sizes[0]; +- if (abs(size-x) < IMAT_COLRES_TOL) ++ x_col = ih->data->columns.sizes[0]; ++ if (abs(x_col-x) < IMAT_COLRES_TOL) + { +- ih->data->colres_drag_col_start_x = 0; ++ ih->data->colres_drag_col_start_x = x; + ih->data->colres_dragging = 1; + ih->data->colres_drag_col_last_x = -1; + ih->data->colres_drag_col = 0; +@@ -51,12 +53,13 @@ int iupMatrixColResStart(Ihandle* ih, int x, int y) + else + { + /* find the column */ ++ x_col -= ih->data->columns.first_offset; + for(col = ih->data->columns.first; col <= ih->data->columns.last; col++) + { +- ih->data->colres_drag_col_start_x = size; +- size += ih->data->columns.sizes[col]; +- if (abs(size-x) < IMAT_COLRES_TOL) ++ x_col += ih->data->columns.sizes[col]; ++ if (abs(x_col-x) < IMAT_COLRES_TOL) + { ++ ih->data->colres_drag_col_start_x = x; + ih->data->colres_dragging = 1; + ih->data->colres_drag_col_last_x = -1; + ih->data->colres_drag_col = col; +@@ -71,7 +74,8 @@ int iupMatrixColResStart(Ihandle* ih, int x, int y) + void iupMatrixColResFinish(Ihandle* ih, int x) + { + char str[100]; +- int width = x - ih->data->colres_drag_col_start_x; ++ int delta = x - ih->data->colres_drag_col_start_x; ++ int width = ih->data->columns.sizes[ih->data->colres_drag_col] + delta; + if (width < 0) + width = 0; +  +@@ -83,8 +87,8 @@ void iupMatrixColResFinish(Ihandle* ih, int x) +  + cdCanvasWriteMode(ih->data->cdcanvas, CD_XOR); + cdCanvasForeground(ih->data->cdcanvas, IMAT_RESIZE_COLOR);  +- cdCanvasLine(ih->data->cdcanvas, ih->data->colres_drag_col_last_x, iupMatrixInvertYAxis(ih, y1),  +- ih->data->colres_drag_col_last_x, iupMatrixInvertYAxis(ih, y2)); ++ cdCanvasLine(ih->data->cdcanvas, ih->data->colres_drag_col_last_x, iupMATRIX_INVERTYAXIS(ih, y1),  ++ ih->data->colres_drag_col_last_x, iupMATRIX_INVERTYAXIS(ih, y2)); + cdCanvasWriteMode(ih->data->cdcanvas, CD_REPLACE); + } +  +@@ -106,7 +110,8 @@ void iupMatrixColResMove(Ihandle* ih, int x) + { + int y1, y2; +  +- int width = x - ih->data->colres_drag_col_start_x; ++ int delta = x - ih->data->colres_drag_col_start_x; ++ int width = ih->data->columns.sizes[ih->data->colres_drag_col] + delta; + if (width < 0) + return; +  +@@ -119,12 +124,12 @@ void iupMatrixColResMove(Ihandle* ih, int x) + /* If it is not the first time, move old line */ + if (ih->data->colres_drag_col_last_x != -1) + { +- cdCanvasLine(ih->data->cdcanvas, ih->data->colres_drag_col_last_x, iupMatrixInvertYAxis(ih, y1),  +- ih->data->colres_drag_col_last_x, iupMatrixInvertYAxis(ih, y2)); ++ cdCanvasLine(ih->data->cdcanvas, ih->data->colres_drag_col_last_x, iupMATRIX_INVERTYAXIS(ih, y1),  ++ ih->data->colres_drag_col_last_x, iupMATRIX_INVERTYAXIS(ih, y2)); + } +  +- cdCanvasLine(ih->data->cdcanvas, x, iupMatrixInvertYAxis(ih, y1),  +- x, iupMatrixInvertYAxis(ih, y2)); ++ cdCanvasLine(ih->data->cdcanvas, x, iupMATRIX_INVERTYAXIS(ih, y1),  ++ x, iupMATRIX_INVERTYAXIS(ih, y2)); +  + ih->data->colres_drag_col_last_x = x; + cdCanvasWriteMode(ih->data->cdcanvas, CD_REPLACE); +@@ -144,20 +149,23 @@ static void iMatrixColResResetMatrixCursor(Ihandle* ih) + /* Change the cursor when it passes over a group of the column titles. */ + void iupMatrixColResCheckChangeCursor(Ihandle* ih, int x, int y) + { +- if(ih->data->lines.sizes[0] && y < ih->data->lines.sizes[0] && iupAttribGetBoolean(ih, "RESIZEMATRIX")) ++ if(ih->data->lines.sizes[0] &&  ++ y < ih->data->lines.sizes[0] &&  ++ iupAttribGetBoolean(ih, "RESIZEMATRIX")) + { + /* It is in the column titles area and the resize mode is on */ +- int found = 0, size, col; ++ int found = 0, x_col, col; +  +- size = ih->data->columns.sizes[0]; +- if (abs(size - x) < IMAT_COLRES_TOL) ++ x_col = ih->data->columns.sizes[0]; ++ if (abs(x_col - x) < IMAT_COLRES_TOL) + found = 1; /* line titles */ + else + { ++ x_col -= ih->data->columns.first_offset; + for(col = ih->data->columns.first; col <= ih->data->columns.last && !found; col++) + { +- size += ih->data->columns.sizes[col]; +- if(abs(size - x) < IMAT_COLRES_TOL) ++ x_col += ih->data->columns.sizes[col]; ++ if(abs(x_col - x) < IMAT_COLRES_TOL) + found = 1; + } + } +@@ -168,7 +176,7 @@ void iupMatrixColResCheckChangeCursor(Ihandle* ih, int x, int y) + iupAttribStoreStr(ih, "_IUPMAT_CURSOR", IupGetAttribute(ih, "CURSOR")); + IupSetAttribute(ih, "CURSOR", "RESIZE_W"); + } +- else /* It is in the empty area after the last column */ ++ else /* It is in the empty area after the last column, or inside a cell */ + iMatrixColResResetMatrixCursor(ih);  + } + else +diff --git a/iup/srccontrols/matrix/iupmat_def.h b/iup/srccontrols/matrix/iupmat_def.h +index d45acde..225cc16 100755 +--- a/iup/srccontrols/matrix/iupmat_def.h ++++ b/iup/srccontrols/matrix/iupmat_def.h +@@ -49,6 +49,7 @@ typedef struct _ImatLinColData + int num; /* Number of columns/lines in the matrix, default/minimum=1, always includes the title */ + int num_alloc; /* Number of columns/lines allocated, default=5 */ +  ++ int first_offset; /* scroll offset of the first visible column/line from right to left (or the invisible part of the first cell) */ + int first; /* First visible column/line */ + int last; /* Last visible column/line */ +  +@@ -84,7 +85,7 @@ struct _IcontrolData +  + /* attributes */ + int mark_continuous, mark_mode, mark_multiple; +- int checkframecolor; ++ int checkframecolor, hidden_text_marks; +  + /* Mouse and Keyboard AUX */ + int leftpressed; /* left mouse button is pressed */ +@@ -92,8 +93,8 @@ struct _IcontrolData +  + /* ColRes AUX */ + int colres_dragging, /* indicates if it is being made a column resize */ +- colres_drag_col, /* column being resized */ +- colres_drag_col_start_x, /* position of the start of the column being resized */ ++ colres_drag_col, /* column being resized, handler is at right of the column */ ++ colres_drag_col_start_x, /* handler start position */ + colres_drag_col_last_x; /* previous position */ +  + /* Mark AUX */ +@@ -107,12 +108,14 @@ struct _IcontrolData + IFniiIII fgcolor_cb; + IFniiIII bgcolor_cb; + char *bgcolor, *bgcolor_parent, *fgcolor, *font; /* not need to free */ ++ ++ int clip_x1, clip_x2, clip_y1, clip_y2; /* aux for cell clipping */ + }; +  +  + int iupMatrixIsValid(Ihandle* ih, int check_cells); +  +-#define iupMatrixInvertYAxis(_ih, _y) ((_ih)->data->h-1 - (_y)) ++#define iupMATRIX_INVERTYAXIS(_ih, _y) ((_ih)->data->h-1 - (_y)) +  +  + #ifdef __cplusplus +diff --git a/iup/srccontrols/matrix/iupmat_draw.c b/iup/srccontrols/matrix/iupmat_draw.c +index 7c53fb5..ec3df59 100755 +--- a/iup/srccontrols/matrix/iupmat_draw.c ++++ b/iup/srccontrols/matrix/iupmat_draw.c +@@ -47,13 +47,38 @@ + #define IMAT_COMBOBOX_W 16 +  +  +-typedef int (*IFniiiiiiC)(Ihandle *h, int lin, int col,int x1, int x2, int y1, int y2, cdCanvas* cnv); ++typedef int (*IFniiiiiiC)(Ihandle *h, int lin, int col, int x1, int x2, int y1, int y2, cdCanvas* cnv); +  +  + /**************************************************************************/ + /* Private functions */ + /**************************************************************************/ +  ++static void iMatrixDrawSetCellClipping(Ihandle* ih, int x1, int x2, int y1, int y2) ++{ ++ int old_clip = cdCanvasClip(ih->data->cddbuffer, CD_QUERY); ++ if (old_clip == CD_CLIPAREA) ++ { ++ cdCanvasGetClipArea(ih->data->cddbuffer, &(ih->data->clip_x1), &(ih->data->clip_x2), &(ih->data->clip_y1), &(ih->data->clip_y2)); ++ y1 = iupMATRIX_INVERTYAXIS(ih, y1); ++ y2 = iupMATRIX_INVERTYAXIS(ih, y2); ++ if (x1 > x2) {int tmp = x1; x1 = x2; x2 = tmp;} ++ if (y1 > y2) {int tmp = y1; y1 = y2; y2 = tmp;} ++ if (x1 < ih->data->clip_x1) x1 = ih->data->clip_x1; ++ if (x2 > ih->data->clip_x2) x2 = ih->data->clip_x2; ++ if (y1 < ih->data->clip_y1) y1 = ih->data->clip_y1; ++ if (y2 > ih->data->clip_y2) y2 = ih->data->clip_y2; ++ cdCanvasClipArea(ih->data->cddbuffer, x1, x2, y1, y2); ++ cdCanvasClip(ih->data->cddbuffer, CD_CLIPAREA); ++ } ++} ++ ++static void iMatrixDrawResetCellClipping(Ihandle* ih) ++{ ++ int old_clip = cdCanvasClip(ih->data->cddbuffer, CD_QUERY); ++ if (old_clip == CD_CLIPAREA) ++ cdCanvasClipArea(ih->data->cddbuffer, ih->data->clip_x1, ih->data->clip_x2, ih->data->clip_y1, ih->data->clip_y2); ++} +  + static int iMatrixDrawGetColAlignment(Ihandle* ih, int col, char* str) + { +@@ -61,6 +86,8 @@ static int iMatrixDrawGetColAlignment(Ihandle* ih, int col, char* str) + sprintf(str, "ALIGNMENT%d", col); + align = iupAttribGet(ih, str); + if (!align) ++ align = iupAttribGet(ih, "ALIGNMENT"); ++ if (!align) + { + if (col == 0) + return IMAT_T_LEFT; +@@ -80,16 +107,15 @@ static int iMatrixDrawCallDrawCB(Ihandle* ih, int lin, int col, int x1, int x2, + int ret; + cdCanvas* old_cnv; +  +- IUPMAT_CLIPAREA(ih, x1, x2, y1, y2); +- cdCanvasClip(ih->data->cddbuffer, CD_CLIPAREA); ++ iMatrixDrawSetCellClipping(ih, x1, x2, y1, y2); +  + old_cnv = cdActiveCanvas(); + if (old_cnv != ih->data->cddbuffer) /* backward compatibility code */ + cdActivate(ih->data->cddbuffer); +  +- ret = draw_cb(ih, lin, col, x1, x2, iupMatrixInvertYAxis(ih, y1), iupMatrixInvertYAxis(ih, y2), ih->data->cddbuffer); ++ ret = draw_cb(ih, lin, col, x1, x2, iupMATRIX_INVERTYAXIS(ih, y1), iupMATRIX_INVERTYAXIS(ih, y2), ih->data->cddbuffer); +  +- cdCanvasClip(ih->data->cddbuffer, CD_CLIPOFF); ++ iMatrixDrawResetCellClipping(ih); +  + if (old_cnv && old_cnv != ih->data->cddbuffer) /* backward compatibility code */ + { +@@ -165,28 +191,36 @@ static void iMatrixDrawFrameHorizLineCell(Ihandle* ih, int lin, int col, int x1, + { + if (ih->data->checkframecolor && (ih->data->callback_mode || ih->data->cells[lin][col].flags & IUPMAT_FRAMEHCOLOR)) + { ++ char* color; + unsigned char r,g,b; + sprintf(str, "FRAMEHORIZCOLOR%d:%d", lin, col); +- if (iupStrToRGB(iupAttribGet(ih, str), &r, &g, &b)) ++ color = iupAttribGet(ih, str); ++ if (iupStrEqual(color, "BGCOLOR")) ++ return; ++ if (iupStrToRGB(color, &r, &g, &b)) + framecolor = cdEncodeColor(r, g, b); + } +  + cdCanvasForeground(ih->data->cddbuffer, framecolor); +- IUPMAT_LINE(ih, x1, y, x2, y); /* bottom horizontal line */ ++ iupMATRIX_LINE(ih, x1, y, x2, y); /* bottom horizontal line */ + } +  + static void iMatrixDrawFrameVertLineCell(Ihandle* ih, int lin, int col, int x, int y1, int y2, long framecolor, char* str) + { + if (ih->data->checkframecolor && (ih->data->callback_mode || ih->data->cells[lin][col].flags & IUPMAT_FRAMEVCOLOR)) + { ++ char* color; + unsigned char r,g,b; + sprintf(str, "FRAMEVERTCOLOR%d:%d", lin, col); +- if (iupStrToRGB(iupAttribGet(ih, str), &r, &g, &b)) ++ color = iupAttribGet(ih, str); ++ if (iupStrEqual(color, "BGCOLOR")) ++ return; ++ if (iupStrToRGB(color, &r, &g, &b)) + framecolor = cdEncodeColor(r, g, b); + } +  + cdCanvasForeground(ih->data->cddbuffer, framecolor); +- IUPMAT_LINE(ih, x, y1, x, y2); /* right vertical line */ ++ iupMATRIX_LINE(ih, x, y1, x, y2); /* right vertical line */ + } +  + static void iMatrixDrawFrameRectTitle(Ihandle* ih, int lin, int col, int x1, int x2, int y1, int y2, long framecolor, char* str) +@@ -195,37 +229,43 @@ static void iMatrixDrawFrameRectTitle(Ihandle* ih, int lin, int col, int x1, int + x2 -= IMAT_FRAME_W/2; + y2 -= IMAT_FRAME_H/2; +  +- iMatrixDrawFrameVertLineCell(ih, lin, col, x2, y1, y2, framecolor, str); /* right vertical line */ ++ /* right vertical line */ ++ iMatrixDrawFrameVertLineCell(ih, lin, col, x2, y1, y2, framecolor, str);  + if (col==0) + { +- IUPMAT_LINE(ih, x1, y1, x1, y2); /* left vertical line, reuse Foreground */ ++ /* left vertical line, reuse Foreground */ ++ iupMATRIX_LINE(ih, x1, y1, x1, y2);  + x1++; + } + else if (col==1 && ih->data->columns.sizes[0] == 0) + { + /* If does not have line titles then draw the left line of the cell frame */ +- IUPMAT_LINE(ih, x1, y1, x1, y2-1); ++ iupMATRIX_LINE(ih, x1, y1, x1, y2-1); + x1++; + } +  +- cdCanvasForeground(ih->data->cddbuffer, CD_WHITE); /* Titles have a white line near the frame */ +- IUPMAT_LINE(ih, x1, y1+1, x1, y2-1); ++ /* Titles have a white line near the frame, at left */ ++ cdCanvasForeground(ih->data->cddbuffer, CD_WHITE);  ++ iupMATRIX_LINE(ih, x1, y1+1, x1, y2-1); +  +- iMatrixDrawFrameHorizLineCell(ih, lin, col, x1, x2, y2, framecolor, str); /* bottom horizontal line */ ++ /* bottom horizontal line */ ++ iMatrixDrawFrameHorizLineCell(ih, lin, col, x1, x2, y2, framecolor, str);  + if (lin==0) + { +- IUPMAT_LINE(ih, x1, y1, x2, y1); /* top horizontal line, reuse Foreground */ ++ /* top horizontal line, reuse Foreground */ ++ iupMATRIX_LINE(ih, x1, y1, x2, y1);  + y1++; + } + else if (lin==1 && ih->data->lines.sizes[0] == 0) + { + /* If does not have column titles then draw the top line of the cell frame */ +- IUPMAT_LINE(ih, x1, y1, x2-1, y1); ++ iupMATRIX_LINE(ih, x1, y1, x2-1, y1); + y1++; + } +  +- cdCanvasForeground(ih->data->cddbuffer, CD_WHITE); /* Titles have a white line near the frame */ +- IUPMAT_LINE(ih, x1, y1, x2-1, y1); ++ /* Titles have a white line near the frame, at top */ ++ cdCanvasForeground(ih->data->cddbuffer, CD_WHITE);  ++ iupMATRIX_LINE(ih, x1, y1, x2-1, y1); + } +  + static void iMatrixDrawFrameRectCell(Ihandle* ih, int lin, int col, int x1, int x2, int y1, int y2, long framecolor, char* str) +@@ -233,20 +273,20 @@ static void iMatrixDrawFrameRectCell(Ihandle* ih, int lin, int col, int x1, int + if (col==1 && ih->data->columns.sizes[0] == 0) + { + /* If does not have line titles then draw the left line of the cell frame */ +- iMatrixDrawFrameVertLineCell(ih, lin, col, x1, y1, y2-1-1, framecolor, str); ++ iMatrixDrawFrameVertLineCell(ih, lin, col, x1, y1, y2-1, framecolor, str); + } +  + if (lin==1 && ih->data->lines.sizes[0] == 0) + { + /* If does not have column titles then draw the top line of the cell frame */ +- iMatrixDrawFrameHorizLineCell(ih, lin, col, x1, x2-1-1, y1, framecolor, str); ++ iMatrixDrawFrameHorizLineCell(ih, lin, col, x1, x2-1, y1, framecolor, str); + } +  + /* bottom line */ + iMatrixDrawFrameHorizLineCell(ih, lin, col, x1, x2-1, y2-1, framecolor, str); +  + /* rigth line */ +- iMatrixDrawFrameVertLineCell(ih, lin, col, x2-1, y1, y2-1, framecolor, str); ++ iMatrixDrawFrameVertLineCell(ih, lin, col, x2-1, y1, y2-2, framecolor, str); + } +  + static int iMatrixDrawSortSign(Ihandle* ih, int x2, int y1, int y2, int col, int active, char* str) +@@ -274,15 +314,15 @@ static int iMatrixDrawSortSign(Ihandle* ih, int x2, int y1, int y2, int col, int +  + if (iupStrEqualNoCase(sort, "DOWN")) + { +- IUPMAT_VERTEX(ih, x2 - 5, yc + 2); +- IUPMAT_VERTEX(ih, x2 - 1, yc - 2); +- IUPMAT_VERTEX(ih, x2 - 9, yc - 2); ++ iupMATRIX_VERTEX(ih, x2 - 5, yc + 2); ++ iupMATRIX_VERTEX(ih, x2 - 1, yc - 2); ++ iupMATRIX_VERTEX(ih, x2 - 9, yc - 2); + } + else + { +- IUPMAT_VERTEX(ih, x2 - 1, yc + 2); +- IUPMAT_VERTEX(ih, x2 - 9, yc + 2); +- IUPMAT_VERTEX(ih, x2 - 5, yc - 2); ++ iupMATRIX_VERTEX(ih, x2 - 1, yc + 2); ++ iupMATRIX_VERTEX(ih, x2 - 9, yc + 2); ++ iupMATRIX_VERTEX(ih, x2 - 5, yc - 2); + } +  + cdCanvasEnd(ih->data->cddbuffer); +@@ -301,20 +341,20 @@ static void iMatrixDrawComboFeedback(Ihandle* ih, int x2, int y1, int y2, int ac +  + /* feedback background */ + iMatrixDrawSetBgColor(ih, 0, 0, 0, active); +- IUPMAT_BOX(ih, x1, x2, y1, y2); ++ iupMATRIX_BOX(ih, x1, x2, y1, y2); +  + /* feedback frame */ + cdCanvasForeground(ih->data->cddbuffer, framecolor); +- IUPMAT_RECT(ih, x1, x2, y1, y2); ++ iupMATRIX_RECT(ih, x1, x2, y1, y2); +  + /* feedback arrow */ + xh2 = x2 - IMAT_COMBOBOX_W / 2; + yh2 = y2 - (y2 - y1) / 2; +  + cdCanvasBegin(ih->data->cddbuffer, CD_FILL); +- IUPMAT_VERTEX(ih, xh2, yh2 + 3); +- IUPMAT_VERTEX(ih, xh2 + 4, yh2 - 1); +- IUPMAT_VERTEX(ih, xh2 - 4, yh2 - 1); ++ iupMATRIX_VERTEX(ih, xh2, yh2 + 3); ++ iupMATRIX_VERTEX(ih, xh2 + 4, yh2 - 1); ++ iupMATRIX_VERTEX(ih, xh2 - 4, yh2 - 1); + cdCanvasEnd(ih->data->cddbuffer); + } +  +@@ -325,7 +365,7 @@ static void iMatrixDrawBackground(Ihandle* ih, int x1, int x2, int y1, int y2, i + y2 -= IMAT_FRAME_H/2; +  + iMatrixDrawSetBgColor(ih, lin, col, marked, active); +- IUPMAT_BOX(ih, x1, x2, y1, y2); ++ iupMATRIX_BOX(ih, x1, x2, y1, y2); + } +  + /* Put the cell contents in the screen, using the specified color and alignment. +@@ -372,7 +412,7 @@ static void iMatrixDrawCellValue(Ihandle* ih, int x1, int x2, int y1, int y2, in + if (text && *text) + { + int num_line, line_height, total_height; +- int charheight, ypos; ++ int charheight, ypos, hidden_text_marks = 0; +  + num_line = iupStrLineCount(text); + iupdrvFontGetCharSize(ih, NULL, &charheight); +@@ -380,12 +420,18 @@ static void iMatrixDrawCellValue(Ihandle* ih, int x1, int x2, int y1, int y2, in + line_height = charheight; + total_height = (line_height + IMAT_PADDING_H/2) * num_line - IMAT_PADDING_H/2 - IMAT_FRAME_H/2; +  +- if (lin==0) ++ if (lin==0 || ih->data->hidden_text_marks) + { + int text_w; + iupdrvFontGetMultiLineStringSize(ih, text, &text_w, NULL); + if (text_w > x2 - x1 + 1 - IMAT_PADDING_W - IMAT_FRAME_W) +- alignment = IMAT_T_LEFT; ++ { ++ if (lin == 0) ++ alignment = IMAT_T_LEFT; ++ ++ if (ih->data->hidden_text_marks) ++ hidden_text_marks = 1; ++ } + } +  + /* Set the color used to draw the text */ +@@ -395,8 +441,13 @@ static void iMatrixDrawCellValue(Ihandle* ih, int x1, int x2, int y1, int y2, in + iMatrixDrawSetFgColor(ih, lin, col, marked); +  + /* Set the clip area to the cell region informed, the text maybe greatter than the cell */ +- IUPMAT_CLIPAREA(ih, x1, x2, y1, y2); +- cdCanvasClip(ih->data->cddbuffer, CD_CLIPAREA); ++ if (hidden_text_marks) ++ { ++ int crop = iupdrvFontGetStringWidth(ih, "...") + 2; ++ iMatrixDrawSetCellClipping(ih, x1, x2-crop, y1, y2); ++ } ++ else ++ iMatrixDrawSetCellClipping(ih, x1, x2, y1, y2); +  + cdCanvasNativeFont(ih->data->cddbuffer, iupMatrixGetFont(ih, lin, col)); +  +@@ -417,11 +468,11 @@ static void iMatrixDrawCellValue(Ihandle* ih, int x1, int x2, int y1, int y2, in +  + /* Put the text */ + if (alignment == IMAT_T_CENTER) +- IUPMAT_TEXT(ih, (x1 + x2) / 2, ypos, text); ++ iupMATRIX_TEXT(ih, (x1 + x2) / 2, ypos, text); + else if(alignment == IMAT_T_LEFT) +- IUPMAT_TEXT(ih, x1, ypos, text); ++ iupMATRIX_TEXT(ih, x1, ypos, text); + else +- IUPMAT_TEXT(ih, x2, ypos, text); ++ iupMATRIX_TEXT(ih, x2, ypos, text); + } + else + { +@@ -441,11 +492,11 @@ static void iMatrixDrawCellValue(Ihandle* ih, int x1, int x2, int y1, int y2, in +  + /* Draw the text */ + if(alignment == IMAT_T_CENTER) +- IUPMAT_TEXT(ih, (x1 + x2) / 2, ypos, p); ++ iupMATRIX_TEXT(ih, (x1 + x2) / 2, ypos, p); + else if(alignment == IMAT_T_LEFT) +- IUPMAT_TEXT(ih, x1, ypos, p); ++ iupMATRIX_TEXT(ih, x1, ypos, p); + else +- IUPMAT_TEXT(ih, x2, ypos, p); ++ iupMATRIX_TEXT(ih, x2, ypos, p); +  + /* Advance the string */ + if (q) p = q + 1; +@@ -457,7 +508,15 @@ static void iMatrixDrawCellValue(Ihandle* ih, int x1, int x2, int y1, int y2, in + free(newtext); + } +  +- cdCanvasClip(ih->data->cddbuffer, CD_CLIPOFF); ++ iMatrixDrawResetCellClipping(ih); ++ ++ if (hidden_text_marks) ++ { ++ cdCanvasTextAlignment(ih->data->cddbuffer, CD_EAST); ++ ypos = (int)((y1 + y2) / 2.0 - 0.5); ++ iupMATRIX_TEXT(ih, x2+IMAT_PADDING_W/2, ypos, "..."); ++ } ++ + } + } +  +@@ -522,7 +581,7 @@ static void iMatrixDrawFocus(Ihandle* ih) + if (ih->data->lines.focus_cell == 1 && ih->data->lines.sizes[0] == 0) + y1++; +  +- cdIupDrawFocusRect(ih, ih->data->cdcanvas, x1, iupMatrixInvertYAxis(ih, y1), x2, iupMatrixInvertYAxis(ih, y2)); ++ cdIupDrawFocusRect(ih, ih->data->cdcanvas, x1, iupMATRIX_INVERTYAXIS(ih, y1), x2, iupMATRIX_INVERTYAXIS(ih, y2)); + } +  +  +@@ -560,6 +619,11 @@ void iupMatrixDrawLineTitle(Ihandle* ih, int lin1, int lin2) + x2 = ih->data->columns.sizes[0]; +  + y1 = ih->data->lines.sizes[0]; ++ ++ iupMATRIX_CLIPAREA(ih, x1, x2, y1, ih->data->h-1); ++ cdCanvasClip(ih->data->cddbuffer, CD_CLIPAREA); ++ ++ y1 -= ih->data->lines.first_offset; + for(lin = ih->data->lines.first; lin < lin1; lin++) + y1 += ih->data->lines.sizes[lin]; +  +@@ -592,6 +656,8 @@ void iupMatrixDrawLineTitle(Ihandle* ih, int lin1, int lin2) +  + y1 = y2; + } ++ ++ cdCanvasClip(ih->data->cddbuffer, CD_CLIPOFF); + } +  + /* Draw the column titles, visible, between col and lastcol, include it.  +@@ -623,6 +689,11 @@ void iupMatrixDrawColumnTitle(Ihandle* ih, int col1, int col2) + y2 = ih->data->lines.sizes[0]; +  + x1 = ih->data->columns.sizes[0]; ++ ++ iupMATRIX_CLIPAREA(ih, x1, ih->data->w-1, y1, y2); ++ cdCanvasClip(ih->data->cddbuffer, CD_CLIPAREA); ++ ++ x1 -= ih->data->columns.first_offset; + for(col = ih->data->columns.first; col < col1; col++) + x1 += ih->data->columns.sizes[col]; +  +@@ -657,6 +728,8 @@ void iupMatrixDrawColumnTitle(Ihandle* ih, int col1, int col2) +  + x1 = x2; + } ++ ++ cdCanvasClip(ih->data->cddbuffer, CD_CLIPOFF); + } +  + /* Redraw a block of cells of the matrix. Handle marked cells, change +@@ -673,13 +746,11 @@ void iupMatrixDrawCells(Ihandle* ih, int lin1, int col1, int lin2, int col2) + IFnii dropcheck_cb; + IFniiiiiiC draw_cb; +  +- x1 = 0; + x2 = ih->data->w-1; +- y1 = 0; + y2 = ih->data->h-1; +  + old_x2 = x2; +- old_y1 = y1; ++ old_y1 = 0; + old_y2 = y2; +  + if (col1 > ih->data->columns.last || +@@ -697,8 +768,14 @@ void iupMatrixDrawCells(Ihandle* ih, int lin1, int col1, int lin2, int col2) + if (lin2 > ih->data->lines.last) + lin2 = ih->data->lines.last; +  ++ x1 = ih->data->columns.sizes[0]; ++ y1 = ih->data->lines.sizes[0]; ++ ++ iupMATRIX_CLIPAREA(ih, x1, x2, y1, y2); ++ cdCanvasClip(ih->data->cddbuffer, CD_CLIPOFF); /* wait for background */ ++ + /* Find the initial position of the first column */ +- x1 += ih->data->columns.sizes[0]; ++ x1 -= ih->data->columns.first_offset; + for(col = ih->data->columns.first; col < col1; col++) + x1 += ih->data->columns.sizes[col]; +  +@@ -708,7 +785,7 @@ void iupMatrixDrawCells(Ihandle* ih, int lin1, int col1, int lin2, int col2) + x2 += ih->data->columns.sizes[col]; +  + /* Find the initial position of the first line */ +- y1 += ih->data->lines.sizes[0]; ++ y1 -= ih->data->lines.first_offset; + for(lin = ih->data->lines.first; lin < lin1; lin++) + y1 += ih->data->lines.sizes[lin]; +  +@@ -724,7 +801,7 @@ void iupMatrixDrawCells(Ihandle* ih, int lin1, int col1, int lin2, int col2) +  + /* If it was drawn until the last column and remains space in the right of it, + then delete this area with the the background color. */ +- IUPMAT_BOX(ih, x2, old_x2, old_y1, old_y2); ++ iupMATRIX_BOX(ih, x2, old_x2, old_y1, old_y2); + } +  + if ((lin2 == ih->data->lines.num-1) && (old_y2 > y2)) +@@ -735,9 +812,12 @@ void iupMatrixDrawCells(Ihandle* ih, int lin1, int col1, int lin2, int col2) +  + /* If it was drawn until the last line visible and remains space below it, + then delete this area with the the background color. */ +- IUPMAT_BOX(ih, 0, old_x2, y2, old_y2); ++ iupMATRIX_BOX(ih, 0, old_x2, y2, old_y2); + } +  ++ /* after the background */ ++ cdCanvasClip(ih->data->cddbuffer, CD_CLIPAREA); ++ + /***** Draw the cell values and frame */ + old_y1 = y1; + framecolor = cdIupConvertColor(iupAttribGetStr(ih, "FRAMECOLOR")); +@@ -775,7 +855,7 @@ void iupMatrixDrawCells(Ihandle* ih, int lin1, int col1, int lin2, int col2) +  + if (dropcheck_cb && dropcheck_cb(ih, lin, col) == IUP_DEFAULT) + { +- drop = IMAT_COMBOBOX_W; ++ drop = IMAT_COMBOBOX_W+IMAT_PADDING_W/2; + iMatrixDrawComboFeedback(ih, x2, y1, y2, active, framecolor); + } +  +@@ -788,6 +868,8 @@ void iupMatrixDrawCells(Ihandle* ih, int lin1, int col1, int lin2, int col2) + x1 = x2; + y1 = old_y1; /* must reset also y */ + } ++ ++ cdCanvasClip(ih->data->cddbuffer, CD_CLIPOFF); + } +  + void iupMatrixDraw(Ihandle* ih, int update) +diff --git a/iup/srccontrols/matrix/iupmat_edit.c b/iup/srccontrols/matrix/iupmat_edit.c +index a7e0a74..551baed 100755 +--- a/iup/srccontrols/matrix/iupmat_edit.c ++++ b/iup/srccontrols/matrix/iupmat_edit.c +@@ -67,7 +67,7 @@ static int iMatrixEditDropDownAction_CB(Ihandle* ih, char* t, int i, int v) + if (ret == IUP_CONTINUE) + { + iupMatrixEditHide(ih_matrix); +- iupMatrixDrawUpdate(ih); ++ iupMatrixDrawUpdate(ih_matrix); + } + } +  +@@ -137,13 +137,31 @@ static int iMatrixEditCancel(Ihandle* ih, int focus, int update, int ignore) + return IUP_DEFAULT; + } +  ++static int iMatrixEditDropDown_CB(Ihandle* ih, int state) ++{ ++ /* In Motif if DROPDOWN=YES then when the dropdown button is clicked  ++ the list looses its focus and when the dropped list is closed  ++ the list regain the focus, also when that happen if the list looses its focus  ++ to another control the kill focus callback is not called. */ ++ Ihandle* ih_matrix = ih->parent; ++ if (state == 1) ++ iupAttribSetStr(ih_matrix, "_IUPMAT_DROPDOWN", "1"); ++ ++ return IUP_DEFAULT; ++} ++ + static int iMatrixEditKillFocus_CB(Ihandle* ih) + { + Ihandle* ih_matrix = ih->parent; +- if (iupStrEqualNoCase(IupGetGlobal("DRIVER"), "Motif")) ++ if (IupGetGlobal("MOTIFVERSION")) + { +- if (iupAttribGet(ih_matrix, "_IUPMAT_DOUBLE_CLICK")) ++ if (iupAttribGet(ih_matrix, "_IUPMAT_DROPDOWN") || /* from iMatrixEditDropDown_CB, in Motif */ ++ iupAttribGet(ih_matrix, "_IUPMAT_DOUBLECLICK")) /* from iMatrixMouseLeftPress, in Motif */ ++ { ++ iupAttribSetStr(ih_matrix, "_IUPMAT_DOUBLECLICK", NULL); ++ iupAttribSetStr(ih_matrix, "_IUPMAT_DROPDOWN", NULL); + return IUP_DEFAULT; ++ } + } +  + iupMatrixEditForceHidden(ih_matrix); +@@ -200,7 +218,7 @@ int iupMatrixEditShow(Ihandle* ih) +  + /* position the cell to make it visible */ + /* If the focus is not visible, a scroll is done for that the focus to be visible */ +- if (!iupMatrixAuxIsCellFullVisible(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell)) ++ if (!iupMatrixAuxIsCellStartVisible(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell)) + iupMatrixScrollToVisible(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell); +  + /* set attributes */ +@@ -235,7 +253,7 @@ int iupMatrixEditShow(Ihandle* ih) + ih->data->datah->y = y; + if (IupGetGlobal("GTKVERSION")) + { +- /* In GTK, IupCanvas is not the actual container of the IupText/IupList */ ++ /* In GTK, IupCanvas is NOT the actual container of the IupText/IupList */ + ih->data->datah->x += ih->x; + ih->data->datah->y += ih->y; + } +@@ -366,7 +384,7 @@ static int iMatrixEditTextKeyAny_CB(Ihandle* ih, int c) +  + if (iupMatrixAuxCallLeaveCellCb(ih_matrix) != IUP_IGNORE) + { +- iupMatrixScrollKeyCr(ih_matrix); ++ iupMATRIX_ScrollKeyCr(ih_matrix); + iupMatrixAuxCallEnterCellCb(ih_matrix); + } + iupMatrixDrawUpdate(ih_matrix); +@@ -399,7 +417,7 @@ static int iMatrixEditDropDownKeyAny_CB(Ihandle* ih, int c) + { + if (iupMatrixAuxCallLeaveCellCb(ih_matrix) != IUP_IGNORE) + { +- iupMatrixScrollKeyCr(ih_matrix); ++ iupMATRIX_ScrollKeyCr(ih_matrix); + iupMatrixAuxCallEnterCellCb(ih_matrix); + } + iupMatrixDrawUpdate(ih_matrix); +@@ -440,6 +458,9 @@ void iupMatrixEditCreate(Ihandle* ih) + ih->data->droph = IupList(NULL); + iupChildTreeAppend(ih, ih->data->droph); +  ++ if (IupGetGlobal("MOTIFVERSION")) ++ IupSetCallback(ih->data->droph, "DROPDOWN_CB", (Icallback)iMatrixEditDropDown_CB); ++ + IupSetCallback(ih->data->droph, "ACTION", (Icallback)iMatrixEditDropDownAction_CB); + IupSetCallback(ih->data->droph, "KILLFOCUS_CB", (Icallback)iMatrixEditKillFocus_CB); + IupSetCallback(ih->data->droph, "K_ANY", (Icallback)iMatrixEditDropDownKeyAny_CB); +diff --git a/iup/srccontrols/matrix/iupmat_focus.c b/iup/srccontrols/matrix/iupmat_focus.c +index 3c000f8..0cf680d 100755 +--- a/iup/srccontrols/matrix/iupmat_focus.c ++++ b/iup/srccontrols/matrix/iupmat_focus.c +@@ -35,13 +35,11 @@ int iupMatrixFocus_CB(Ihandle* ih, int focus) + if (!iupMatrixIsValid(ih, 1)) + return IUP_DEFAULT; +  +- if (iupStrEqualNoCase(IupGetGlobal("DRIVER"), "Motif")) ++ if (IupGetGlobal("MOTIFVERSION")) + { +- if (focus && iupAttribGet(ih, "_IUPMAT_DOUBLE_CLICK")) +- { +- iupAttribSetStr(ih, "_IUPMAT_DOUBLE_CLICK", NULL); ++ if (iupAttribGet(ih, "_IUPMAT_DROPDOWN") || /* from iMatrixEditDropDown_CB, in Motif */ ++ iupAttribGet(ih, "_IUPMAT_DOUBLECLICK")) /* from iMatrixMouseLeftPress, in Motif */ + return IUP_DEFAULT; +- } + } +  + ih->data->has_focus = focus; +diff --git a/iup/srccontrols/matrix/iupmat_getset.c b/iup/srccontrols/matrix/iupmat_getset.c +index 34947b6..4424948 100755 +--- a/iup/srccontrols/matrix/iupmat_getset.c ++++ b/iup/srccontrols/matrix/iupmat_getset.c +@@ -313,7 +313,7 @@ char* iupMatrixGetFont(Ihandle* ih, int lin, int col) + return font; + } +  +-char *iupMatrixGetSize(Ihandle* ih, int index, int m, int pixels) ++char *iupMatrixGetSize(Ihandle* ih, int index, int m, int pixels_unit) + { + char* str; + int size; +@@ -342,7 +342,7 @@ char *iupMatrixGetSize(Ihandle* ih, int index, int m, int pixels) + else + size -= IMAT_PADDING_H + IMAT_FRAME_H; +  +- if (!pixels) ++ if (!pixels_unit) + { + int charwidth, charheight; + iupdrvFontGetCharSize(ih, &charwidth, &charheight); +diff --git a/iup/srccontrols/matrix/iupmat_getset.h b/iup/srccontrols/matrix/iupmat_getset.h +index 9ae3d07..f26e01e 100755 +--- a/iup/srccontrols/matrix/iupmat_getset.h ++++ b/iup/srccontrols/matrix/iupmat_getset.h +@@ -26,7 +26,7 @@ void iupMatrixGetFgRGB(Ihandle* ih, int lin, int col, unsigned char *r, unsigned +  + void iupMatrixCellUpdateValue(Ihandle* ih); +  +-char* iupMatrixGetSize(Ihandle* ih, int index, int m, int pixels); ++char* iupMatrixGetSize(Ihandle* ih, int index, int m, int pixels_unit); +  + int iupMatrixCheckCellPos(Ihandle* ih, int lin, int col); +  +diff --git a/iup/srccontrols/matrix/iupmat_key.c b/iup/srccontrols/matrix/iupmat_key.c +index ae9ed55..4824438 100755 +--- a/iup/srccontrols/matrix/iupmat_key.c ++++ b/iup/srccontrols/matrix/iupmat_key.c +@@ -37,7 +37,7 @@ int iupMatrixProcessKeyPress(Ihandle* ih, int c) + int ret = IUP_IGNORE; /* default for processed keys */ +  + /* If the focus is not visible, a scroll is done for that the focus to be visible */ +- if (!iupMatrixAuxIsCellFullVisible(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell)) ++ if (!iupMatrixAuxIsCellStartVisible(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell)) + iupMatrixScrollToVisible(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell); +  + switch (c) +@@ -47,7 +47,7 @@ int iupMatrixProcessKeyPress(Ihandle* ih, int c) + case K_HOME: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; +- iupMatrixScrollKeyHome(ih); ++ iupMATRIX_ScrollKeyHome(ih); + ih->data->homekeycount++; + iupMatrixAuxCallEnterCellCb(ih); + break; +@@ -57,7 +57,7 @@ int iupMatrixProcessKeyPress(Ihandle* ih, int c) + case K_END: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; +- iupMatrixScrollKeyEnd(ih); ++ iupMATRIX_ScrollKeyEnd(ih); + ih->data->endkeycount++; + iupMatrixAuxCallEnterCellCb(ih); + break; +@@ -71,7 +71,7 @@ int iupMatrixProcessKeyPress(Ihandle* ih, int c) + case K_LEFT: + if (iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; +- iupMatrixScrollKeyLeft(ih); ++ iupMATRIX_ScrollKeyLeft(ih); + iupMatrixAuxCallEnterCellCb(ih); + break; +  +@@ -80,7 +80,7 @@ int iupMatrixProcessKeyPress(Ihandle* ih, int c) + case K_RIGHT: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; +- iupMatrixScrollKeyRight(ih); ++ iupMATRIX_ScrollKeyRight(ih); + iupMatrixAuxCallEnterCellCb(ih); + break; +  +@@ -89,7 +89,7 @@ int iupMatrixProcessKeyPress(Ihandle* ih, int c) + case K_UP: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; +- iupMatrixScrollKeyUp(ih); ++ iupMATRIX_ScrollKeyUp(ih); + iupMatrixAuxCallEnterCellCb(ih); + break ; +  +@@ -98,7 +98,7 @@ int iupMatrixProcessKeyPress(Ihandle* ih, int c) + case K_DOWN: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; +- iupMatrixScrollKeyDown(ih); ++ iupMATRIX_ScrollKeyDown(ih); + iupMatrixAuxCallEnterCellCb(ih); + break; +  +@@ -106,7 +106,7 @@ int iupMatrixProcessKeyPress(Ihandle* ih, int c) + case K_PGUP: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; +- iupMatrixScrollKeyPgUp(ih); ++ iupMATRIX_ScrollKeyPgUp(ih); + iupMatrixAuxCallEnterCellCb(ih); + break; +  +@@ -114,7 +114,7 @@ int iupMatrixProcessKeyPress(Ihandle* ih, int c) + case K_PGDN: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; +- iupMatrixScrollKeyPgDown(ih); ++ iupMATRIX_ScrollKeyPgDown(ih); + iupMatrixAuxCallEnterCellCb(ih); + break; +  +diff --git a/iup/srccontrols/matrix/iupmat_mouse.c b/iup/srccontrols/matrix/iupmat_mouse.c +index 33b5fe7..a3ffa82 100755 +--- a/iup/srccontrols/matrix/iupmat_mouse.c ++++ b/iup/srccontrols/matrix/iupmat_mouse.c +@@ -80,12 +80,18 @@ static void iMatrixMouseLeftPress(Ihandle* ih, int lin, int col, int shift, int +  + if (iupMatrixEditShow(ih)) + { +- if(ih->data->datah == ih->data->droph)  ++ if (ih->data->datah == ih->data->droph) + IupSetAttribute(ih->data->datah, "SHOWDROPDOWN", "YES"); +  +- if (iupStrEqualNoCase(IupGetGlobal("DRIVER"), "Motif")) +- if(atoi(IupGetGlobal("MOTIFNUMBER")) < 2203) /* since OpenMotif version 2.2.3 this is not necessary */ +- iupAttribSetStr(ih, "_IUPMAT_DOUBLE_CLICK", "1"); ++ if (IupGetGlobal("MOTIFVERSION")) ++ { ++ /* Sequece of focus_cb in Motif from here: ++ Matrix-Focus(0) - ok ++ Edit-KillFocus - weird, must avoid using _IUPMAT_DOUBLECLICK ++ Since OpenMotif version 2.2.3 this is not necessary anymore. */ ++ if (atoi(IupGetGlobal("MOTIFNUMBER")) < 2203)  ++ iupAttribSetStr(ih, "_IUPMAT_DOUBLECLICK", "1"); ++ } + } + } + else /* single click */ +@@ -182,14 +188,14 @@ int iupMatrixMouseMove_CB(Ihandle* ih, int x, int y) + if (ih->data->leftpressed && ih->data->mark_multiple && ih->data->mark_mode != IMAT_MARK_NO) + { + if ((x < ih->data->columns.sizes[0] || x < IMAT_DRAG_SCROLL_DELTA) && (ih->data->columns.first > 1)) +- iupMatrixScrollLeft(ih); ++ iupMATRIX_ScrollLeft(ih); + else if ((x > ih->data->w - IMAT_DRAG_SCROLL_DELTA) && (ih->data->columns.last < ih->data->columns.num-1)) +- iupMatrixScrollRight(ih); ++ iupMATRIX_ScrollRight(ih); +  + if ((y < ih->data->lines.sizes[0] || y < IMAT_DRAG_SCROLL_DELTA) && (ih->data->lines.first > 1)) +- iupMatrixScrollUp(ih); ++ iupMATRIX_ScrollUp(ih); + else if ((y > ih->data->h - IMAT_DRAG_SCROLL_DELTA) && (ih->data->lines.last < ih->data->lines.num-1)) +- iupMatrixScrollDown(ih); ++ iupMATRIX_ScrollDown(ih); +  + if (iupMatrixAuxGetLinColFromXY(ih, x, y, &lin, &col)) + { +diff --git a/iup/srccontrols/matrix/iupmat_numlc.c b/iup/srccontrols/matrix/iupmat_numlc.c +index e48720a..6e628b7 100755 +--- a/iup/srccontrols/matrix/iupmat_numlc.c ++++ b/iup/srccontrols/matrix/iupmat_numlc.c +@@ -294,7 +294,7 @@ int iupMatrixSetAddLinAttrib(Ihandle* ih, const char* value) + { + int base, count, lines_num = ih->data->lines.num; +  +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; +  + if (!iMatrixGetStartEnd(value, &base, &count, lines_num, 0)) +@@ -326,7 +326,7 @@ int iupMatrixSetDelLinAttrib(Ihandle* ih, const char* value) + { + int base, count, lines_num = ih->data->lines.num; +  +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; +  + if (!iMatrixGetStartEnd(value, &base, &count, lines_num, 1)) +@@ -366,7 +366,7 @@ int iupMatrixSetAddColAttrib(Ihandle* ih, const char* value) + { + int base, count, columns_num = ih->data->columns.num; +  +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; +  + if (!iMatrixGetStartEnd(value, &base, &count, columns_num, 0)) +@@ -398,7 +398,7 @@ int iupMatrixSetDelColAttrib(Ihandle* ih, const char* value) + { + int base, count, columns_num = ih->data->columns.num; +  +- if (!ih->handle) /* do not store the action before map */ ++ if (!ih->handle) /* do not do the action before map */ + return 0; +  + if (!iMatrixGetStartEnd(value, &base, &count, columns_num, 1)) +diff --git a/iup/srccontrols/matrix/iupmat_scroll.c b/iup/srccontrols/matrix/iupmat_scroll.c +index 24bbef2..845d248 100755 +--- a/iup/srccontrols/matrix/iupmat_scroll.c ++++ b/iup/srccontrols/matrix/iupmat_scroll.c +@@ -32,54 +32,32 @@ + /* Private functions */ + /**************************************************************************/ +  +- +-static int iMatrixScrollIsFullVisibleLast(ImatLinColData *p) +-{ +- int i, sum = 0; +- +- for(i = p->first; i <= p->last; i++) +- sum += p->sizes[i]; +- +- if (sum > p->visible_size) +- return 0; +- else +- return 1; +-} +- +-/* Scroll columns/lines in the left/top side of the matriz until the last column/line is FULLY visible. +- -> m : Define the mode of operation: lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] */ +-static void iMatrixScrollToVisible(Ihandle* ih, int m, int index) ++static void iMatrixScrollToVisible(ImatLinColData* p, int index) + { +- ImatLinColData* p; ++ /* The work here is just to position first and first_offset,  ++ so "index" is between "first" and "last". */ ++  ++ /* It is called only for discrete scrolling,  ++ so first_offset usually will be set to 0. */ ++ ++ /* already visible, change nothing */ ++ if (index > p->first && index < p->last) ++ return; +  +- if (m == IMAT_PROCESS_LIN) +- p = &(ih->data->lines); +- else +- p = &(ih->data->columns); ++ /* scroll to visible, means position the cell so the start at left is visible */ +  +- if (index < p->first) ++ if (index <= p->first) + { + p->first = index; ++ p->first_offset = 0; + return; + } +- else if (index > p->last) ++ else /* (index >= p->last) */ + { +- /* Increment the first column/line until the index is visible */ +- while(index > p->last && p->last != (p->num - 1)) +- { +- p->first++; +- iupMatrixAuxUpdateLast(p); +- }  +- } ++ p->last = index; +  +- if (index == p->last) +- { +- /* must increment util the last is fully visible */ +- while(index == p->last && p->last != (p->num - 1) && !iMatrixScrollIsFullVisibleLast(p)) +- { +- p->first++; +- iupMatrixAuxUpdateLast(p); +- }  ++ /* adjust "first" according to "last" */ ++ iupMatrixAuxAdjustFirstFromLast(p); + } + } +  +@@ -133,119 +111,114 @@ static int iMatrixScrollGetPrevNonEmpty(Ihandle* ih, int m, int index) + return index; + } +  +-static void iMatrixScrollSetFocusScrollToVisible(Ihandle* ih, int m, int index) ++static void iMatrixScrollSetFocusScrollToVisible(Ihandle* ih, int lin, int col) ++{ ++ /* moving focus and eventually scrolling */ ++ iupMatrixFocusSet(ih, lin, col); ++ ++ /* set for both because focus maybe hidden */ ++ iMatrixScrollToVisible(&ih->data->columns, ih->data->columns.focus_cell); ++ iMatrixScrollToVisible(&ih->data->lines, ih->data->lines.focus_cell); ++} ++ ++static void iMatrixScrollSetFocusScrollToVisibleLinCol(Ihandle* ih, int m, int index) + { + if (m == IMAT_PROCESS_COL) +- iupMatrixFocusSet(ih, ih->data->lines.focus_cell, index); ++ iMatrixScrollSetFocusScrollToVisible(ih, ih->data->lines.focus_cell, index); + else +- iupMatrixFocusSet(ih, index, ih->data->columns.focus_cell); +- +- /* set for both because current focus maybe hidden */ +- iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.focus_cell); +- iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, ih->data->lines.focus_cell); ++ iMatrixScrollSetFocusScrollToVisible(ih, index, ih->data->columns.focus_cell); + } +  ++ + /**************************************************************************/ + /* Exported functions */ + /**************************************************************************/ +  +  +-/* Move using the cells of matrix. +- Receive as a parameter a pointer to a function that will make the work, +- in fact. This is done to avoid a test to each of the manipulation cursor +- functions, verifying if it is necessary to call or not the scroll +- callback. This is only done here. +- -> func - pointer to the function that will make the movement +- -> mode - parameter passed to func, specify if the movement request is of +- the scrollbar or the keyboard +- -> pos - parameter passed to func, that will be the handle position function +- of the scrollbar, returning the scrollbar thumb position... +- if func is other function, this parameter will be ignored +- -> m - parameter passed to func, specify which is the mode of operation: +- lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] +-*/ +-void iupMatrixScrollMoveCursor(iupMatrixScrollMoveF func, Ihandle* ih, int mode, float pos, int m) ++void iupMatrixScrollToVisible(Ihandle* ih, int lin, int col) + { + int old_lines_first = ih->data->lines.first; + int old_columns_first = ih->data->columns.first; ++ int old_lines_first_offset = ih->data->lines.first_offset; ++ int old_columns_first_offset = ih->data->columns.first_offset; +  +- iupMatrixEditForceHidden(ih); ++ iMatrixScrollToVisible(&ih->data->columns, col); ++ iMatrixScrollToVisible(&ih->data->lines, lin); +  +- func(ih, mode, pos, m); +- +- if (ih->data->lines.first != old_lines_first || ih->data->columns.first != old_columns_first) ++ if ((ih->data->lines.first != old_lines_first || ih->data->lines.first_offset != old_lines_first_offset) || ++ (ih->data->columns.first != old_columns_first || ih->data->columns.first_offset != old_columns_first_offset)) + { +- if (ih->data->columns.first != old_columns_first) +- iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_COL); ++ /* when "first" is changed must update scroll pos */ ++ if (ih->data->columns.first != old_columns_first || ih->data->columns.first_offset != old_columns_first_offset) ++ iupMatrixAuxUpdateScrollPos(ih, IMAT_PROCESS_COL); +  +- if (ih->data->lines.first != old_lines_first) +- iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_LIN); ++ if (ih->data->lines.first != old_lines_first || ih->data->lines.first_offset != old_lines_first_offset) ++ iupMatrixAuxUpdateScrollPos(ih, IMAT_PROCESS_LIN); +  + iMatrixScrollCallScrollTopCb(ih); +  +- iupMatrixDraw(ih, 0); ++ iupMatrixDraw(ih, 1); + } + } +  +-void iupMatrixScrollToVisible(Ihandle* ih, int lin, int col) ++void iupMatrixScrollMove(iupMatrixScrollMoveFunc func, Ihandle* ih, int mode, float pos, int m) + { + int old_lines_first = ih->data->lines.first; + int old_columns_first = ih->data->columns.first; ++ int old_lines_first_offset = ih->data->lines.first_offset; ++ int old_columns_first_offset = ih->data->columns.first_offset; +  +- iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, col); +- iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, lin); ++ iupMatrixEditForceHidden(ih); +  +- if (ih->data->lines.first != old_lines_first || ih->data->columns.first != old_columns_first) ++ func(ih, mode, pos, m); ++ ++ if ((ih->data->lines.first != old_lines_first || ih->data->lines.first_offset != old_lines_first_offset) || ++ (ih->data->columns.first != old_columns_first || ih->data->columns.first_offset != old_columns_first_offset)) + { +- if (ih->data->columns.first != old_columns_first) +- iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_COL); ++ /* when "first" is changed must update scroll pos */ ++ if (ih->data->columns.first != old_columns_first || ih->data->columns.first_offset != old_columns_first_offset) ++ iupMatrixAuxUpdateScrollPos(ih, IMAT_PROCESS_COL); +  +- if (ih->data->lines.first != old_lines_first) +- iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_LIN); ++ if (ih->data->lines.first != old_lines_first || ih->data->lines.first_offset != old_lines_first_offset) ++ iupMatrixAuxUpdateScrollPos(ih, IMAT_PROCESS_LIN); +  + iMatrixScrollCallScrollTopCb(ih); +  +- iupMatrixDraw(ih, 1); ++ iupMatrixDraw(ih, 0); + } + } +  ++/************************************************************************************/ ++ + /* This function is called when the "home" key is pressed. + In the first time, go to the beginning of the line. + In the second time, go to the beginning of the page. + In the third time, go to the beginning of the matrix. + -> mode and pos : DO NOT USED. + */ +-void iupMatrixScrollHome(Ihandle* ih, int unused_mode, float unused_pos, int unused_m) ++void iupMatrixScrollHomeFunc(Ihandle* ih, int unused_mode, float unused_pos, int unused_m) + { + (void)unused_m; + (void)unused_mode; + (void)unused_pos; +  + /* called only for mode==IMAT_SCROLLKEY */ ++ /* moving focus and eventually scrolling */ +  + if(ih->data->homekeycount == 0) /* go to the beginning of the line */ + { +- ih->data->columns.first = iMatrixScrollGetNextNonEmpty(ih, IMAT_PROCESS_COL, 1); +- iMatrixScrollSetFocusScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.first); ++ int col = iMatrixScrollGetNextNonEmpty(ih, IMAT_PROCESS_COL, 1); ++ iMatrixScrollSetFocusScrollToVisibleLinCol(ih, IMAT_PROCESS_COL, col); + } + else if(ih->data->homekeycount == 1) /* go to the beginning of the visible page */ + { +- iupMatrixFocusSet(ih, ih->data->lines.first, ih->data->columns.first); +- +- /* set for both because current focus maybe hidden */ +- iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.focus_cell); +- iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, ih->data->lines.focus_cell); ++ iMatrixScrollSetFocusScrollToVisible(ih, ih->data->lines.first, ih->data->columns.first); + } + else if(ih->data->homekeycount == 2) /* go to the beginning of the matrix 1:1 */ + { +- ih->data->columns.first = iMatrixScrollGetNextNonEmpty(ih, IMAT_PROCESS_COL, 1); +- ih->data->lines.first = iMatrixScrollGetNextNonEmpty(ih, IMAT_PROCESS_LIN, 1); +- +- iupMatrixFocusSet(ih, ih->data->lines.first, ih->data->columns.first); +- +- /* set for both because current focus maybe hidden */ +- iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.focus_cell); +- iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, ih->data->lines.focus_cell); ++ int lin = iMatrixScrollGetNextNonEmpty(ih, IMAT_PROCESS_LIN, 1); ++ int col = iMatrixScrollGetNextNonEmpty(ih, IMAT_PROCESS_COL, 1); ++ iMatrixScrollSetFocusScrollToVisible(ih, lin, col); + } + } +  +@@ -255,37 +228,29 @@ void iupMatrixScrollHome(Ihandle* ih, int unused_mode, float unused_pos, int unu + In the third time, go to the end of the matrix. + -> mode and pos : DO NOT USED. + */ +-void iupMatrixScrollEnd(Ihandle* ih, int unused_mode, float unused_pos, int unused_m) ++void iupMatrixScrollEndFunc(Ihandle* ih, int unused_mode, float unused_pos, int unused_m) + { + (void)unused_m; + (void)unused_mode; + (void)unused_pos; +  + /* called only for mode==IMAT_SCROLLKEY */ ++ /* moving focus and eventually scrolling */ +  + if(ih->data->endkeycount == 0) /* go to the end of the line */ + { +- int last_col = iMatrixScrollGetPrevNonEmpty(ih, IMAT_PROCESS_COL, ih->data->columns.num-1); +- iMatrixScrollSetFocusScrollToVisible(ih, IMAT_PROCESS_COL, last_col); ++ int col = iMatrixScrollGetPrevNonEmpty(ih, IMAT_PROCESS_COL, ih->data->columns.num-1); ++ iMatrixScrollSetFocusScrollToVisibleLinCol(ih, IMAT_PROCESS_COL, col); + } + else if(ih->data->endkeycount == 1) /* go to the end of the visible page */ + { +- iupMatrixFocusSet(ih, ih->data->lines.last, ih->data->columns.last); +- +- /* set for both because current focus maybe hidden */ +- iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.focus_cell); +- iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, ih->data->lines.focus_cell); ++ iMatrixScrollSetFocusScrollToVisible(ih, ih->data->lines.last, ih->data->columns.last); + } + else if(ih->data->endkeycount == 2) /* go to the end of the matrix */ + { +- int last_col = iMatrixScrollGetPrevNonEmpty(ih, IMAT_PROCESS_COL, ih->data->columns.num-1); +- int last_lin = iMatrixScrollGetPrevNonEmpty(ih, IMAT_PROCESS_LIN, ih->data->lines.num-1); +- +- iupMatrixFocusSet(ih, last_lin, last_col); +- +- /* set for both because current focus maybe hidden */ +- iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.focus_cell); +- iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, ih->data->lines.focus_cell); ++ int lin = iMatrixScrollGetPrevNonEmpty(ih, IMAT_PROCESS_LIN, ih->data->lines.num-1); ++ int col = iMatrixScrollGetPrevNonEmpty(ih, IMAT_PROCESS_COL, ih->data->columns.num-1); ++ iMatrixScrollSetFocusScrollToVisible(ih, lin, col); + } + } +  +@@ -295,7 +260,7 @@ void iupMatrixScrollEnd(Ihandle* ih, int unused_mode, float unused_pos, int unus + -> pos : DO NOT USED + -> m : define the mode of operation: lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] + */ +-void iupMatrixScrollLeftUp(Ihandle* ih, int mode, float pos, int m) ++void iupMatrixScrollLeftUpFunc(Ihandle* ih, int mode, float pos, int m) + { + ImatLinColData* p; + (void)pos; +@@ -307,12 +272,15 @@ void iupMatrixScrollLeftUp(Ihandle* ih, int mode, float pos, int m) +  + if (mode == IMAT_SCROLLKEY) + { ++ /* moving focus and eventually scrolling */ + int next = iMatrixScrollGetPrevNonEmpty(ih, m, p->focus_cell-1); +- iMatrixScrollSetFocusScrollToVisible(ih, m, next); ++ iMatrixScrollSetFocusScrollToVisibleLinCol(ih, m, next); + } + else /* IMAT_SCROLLBAR */ + { ++ /* always scrolling without changing focus */ + p->first = iMatrixScrollGetPrevNonEmpty(ih, m, p->first-1); ++ p->first_offset = 0; + } + } +  +@@ -322,7 +290,7 @@ void iupMatrixScrollLeftUp(Ihandle* ih, int mode, float pos, int m) + -> pos : DO NOT USED + -> m : define the mode of operation: lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] + */ +-void iupMatrixScrollRightDown(Ihandle* ih, int mode, float pos, int m) ++void iupMatrixScrollRightDownFunc(Ihandle* ih, int mode, float pos, int m) + { + ImatLinColData* p; + (void)pos; +@@ -334,12 +302,15 @@ void iupMatrixScrollRightDown(Ihandle* ih, int mode, float pos, int m) +  + if (mode == IMAT_SCROLLKEY) + { ++ /* moving focus and eventually scrolling */ + int next = iMatrixScrollGetNextNonEmpty(ih, m, p->focus_cell+1); +- iMatrixScrollSetFocusScrollToVisible(ih, m, next); ++ iMatrixScrollSetFocusScrollToVisibleLinCol(ih, m, next); + } + else /* IMAT_SCROLLBAR */ + { ++ /* always scrolling without changing focus */ + p->first = iMatrixScrollGetNextNonEmpty(ih, m, p->first+1); ++ p->first_offset = 0; + } + } +  +@@ -349,7 +320,7 @@ void iupMatrixScrollRightDown(Ihandle* ih, int mode, float pos, int m) + -> pos : DO NOT USED + -> m : define the mode of operation: lines (PgLeft) or columns (PgUp) [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] + */ +-void iupMatrixScrollPgLeftUp(Ihandle* ih, int mode, float pos, int m) ++void iupMatrixScrollPgLeftUpFunc(Ihandle* ih, int mode, float pos, int m) + { + ImatLinColData* p; + (void)pos; +@@ -361,12 +332,15 @@ void iupMatrixScrollPgLeftUp(Ihandle* ih, int mode, float pos, int m) +  + if (mode == IMAT_SCROLLKEY) + { ++ /* moving focus and eventually scrolling */ + int next = iMatrixScrollGetPrevNonEmpty(ih, m, p->focus_cell - (p->last - p->first)); +- iMatrixScrollSetFocusScrollToVisible(ih, m, next); ++ iMatrixScrollSetFocusScrollToVisibleLinCol(ih, m, next); + } + else /* IMAT_SCROLLBAR */ + { ++ /* always scrolling without changing focus */ + p->first = iMatrixScrollGetPrevNonEmpty(ih, m, p->first - (p->last - p->first)); ++ p->first_offset = 0; + } + } +  +@@ -376,7 +350,7 @@ void iupMatrixScrollPgLeftUp(Ihandle* ih, int mode, float pos, int m) + -> pos : DO NOT USED + -> m : define the mode of operation: lines (PgDown) or columns (PgRight) [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] + */ +-void iupMatrixScrollPgRightDown(Ihandle* ih, int mode, float pos, int m) ++void iupMatrixScrollPgRightDownFunc(Ihandle* ih, int mode, float pos, int m) + { + ImatLinColData* p; + (void)pos; +@@ -388,16 +362,19 @@ void iupMatrixScrollPgRightDown(Ihandle* ih, int mode, float pos, int m) +  + if (mode == IMAT_SCROLLKEY) + { +- int next = iMatrixScrollGetNextNonEmpty(ih, IMAT_PROCESS_COL, p->focus_cell + (p->last - p->first)); +- iMatrixScrollSetFocusScrollToVisible(ih, m, next); ++ /* moving focus and eventually scrolling */ ++ int next = iMatrixScrollGetNextNonEmpty(ih, m, p->focus_cell + (p->last - p->first)); ++ iMatrixScrollSetFocusScrollToVisibleLinCol(ih, m, next); + } + else /* IMAT_SCROLLBAR */ + { ++ /* always scrolling without changing focus */ + p->first = iMatrixScrollGetPrevNonEmpty(ih, m, p->first + (p->last - p->first)); ++ p->first_offset = 0; + } + } +  +-void iupMatrixScrollCr(Ihandle* ih, int unused_mode, float unused_pos, int unused_m) ++void iupMatrixScrollCrFunc(Ihandle* ih, int unused_mode, float unused_pos, int unused_m) + { + int oldlin = ih->data->lines.focus_cell; + int oldcol = ih->data->columns.focus_cell; +@@ -408,13 +385,13 @@ void iupMatrixScrollCr(Ihandle* ih, int unused_mode, float unused_pos, int unuse + /* called only for mode==IMAT_SCROLLKEY */ +  + /* try the normal processing of next cell down */ +- iupMatrixScrollRightDown(ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN); ++ iupMatrixScrollRightDownFunc(ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN); +  + if(ih->data->lines.focus_cell == oldlin && ih->data->columns.focus_cell == oldcol) + { + /* If focus was not changed, it was because it is in the last line of the column. + Go to the next column of the same line. */ +- iupMatrixScrollRightDown(ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_COL); ++ iupMatrixScrollRightDownFunc(ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_COL); + } + } +  +@@ -423,70 +400,51 @@ void iupMatrixScrollCr(Ihandle* ih, int unused_mode, float unused_pos, int unuse + -> mode : DO NOT USED + -> m : define the mode of operation: lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] + */ +-void iupMatrixScrollPos(Ihandle* ih, int mode, float pos, int m) ++void iupMatrixScrollPosFunc(Ihandle* ih, int mode, float pos, int m) + { +- int scroll_pos, index, vp; +- float d; ++ int scroll_pos; + ImatLinColData* p; + (void)mode; +  + if (m == IMAT_PROCESS_LIN) +- { + p = &(ih->data->lines); +- d = IupGetFloat(ih, "DY"); +- } + else +- { + p = &(ih->data->columns); +- d = IupGetFloat(ih, "DX"); +- } +  + if (p->num == 1) + { + p->first = 1; ++ p->first_offset = 0; + return; + } +  + scroll_pos = (int)(pos * p->total_size + 0.5); +  +- vp = 0; +- for(index = 1; index < p->num; index++) +- { +- vp += p->sizes[index]; +- if (vp > scroll_pos) +- break; +- } +- +- if (index == p->num) +- { +- if (p->num == 1) +- index = 1; +- else +- index = p->num-1; +- } +- +- p->first = index; ++ /* position first and first_offset, according to scroll pos */ ++ iupMatrixAuxAdjustFirstFromScrollPos(p, scroll_pos); + } +  +-int iupMatrixScroll_CB(Ihandle* ih, int action, float x, float y) ++/************************************************************************************/ ++ ++int iupMatrixScroll_CB(Ihandle* ih, int action, float posx, float posy) + { + if (!iupMatrixIsValid(ih, 0)) + return IUP_DEFAULT; +  + switch(action) + { +- case IUP_SBUP : iupMatrixScrollUp(ih); break; +- case IUP_SBDN : iupMatrixScrollDown(ih); break; +- case IUP_SBPGUP : iupMatrixScrollPgUp(ih); break; +- case IUP_SBPGDN : iupMatrixScrollPgDown(ih); break; +- case IUP_SBRIGHT : iupMatrixScrollRight(ih); break; +- case IUP_SBLEFT : iupMatrixScrollLeft(ih); break; +- case IUP_SBPGRIGHT : iupMatrixScrollPgRight(ih); break; +- case IUP_SBPGLEFT : iupMatrixScrollPgLeft(ih); break; +- case IUP_SBPOSV : iupMatrixScrollPosVer(ih,y); break; +- case IUP_SBPOSH : iupMatrixScrollPosHor(ih,x); break; +- case IUP_SBDRAGV : iupMatrixScrollPosVer(ih,y); break; +- case IUP_SBDRAGH : iupMatrixScrollPosHor(ih,x); break; ++ case IUP_SBUP : iupMATRIX_ScrollUp(ih); break; ++ case IUP_SBDN : iupMATRIX_ScrollDown(ih); break; ++ case IUP_SBPGUP : iupMATRIX_ScrollPgUp(ih); break; ++ case IUP_SBPGDN : iupMATRIX_ScrollPgDown(ih); break; ++ case IUP_SBRIGHT : iupMATRIX_ScrollRight(ih); break; ++ case IUP_SBLEFT : iupMATRIX_ScrollLeft(ih); break; ++ case IUP_SBPGRIGHT : iupMATRIX_ScrollPgRight(ih); break; ++ case IUP_SBPGLEFT : iupMATRIX_ScrollPgLeft(ih); break; ++ case IUP_SBPOSV : iupMATRIX_ScrollPosVer(ih,posy); break; ++ case IUP_SBPOSH : iupMATRIX_ScrollPosHor(ih,posx); break; ++ case IUP_SBDRAGV : iupMATRIX_ScrollPosVer(ih,posy); break; ++ case IUP_SBDRAGH : iupMATRIX_ScrollPosHor(ih,posx); break; + } +  + iupMatrixDrawUpdate(ih); +diff --git a/iup/srccontrols/matrix/iupmat_scroll.h b/iup/srccontrols/matrix/iupmat_scroll.h +index 582442b..45d7417 100755 +--- a/iup/srccontrols/matrix/iupmat_scroll.h ++++ b/iup/srccontrols/matrix/iupmat_scroll.h +@@ -12,54 +12,54 @@ + extern "C" { + #endif +  +-int iupMatrixScroll_CB(Ihandle* ih, int action, float x, float y); ++int iupMatrixScroll_CB(Ihandle* ih, int action, float posx, float posy); +  + void iupMatrixScrollToVisible(Ihandle* ih, int lin, int col); +  +-typedef void (*iupMatrixScrollMoveF)(Ihandle* ih, int mode, float pos, int m); +-void iupMatrixScrollMoveCursor(iupMatrixScrollMoveF func, Ihandle* ih, int mode, float pos, int m); ++typedef void (*iupMatrixScrollMoveFunc)(Ihandle* ih, int mode, float pos, int m); ++void iupMatrixScrollMove(iupMatrixScrollMoveFunc func, Ihandle* ih, int mode, float pos, int m); +  + /* Used only by the macros bellow */ +-void iupMatrixScrollHome (Ihandle* ih, int, float, int); +-void iupMatrixScrollEnd (Ihandle* ih, int, float, int); +-void iupMatrixScrollLeftUp (Ihandle* ih, int, float, int); +-void iupMatrixScrollRightDown (Ihandle* ih, int, float, int); +-void iupMatrixScrollPgLeftUp (Ihandle* ih, int, float, int); +-void iupMatrixScrollPgRightDown(Ihandle* ih, int, float, int); +-void iupMatrixScrollPos (Ihandle* ih, int, float, int); +-void iupMatrixScrollCr (Ihandle* ih, int, float, int); ++void iupMatrixScrollHomeFunc (Ihandle* ih, int, float, int); ++void iupMatrixScrollEndFunc (Ihandle* ih, int, float, int); ++void iupMatrixScrollLeftUpFunc (Ihandle* ih, int, float, int); ++void iupMatrixScrollRightDownFunc (Ihandle* ih, int, float, int); ++void iupMatrixScrollPgLeftUpFunc (Ihandle* ih, int, float, int); ++void iupMatrixScrollPgRightDownFunc(Ihandle* ih, int, float, int); ++void iupMatrixScrollPosFunc (Ihandle* ih, int, float, int); ++void iupMatrixScrollCrFunc (Ihandle* ih, int, float, int); +  + /* Mode used to "walk" inside the matrix. + It shows if the movement request was from the scrollbar or from a key. +- Possible values for the "mode" parameter of the iupMatrixScrollMoveCursor function. ++ Possible values for the "mode" parameter of the iupMatrixScrollMove function. + */ + #define IMAT_SCROLLBAR 0 + #define IMAT_SCROLLKEY 1 +  +-/* Macros to help during the call of iupMatrixScrollMoveCursor function */ ++/* Macros to help during the call of iupMatrixScrollMove function */ +  + /* used in the keyboard processing module */ +-#define iupMatrixScrollKeyHome(ih) iupMatrixScrollMoveCursor(iupMatrixScrollHome , ih, IMAT_SCROLLKEY, 0, 0) +-#define iupMatrixScrollKeyEnd(ih) iupMatrixScrollMoveCursor(iupMatrixScrollEnd , ih, IMAT_SCROLLKEY, 0, 0) +-#define iupMatrixScrollKeyPgUp(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgLeftUp , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) +-#define iupMatrixScrollKeyPgDown(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgRightDown, ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) +-#define iupMatrixScrollKeyDown(ih) iupMatrixScrollMoveCursor(iupMatrixScrollRightDown , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) +-#define iupMatrixScrollKeyRight(ih) iupMatrixScrollMoveCursor(iupMatrixScrollRightDown , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_COL) +-#define iupMatrixScrollKeyUp(ih) iupMatrixScrollMoveCursor(iupMatrixScrollLeftUp , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) +-#define iupMatrixScrollKeyLeft(ih) iupMatrixScrollMoveCursor(iupMatrixScrollLeftUp , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_COL) +-#define iupMatrixScrollKeyCr(ih) iupMatrixScrollMoveCursor(iupMatrixScrollCr , ih, IMAT_SCROLLKEY, 0, 0) ++#define iupMATRIX_ScrollKeyHome(ih) iupMatrixScrollMove(iupMatrixScrollHomeFunc , ih, IMAT_SCROLLKEY, 0, 0) ++#define iupMATRIX_ScrollKeyEnd(ih) iupMatrixScrollMove(iupMatrixScrollEndFunc , ih, IMAT_SCROLLKEY, 0, 0) ++#define iupMATRIX_ScrollKeyPgUp(ih) iupMatrixScrollMove(iupMatrixScrollPgLeftUpFunc , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) ++#define iupMATRIX_ScrollKeyPgDown(ih) iupMatrixScrollMove(iupMatrixScrollPgRightDownFunc, ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) ++#define iupMATRIX_ScrollKeyDown(ih) iupMatrixScrollMove(iupMatrixScrollRightDownFunc , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) ++#define iupMATRIX_ScrollKeyRight(ih) iupMatrixScrollMove(iupMatrixScrollRightDownFunc , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_COL) ++#define iupMATRIX_ScrollKeyUp(ih) iupMatrixScrollMove(iupMatrixScrollLeftUpFunc , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) ++#define iupMATRIX_ScrollKeyLeft(ih) iupMatrixScrollMove(iupMatrixScrollLeftUpFunc , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_COL) ++#define iupMATRIX_ScrollKeyCr(ih) iupMatrixScrollMove(iupMatrixScrollCrFunc , ih, IMAT_SCROLLKEY, 0, 0) +  + /* Used by the scrollbar callback only */ +-#define iupMatrixScrollUp(ih) iupMatrixScrollMoveCursor(iupMatrixScrollLeftUp , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) +-#define iupMatrixScrollLeft(ih) iupMatrixScrollMoveCursor(iupMatrixScrollLeftUp , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) +-#define iupMatrixScrollDown(ih) iupMatrixScrollMoveCursor(iupMatrixScrollRightDown , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) +-#define iupMatrixScrollRight(ih) iupMatrixScrollMoveCursor(iupMatrixScrollRightDown , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) +-#define iupMatrixScrollPgUp(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgLeftUp , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) +-#define iupMatrixScrollPgLeft(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgLeftUp , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) +-#define iupMatrixScrollPgDown(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgRightDown, ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) +-#define iupMatrixScrollPgRight(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgRightDown, ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) +-#define iupMatrixScrollPosVer(ih, y) iupMatrixScrollMoveCursor(iupMatrixScrollPos , ih, IMAT_SCROLLBAR, y, IMAT_PROCESS_LIN) +-#define iupMatrixScrollPosHor(ih, x) iupMatrixScrollMoveCursor(iupMatrixScrollPos , ih, IMAT_SCROLLBAR, x, IMAT_PROCESS_COL) ++#define iupMATRIX_ScrollUp(ih) iupMatrixScrollMove(iupMatrixScrollLeftUpFunc , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) ++#define iupMATRIX_ScrollLeft(ih) iupMatrixScrollMove(iupMatrixScrollLeftUpFunc , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) ++#define iupMATRIX_ScrollDown(ih) iupMatrixScrollMove(iupMatrixScrollRightDownFunc , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) ++#define iupMATRIX_ScrollRight(ih) iupMatrixScrollMove(iupMatrixScrollRightDownFunc , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) ++#define iupMATRIX_ScrollPgUp(ih) iupMatrixScrollMove(iupMatrixScrollPgLeftUpFunc , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) ++#define iupMATRIX_ScrollPgLeft(ih) iupMatrixScrollMove(iupMatrixScrollPgLeftUpFunc , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) ++#define iupMATRIX_ScrollPgDown(ih) iupMatrixScrollMove(iupMatrixScrollPgRightDownFunc, ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) ++#define iupMATRIX_ScrollPgRight(ih) iupMatrixScrollMove(iupMatrixScrollPgRightDownFunc, ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) ++#define iupMATRIX_ScrollPosVer(ih, y) iupMatrixScrollMove(iupMatrixScrollPosFunc , ih, IMAT_SCROLLBAR, posy, IMAT_PROCESS_LIN) ++#define iupMATRIX_ScrollPosHor(ih, x) iupMatrixScrollMove(iupMatrixScrollPosFunc , ih, IMAT_SCROLLBAR, posx, IMAT_PROCESS_COL) +  +  + #ifdef __cplusplus +diff --git a/iup/srccontrols/matrix/iupmatrix.c b/iup/srccontrols/matrix/iupmatrix.c +index 20d618d..9e379e2 100755 +--- a/iup/srccontrols/matrix/iupmatrix.c ++++ b/iup/srccontrols/matrix/iupmatrix.c +@@ -76,10 +76,13 @@ static int iMatrixSetOriginAttrib(Ihandle* ih, const char* value) + return 0; +  + ih->data->columns.first = col; ++ ih->data->columns.first_offset = 0; + ih->data->lines.first = lin; ++ ih->data->lines.first_offset = 0; +  +- iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_COL); +- iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_LIN); ++ /* when "first" is changed must update scroll pos */ ++ iupMatrixAuxUpdateScrollPos(ih, IMAT_PROCESS_COL); ++ iupMatrixAuxUpdateScrollPos(ih, IMAT_PROCESS_LIN); +  + iupMatrixDraw(ih, 1); + return 0; +@@ -109,7 +112,7 @@ static int iMatrixSetShowAttrib(Ihandle* ih, const char* value) + if((lin < 1) || (col < 1)) + return 0; +  +- if (!iupMatrixAuxIsCellFullVisible(ih, lin, col)) ++ if (!iupMatrixAuxIsCellStartVisible(ih, lin, col)) + iupMatrixScrollToVisible(ih, lin, col); +  + return 0; +@@ -173,6 +176,23 @@ static char* iMatrixGetUseTitleSizeAttrib(Ihandle* ih) + return "NO"; + } +  ++static int iMatrixSetHiddenTextMarksAttrib(Ihandle* ih, const char* value) ++{ ++ if (iupStrBoolean(value)) ++ ih->data->hidden_text_marks = 1; ++ else  ++ ih->data->hidden_text_marks = 0; ++ return 0; ++} ++ ++static char* iMatrixGetHiddenTextMarksAttrib(Ihandle* ih) ++{ ++ if (ih->data->hidden_text_marks) ++ return "YES"; ++ else ++ return "NO"; ++} ++ + static int iMatrixSetValueAttrib(Ihandle* ih, const char* value) + { + if (IupGetInt(ih->data->datah, "VISIBLE")) +@@ -228,14 +248,14 @@ static char* iMatrixGetMultilineAttrib(Ihandle* ih) + static char* iMatrixGetNumLinAttrib(Ihandle* ih) + { + char* num = iupStrGetMemory(100); +- sprintf(num, "%d", ih->data->lines.num-1); ++ sprintf(num, "%d", ih->data->lines.num-1); /* the attribute does not include the title */ + return num; + } +  + static char* iMatrixGetNumColAttrib(Ihandle* ih) + { + char* num = iupStrGetMemory(100); +- sprintf(num, "%d", ih->data->columns.num-1); ++ sprintf(num, "%d", ih->data->columns.num-1); /* the attribute does not include the title */ + return num; + } +  +@@ -427,13 +447,19 @@ static char* iMatrixGetAlignmentAttrib(Ihandle* ih, const char* name_id) + align = iupAttribGet(ih, str); + if (!align) + { +- int col; +- if (iupStrToInt(name_id, &col)) ++ align = iupAttribGet(ih, "ALIGNMENT"); ++ if (align) ++ return align; ++ else + { +- if (col == 0) +- return "ALEFT"; +- else +- return "ACENTER"; ++ int col; ++ if (iupStrToInt(name_id, &col)) ++ { ++ if (col == 0) ++ return "ALEFT"; ++ else ++ return "ACENTER"; ++ } + } + } +  +@@ -642,7 +668,7 @@ static int iMatrixCreateMethod(Ihandle* ih, void **params) + /* Create the edit fields */ + iupMatrixEditCreate(ih); +  +- /* defaults */ ++ /* defaults that are non zero */ + ih->data->datah = ih->data->texth; + ih->data->mark_continuous = 1; + ih->data->columns.num = 1; +@@ -656,7 +682,6 @@ static int iMatrixCreateMethod(Ihandle* ih, void **params) + ih->data->mark_col1 = -1; + ih->data->mark_lin2 = -1; + ih->data->mark_col2 = -1; +- ih->data->use_title_size = 0; +  + return IUP_NOERROR; + } +@@ -700,11 +725,34 @@ static void iMatrixUnMapMethod(Ihandle* ih) + iupMatrixMemRelease(ih); + } +  ++static char* iMatrixGetDefault(Ihandle* ih, const char* name) ++{ ++ int inherit; ++ char *def_value; ++ iupClassObjectGetAttributeInfo(ih, name, &def_value, &inherit); ++ return def_value; ++} ++ ++static int iMatrixGetInt(Ihandle* ih, const char* name) ++{ ++ char *value = iupAttribGet(ih, name); ++ if (!value) value = iMatrixGetDefault(ih, name); ++ if (value) ++ { ++ int i = 0; ++ if (iupStrToInt(value, &i)) ++ return i; ++ } ++ return 0; ++} ++ + static int iMatrixGetNaturalWidth(Ihandle* ih) + { + int width = 0, num, col; +  +- num = iupAttribGetInt(ih, "NUMCOL_VISIBLE")+1; /* include the title column */ ++ /* must use this custom function because  ++ the get method for this attribute returns a value with a different meaning */ ++ num = iMatrixGetInt(ih, "NUMCOL_VISIBLE")+1; /* include the title column */ +  + if (iupAttribGetInt(ih, "NUMCOL_VISIBLE_LAST")) + { +@@ -716,9 +764,7 @@ static int iMatrixGetNaturalWidth(Ihandle* ih) + } + else + { +- if (num > ih->data->columns.num) +- num = ih->data->columns.num; +- for(col = 0; col < num; col++) ++ for(col = 0; col < num; col++) /* num can be > numcol */ + width += iupMatrixAuxGetColumnWidth(ih, col); + } +  +@@ -729,7 +775,9 @@ static int iMatrixGetNaturalHeight(Ihandle* ih) + { + int height = 0, num, lin; +  +- num = iupAttribGetInt(ih, "NUMLIN_VISIBLE")+1; /* include the title line */ ++ /* must use this custom function because  ++ the get method for this attribute returns a value with a different meaning */ ++ num = iMatrixGetInt(ih, "NUMLIN_VISIBLE")+1; /* include the title line */ +  + if (iupAttribGetInt(ih, "NUMLIN_VISIBLE_LAST")) + { +@@ -741,9 +789,7 @@ static int iMatrixGetNaturalHeight(Ihandle* ih) + } + else + { +- if (num > ih->data->lines.num) +- num = ih->data->lines.num; +- for(lin = 0; lin < num; lin++) ++ for(lin = 0; lin < num; lin++) /* num can be > numlin */ + height += iupMatrixAuxGetLineHeight(ih, lin); + } +  +@@ -902,6 +948,8 @@ Iclass* iupMatrixGetClass(void) +  + /* IupMatrix Attributes - GENERAL */ + iupClassRegisterAttribute(ic, "USETITLESIZE", iMatrixGetUseTitleSizeAttrib, iMatrixSetUseTitleSizeAttrib, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); ++ iupClassRegisterAttribute(ic, "HIDDENTEXTMARKS", iMatrixGetHiddenTextMarksAttrib, iMatrixSetHiddenTextMarksAttrib, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); ++  + iupClassRegisterAttribute(ic, "FRAMECOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "100 100 100", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RESIZEMATRIX", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); +diff --git a/iup/srcgl/Makefile b/iup/srcgl/Makefile +index 882d0d2..48037f0 100755 +--- a/iup/srcgl/Makefile ++++ b/iup/srcgl/Makefile +@@ -3,4 +3,4 @@ + do_all: iupgl +  + iupgl: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak  ++ @$(MAKE) --no-print-directory -f ../tecmake.mak  +diff --git a/iup/srcim/Makefile b/iup/srcim/Makefile +index 933ded1..d47e014 100755 +--- a/iup/srcim/Makefile ++++ b/iup/srcim/Makefile +@@ -3,4 +3,4 @@ + do_all: iupim +  + iupim: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak  ++ @$(MAKE) --no-print-directory -f ../tecmake.mak  +diff --git a/iup/srcim/iup_im.c b/iup/srcim/iup_im.c +index c26a3ff..ce58d80 100755 +--- a/iup/srcim/iup_im.c ++++ b/iup/srcim/iup_im.c +@@ -23,7 +23,7 @@ + #include "iup_image.h" +  +  +-static void PrintError(int error) ++static void iSaveErrorMsg(int error) + { + char* lang = IupGetLanguage(); + char* msg; +@@ -31,20 +31,22 @@ static void PrintError(int error) + { + switch (error) + { ++ case IM_ERR_NONE: ++ msg = NULL; + case IM_ERR_OPEN: +- msg = "Error Opening File.\n"; ++ msg = "Error Opening Image File.\n"; + break; + case IM_ERR_MEM: + msg = "Insuficient memory.\n"; + break; + case IM_ERR_ACCESS: +- msg = "Error Accessing File.\n"; ++ msg = "Error Accessing Image File.\n"; + break; + case IM_ERR_DATA: + msg = "Image type not Suported.\n"; + break; + case IM_ERR_FORMAT: +- msg = "Invalid Format.\n"; ++ msg = "Invalid Image File Format.\n"; + break; + case IM_ERR_COMPRESS: + msg = "Invalid or unsupported compression.\n"; +@@ -57,20 +59,22 @@ static void PrintError(int error) + { + switch (error) + { ++ case IM_ERR_NONE: ++ msg = NULL; + case IM_ERR_OPEN: +- msg = "Erro Abrindo Arquivo.\n"; ++ msg = "Erro Abrindo Arquivo de Imagem.\n"; + break; + case IM_ERR_MEM: + msg = "Memória Insuficiente.\n"; + break; + case IM_ERR_ACCESS: +- msg = "Erro Acessando Arquivo.\n"; ++ msg = "Erro Acessando Arquivo de Imagem.\n"; + break; + case IM_ERR_DATA: + msg = "Tipo de Imagem não Suportado.\n"; + break; + case IM_ERR_FORMAT: +- msg = "Formato Inválido.\n"; ++ msg = "Formato de Arquivo de Imagem Inválido.\n"; + break; + case IM_ERR_COMPRESS: + msg = "Compressão Inválida ou não Suportada.\n"; +@@ -80,7 +84,7 @@ static void PrintError(int error) + } + } +  +- IupMessage("Error", msg); ++ IupSetGlobal("IUPIM_LASTERROR", msg); + } +  + Ihandle* IupLoadImage(const char* file_name) +@@ -165,7 +169,7 @@ load_finish: + imCounterSetCallback(NULL, old_callback); + if (ifile) imFileClose(ifile); + if (image_data) free(image_data); +- if (error) PrintError(error); ++ iSaveErrorMsg(error); + return iup_image; + } +  +@@ -188,7 +192,7 @@ int IupSaveImage(Ihandle* ih, const char* file_name, const char* format) + ifile = imFileNew(file_name, format, &error); + if (!ifile) + { +- PrintError(error); ++ iSaveErrorMsg(error); + return 0; + } +  +@@ -238,8 +242,7 @@ int IupSaveImage(Ihandle* ih, const char* file_name, const char* format) +  + imFileClose(ifile);  +  +- if (error) +- PrintError(error); ++ iSaveErrorMsg(error); +  + return error == IM_ERR_NONE? 1: 0; + } +diff --git a/iup/srcimglib/Makefile b/iup/srcimglib/Makefile +index 261537a..873715f 100755 +--- a/iup/srcimglib/Makefile ++++ b/iup/srcimglib/Makefile +@@ -3,4 +3,4 @@ + do_all: iupimglib +  + iupimglib: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak ++ @$(MAKE) --no-print-directory -f ../tecmake.mak +diff --git a/iup/srcledc/Makefile b/iup/srcledc/Makefile +index 8854269..71b9235 100755 +--- a/iup/srcledc/Makefile ++++ b/iup/srcledc/Makefile +@@ -3,4 +3,4 @@ + do_all: ledc +  + ledc: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak  ++ @$(MAKE) --no-print-directory -f ../tecmake.mak  +diff --git a/iup/srclua3/Makefile b/iup/srclua3/Makefile +index b63716a..0551725 100755 +--- a/iup/srclua3/Makefile ++++ b/iup/srclua3/Makefile +@@ -3,19 +3,19 @@ + do_all: iuplua iupluacd iupluacontrols iuplua_pplot iupluagl iupluaim +  + iuplua: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak  ++ @$(MAKE) --no-print-directory -f ../tecmake.mak  +  + iupluacd: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iupcd ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iupcd +  + iupluacontrols: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iupcontrols ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iupcontrols +  + iuplua_pplot: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iup_pplot ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iup_pplot +  + iupluagl: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iupgl ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iupgl +  + iupluaim: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iupim ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iupim +diff --git a/iup/srclua3/config.mak b/iup/srclua3/config.mak +index fae6145..a3ffb1d 100755 +--- a/iup/srclua3/config.mak ++++ b/iup/srclua3/config.mak +@@ -6,9 +6,9 @@ OPT = YES +  + LOHDIR = loh + SRCLUA = iuplua.lua iuplua_widgets.lua constants.lua spin.lua \ +- sbox.lua val.lua tree.lua tabs.lua ++ sbox.lua split.lua val.lua tree.lua tabs.lua + SRC = iuplua.c iuplua_api.c iuplua_widgets.c il_scanf.c il_cbox.c \ +- il_sbox.c il_spin.c il_val.c il_tree.c il_tabs.c il_getcolor.c il_getparam.c ++ il_sbox.c il_split.c il_spin.c il_val.c il_tree.c il_tabs.c il_getcolor.c il_getparam.c +  + USE_LUA = Yes +  +diff --git a/iup/srclua3/il.h b/iup/srclua3/il.h +index 406ccc4..63f9866 100755 +--- a/iup/srclua3/il.h ++++ b/iup/srclua3/il.h +@@ -15,6 +15,7 @@ int iupluaapi_open(void); + int iupluawidgets_open(int tag); +  + int sboxlua_open(void); ++int splitlua_open(void); + int spinlua_open(void); + int cboxlua_open(void); + int gclua_open (void); +diff --git a/iup/srclua3/il_getparam.c b/iup/srclua3/il_getparam.c +index 28a41be..6005ce8 100755 +--- a/iup/srclua3/il_getparam.c ++++ b/iup/srclua3/il_getparam.c +@@ -93,6 +93,8 @@ static void GetParam(void) + param_data[i] = malloc(sizeof(float)); + *(float*)(param_data[i]) = (float)luaL_check_number(lua_param_start); lua_param_start++; + break; ++ case 'f': ++ case 'c': + case 's': + case 'm': + s = luaL_check_string(lua_param_start); lua_param_start++; +@@ -136,6 +138,8 @@ static void GetParam(void) + case 'r': + lua_pushnumber(*(float*)(param_data[i])); + break; ++ case 'f': ++ case 'c': + case 's': + case 'm': + lua_pushstring((char*)(param_data[i])); +diff --git a/iup/srclua3/il_tree.c b/iup/srclua3/il_tree.c +index 8d5fcf8..5d145bf 100755 +--- a/iup/srclua3/il_tree.c ++++ b/iup/srclua3/il_tree.c +@@ -91,6 +91,29 @@ static int TREE_multiselection (Ihandle *handle, int *ids, int n) + return iuplua_call(); + } +  ++static int TREE_multiunselection (Ihandle *handle, int *ids, int n) ++{ ++ int i; ++ lua_Object tb; ++ ++ iuplua_call_start(handle, "multiunselection"); ++ ++ tb = lua_createtable(); ++ for (i = 0; i < n; i++)  ++ { ++ lua_beginblock(); ++ lua_pushobject(tb); ++ lua_pushnumber(i+1); ++ lua_pushnumber(ids[i]); ++ lua_settable(); ++ lua_endblock();  ++ } ++ lua_pushobject(tb); ++ ++ lua_pushnumber (n); ++ return iuplua_call(); ++} ++ + static int TREE_dragdrop(Ihandle* handle, int drag_id, int drop_id, int isshift, int iscontrol) + { + iuplua_call_start(handle, "dragdrop"); +@@ -232,6 +255,7 @@ int treelua_open(void) + lua_CFunction func; + } TreeAssocList [] = { + {"iup_tree_multiselection_cb", (lua_CFunction)TREE_multiselection}, ++ {"iup_tree_multiunselection_cb", (lua_CFunction)TREE_multiunselection}, + {"iup_tree_selection_cb", (lua_CFunction)TREE_selection}, + {"iup_tree_branchopen_cb", (lua_CFunction)TREE_branchopen}, + {"iup_tree_branchclose_cb", (lua_CFunction)TREE_branchclose}, +diff --git a/iup/srclua3/iuplua.c b/iup/srclua3/iuplua.c +index 7789ce8..5563699 100755 +--- a/iup/srclua3/iuplua.c ++++ b/iup/srclua3/iuplua.c +@@ -481,6 +481,7 @@ int iuplua_open(void) + iupluawidgets_open(iuplua_tag); +  + sboxlua_open(); ++ splitlua_open(); + spinlua_open(); + cboxlua_open(); + vallua_open(); +diff --git a/iup/srclua3/iuplua_api.c b/iup/srclua3/iuplua_api.c +index 3221658..a9acf1d 100755 +--- a/iup/srclua3/iuplua_api.c ++++ b/iup/srclua3/iuplua_api.c +@@ -182,7 +182,7 @@ static void GetAttribute(void) + char *name = luaL_check_string(2); + Ihandle* ih = iuplua_checkihandle(1); + char *value = IupGetAttribute(ih, name); +- if (!value || iupAttribIsInternal(name)) ++ if (!value || iupATTRIB_ISINTERNAL(name)) + lua_pushnil(); + else + { +diff --git a/iup/srclua3/iuplua_widgets.c b/iup/srclua3/iuplua_widgets.c +index f6b801b..7591580 100755 +--- a/iup/srclua3/iuplua_widgets.c ++++ b/iup/srclua3/iuplua_widgets.c +@@ -170,6 +170,12 @@ static int iupluaUnMapCb(Ihandle* handle) + return iuplua_call(); + } +  ++static int iupluaDestroyCb(Ihandle* handle) ++{ ++ iuplua_call_start(handle, "destroycb"); ++ return iuplua_call(); ++} ++ + static int iupluaMapCb(Ihandle* handle) + { + iuplua_call_start(handle, "mapcb"); +@@ -610,6 +616,7 @@ int iupluawidgets_open(int tag) + { "iup_show_cb", (lua_CFunction)dialog_show}, + { "iup_map_cb", (lua_CFunction)iupluaMapCb}, + { "iup_unmap_cb", (lua_CFunction)iupluaUnMapCb}, ++ { "iup_destroy_cb", (lua_CFunction)iupluaDestroyCb}, + { "iup_dropfiles_cb", (lua_CFunction)iupluaDropfilesCb}, + { "iup_trayclick_cb", (lua_CFunction)dialog_trayclick}, + { "iup_getfocus_cb", (lua_CFunction)iupluaGetfocusCb}, +diff --git a/iup/srclua3/iuplua_widgets.lua b/iup/srclua3/iuplua_widgets.lua +index 33be9e3..a59bde6 100755 +--- a/iup/srclua3/iuplua_widgets.lua ++++ b/iup/srclua3/iuplua_widgets.lua +@@ -875,6 +875,7 @@ iup_callbacks = + showcb = {"SHOW_CB", iup_show_cb}, + mapcb = {"MAP_CB", iup_map_cb}, + unmapcb = {"UNMAP_CB", iup_unmap_cb}, ++ destroycb = {"DESTROY_CB", iup_destroy_cb}, + dropfiles = {"DROPFILES_CB", iup_dropfiles_cb}, + menuclose = {"MENUCLOSE_CB", iup_menuclose_cb}, + highlight = {"HIGHLIGHT_CB", iup_highlight_cb}, +@@ -921,6 +922,7 @@ iup_callbacks.open_cb = iup_callbacks.open + iup_callbacks.show_cb = iup_callbacks.showcb  + iup_callbacks.map_cb = iup_callbacks.mapcb  + iup_callbacks.unmap_cb = iup_callbacks.unmapcb  ++iup_callbacks.destroy_cb = iup_callbacks.destroycb  + iup_callbacks.dropfiles_cb = iup_callbacks.dropfiles  + iup_callbacks.menuclose_cb = iup_callbacks.menuclose  + iup_callbacks.highlight_cb = iup_callbacks.highlight  +diff --git a/iup/srclua3/tree.lua b/iup/srclua3/tree.lua +index 659afdb..bf53bca 100755 +--- a/iup/srclua3/tree.lua ++++ b/iup/srclua3/tree.lua +@@ -47,6 +47,7 @@ iup.TreeSetValue = TreeSetValue +  + iup_callbacks.selection = {"SELECTION_CB", iup_tree_selection_cb} + iup_callbacks.multiselection = {"MULTISELECTION_CB", iup_tree_multiselection_cb} ++iup_callbacks.multiunselection = {"MULTIUNSELECTION_CB", iup_tree_multiunselection_cb} + iup_callbacks.branchopen = {"BRANCHOPEN_CB", iup_tree_branchopen_cb} + iup_callbacks.branchclose = {"BRANCHCLOSE_CB", iup_tree_branchclose_cb} + iup_callbacks.executeleaf = {"EXECUTELEAF_CB", iup_tree_executeleaf_cb} +@@ -58,6 +59,7 @@ iup_callbacks.dragdrop = {"DRAGDROP_CB", iup_tree_dragdrop_cb} +  + iup_callbacks.selection_cb = iup_callbacks.selection  + iup_callbacks.multiselection_cb = iup_callbacks.multiselection  ++iup_callbacks.multiunselection_cb = iup_callbacks.multiunselection  + iup_callbacks.branchopen_cb = iup_callbacks.branchopen  + iup_callbacks.branchclose_cb = iup_callbacks.branchclose  + iup_callbacks.executeleaf_cb = iup_callbacks.executeleaf  +diff --git a/iup/srclua5/Makefile b/iup/srclua5/Makefile +index 3942e79..1189d32 100755 +--- a/iup/srclua5/Makefile ++++ b/iup/srclua5/Makefile +@@ -3,22 +3,22 @@ + do_all: iuplua iupluacd iupluacontrols iuplua_pplot iupluagl iupluaim iupluaimglib +  + iuplua: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak  ++ @$(MAKE) --no-print-directory -f ../tecmake.mak  +  + iupluacd: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iupcd ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iupcd +  + iupluacontrols: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iupcontrols ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iupcontrols +  + iuplua_pplot: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iup_pplot ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iup_pplot +  + iupluagl: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iupgl ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iupgl +  + iupluaim: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iupim ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iupim +  + iupluaimglib: +- @$(MAKE) --no-print-directory -f ../tecmake_compact.mak MF=iupimglib ++ @$(MAKE) --no-print-directory -f ../tecmake.mak MF=iupimglib +diff --git a/iup/srclua5/button.lua b/iup/srclua5/button.lua +index 946a05e..fc57b1a 100755 +--- a/iup/srclua5/button.lua ++++ b/iup/srclua5/button.lua +@@ -3,16 +3,16 @@ + ------------------------------------------------------------------------------ + local ctrl = { + nick = "button", +- parent = WIDGET, ++ parent = iup.WIDGET, + creation = "S-", + callback = { + action = "",  + } + }  +  +-function ctrl.createElement(class, arg) +- return Button(arg.title) ++function ctrl.createElement(class, param) ++ return iup.Button(param.title) + end +  +-iupRegisterWidget(ctrl) +-iupSetClass(ctrl, "iup widget") ++iup.RegisterWidget(ctrl) ++iup.SetClass(ctrl, "iup widget") +diff --git a/iup/srclua5/canvas.lua b/iup/srclua5/canvas.lua +index 562d671..101c4f4 100755 +--- a/iup/srclua5/canvas.lua ++++ b/iup/srclua5/canvas.lua +@@ -3,7 +3,7 @@ + ------------------------------------------------------------------------------ + local ctrl = { + nick = "canvas", +- parent = WIDGET, ++ parent = iup.WIDGET, + creation = "-", + callback = { + action = "ff", +@@ -21,9 +21,9 @@ local ctrl = { + } + } +  +-function ctrl.createElement(class, arg) +- return Canvas() ++function ctrl.createElement(class, param) ++ return iup.Canvas() + end +  +-iupRegisterWidget(ctrl) +-iupSetClass(ctrl, "iup widget") ++iup.RegisterWidget(ctrl) ++iup.SetClass(ctrl, "iup widget") +diff --git a/iup/srclua5/cbox.lua b/iup/srclua5/cbox.lua +index 3533970..81ba9be 100755 +--- a/iup/srclua5/cbox.lua ++++ b/iup/srclua5/cbox.lua +@@ -3,7 +3,7 @@ + ------------------------------------------------------------------------------ + local ctrl = { + nick = "cbox", +- parent = WIDGET, ++ parent = iup.WIDGET, + creation = "v", + callback = {}, + funcname = "Cboxv", +@@ -20,9 +20,9 @@ static int Cboxv(lua_State *L) + ]], + } +  +-function ctrl.createElement(class, arg) +- return Cboxv(arg) ++function ctrl.createElement(class, param) ++ return iup.Cboxv(param) + end +  +-iupRegisterWidget(ctrl) +-iupSetClass(ctrl, "iup widget") ++iup.RegisterWidget(ctrl) ++iup.SetClass(ctrl, "iup widget") +diff --git a/iup/srclua5/cells.lua b/iup/srclua5/cells.lua +index 9c914f2..0355b17 100755 +--- a/iup/srclua5/cells.lua ++++ b/iup/srclua5/cells.lua +@@ -3,7 +3,7 @@ + ------------------------------------------------------------------------------ + local ctrl = { + nick = "cells", +- parent = WIDGET, ++ parent = iup.WIDGET, + creation = "", + callback = { + mouseclick_cb = "nnnnnns", +@@ -24,9 +24,9 @@ function ctrl.redraw(handle) + handle.repaint = "YES" + end +  +-function ctrl.createElement(class, arg) +- return Cells() ++function ctrl.createElement(class, param) ++ return iup.Cells() + end +  +-iupRegisterWidget(ctrl) +-iupSetClass(ctrl, "iup widget") ++iup.RegisterWidget(ctrl) ++iup.SetClass(ctrl, "iup widget") +diff --git a/iup/srclua5/clipboard.lua b/iup/srclua5/clipboard.lua +index e60b8bd..663215b 100755 +--- a/iup/srclua5/clipboard.lua ++++ b/iup/srclua5/clipboard.lua +@@ -3,15 +3,15 @@ + ------------------------------------------------------------------------------ + local ctrl = { + nick = "clipboard", +- parent = WIDGET, ++ parent = iup.WIDGET, + creation = "", + callback = { + }, + }  +  +-function ctrl.createElement(class, arg) +- return Clipboard() ++function ctrl.createElement(class, param) ++ return iup.Clipboard() + end +  +-iupRegisterWidget(ctrl) +-iupSetClass(ctrl, "iup widget") ++iup.RegisterWidget(ctrl) ++iup.SetClass(ctrl, "iup widget") +diff --git a/iup/srclua5/colorbar.lua b/iup/srclua5/colorbar.lua +index 524d5f3..7cc07db 100755 +--- a/iup/srclua5/colorbar.lua ++++ b/iup/srclua5/colorbar.lua +@@ -3,7 +3,7 @@ + ------------------------------------------------------------------------------ + local ctrl = { + nick = "colorbar", +- parent = WIDGET, ++ parent = iup.WIDGET, + creation = "", + callback = { + select_cb = "nn", +@@ -15,12 +15,12 @@ local ctrl = { + include = "iupcontrols.h", + } +  +-PRIMARY = -1 +-SECONDARY = -2 ++iup.PRIMARY = -1 ++iup.SECONDARY = -2 +  +-function ctrl.createElement(class, arg) +- return Colorbar(arg.action) ++function ctrl.createElement(class, param) ++ return iup.Colorbar(param.action) + end +  +-iupRegisterWidget(ctrl) +-iupSetClass(ctrl, "iup widget") ++iup.RegisterWidget(ctrl) ++iup.SetClass(ctrl, "iup widget") +diff --git a/iup/srclua5/colorbrowser.lua b/iup/srclua5/colorbrowser.lua +index 16ac58f..496ce21 100755 +--- a/iup/srclua5/colorbrowser.lua ++++ b/iup/srclua5/colorbrowser.lua +@@ -3,7 +3,7 @@ + ------------------------------------------------------------------------------ + local ctrl = { + nick = "colorbrowser", +- parent = WIDGET, ++ parent = iup.WIDGET, + creation = "", + callback = { + drag_cb = "ccc", +@@ -13,9 +13,9 @@ local ctrl = { + include = "iupcontrols.h", + } +  +-function ctrl.createElement(class, arg) +- return ColorBrowser(arg.action) ++function ctrl.createElement(class, param) ++ return iup.ColorBrowser(param.action) + end +  +-iupRegisterWidget(ctrl) +-iupSetClass(ctrl, "iup widget") ++iup.RegisterWidget(ctrl) ++iup.SetClass(ctrl, "iup widget") +diff --git a/iup/srclua5/colordlg.lua b/iup/srclua5/colordlg.lua +index 6eea53b..d6a71a4 100755 +--- a/iup/srclua5/colordlg.lua ++++ b/iup/srclua5/colordlg.lua +@@ -3,24 +3,24 @@ + ------------------------------------------------------------------------------ + local ctrl = { + nick = "colordlg", +- parent = WIDGET, ++ parent = iup.WIDGET, + creation = "", + funcname = "ColorDlg", + callback = {} + }  +  + function ctrl.popup(handle, x, y) +- Popup(handle,x,y) ++ iup.Popup(handle,x,y) + end +  + function ctrl.destroy(handle) +- return Destroy(handle) ++ return iup.Destroy(handle) + end +  +-function ctrl.createElement(class, arg) +- return ColorDlg() ++function ctrl.createElement(class, param) ++ return iup.ColorDlg() + end +  +-iupRegisterWidget(ctrl) +-iupSetClass(ctrl, "iup widget") ++iup.RegisterWidget(ctrl) ++iup.SetClass(ctrl, "iup widget") +  +diff --git a/iup/srclua5/config.mak b/iup/srclua5/config.mak +index 7979f0e..921aa29 100755 +--- a/iup/srclua5/config.mak ++++ b/iup/srclua5/config.mak +@@ -17,7 +17,7 @@ CTRLUA = button.lua canvas.lua dialog.lua colordlg.lua clipboard.lua \ + item.lua image.lua imagergb.lua imagergba.lua label.lua \ + menu.lua multiline.lua list.lua separator.lua user.lua \ + submenu.lua text.lua toggle.lua vbox.lua zbox.lua timer.lua \ +- sbox.lua spin.lua spinbox.lua cbox.lua messagedlg.lua \ ++ sbox.lua split.lua spin.lua spinbox.lua cbox.lua messagedlg.lua \ + radio.lua val.lua tabs.lua fontdlg.lua tree.lua progressbar.lua +  + GC := $(addsuffix .c, $(basename $(CTRLUA))) +diff --git a/iup/srclua5/constants.lua b/iup/srclua5/constants.lua +index 9a72f6a..2a1e76f 100755 +--- a/iup/srclua5/constants.lua ++++ b/iup/srclua5/constants.lua +@@ -3,70 +3,70 @@ + ---------------------------------------------------------------------------- + -- Common return values  + ---------------------------------------------------------------------------- +-ERROR = 1 +-NOERROR = 0 +-OPENED = -1 +-INVALID = -1 ++iup.ERROR = 1 ++iup.NOERROR = 0 ++iup.OPENED = -1 ++iup.INVALID = -1 +  + ---------------------------------------------------------------------------- + -- Callback return values  + ---------------------------------------------------------------------------- +-IGNORE = -1 +-DEFAULT = -2 +-CLOSE = -3 +-CONTINUE = -4 ++iup.IGNORE = -1 ++iup.DEFAULT = -2 ++iup.CLOSE = -3 ++iup.CONTINUE = -4 +  + ---------------------------------------------------------------------------- + -- IupPopup e IupShowXY  + ------------------------------- \ No newline at end of file -- cgit v1.2.3