summaryrefslogtreecommitdiff
path: root/iup/src
diff options
context:
space:
mode:
authorPixel <pixel@nobis-crew.org>2009-11-04 11:56:41 -0800
committerPixel <pixel@nobis-crew.org>2009-11-04 11:59:33 -0800
commitd577d991b97ae2b5ee1af23641bcffc3f83af5b2 (patch)
tree590639d50205d1bcfaff2a7d2dc6ebf3f373c7ed /iup/src
Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux.
Diffstat (limited to 'iup/src')
-rwxr-xr-xiup/src/Makefile9
-rwxr-xr-xiup/src/config.mak118
-rwxr-xr-xiup/src/gtk/iupgtk_button.c477
-rwxr-xr-xiup/src/gtk/iupgtk_canvas.c624
-rwxr-xr-xiup/src/gtk/iupgtk_clipboard.c125
-rwxr-xr-xiup/src/gtk/iupgtk_colordlg.c211
-rwxr-xr-xiup/src/gtk/iupgtk_common.c830
-rwxr-xr-xiup/src/gtk/iupgtk_dialog.c1023
-rwxr-xr-xiup/src/gtk/iupgtk_drv.h82
-rwxr-xr-xiup/src/gtk/iupgtk_filedlg.c536
-rwxr-xr-xiup/src/gtk/iupgtk_focus.c44
-rwxr-xr-xiup/src/gtk/iupgtk_font.c413
-rwxr-xr-xiup/src/gtk/iupgtk_fontdlg.c91
-rwxr-xr-xiup/src/gtk/iupgtk_frame.c155
-rwxr-xr-xiup/src/gtk/iupgtk_globalattrib.c211
-rwxr-xr-xiup/src/gtk/iupgtk_help.c52
-rwxr-xr-xiup/src/gtk/iupgtk_image.c430
-rwxr-xr-xiup/src/gtk/iupgtk_key.c422
-rwxr-xr-xiup/src/gtk/iupgtk_label.c318
-rwxr-xr-xiup/src/gtk/iupgtk_list.c1439
-rwxr-xr-xiup/src/gtk/iupgtk_loop.c93
-rwxr-xr-xiup/src/gtk/iupgtk_menu.c525
-rwxr-xr-xiup/src/gtk/iupgtk_messagedlg.c128
-rwxr-xr-xiup/src/gtk/iupgtk_open.c172
-rwxr-xr-xiup/src/gtk/iupgtk_progressbar.c131
-rwxr-xr-xiup/src/gtk/iupgtk_tabs.c444
-rwxr-xr-xiup/src/gtk/iupgtk_text.c1716
-rwxr-xr-xiup/src/gtk/iupgtk_timer.c61
-rwxr-xr-xiup/src/gtk/iupgtk_tips.c100
-rwxr-xr-xiup/src/gtk/iupgtk_toggle.c519
-rwxr-xr-xiup/src/gtk/iupgtk_tree.c2369
-rwxr-xr-xiup/src/gtk/iupgtk_val.c208
-rwxr-xr-xiup/src/iup.c86
-rwxr-xr-xiup/src/iup.def353
-rw-r--r--iup/src/iup.dep334
-rwxr-xr-xiup/src/iup_array.c108
-rwxr-xr-xiup/src/iup_array.h63
-rwxr-xr-xiup/src/iup_assert.c54
-rwxr-xr-xiup/src/iup_assert.h68
-rwxr-xr-xiup/src/iup_attrib.c673
-rwxr-xr-xiup/src/iup_attrib.h137
-rwxr-xr-xiup/src/iup_box.c238
-rwxr-xr-xiup/src/iup_box.h40
-rwxr-xr-xiup/src/iup_button.c206
-rwxr-xr-xiup/src/iup_button.h39
-rwxr-xr-xiup/src/iup_callback.c90
-rwxr-xr-xiup/src/iup_canvas.c169
-rwxr-xr-xiup/src/iup_canvas.h37
-rwxr-xr-xiup/src/iup_cbox.c143
-rwxr-xr-xiup/src/iup_childtree.c455
-rwxr-xr-xiup/src/iup_childtree.h54
-rwxr-xr-xiup/src/iup_class.c314
-rwxr-xr-xiup/src/iup_class.h414
-rwxr-xr-xiup/src/iup_classattrib.c508
-rwxr-xr-xiup/src/iup_classbase.c466
-rwxr-xr-xiup/src/iup_classbase.h175
-rwxr-xr-xiup/src/iup_colordlg.c44
-rwxr-xr-xiup/src/iup_dialog.c747
-rwxr-xr-xiup/src/iup_dialog.h89
-rwxr-xr-xiup/src/iup_dlglist.c130
-rwxr-xr-xiup/src/iup_dlglist.h58
-rwxr-xr-xiup/src/iup_dll.rc41
-rwxr-xr-xiup/src/iup_drv.h99
-rwxr-xr-xiup/src/iup_drvfont.h116
-rwxr-xr-xiup/src/iup_drvinfo.h103
-rwxr-xr-xiup/src/iup_filedlg.c67
-rwxr-xr-xiup/src/iup_fill.c242
-rwxr-xr-xiup/src/iup_focus.c281
-rwxr-xr-xiup/src/iup_focus.h53
-rwxr-xr-xiup/src/iup_font.c714
-rwxr-xr-xiup/src/iup_fontdlg.c48
-rwxr-xr-xiup/src/iup_frame.c165
-rwxr-xr-xiup/src/iup_frame.h22
-rwxr-xr-xiup/src/iup_func.c78
-rwxr-xr-xiup/src/iup_func.h28
-rwxr-xr-xiup/src/iup_getparam.c1254
-rwxr-xr-xiup/src/iup_globalattrib.c153
-rwxr-xr-xiup/src/iup_globalattrib.h33
-rwxr-xr-xiup/src/iup_hbox.c309
-rwxr-xr-xiup/src/iup_image.c1017
-rwxr-xr-xiup/src/iup_image.h61
-rwxr-xr-xiup/src/iup_key.c269
-rwxr-xr-xiup/src/iup_key.h70
-rwxr-xr-xiup/src/iup_label.c183
-rwxr-xr-xiup/src/iup_label.h37
-rwxr-xr-xiup/src/iup_layout.c273
-rwxr-xr-xiup/src/iup_layout.h28
-rwxr-xr-xiup/src/iup_ledlex.c366
-rwxr-xr-xiup/src/iup_ledlex.h54
-rwxr-xr-xiup/src/iup_ledparse.c288
-rwxr-xr-xiup/src/iup_list.c711
-rwxr-xr-xiup/src/iup_list.h53
-rwxr-xr-xiup/src/iup_mask.c146
-rwxr-xr-xiup/src/iup_mask.h55
-rwxr-xr-xiup/src/iup_maskmatch.c582
-rwxr-xr-xiup/src/iup_maskmatch.h62
-rwxr-xr-xiup/src/iup_maskparse.c547
-rwxr-xr-xiup/src/iup_maskparse.h46
-rwxr-xr-xiup/src/iup_menu.c364
-rwxr-xr-xiup/src/iup_menu.h35
-rwxr-xr-xiup/src/iup_messagedlg.c70
-rwxr-xr-xiup/src/iup_names.c193
-rwxr-xr-xiup/src/iup_names.h34
-rwxr-xr-xiup/src/iup_normalizer.c188
-rwxr-xr-xiup/src/iup_object.c180
-rwxr-xr-xiup/src/iup_object.h132
-rwxr-xr-xiup/src/iup_open.c119
-rwxr-xr-xiup/src/iup_predial.c510
-rwxr-xr-xiup/src/iup_predial.h32
-rwxr-xr-xiup/src/iup_progressbar.c118
-rwxr-xr-xiup/src/iup_progressbar.h35
-rwxr-xr-xiup/src/iup_radio.c195
-rwxr-xr-xiup/src/iup_register.c123
-rwxr-xr-xiup/src/iup_register.h47
-rwxr-xr-xiup/src/iup_sbox.c413
-rwxr-xr-xiup/src/iup_scanf.c200
-rwxr-xr-xiup/src/iup_show.c256
-rwxr-xr-xiup/src/iup_spin.c301
-rwxr-xr-xiup/src/iup_stdcontrols.h76
-rwxr-xr-xiup/src/iup_str.c716
-rwxr-xr-xiup/src/iup_str.h183
-rwxr-xr-xiup/src/iup_strmessage.c137
-rwxr-xr-xiup/src/iup_strmessage.h45
-rwxr-xr-xiup/src/iup_table.c736
-rwxr-xr-xiup/src/iup_table.h143
-rwxr-xr-xiup/src/iup_tabs.c471
-rwxr-xr-xiup/src/iup_tabs.h50
-rwxr-xr-xiup/src/iup_text.c513
-rwxr-xr-xiup/src/iup_text.h48
-rwxr-xr-xiup/src/iup_timer.c80
-rwxr-xr-xiup/src/iup_timer.h24
-rwxr-xr-xiup/src/iup_toggle.c140
-rwxr-xr-xiup/src/iup_toggle.h37
-rwxr-xr-xiup/src/iup_tree.c499
-rwxr-xr-xiup/src/iup_tree.h57
-rwxr-xr-xiup/src/iup_user.c41
-rwxr-xr-xiup/src/iup_val.c209
-rwxr-xr-xiup/src/iup_val.h42
-rwxr-xr-xiup/src/iup_vbox.c311
-rwxr-xr-xiup/src/iup_zbox.c375
-rw-r--r--iup/src/iupgtk.dep259
-rwxr-xr-xiup/src/iupstub.mak12
-rwxr-xr-xiup/src/make_uname4
-rwxr-xr-xiup/src/make_uname.bat55
-rwxr-xr-xiup/src/mot/iupmot_button.c301
-rwxr-xr-xiup/src/mot/iupmot_canvas.c639
-rwxr-xr-xiup/src/mot/iupmot_clipboard.c208
-rwxr-xr-xiup/src/mot/iupmot_color.c380
-rwxr-xr-xiup/src/mot/iupmot_color.h36
-rwxr-xr-xiup/src/mot/iupmot_colordlg.c31
-rwxr-xr-xiup/src/mot/iupmot_common.c630
-rwxr-xr-xiup/src/mot/iupmot_dialog.c1069
-rwxr-xr-xiup/src/mot/iupmot_drv.h75
-rwxr-xr-xiup/src/mot/iupmot_filedlg.c578
-rwxr-xr-xiup/src/mot/iupmot_focus.c35
-rwxr-xr-xiup/src/mot/iupmot_font.c443
-rwxr-xr-xiup/src/mot/iupmot_fontdlg.c31
-rwxr-xr-xiup/src/mot/iupmot_frame.c257
-rwxr-xr-xiup/src/mot/iupmot_globalattrib.c155
-rwxr-xr-xiup/src/mot/iupmot_image.c397
-rwxr-xr-xiup/src/mot/iupmot_key.c425
-rwxr-xr-xiup/src/mot/iupmot_label.c256
-rwxr-xr-xiup/src/mot/iupmot_list.c1404
-rwxr-xr-xiup/src/mot/iupmot_loop.c108
-rwxr-xr-xiup/src/mot/iupmot_menu.c457
-rwxr-xr-xiup/src/mot/iupmot_messagedlg.c191
-rwxr-xr-xiup/src/mot/iupmot_open.c141
-rwxr-xr-xiup/src/mot/iupmot_progressbar.c165
-rwxr-xr-xiup/src/mot/iupmot_tabs.c593
-rwxr-xr-xiup/src/mot/iupmot_text.c1165
-rwxr-xr-xiup/src/mot/iupmot_timer.c70
-rwxr-xr-xiup/src/mot/iupmot_tips.c226
-rwxr-xr-xiup/src/mot/iupmot_toggle.c469
-rwxr-xr-xiup/src/mot/iupmot_tree.c2848
-rwxr-xr-xiup/src/mot/iupmot_val.c488
-rwxr-xr-xiup/src/mot/iupunix_help.c44
-rwxr-xr-xiup/src/mot/iupunix_info.c305
-rwxr-xr-xiup/src/win/iupwin_brush.c62
-rwxr-xr-xiup/src/win/iupwin_brush.h26
-rwxr-xr-xiup/src/win/iupwin_button.c715
-rwxr-xr-xiup/src/win/iupwin_canvas.c724
-rwxr-xr-xiup/src/win/iupwin_clipboard.c190
-rwxr-xr-xiup/src/win/iupwin_colordlg.c133
-rwxr-xr-xiup/src/win/iupwin_common.c865
-rwxr-xr-xiup/src/win/iupwin_dialog.c1439
-rwxr-xr-xiup/src/win/iupwin_draw.c328
-rwxr-xr-xiup/src/win/iupwin_draw.h47
-rwxr-xr-xiup/src/win/iupwin_drv.h113
-rwxr-xr-xiup/src/win/iupwin_filedlg.c580
-rwxr-xr-xiup/src/win/iupwin_focus.c62
-rwxr-xr-xiup/src/win/iupwin_font.c342
-rwxr-xr-xiup/src/win/iupwin_fontdlg.c160
-rwxr-xr-xiup/src/win/iupwin_frame.c203
-rwxr-xr-xiup/src/win/iupwin_globalattrib.c243
-rwxr-xr-xiup/src/win/iupwin_handle.c56
-rwxr-xr-xiup/src/win/iupwin_handle.h28
-rwxr-xr-xiup/src/win/iupwin_image.c668
-rwxr-xr-xiup/src/win/iupwin_info.c277
-rwxr-xr-xiup/src/win/iupwin_info.h29
-rwxr-xr-xiup/src/win/iupwin_key.c348
-rwxr-xr-xiup/src/win/iupwin_label.c339
-rwxr-xr-xiup/src/win/iupwin_list.c1460
-rwxr-xr-xiup/src/win/iupwin_loop.c135
-rwxr-xr-xiup/src/win/iupwin_menu.c667
-rwxr-xr-xiup/src/win/iupwin_messagedlg.c105
-rwxr-xr-xiup/src/win/iupwin_open.c124
-rwxr-xr-xiup/src/win/iupwin_progressbar.c164
-rwxr-xr-xiup/src/win/iupwin_tabs.c680
-rwxr-xr-xiup/src/win/iupwin_text.c1993
-rwxr-xr-xiup/src/win/iupwin_timer.c88
-rwxr-xr-xiup/src/win/iupwin_tips.c191
-rwxr-xr-xiup/src/win/iupwin_toggle.c693
-rwxr-xr-xiup/src/win/iupwin_tree.c2542
-rwxr-xr-xiup/src/win/iupwin_val.c315
-rwxr-xr-xiup/src/win/iupwindows_help.c32
-rwxr-xr-xiup/src/win/iupwindows_info.c212
-rwxr-xr-xiup/src/win/iupwindows_main.c66
217 files changed, 69894 insertions, 0 deletions
diff --git a/iup/src/Makefile b/iup/src/Makefile
new file mode 100755
index 0000000..028047f
--- /dev/null
+++ b/iup/src/Makefile
@@ -0,0 +1,9 @@
+
+.PHONY: do_all iup iupgtk
+do_all: iup iupgtk
+
+iup:
+ @$(MAKE) --no-print-directory -f ../tecmake_compact.mak
+
+iupgtk:
+ @$(MAKE) --no-print-directory -f ../tecmake_compact.mak USE_GTK=Yes
diff --git a/iup/src/config.mak b/iup/src/config.mak
new file mode 100755
index 0000000..e857643
--- /dev/null
+++ b/iup/src/config.mak
@@ -0,0 +1,118 @@
+PROJNAME = iup
+LIBNAME = iup
+OPT = YES
+
+#ifdef DBG
+ DEFINES += IUP_ASSERT
+#endif
+
+INCLUDES = ../include .
+
+SRC = iup_array.c iup_callback.c iup_dlglist.c iup_attrib.c iup_focus.c iup_font.c \
+ iup_globalattrib.c iup_object.c iup_key.c iup_layout.c iup_ledlex.c iup_names.c iup_open.c \
+ iup_ledparse.c iup_predial.c iup_register.c iup_scanf.c iup_show.c iup_str.c iup_table.c \
+ iup_func.c iup_childtree.c iup.c iup_classattrib.c iup_dialog.c iup_assert.c iup_canvas.c \
+ iup_messagedlg.c iup_timer.c iup_image.c iup_label.c iup_fill.c iup_zbox.c \
+ iup_colordlg.c iup_fontdlg.c iup_filedlg.c iup_strmessage.c iup_menu.c iup_frame.c \
+ 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
+
+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_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 \
+ gtk/iupgtk_text.c gtk/iupgtk_val.c gtk/iupgtk_frame.c gtk/iupgtk_canvas.c \
+ gtk/iupgtk_tabs.c gtk/iupgtk_menu.c gtk/iupgtk_list.c gtk/iupgtk_tree.c
+
+ ifneq ($(findstring Win, $(TEC_SYSNAME)), )
+ 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
+ endif
+
+ ifdef USE_HILDON
+ DEFINES += HILDON
+ INCLUDES += /usr/include/hildon-1
+ 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
+endif
+
+ifeq "$(TEC_SYSNAME)" "SunOS"
+ # Necessary or the fileopen will not work in SunOS (needs to be retested)
+ #DEFINES += NO_PATH_MODE_RELATIVE
+endif
+
+ifneq ($(findstring dll, $(TEC_UNAME)), )
+ DEFINES += IUP_DLL
+ SRC += iup_dll.rc
+ DEF_FILE = iup.def
+endif
+
+ifeq "$(TEC_UNAME)" "vc6"
+ # Necessary because VC6 has an old WinSDK
+ #WINSDK = d:/lng/vc7/PlatformSDK
+ #INCLUDES += $(WINSDK)/include
+ #LDIR = $(WINSDK)/lib
+endif
+
+ifeq "$(TEC_UNAME)" "dll"
+ # Necessary because VC6 has an old WinSDK
+ #WINSDK = d:/lng/vc7/PlatformSDK
+ #INCLUDES += $(WINSDK)/include
+ #LDIR = $(WINSDK)/lib
+endif
+
+ifeq "$(TEC_UNAME)" "owc1"
+ # Necessary or IUP 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
new file mode 100755
index 0000000..18be87c
--- /dev/null
+++ b/iup/src/gtk/iupgtk_button.c
@@ -0,0 +1,477 @@
+/** \file
+ * \brief Button Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_button.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+#include "iup_key.h"
+
+#include "iupgtk_drv.h"
+
+
+#if !GTK_CHECK_VERSION(2, 6, 0)
+static void gtk_button_set_image(GtkButton *button, GtkWidget *image)
+{
+}
+static GtkWidget* gtk_button_get_image(GtkButton *button)
+{
+ return NULL;
+}
+#endif
+
+void iupdrvButtonAddBorders(int *x, int *y)
+{
+#ifdef WIN32
+ int border_size = 2*5;
+#else
+#ifdef HILDON
+ int border_size = 2*7+1; /* borders are not symetric */
+#else
+ int border_size = 2*5+1; /* borders are not symetric */
+#endif
+#endif
+ (*x) += border_size;
+ (*y) += border_size;
+}
+
+static void gtk_button_children_callback(GtkWidget *widget, gpointer client_data)
+{
+ if (GTK_IS_LABEL(widget))
+ {
+ GtkLabel **label = (GtkLabel**) client_data;
+ *label = (GtkLabel*)widget;
+ }
+}
+
+static GtkLabel* gtkButtonGetLabel(Ihandle* ih)
+{
+ if (ih->data->type == IUP_BUTTON_TEXT) /* text only */
+ return (GtkLabel*)gtk_bin_get_child((GtkBin*)ih->handle);
+ else if (ih->data->type == IUP_BUTTON_BOTH) /* both */
+ {
+ /* when both is set, button contains an GtkAlignment,
+ that contains a GtkBox, that contains a label and an image */
+ GtkContainer *container = (GtkContainer*)gtk_bin_get_child((GtkBin*)gtk_bin_get_child((GtkBin*)ih->handle));
+ GtkLabel* label = NULL;
+ gtk_container_foreach(container, gtk_button_children_callback, &label);
+ return label;
+ }
+ return NULL;
+}
+
+static int gtkButtonSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_BUTTON_IMAGE) /* text or both */
+ {
+ GtkLabel* label = gtkButtonGetLabel(ih);
+ iupgtkSetMnemonicTitle(ih, label, value);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int gtkButtonSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ GtkButton* button = (GtkButton*)ih->handle;
+ PangoAlignment alignment;
+ float xalign, yalign;
+ char value1[30]="", value2[30]="";
+
+ iupStrToStrStr(value, value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ {
+ xalign = 1.0f;
+ alignment = PANGO_ALIGN_RIGHT;
+ }
+ else if (iupStrEqualNoCase(value1, "ACENTER"))
+ {
+ xalign = 0.5f;
+ alignment = PANGO_ALIGN_CENTER;
+ }
+ else /* "ALEFT" */
+ {
+ xalign = 0;
+ alignment = PANGO_ALIGN_LEFT;
+ }
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ yalign = 1.0f;
+ else if (iupStrEqualNoCase(value2, "ATOP"))
+ yalign = 0;
+ else /* ACENTER (default) */
+ yalign = 0.5f;
+
+ gtk_button_set_alignment(button, xalign, yalign);
+
+ if (ih->data->type == IUP_BUTTON_TEXT && !GTK_IS_COLOR_BUTTON(ih->handle)) /* text only */
+ {
+ PangoLayout* layout = gtk_label_get_layout(gtkButtonGetLabel(ih));
+ if (layout) pango_layout_set_alignment(layout, alignment);
+ }
+
+ return 1;
+}
+
+static int gtkButtonSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle)
+ {
+ if (ih->data->type == IUP_BUTTON_TEXT) /* text only */
+ {
+ GtkMisc* misc = (GtkMisc*)gtk_bin_get_child((GtkBin*)ih->handle);
+ gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding);
+ }
+ else
+ {
+ GtkAlignment* alignment = (GtkAlignment*)gtk_bin_get_child((GtkBin*)ih->handle);
+ gtk_alignment_set_padding(alignment, ih->data->vert_padding, ih->data->vert_padding,
+ ih->data->horiz_padding, ih->data->horiz_padding);
+ }
+ }
+ return 0;
+}
+
+#ifdef WIN32
+static int gtkButtonSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_BUTTON_TEXT && GTK_IS_COLOR_BUTTON(ih->handle))
+ {
+ GdkColor color;
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgdkColorSet(&color, r, g, b);
+ gtk_color_button_set_color((GtkColorButton*)ih->handle, &color);
+ return 1;
+ }
+
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+}
+#endif
+
+static int gtkButtonSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ GtkLabel* label = gtkButtonGetLabel(ih);
+ if (!label) return 0;
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor((GtkWidget*)label, r, g, b);
+
+ return 1;
+}
+
+static int gtkButtonSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+
+ if (ih->handle)
+ {
+ GtkLabel* label = gtkButtonGetLabel(ih);
+ if (!label) return 1;
+
+ gtk_widget_modify_font((GtkWidget*)label, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih));
+ if (ih->data->type == IUP_BUTTON_TEXT && !GTK_IS_COLOR_BUTTON(ih->handle)) /* text only */
+ iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout(label));
+ }
+ return 1;
+}
+
+static void gtkButtonSetPixbuf(Ihandle* ih, const char* name, int make_inactive)
+{
+ GtkButton* button = (GtkButton*)ih->handle;
+ GtkImage* image = (GtkImage*)gtk_button_get_image(button);
+
+ if (name && image)
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(name, ih, make_inactive);
+ GdkPixbuf* old_pixbuf = gtk_image_get_pixbuf(image);
+ if (pixbuf != old_pixbuf)
+ gtk_image_set_from_pixbuf(image, pixbuf);
+ return;
+ }
+
+ /* if not defined */
+#if GTK_CHECK_VERSION(2, 8, 0)
+ if (image)
+ gtk_image_clear(image);
+#endif
+}
+
+static int gtkButtonSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */
+ {
+ if (iupdrvIsActive(ih))
+ gtkButtonSetPixbuf(ih, value, 0);
+ else
+ {
+ if (!iupAttribGet(ih, "IMINACTIVE"))
+ {
+ /* if not active and IMINACTIVE is not defined
+ then automaticaly create one based on IMAGE */
+ gtkButtonSetPixbuf(ih, value, 1); /* make_inactive */
+ }
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkButtonSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */
+ {
+ if (!iupdrvIsActive(ih))
+ {
+ if (value)
+ gtkButtonSetPixbuf(ih, value, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ char* name = iupAttribGet(ih, "IMAGE");
+ gtkButtonSetPixbuf(ih, name, 1); /* make_inactive */
+ }
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkButtonSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ /* update the inactive image if necessary */
+ if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */
+ {
+ if (!iupStrBoolean(value))
+ {
+ char* name = iupAttribGet(ih, "IMINACTIVE");
+ if (name)
+ gtkButtonSetPixbuf(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ gtkButtonSetPixbuf(ih, name, 1); /* make_inactive */
+ }
+ }
+ else
+ {
+ /* must restore the normal image */
+ char* name = iupAttribGet(ih, "IMAGE");
+ gtkButtonSetPixbuf(ih, name, 0);
+ }
+ }
+
+ return iupBaseSetActiveAttrib(ih, value);
+}
+
+static int gtkButtonSetFocusOnClickAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ gtk_button_set_focus_on_click((GtkButton*)ih->handle, TRUE);
+ else
+ gtk_button_set_focus_on_click((GtkButton*)ih->handle, FALSE);
+ return 1;
+}
+
+static gboolean gtkButtonEnterLeaveEvent(GtkWidget *widget, GdkEventCrossing *evt, Ihandle *ih)
+{
+ iupgtkEnterLeaveEvent(widget, evt, ih);
+ (void)widget;
+
+ if (evt->type == GDK_ENTER_NOTIFY)
+ gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NORMAL);
+ else if (evt->type == GDK_LEAVE_NOTIFY)
+ gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NONE);
+
+ return FALSE;
+}
+
+static gboolean gtkButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ if (iupgtkButtonEvent(widget, evt, ih)==TRUE)
+ return TRUE;
+
+ if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */
+ {
+ char* name = iupAttribGet(ih, "IMPRESS");
+ if (name)
+ {
+ if (evt->type == GDK_BUTTON_PRESS)
+ gtkButtonSetPixbuf(ih, name, 0);
+ else
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ gtkButtonSetPixbuf(ih, name, 0);
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static void gtkButtonClicked(GtkButton *widget, Ihandle* ih)
+{
+ Icallback cb = IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ if (cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+ }
+ (void)widget;
+}
+
+static int gtkButtonMapMethod(Ihandle* ih)
+{
+ int impress;
+ char* value;
+
+ ih->handle = gtk_button_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ {
+ gtk_button_set_image((GtkButton*)ih->handle, gtk_image_new());
+ ih->data->type = IUP_BUTTON_IMAGE;
+
+ value = iupAttribGet(ih, "TITLE");
+ if (value)
+ {
+ 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);
+ ih->data->type |= IUP_BUTTON_TEXT;
+
+#if GTK_CHECK_VERSION(2, 10, 0)
+ gtk_button_set_image_position((GtkButton*)ih->handle, ih->data->img_position); /* IUP and GTK have the same Ids */
+#endif
+ }
+ }
+ else
+ {
+ char* title = iupAttribGet(ih, "TITLE");
+ if (!title)
+ {
+#ifdef WIN32
+ if (iupAttribGet(ih, "BGCOLOR"))
+ {
+ gtk_widget_destroy(ih->handle);
+ ih->handle = gtk_color_button_new();
+ }
+ else
+ gtk_button_set_label((GtkButton*)ih->handle, "");
+#else
+ gtk_button_set_label((GtkButton*)ih->handle, "");
+#endif
+ }
+ else
+ gtk_button_set_label((GtkButton*)ih->handle, title);
+ ih->data->type = IUP_BUTTON_TEXT;
+ }
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ value = iupAttribGet(ih, "IMPRESS");
+ impress = (ih->data->type & IUP_BUTTON_IMAGE && value)? 1: 0;
+ if (!impress && iupAttribGetBoolean(ih, "FLAT"))
+ {
+ gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NONE);
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(gtkButtonEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(gtkButtonEnterLeaveEvent), ih);
+ }
+ else
+ {
+ if (impress && !iupAttribGetStr(ih, "IMPRESSBORDER"))
+ gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NONE);
+ else
+ gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NORMAL);
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ }
+
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "clicked", G_CALLBACK(gtkButtonClicked), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkButtonEvent), ih);
+
+ gtk_widget_realize(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvButtonInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkButtonMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkButtonSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, gtkButtonSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+
+ /* Visual */
+#ifdef WIN32
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkButtonSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+#else
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+#endif
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkButtonSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, gtkButtonSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupButton only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkButtonSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkButtonSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, gtkButtonSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FOCUSONCLICK", NULL, gtkButtonSetFocusOnClickAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupButtonGetPaddingAttrib, gtkButtonSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "MARKUP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
+}
diff --git a/iup/src/gtk/iupgtk_canvas.c b/iup/src/gtk/iupgtk_canvas.c
new file mode 100755
index 0000000..daae4ad
--- /dev/null
+++ b/iup/src/gtk/iupgtk_canvas.c
@@ -0,0 +1,624 @@
+/** \file
+ * \brief Canvas Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_drvfont.h"
+#include "iup_canvas.h"
+#include "iup_key.h"
+
+#include "iupgtk_drv.h"
+
+
+static int gtkCanvasScroll2Iup(GtkScrollType scroll, int vert)
+{
+ switch(scroll)
+ {
+ case GTK_SCROLL_STEP_UP:
+ return IUP_SBUP;
+ case GTK_SCROLL_STEP_DOWN:
+ return IUP_SBDN;
+ case GTK_SCROLL_PAGE_UP:
+ return IUP_SBPGUP;
+ case GTK_SCROLL_PAGE_DOWN:
+ return IUP_SBPGDN;
+ case GTK_SCROLL_STEP_LEFT:
+ return IUP_SBLEFT;
+ case GTK_SCROLL_STEP_RIGHT:
+ return IUP_SBRIGHT;
+ case GTK_SCROLL_PAGE_LEFT:
+ return IUP_SBPGLEFT;
+ case GTK_SCROLL_PAGE_RIGHT:
+ return IUP_SBPGRIGHT;
+ case GTK_SCROLL_STEP_BACKWARD:
+ return vert? IUP_SBUP: IUP_SBLEFT;
+ case GTK_SCROLL_STEP_FORWARD:
+ return vert? IUP_SBDN: IUP_SBRIGHT;
+ case GTK_SCROLL_PAGE_BACKWARD:
+ return vert? IUP_SBPGUP: IUP_SBPGLEFT;
+ case GTK_SCROLL_PAGE_FORWARD:
+ return vert? IUP_SBPGDN: IUP_SBPGRIGHT;
+ case GTK_SCROLL_JUMP:
+ case GTK_SCROLL_START:
+ case GTK_SCROLL_END:
+ return vert? IUP_SBPOSV: IUP_SBPOSH;
+ case GTK_SCROLL_NONE:
+ return -1;
+ }
+
+ /* No IUP_SBDRAGV or IUP_SBDRAGH support in GTK */
+
+ return -1;
+}
+
+static gboolean gtkCanvasHChangeValue(GtkRange *range, GtkScrollType scroll, double value, Ihandle *ih)
+{
+ double posx, posy;
+ IFniff cb;
+
+ double xmin = iupAttribGetFloat(ih, "XMIN");
+ double xmax = iupAttribGetFloat(ih, "XMAX");
+ double dx = iupAttribGetFloat(ih, "DX");
+ if (value < xmin) value = xmin;
+ if (value > xmax-dx) value = xmax-dx;
+
+ posx = value;
+ ih->data->posx = (float)posx;
+ posy = ih->data->posy;
+
+ cb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ if (cb)
+ {
+ int op = gtkCanvasScroll2Iup(scroll, 0);
+ if (op == -1)
+ return FALSE;
+
+ cb(ih, op, (float)posx, (float)posy);
+ }
+ else
+ {
+ IFnff cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ cb (ih, (float)posx, (float)posy);
+ }
+
+ (void)range;
+ return FALSE;
+}
+
+static gboolean gtkCanvasVChangeValue(GtkRange *range, GtkScrollType scroll, double value, Ihandle *ih)
+{
+ double posx, posy;
+ IFniff cb;
+
+ double ymin = iupAttribGetFloat(ih, "YMIN");
+ double ymax = iupAttribGetFloat(ih, "YMAX");
+ double dy = iupAttribGetFloat(ih, "DY");
+ if (value < ymin) value = ymin;
+ if (value > ymax-dy) value = ymax-dy;
+
+ posy = value;
+ ih->data->posy = (float)posy;
+ posx = ih->data->posx;
+
+ cb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ if (cb)
+ {
+ int op = gtkCanvasScroll2Iup(scroll, 1);
+ if (op == -1)
+ return FALSE;
+
+ cb(ih, op, (float)posx, (float)posy);
+ }
+ else
+ {
+ IFnff cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ cb (ih, (float)posx, (float)posy);
+ }
+
+ (void)range;
+ return FALSE;
+}
+
+static gboolean gtkCanvasScrollEvent(GtkWidget *widget, GdkEventScroll *evt, Ihandle *ih)
+{
+ IFnfiis wcb = (IFnfiis)IupGetCallback(ih, "WHEEL_CB");
+ if (wcb)
+ {
+ int delta = evt->direction==GDK_SCROLL_UP||evt->direction==GDK_SCROLL_LEFT? 1: -1;
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ int button = evt->direction==GDK_SCROLL_UP||evt->direction==GDK_SCROLL_LEFT? 4: 5;
+ iupgtkButtonKeySetStatus(evt->state, button, status, 0);
+
+ wcb(ih, (float)delta, (int)evt->x, (int)evt->y, status);
+ }
+ else
+ {
+ IFniff scb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ int delta = evt->direction==GDK_SCROLL_UP||evt->direction==GDK_SCROLL_LEFT? 1: -1;
+
+ if (evt->direction==GDK_SCROLL_UP || evt->direction==GDK_SCROLL_DOWN)
+ {
+ float posy = ih->data->posy;
+ posy -= delta*iupAttribGetFloat(ih, "DY")/10.0f;
+ IupSetfAttribute(ih, "POSY", "%g", posy);
+ }
+ else
+ {
+ float posx = ih->data->posx;
+ posx -= delta*iupAttribGetFloat(ih, "DX")/10.0f;
+ IupSetfAttribute(ih, "POSX", "%g", posx);
+ }
+
+ if (scb)
+ {
+ int scroll_gtk2iup[4] = {IUP_SBUP, IUP_SBDN, IUP_SBLEFT, IUP_SBRIGHT};
+ int op = scroll_gtk2iup[evt->direction];
+ scb(ih,op,ih->data->posx,ih->data->posy);
+ }
+ }
+ (void)widget;
+ return TRUE;
+}
+
+static gboolean gtkCanvasButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ if (evt->type == GDK_BUTTON_PRESS)
+ {
+ /* Force focus on canvas click */
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ gtk_widget_grab_focus(ih->handle);
+ }
+
+ return iupgtkButtonEvent(widget, evt, ih);
+}
+
+static int gtkCanvasSetBgColorAttrib(Ihandle* ih, const char* value);
+
+static gboolean gtkCanvasExposeEvent(GtkWidget *widget, GdkEventExpose *evt, Ihandle *ih)
+{
+ IFnff cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ {
+ if (!iupAttribGet(ih, "_IUPGTK_NO_BGCOLOR"))
+ gtkCanvasSetBgColorAttrib(ih, iupAttribGetStr(ih, "BGCOLOR")); /* reset to update window attributes */
+
+ iupAttribSetStrf(ih, "CLIPRECT", "%d %d %d %d", evt->area.x, evt->area.y, evt->area.x+evt->area.width-1, evt->area.y+evt->area.height-1);
+ cb(ih,ih->data->posx,ih->data->posy);
+ iupAttribSetStr(ih, "CLIPRECT", NULL);
+ }
+
+ (void)widget;
+ return TRUE; /* stop other handlers */
+}
+
+static gboolean gtkCanvasConfigureEvent(GtkWidget *widget, GdkEventConfigure *evt, Ihandle *ih)
+{
+ IFnii cb = (IFnii)IupGetCallback(ih,"RESIZE_CB");
+ if (cb)
+ cb(ih,evt->width,evt->height);
+
+ (void)widget;
+ return FALSE;
+}
+
+static GtkScrolledWindow* gtkCanvasGetScrolledWindow(Ihandle* ih)
+{
+ return (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+}
+
+static int gtkCanvasSetXAutoHideAttrib(Ihandle* ih, const char *value)
+{
+ GtkPolicyType vscrollbar_policy;
+ gtk_scrolled_window_get_policy(gtkCanvasGetScrolledWindow(ih), NULL, &vscrollbar_policy);
+
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ GtkPolicyType hscrollbar_policy;
+
+ if (iupStrBoolean(value))
+ hscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ else
+ hscrollbar_policy = GTK_POLICY_ALWAYS;
+
+ gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), hscrollbar_policy, vscrollbar_policy);
+ }
+ else
+ gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), GTK_POLICY_NEVER, vscrollbar_policy);
+
+ return 1;
+}
+
+static int gtkCanvasSetYAutoHideAttrib(Ihandle* ih, const char *value)
+{
+ GtkPolicyType hscrollbar_policy;
+ gtk_scrolled_window_get_policy(gtkCanvasGetScrolledWindow(ih), &hscrollbar_policy, NULL);
+
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ GtkPolicyType vscrollbar_policy;
+
+ if (iupStrBoolean(value))
+ vscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ else
+ vscrollbar_policy = GTK_POLICY_ALWAYS;
+
+ gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), hscrollbar_policy, vscrollbar_policy);
+ }
+ else
+ gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), hscrollbar_policy, GTK_POLICY_NEVER);
+
+ return 1;
+}
+
+static int gtkCanvasCheckScroll(double min, double max, double *page, double *pos)
+{
+ double old_pos = *pos;
+ double range = max-min;
+ if (*page > range) *page = range;
+ if (*page <= 0) *page = range/10.;
+
+ if (*pos < min) *pos = min;
+ if (*pos > (max - *page)) *pos = max - *page;
+
+ if (old_pos == *pos)
+ return 0;
+ else
+ return 1;
+}
+
+static int gtkCanvasSetDXAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ double xmin, xmax, linex;
+ float dx;
+ int value_changed;
+ GtkAdjustment* sb_horiz = gtk_scrolled_window_get_hadjustment(gtkCanvasGetScrolledWindow(ih));
+ if (!sb_horiz) return 1;
+
+ if (!iupStrToFloat(value, &dx))
+ return 1;
+
+ xmin = iupAttribGetFloat(ih, "XMIN");
+ xmax = iupAttribGetFloat(ih, "XMAX");
+
+ if (!iupAttribGet(ih,"LINEX"))
+ {
+ linex = dx/10;
+ if (linex==0)
+ linex = 1;
+ }
+ else
+ linex = iupAttribGetFloat(ih,"LINEX");
+
+ sb_horiz->lower = xmin;
+ sb_horiz->upper = xmax;
+ sb_horiz->step_increment = linex;
+ sb_horiz->page_size = dx;
+
+ value_changed = gtkCanvasCheckScroll(xmin, xmax, &sb_horiz->page_size, &sb_horiz->value);
+ sb_horiz->page_increment = sb_horiz->page_size;
+
+ gtk_adjustment_changed(sb_horiz);
+
+ if (value_changed)
+ gtk_adjustment_value_changed(sb_horiz);
+ }
+ return 1;
+}
+
+static int gtkCanvasSetDYAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ double ymin, ymax, liney;
+ float dy;
+ int value_changed;
+ GtkAdjustment* sb_vert = gtk_scrolled_window_get_vadjustment(gtkCanvasGetScrolledWindow(ih));
+ if (!sb_vert) return 1;
+
+ if (!iupStrToFloat(value, &dy))
+ return 1;
+
+ ymin = iupAttribGetFloat(ih, "YMIN");
+ ymax = iupAttribGetFloat(ih, "YMAX");
+
+ if (!iupAttribGet(ih,"LINEY"))
+ {
+ liney = dy/10;
+ if (liney==0)
+ liney = 1;
+ }
+ else
+ liney = iupAttribGetFloat(ih,"LINEY");
+
+ sb_vert->lower = ymin;
+ sb_vert->upper = ymax;
+ sb_vert->step_increment = liney;
+ sb_vert->page_size = dy;
+
+ value_changed = gtkCanvasCheckScroll(ymin, ymax, &sb_vert->page_size, &sb_vert->value);
+ sb_vert->page_increment = sb_vert->page_size;
+
+ gtk_adjustment_changed(sb_vert);
+
+ if (value_changed)
+ gtk_adjustment_value_changed(sb_vert);
+ }
+ return 1;
+}
+
+static int gtkCanvasSetPosXAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ float posx, xmin, xmax, dx;
+ GtkAdjustment* sb_horiz = gtk_scrolled_window_get_hadjustment(gtkCanvasGetScrolledWindow(ih));
+ if (!sb_horiz) return 1;
+
+ if (!iupStrToFloat(value, &posx))
+ return 1;
+
+ xmin = iupAttribGetFloat(ih, "XMIN");
+ xmax = iupAttribGetFloat(ih, "XMAX");
+ dx = iupAttribGetFloat(ih, "DX");
+
+ if (posx < xmin) posx = xmin;
+ if (posx > (xmax - dx)) posx = xmax - dx;
+ ih->data->posx = posx;
+
+ gtk_adjustment_set_value(sb_horiz, posx);
+ }
+ return 1;
+}
+
+static int gtkCanvasSetPosYAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ float posy, ymin, ymax, dy;
+ GtkAdjustment* sb_vert = gtk_scrolled_window_get_vadjustment(gtkCanvasGetScrolledWindow(ih));
+ if (!sb_vert) return 1;
+
+ if (!iupStrToFloat(value, &posy))
+ return 1;
+
+ ymin = iupAttribGetFloat(ih, "YMIN");
+ ymax = iupAttribGetFloat(ih, "YMAX");
+ dy = iupAttribGetFloat(ih, "DY");
+
+ if (posy < ymin) posy = ymin;
+ if (posy > (ymax - dy)) posy = ymax - dy;
+ ih->data->posy = posy;
+
+ gtk_adjustment_set_value(sb_vert, posy);
+ }
+ return 1;
+}
+
+static int gtkCanvasSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ GtkScrolledWindow* scrolled_window = gtkCanvasGetScrolledWindow(ih);
+ unsigned char r, g, b;
+
+ /* ignore given value, must use only from parent for the scrollbars */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ if (iupStrToRGB(parent_value, &r, &g, &b))
+ {
+ GtkWidget* sb;
+
+ iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ sb = gtk_scrolled_window_get_hscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+ sb = gtk_scrolled_window_get_vscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+#endif
+ }
+
+ if (!IupGetCallback(ih, "ACTION"))
+ {
+ /* enable automatic double buffering */
+ gtk_widget_set_double_buffered(ih->handle, TRUE);
+ gtk_widget_set_double_buffered((GtkWidget*)scrolled_window, TRUE);
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+ }
+ else
+ {
+ /* disable automatic double buffering */
+ gtk_widget_set_double_buffered(ih->handle, FALSE);
+ gtk_widget_set_double_buffered((GtkWidget*)scrolled_window, FALSE);
+ gdk_window_set_back_pixmap(ih->handle->window, NULL, FALSE);
+ iupAttribSetStr(ih, "_IUPGTK_NO_BGCOLOR", "1");
+ return 1;
+ }
+}
+
+static char* gtkCanvasGetDrawableAttrib(Ihandle* ih)
+{
+ return (char*)ih->handle->window;
+}
+
+static void gtkCanvasDummyLogFunc(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
+{
+ /* does nothing */
+ (void)log_domain;
+ (void)log_level;
+ (void)message;
+ (void)user_data;
+}
+
+static int gtkCanvasMapMethod(Ihandle* ih)
+{
+ GtkScrolledWindow* scrolled_window;
+ void* visual;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ ih->data->sb = iupBaseGetScrollbar(ih);
+
+ visual = (void*)IupGetAttribute(ih, "VISUAL"); /* defined by the OpenGL Canvas in X11 or NULL */
+ if (visual)
+ iupgtkPushVisualAndColormap(visual, (void*)iupAttribGet(ih, "COLORMAP"));
+
+ ih->handle = gtk_drawing_area_new();
+
+ if (visual)
+ gtk_widget_pop_colormap();
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL);
+ if (!scrolled_window)
+ return IUP_ERROR;
+
+ {
+ /* to avoid the "cannot add non scrollable widget" warning */
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GLogFunc def_func = g_log_set_default_handler(gtkCanvasDummyLogFunc, NULL);
+#endif
+ gtk_container_add((GtkContainer*)scrolled_window, ih->handle);
+#if GTK_CHECK_VERSION(2, 6, 0)
+ g_log_set_default_handler(def_func, NULL);
+#endif
+ }
+
+ gtk_widget_show((GtkWidget*)scrolled_window);
+
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window);
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(iupgtkKeyReleaseEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "expose-event", G_CALLBACK(gtkCanvasExposeEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkCanvasButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkCanvasButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "scroll-event",G_CALLBACK(gtkCanvasScrollEvent), ih);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ g_signal_connect(G_OBJECT(gtk_scrolled_window_get_hscrollbar(scrolled_window)), "change-value",G_CALLBACK(gtkCanvasHChangeValue), ih);
+ g_signal_connect(G_OBJECT(gtk_scrolled_window_get_vscrollbar(scrolled_window)), "change-value",G_CALLBACK(gtkCanvasVChangeValue), ih);
+#endif
+
+ /* 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_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK|
+ GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK|
+ GDK_FOCUS_CHANGE_MASK|GDK_STRUCTURE_MASK);
+
+ /* To receive keyboard events, you will need to set the GTK_CAN_FOCUS flag on the drawing area. */
+ if (ih->iclass->is_interactive)
+ {
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) |= GTK_CAN_FOCUS;
+ }
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN);
+ else
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_NONE);
+
+ gtk_widget_realize((GtkWidget*)scrolled_window);
+ gtk_widget_realize(ih->handle);
+
+ /* must be connected after realize or a RESIZE_CB will happen before MAP_CB
+ works only for the GtkDrawingArea. */
+ g_signal_connect(G_OBJECT(ih->handle), "configure-event", G_CALLBACK(gtkCanvasConfigureEvent), ih);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ /* update a mnemonic in a label if necessary */
+ iupgtkUpdateMnemonic(ih);
+
+ /* configure scrollbar */
+ if (ih->data->sb)
+ {
+ GtkPolicyType hscrollbar_policy = GTK_POLICY_NEVER, vscrollbar_policy = GTK_POLICY_NEVER;
+ if (ih->data->sb & IUP_SB_HORIZ)
+ hscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ if (ih->data->sb & IUP_SB_VERT)
+ vscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ gtk_scrolled_window_set_policy(scrolled_window, hscrollbar_policy, vscrollbar_policy);
+ }
+ else
+ gtk_scrolled_window_set_policy(scrolled_window, GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+
+ /* force the update of BGCOLOR here, to let derived classes ignore it if ACTION is defined */
+ gtkCanvasSetBgColorAttrib(ih, iupAttribGetStr(ih, "BGCOLOR"));
+
+ return IUP_NOERROR;
+}
+
+void iupdrvCanvasInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkCanvasMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkCanvasSetBgColorAttrib, "255 255 255", NULL, IUPAF_DEFAULT); /* force new default value */
+
+ /* IupCanvas only */
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CURSOR", NULL, iupdrvBaseSetCursorAttrib, IUPAF_SAMEASSYSTEM, "ARROW", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAWSIZE", iupdrvBaseGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "DX", NULL, gtkCanvasSetDXAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "DY", NULL, gtkCanvasSetDYAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "POSX", iupCanvasGetPosXAttrib, gtkCanvasSetPosXAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "POSY", iupCanvasGetPosYAttrib, gtkCanvasSetPosYAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "XAUTOHIDE", NULL, gtkCanvasSetXAutoHideAttrib, "YES", NULL, IUPAF_DEFAULT); /* force new default value */
+ 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);
+#endif
+}
+
diff --git a/iup/src/gtk/iupgtk_clipboard.c b/iup/src/gtk/iupgtk_clipboard.c
new file mode 100755
index 0000000..f07a3e6
--- /dev/null
+++ b/iup/src/gtk/iupgtk_clipboard.c
@@ -0,0 +1,125 @@
+/** \file
+ * \brief Clipboard for the GTK Driver.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+
+#include "iupgtk_drv.h"
+
+
+static int gtkClipboardSetTextAttrib(Ihandle *ih, const char *value)
+{
+ GtkClipboard *clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), gdk_atom_intern("CLIPBOARD", FALSE));
+ gtk_clipboard_set_text(clipboard, value, -1);
+ (void)ih;
+ return 0;
+}
+
+static char* gtkClipboardGetTextAttrib(Ihandle *ih)
+{
+ GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE));
+ (void)ih;
+ return iupgtkStrConvertFromUTF8(gtk_clipboard_wait_for_text(clipboard));
+}
+
+static int gtkClipboardSetImageAttrib(Ihandle *ih, const char *value)
+{
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE));
+ GdkPixbuf *pixbuf = (GdkPixbuf*)iupImageGetImage(value, ih, 0);
+ if (pixbuf)
+ gtk_clipboard_set_image (clipboard, pixbuf);
+#endif
+ return 0;
+}
+
+static int gtkClipboardSetNativeImageAttrib(Ihandle *ih, const char *value)
+{
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GtkClipboard *clipboard;
+ (void)ih;
+
+ if (!value)
+ return 0;
+
+ clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE));
+
+ gtk_clipboard_set_image (clipboard, (GdkPixbuf*)value);
+#endif
+ return 0;
+}
+
+static char* gtkClipboardGetNativeImageAttrib(Ihandle *ih)
+{
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE));
+ (void)ih;
+ return (char*)gtk_clipboard_wait_for_image (clipboard);
+#else
+ return NULL;
+#endif
+}
+
+static char* gtkClipboardGetTextAvailableAttrib(Ihandle *ih)
+{
+ GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE));
+ (void)ih;
+ if (gtk_clipboard_wait_is_text_available(clipboard))
+ return "YES";
+ else
+ return "NO";
+}
+
+static char* gtkClipboardGetImageAvailableAttrib(Ihandle *ih)
+{
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE));
+ (void)ih;
+ if (gtk_clipboard_wait_is_image_available(clipboard))
+ return "YES";
+ else
+ return "NO";
+#else
+ return NULL;
+#endif
+}
+
+/******************************************************************************/
+
+Ihandle* IupClipboard(void)
+{
+ return IupCreate("clipboard");
+}
+
+Iclass* iupClipboardGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "clipboard";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Attribute functions */
+ iupClassRegisterAttribute(ic, "TEXT", gtkClipboardGetTextAttrib, gtkClipboardSetTextAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "NATIVEIMAGE", gtkClipboardGetNativeImageAttrib, gtkClipboardSetNativeImageAttrib, NULL, NULL, IUPAF_NO_STRING|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkClipboardSetImageAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TEXTAVAILABLE", gtkClipboardGetTextAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEAVAILABLE", gtkClipboardGetImageAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
diff --git a/iup/src/gtk/iupgtk_colordlg.c b/iup/src/gtk/iupgtk_colordlg.c
new file mode 100755
index 0000000..9177f91
--- /dev/null
+++ b/iup/src/gtk/iupgtk_colordlg.c
@@ -0,0 +1,211 @@
+/** \file
+ * \brief IupColorDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <string.h>
+#include <memory.h>
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+
+#include "iupgtk_drv.h"
+
+
+static char* gtkColorDlgPaletteToString(const char* palette)
+{
+ char iup_str[20], *gtk_str, *palette_p;
+ char* str = iupStrGetMemory(300);
+ int off = 0, inc;
+ GdkColor color;
+
+ gtk_str = iupStrDup(palette);
+ iupStrReplace(gtk_str, ':', 0);
+
+ while (palette && *palette)
+ {
+ if (!gdk_color_parse (gtk_str, &color))
+ return NULL;
+
+ inc = sprintf(iup_str, "%d %d %d;", (int)iupCOLOR16TO8(color.red), (int)iupCOLOR16TO8(color.green), (int)iupCOLOR16TO8(color.blue));
+ memcpy(str+off, iup_str, inc);
+ off += inc;
+ palette_p = strchr(palette, ':');
+ if (palette_p)
+ {
+ palette_p++;
+ gtk_str += palette_p-palette;
+ }
+ palette = palette_p;
+ }
+ str[off-1] = 0; /* remove last separator */
+ return str;
+}
+
+static void gtkColorDlgGetPalette(Ihandle* ih, GtkColorSelection* colorsel)
+{
+ char *palette, *str;
+
+ GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(colorsel));
+ g_object_get(settings, "gtk-color-palette", &palette, NULL);
+
+ str = gtkColorDlgPaletteToString(palette);
+ if (str) iupAttribStoreStr(ih, "COLORTABLE", str);
+ g_free(palette);
+}
+
+static char* gtkColorDlgStringToPalette(const char* str)
+{
+ char gtk_str[20];
+ char* palette = iupStrGetMemory(200);
+ int off = 0;
+ unsigned char r, g, b;
+
+ while (str && *str)
+ {
+ if (!iupStrToRGB(str, &r, &g, &b))
+ return NULL;
+
+ sprintf(gtk_str, "#%02X%02X%02X:", (int)r, (int)g, (int)b);
+ memcpy(palette+off, gtk_str, 8);
+ off += 8;
+ str = strchr(str, ';');
+ if (str) str++;
+ }
+ palette[off-1] = 0; /* remove last separator */
+ return palette;
+}
+
+static void gtkColorDlgSetPalette(GtkColorSelection* colorsel, char* str)
+{
+ GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(colorsel));
+ gchar* palette = gtkColorDlgStringToPalette(str);
+ if (palette)
+ gtk_settings_set_string_property(settings,
+ "gtk-color-palette",
+ palette,
+ "gtk_color_selection_palette_to_string");
+}
+
+static int gtkColorDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ GtkColorSelectionDialog* dialog;
+ GtkColorSelection* colorsel;
+ GdkColor color;
+ char *value;
+ unsigned char r = 0, g = 0, b = 0, a = 255;
+ int response, ret;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ dialog = (GtkColorSelectionDialog*)gtk_color_selection_dialog_new(iupgtkStrConvertToUTF8(iupAttribGet(ih, "TITLE")));
+ if (!dialog)
+ return IUP_ERROR;
+
+ if (parent)
+ gtk_window_set_transient_for((GtkWindow*)dialog, (GtkWindow*)parent);
+
+ ret = iupStrToRGBA(iupAttribGet(ih, "VALUE"), &r, &g, &b, &a);
+
+ colorsel = (GtkColorSelection*)dialog->colorsel;
+ iupgdkColorSet(&color, r, g, b);
+ gtk_color_selection_set_current_color(colorsel, &color);
+
+ value = iupAttribGetStr(ih, "ALPHA");
+ if (value)
+ {
+ int alpha;
+ if (iupStrToInt(value, &alpha))
+ {
+ if (alpha<0) alpha=0;
+ if (alpha>255) alpha=255;
+ gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
+ gtk_color_selection_set_current_alpha(colorsel, iupCOLOR8TO16(alpha));
+ }
+ }
+ else if (iupAttribGetBoolean(ih, "SHOWALPHA") || ret == 4)
+ {
+ gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
+ gtk_color_selection_set_current_alpha(colorsel, iupCOLOR8TO16(a));
+ }
+ else
+ gtk_color_selection_set_has_opacity_control(colorsel, FALSE);
+
+ value = iupAttribGetStr(ih, "COLORTABLE");
+ if (value)
+ {
+ gtk_color_selection_set_has_palette (colorsel, TRUE);
+ gtkColorDlgSetPalette(colorsel, value);
+ }
+ else if (iupAttribGetBoolean(ih, "SHOWCOLORTABLE"))
+ gtk_color_selection_set_has_palette (colorsel, TRUE);
+ else
+ gtk_color_selection_set_has_palette (colorsel, FALSE);
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ gtk_widget_show(dialog->help_button);
+
+ /* initialize the widget */
+ gtk_widget_realize(GTK_WIDGET(dialog));
+
+ ih->handle = GTK_WIDGET(dialog);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL;
+
+ do
+ {
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+ if (response == GTK_RESPONSE_HELP)
+ {
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ response = GTK_RESPONSE_CANCEL;
+ }
+ } while (response == GTK_RESPONSE_HELP);
+
+ if (response == GTK_RESPONSE_OK)
+ {
+ GdkColor color;
+ gtk_color_selection_get_current_color(colorsel, &color);
+ IupSetAttribute(ih, "STATUS", "1");
+
+ if (gtk_color_selection_get_has_opacity_control(colorsel))
+ {
+ int alpha = gtk_color_selection_get_current_alpha(colorsel);
+ iupAttribSetInt(ih, "ALPHA", (int)iupCOLOR16TO8(alpha));
+ iupAttribSetStrf(ih, "VALUE", "%d %d %d %d", (int)iupCOLOR16TO8(color.red), (int)iupCOLOR16TO8(color.green), (int)iupCOLOR16TO8(color.blue), (int)iupCOLOR16TO8(alpha));
+ }
+ else
+ iupAttribSetStrf(ih, "VALUE", "%d %d %d", (int)iupCOLOR16TO8(color.red), (int)iupCOLOR16TO8(color.green), (int)iupCOLOR16TO8(color.blue));
+
+ if (gtk_color_selection_get_has_palette(colorsel))
+ gtkColorDlgGetPalette(ih, colorsel);
+ }
+ else
+ {
+ iupAttribSetStr(ih, "ALPHA", NULL);
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "COLORTABLE", NULL);
+ iupAttribSetStr(ih, "STATUS", NULL);
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+
+ return IUP_NOERROR;
+}
+
+void iupdrvColorDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = gtkColorDlgPopup;
+}
diff --git a/iup/src/gtk/iupgtk_common.c b/iup/src/gtk/iupgtk_common.c
new file mode 100755
index 0000000..40368f2
--- /dev/null
+++ b/iup/src/gtk/iupgtk_common.c
@@ -0,0 +1,830 @@
+/** \file
+ * \brief GTK Base Functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+#include "iupkey.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_key.h"
+#include "iup_str.h"
+#include "iup_class.h"
+#include "iup_attrib.h"
+#include "iup_focus.h"
+#include "iup_key.h"
+#include "iup_image.h"
+#include "iup_drv.h"
+
+#include "iupgtk_drv.h"
+
+
+/* WARNING: in GTK there are many controls that are not native windows,
+ so "->window" will NOT return a native window exclusive of that control,
+ in fact it can return a base native window shared by many controls.
+ IupCanvas is a special case that uses an exclusive native window. */
+
+/* GTK only has abssolute positioning using a GtkFixed container,
+ so all elements returned by iupChildTreeGetNativeParentHandle should be a GtkFixed.
+ If not looks in the native parent. */
+static GtkFixed* gtkGetFixedParent(Ihandle* ih)
+{
+ GtkWidget* widget = iupChildTreeGetNativeParentHandle(ih);
+ while (widget && !GTK_IS_FIXED(widget))
+ widget = gtk_widget_get_parent(widget);
+ return (GtkFixed*)widget;
+}
+
+void iupgtkUpdateMnemonic(Ihandle* ih)
+{
+ GtkLabel* label = (GtkLabel*)iupAttribGet(ih, "_IUPGTK_LABELMNEMONIC");
+ if (label) gtk_label_set_mnemonic_widget(label, ih->handle);
+}
+
+void iupdrvActivate(Ihandle* ih)
+{
+ gtk_widget_activate(ih->handle);
+}
+
+void iupdrvReparent(Ihandle* ih)
+{
+ GtkFixed* fixed = gtkGetFixedParent(ih);
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+ gtk_widget_reparent(widget, (GtkWidget*)fixed);
+}
+
+void iupgtkBaseAddToParent(Ihandle* ih)
+{
+ GtkFixed* fixed = gtkGetFixedParent(ih);
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+
+ gtk_fixed_put(fixed, widget, 0, 0);
+}
+
+void iupdrvBaseLayoutUpdateMethod(Ihandle *ih)
+{
+ GtkFixed* fixed = gtkGetFixedParent(ih);
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+
+ gtk_fixed_move(fixed, widget, ih->x, ih->y);
+ gtk_widget_set_size_request(widget, ih->currentwidth, ih->currentheight);
+}
+
+void iupdrvBaseUnMapMethod(Ihandle* ih)
+{
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+ gtk_widget_unrealize(widget);
+ gtk_widget_destroy(widget); /* To match the call to gtk_*****_new */
+}
+
+void iupdrvDisplayUpdate(Ihandle *ih)
+{
+ /* Post a REDRAW */
+ gtk_widget_queue_draw(ih->handle);
+}
+
+void iupdrvDisplayRedraw(Ihandle *ih)
+{
+ GdkWindow* window = ih->handle->window;
+ /* Post a REDRAW */
+ gtk_widget_queue_draw(ih->handle);
+ /* Force a REDRAW */
+ if (window)
+ gdk_window_process_updates(window, FALSE);
+}
+
+void iupdrvScreenToClient(Ihandle* ih, int *x, int *y)
+{
+ gint win_x = 0, win_y = 0;
+ GdkWindow* window = ih->handle->window;
+ if (window)
+ gdk_window_get_origin(window, &win_x, &win_y);
+ *x = *x - win_x;
+ *y = *y - win_y;
+}
+
+gboolean iupgtkShowHelp(GtkWidget *widget, GtkWidgetHelpType *arg1, Ihandle *ih)
+{
+ Icallback cb;
+ (void)widget;
+ (void)arg1;
+
+ cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+
+ return FALSE;
+}
+
+gboolean iupgtkEnterLeaveEvent(GtkWidget *widget, GdkEventCrossing *evt, Ihandle *ih)
+{
+ Icallback cb = NULL;
+ (void)widget;
+
+ if (evt->type == GDK_ENTER_NOTIFY)
+ cb = IupGetCallback(ih, "ENTERWINDOW_CB");
+ else if (evt->type == GDK_LEAVE_NOTIFY)
+ cb = IupGetCallback(ih, "LEAVEWINDOW_CB");
+
+ if (cb)
+ cb(ih);
+
+ return FALSE;
+}
+
+int iupgtkSetMnemonicTitle(Ihandle* ih, GtkLabel* label, const char* value)
+{
+ char c = '_';
+ char* str;
+
+ if (!value)
+ value = "";
+
+ str = iupStrProcessMnemonic(value, &c, 1); /* replace & by c, the returned value of c is ignored in GTK */
+ if (str != value)
+ {
+ gtk_label_set_text_with_mnemonic(label, iupgtkStrConvertToUTF8(str));
+ free(str);
+ return 1;
+ }
+ else
+ {
+ if (iupAttribGetBoolean(ih, "MARKUP"))
+ gtk_label_set_markup(label, iupgtkStrConvertToUTF8(str));
+ else
+ gtk_label_set_text(label, iupgtkStrConvertToUTF8(str));
+ }
+ return 0;
+}
+
+int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value)
+{
+ if (iupdrvIsVisible(ih))
+ {
+ GdkWindow* window = ih->handle->window;
+ if (iupStrEqualNoCase(value, "TOP"))
+ gdk_window_raise(window);
+ else
+ gdk_window_lower(window);
+ }
+
+ return 0;
+}
+
+void iupdrvSetVisible(Ihandle* ih, int visible)
+{
+ GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (visible)
+ {
+ if (container) gtk_widget_show(container);
+ gtk_widget_show(ih->handle);
+ }
+ else
+ {
+ if (container) gtk_widget_hide(container);
+ gtk_widget_hide(ih->handle);
+ }
+}
+
+int iupdrvIsVisible(Ihandle* ih)
+{
+ if (GTK_WIDGET_VISIBLE(ih->handle))
+ {
+ /* if marked as visible, since we use gtk_widget_hide and NOT gtk_widget_hide_all
+ must check its parents. */
+ Ihandle* parent = ih->parent;
+ while (parent)
+ {
+ if (parent->iclass->nativetype != IUP_TYPEVOID)
+ {
+ if (!GTK_WIDGET_VISIBLE(parent->handle))
+ return 0;
+ }
+
+ parent = parent->parent;
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int iupdrvIsActive(Ihandle *ih)
+{
+ return (GTK_WIDGET_IS_SENSITIVE(ih->handle));
+}
+
+void iupdrvSetActive(Ihandle* ih, int enable)
+{
+ GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (container) gtk_widget_set_sensitive(container, enable);
+ gtk_widget_set_sensitive(ih->handle, enable);
+}
+
+char* iupdrvBaseGetXAttrib(Ihandle *ih)
+{
+ GdkWindow* window = ih->handle->window;
+ GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (container) window = container->window;
+
+ if (window)
+ {
+ char* str = iupStrGetMemory(20);
+ int x, y;
+ gdk_window_get_origin(window, &x, &y);
+ x += ih->handle->allocation.x;
+ sprintf(str, "%d", x);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+char* iupdrvBaseGetYAttrib(Ihandle *ih)
+{
+ GdkWindow* window = ih->handle->window;
+ GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (container) window = container->window;
+
+ if (window)
+ {
+ char* str = iupStrGetMemory(20);
+ int x, y;
+ gdk_window_get_origin(window, &x, &y);
+ y += ih->handle->allocation.y;
+ sprintf(str, "%d", y);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+char* iupdrvBaseGetClientSizeAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+ int w, h;
+ GdkWindow* window = ih->handle->window;
+
+ if (window)
+ gdk_drawable_get_size(window, &w, &h);
+ else
+ return NULL;
+
+ sprintf(str, "%dx%d", w, h);
+ return str;
+}
+
+static GdkColor gtkDarkerColor(GdkColor *color)
+{
+ GdkColor dark_color = {0L,0,0,0};
+
+ dark_color.red = (color->red*9)/10;
+ dark_color.green = (color->green*9)/10;
+ dark_color.blue = (color->blue*9)/10;
+
+ return dark_color;
+}
+
+static guint16 gtkCROP16(int x)
+{
+ if (x > 65535) return 65535;
+ return (guint16)x;
+}
+
+static GdkColor gtkLighterColor(GdkColor *color)
+{
+ GdkColor light_color = {0L,0,0,0};
+
+ light_color.red = gtkCROP16(((int)color->red*11)/10);
+ light_color.green = gtkCROP16(((int)color->green*11)/10);
+ light_color.blue = gtkCROP16(((int)color->blue*11)/10);
+
+ return light_color;
+}
+
+void iupgtkBaseSetBgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b)
+{
+ GtkRcStyle *rc_style;
+ GdkColor color;
+
+ iupgdkColorSet(&color, r, g, b);
+
+ rc_style = gtk_widget_get_modifier_style(handle);
+ rc_style->base[GTK_STATE_NORMAL] = rc_style->bg[GTK_STATE_NORMAL] = rc_style->bg[GTK_STATE_INSENSITIVE] = color;
+ rc_style->bg[GTK_STATE_ACTIVE] = rc_style->base[GTK_STATE_ACTIVE] = gtkDarkerColor(&color);
+ rc_style->base[GTK_STATE_PRELIGHT] = rc_style->bg[GTK_STATE_PRELIGHT] = rc_style->base[GTK_STATE_INSENSITIVE] = gtkLighterColor(&color);
+
+ rc_style->color_flags[GTK_STATE_NORMAL] |= GTK_RC_BASE | GTK_RC_BG;
+ rc_style->color_flags[GTK_STATE_ACTIVE] |= GTK_RC_BASE | GTK_RC_BG;
+ rc_style->color_flags[GTK_STATE_PRELIGHT] |= GTK_RC_BASE | GTK_RC_BG;
+ rc_style->color_flags[GTK_STATE_INSENSITIVE] |= GTK_RC_BASE | GTK_RC_BG;
+
+ gtk_widget_modify_style(handle, rc_style);
+}
+
+int iupdrvBaseSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetBgColor(ih->handle, r, g, b);
+
+ /* DO NOT NEED TO UPDATE GTK IMAGES SINCE THEY DO NOT DEPEND ON BGCOLOR */
+
+ return 1;
+}
+
+void iupgtkBaseSetFgGdkColor(InativeHandle* handle, GdkColor *color)
+{
+ GtkRcStyle *rc_style;
+
+ rc_style = gtk_widget_get_modifier_style(handle);
+ rc_style->fg[GTK_STATE_ACTIVE] = rc_style->fg[GTK_STATE_NORMAL] = rc_style->fg[GTK_STATE_PRELIGHT] = *color;
+ rc_style->text[GTK_STATE_ACTIVE] = rc_style->text[GTK_STATE_NORMAL] = rc_style->text[GTK_STATE_PRELIGHT] = *color;
+ rc_style->color_flags[GTK_STATE_NORMAL] |= GTK_RC_TEXT | GTK_RC_FG;
+ rc_style->color_flags[GTK_STATE_ACTIVE] |= GTK_RC_TEXT | GTK_RC_FG;
+ rc_style->color_flags[GTK_STATE_PRELIGHT] |= GTK_RC_TEXT | GTK_RC_FG;
+
+ /* do not set at CHILD_CONTAINER */
+ gtk_widget_modify_style(handle, rc_style);
+}
+
+void iupgtkBaseSetFgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b)
+{
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ iupgtkBaseSetFgGdkColor(handle, &color);
+}
+
+int iupdrvBaseSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(ih->handle, r, g, b);
+
+ return 1;
+}
+
+static GdkCursor* gtkEmptyCursor(Ihandle* ih)
+{
+ /* creates an empty cursor */
+ GdkColor cursor_color = {0L,0,0,0};
+ char bitsnull[1] = {0x00};
+
+ GdkWindow* window = ih->handle->window;
+ GdkPixmap* pixmapnull = gdk_bitmap_create_from_data(
+ (GdkDrawable*)window,
+ bitsnull,
+ 1,1);
+ GdkCursor* cur = gdk_cursor_new_from_pixmap(
+ pixmapnull,
+ pixmapnull,
+ &cursor_color,
+ &cursor_color,
+ 0,0);
+
+ g_object_unref(pixmapnull);
+
+ return cur;
+}
+
+static GdkCursor* gtkGetCursor(Ihandle* ih, const char* name)
+{
+ static struct {
+ const char* iupname;
+ int sysname;
+ } table[] = {
+ { "NONE", 0},
+ { "NULL", 0},
+ { "ARROW", GDK_LEFT_PTR},
+ { "BUSY", GDK_WATCH},
+ { "CROSS", GDK_CROSSHAIR},
+ { "HAND", GDK_HAND2},
+ { "HELP", GDK_QUESTION_ARROW},
+ { "IUP", GDK_QUESTION_ARROW},
+ { "MOVE", GDK_FLEUR},
+ { "PEN", GDK_PENCIL},
+ { "RESIZE_N", GDK_TOP_SIDE},
+ { "RESIZE_S", GDK_BOTTOM_SIDE},
+ { "RESIZE_NS", GDK_SB_V_DOUBLE_ARROW},
+ { "RESIZE_W", GDK_LEFT_SIDE},
+ { "RESIZE_E", GDK_RIGHT_SIDE},
+ { "RESIZE_WE", GDK_SB_H_DOUBLE_ARROW},
+ { "RESIZE_NE", GDK_TOP_RIGHT_CORNER},
+ { "RESIZE_SE", GDK_BOTTOM_RIGHT_CORNER},
+ { "RESIZE_NW", GDK_TOP_LEFT_CORNER},
+ { "RESIZE_SW", GDK_BOTTOM_LEFT_CORNER},
+ { "TEXT", GDK_XTERM},
+ { "UPARROW", GDK_CENTER_PTR}
+ };
+
+ GdkCursor* cur;
+ char str[50];
+ int i, count = sizeof(table)/sizeof(table[0]);
+
+ /* check the cursor cache first (per control)*/
+ sprintf(str, "_IUPGTK_CURSOR_%s", name);
+ cur = (GdkCursor*)iupAttribGet(ih, str);
+ if (cur)
+ return cur;
+
+ /* check the pre-defined IUP names first */
+ for (i = 0; i < count; i++)
+ {
+ if (iupStrEqualNoCase(name, table[i].iupname))
+ {
+ if (table[i].sysname)
+ cur = gdk_cursor_new(table[i].sysname);
+ else
+ cur = gtkEmptyCursor(ih);
+
+ break;
+ }
+ }
+
+ if (i == count)
+ {
+ /* check for a name defined cursor */
+ cur = iupImageGetCursor(name);
+ }
+
+ /* save the cursor in cache */
+ iupAttribSetStr(ih, str, (char*)cur);
+
+ return cur;
+}
+
+int iupdrvBaseSetCursorAttrib(Ihandle* ih, const char* value)
+{
+ GdkCursor* cur = gtkGetCursor(ih, value);
+ if (cur)
+ {
+ GdkWindow* window = ih->handle->window;
+ if (window)
+ gdk_window_set_cursor(window, cur);
+ return 1;
+ }
+ return 0;
+}
+
+void iupgdkColorSet(GdkColor* color, unsigned char r, unsigned char g, unsigned char b)
+{
+ color->red = iupCOLOR8TO16(r);
+ color->green = iupCOLOR8TO16(g);
+ color->blue = iupCOLOR8TO16(b);
+ color->pixel = 0;
+}
+
+static void gtkDragDataReceived(GtkWidget* w, GdkDragContext* context, int x, int y,
+ GtkSelectionData* seldata, guint info, guint time, Ihandle* ih)
+{
+ gchar **uris = NULL;
+ int i, count;
+
+ IFnsiii cb = (IFnsiii)IupGetCallback(ih, "DROPFILES_CB");
+ if (!cb) return;
+
+#if GTK_CHECK_VERSION(2, 6, 0)
+ uris = g_uri_list_extract_uris((char*)seldata->data);
+#endif
+
+ if (!uris)
+ return;
+
+ count = 0;
+ while (uris[count])
+ count++;
+
+ for (i=0; i<count; i++)
+ {
+ char* filename = uris[i];
+ if (iupStrEqualPartial(filename, "file://"))
+ {
+ filename += strlen("file://");
+ if (filename[2] == ':') /* in Windows there is an extra '/' at the begining. */
+ filename++;
+ }
+ if (cb(ih, filename, count-i-1, x, y) == IUP_IGNORE)
+ break;
+ }
+
+ g_strfreev (uris);
+ (void)time;
+ (void)info;
+ (void)w;
+ (void)context;
+}
+
+int iupgtkSetDragDropAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ {
+ GtkTargetEntry dragtypes[] = { { "text/uri-list", 0, 0 } };
+ gtk_drag_dest_set(ih->handle, GTK_DEST_DEFAULT_ALL, dragtypes,
+ sizeof(dragtypes) / sizeof(dragtypes[0]), GDK_ACTION_COPY);
+ g_signal_connect(G_OBJECT(ih->handle), "drag_data_received", G_CALLBACK(gtkDragDataReceived), ih);
+ }
+ else
+ {
+ gtk_drag_dest_unset(ih->handle);
+ }
+ return 1;
+}
+
+int iupdrvGetScrollbarSize(void)
+{
+ static int size = 0;
+
+ if (size == 0)
+ {
+ GtkRequisition requisition;
+ GtkWidget* win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ GtkWidget* sb = gtk_vscrollbar_new(NULL);
+ gtk_container_add((GtkContainer*)win, sb);
+ gtk_widget_realize(win);
+ gtk_widget_size_request(sb, &requisition);
+ size = requisition.width;
+ gtk_widget_destroy(win);
+ }
+
+ return size;
+}
+
+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);
+ (void)_gc;
+
+ gtk_paint_focus(style, window, GTK_WIDGET_STATE(ih->handle), NULL, ih->handle, NULL, x, y, w, h);
+}
+
+void iupdrvBaseRegisterCommonAttrib(Iclass* ic)
+{
+#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
+ iupClassRegisterAttribute(ic, "PANGOFONTDESC", iupgtkGetPangoFontDescAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+}
+
+static int gtkStrIsAscii(const char* str)
+{
+ while(*str)
+ {
+ int c = *str;
+ if (c < 0)
+ return 0;
+ str++;
+ }
+ return 1;
+}
+
+static char* gtkStrToUTF8(const char *str, const char* charset)
+{
+ return g_convert(str, -1, "UTF-8", charset, NULL, NULL, NULL);
+}
+
+static char* gtkStrFromUTF8(const char *str, const char* charset)
+{
+ return g_convert(str, -1, charset, "UTF-8", NULL, NULL, NULL);
+}
+
+static char* gktLastConvertUTF8 = NULL;
+
+void iupgtkReleaseConvertUTF8(void)
+{
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+}
+
+char* iupgtkStrConvertToUTF8(const char* str) /* From IUP to GTK */
+{
+ if (!str || *str == 0)
+ return (char*)str;
+
+ if (iupgtk_utf8autoconvert) /* this means str is in current locale */
+ {
+ const char *charset = NULL;
+ if (g_get_charset(&charset)==TRUE) /* current locale is already UTF-8 */
+ {
+ if (g_utf8_validate(str, -1, NULL))
+ return (char*)str;
+ else
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrToUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ else
+ {
+ if (gtkStrIsAscii(str) || !charset)
+ return (char*)str;
+ else if (charset)
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrToUTF8(str, charset);
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ }
+ return (char*)str;
+}
+
+char* iupgtkStrConvertFromUTF8(const char* str) /* From GTK to IUP */
+{
+ if (!str || *str == 0)
+ return (char*)str;
+
+ if (iupgtk_utf8autoconvert) /* this means str is in current locale */
+ {
+ const gchar *charset = NULL;
+ if (g_get_charset(&charset)==TRUE) /* current locale is already UTF-8 */
+ {
+ if (g_utf8_validate(str, -1, NULL))
+ return (char*)str;
+ else
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrFromUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ else
+ {
+ if (gtkStrIsAscii(str) || !charset)
+ return (char*)str;
+ else if (charset)
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrFromUTF8(str, charset);
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ }
+ return (char*)str;
+}
+
+static gboolean gtkGetFilenameCharset(const gchar **filename_charset)
+{
+ const gchar **charsets = NULL;
+ gboolean is_utf8 = FALSE;
+
+#if GTK_CHECK_VERSION(2, 6, 0)
+ is_utf8 = g_get_filename_charsets (&charsets);
+#endif
+
+ if (filename_charset && charsets)
+ *filename_charset = charsets[0];
+
+ return is_utf8;
+}
+
+char* iupgtkStrConvertToFilename(const char* str) /* From IUP to Filename */
+{
+ if (!str || *str == 0)
+ return (char*)str;
+
+ if (iupgtk_utf8autoconvert) /* this means str is in current locale */
+ return (char*)str;
+ else
+ {
+ const gchar *charset = NULL;
+ if (gtkGetFilenameCharset(&charset)==TRUE) /* current locale is already UTF-8 */
+ {
+ if (g_utf8_validate(str, -1, NULL))
+ return (char*)str;
+ else
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrFromUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ else
+ {
+ if (gtkStrIsAscii(str) || !charset)
+ return (char*)str;
+ else if (charset)
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrFromUTF8(str, charset);
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ }
+ return (char*)str;
+}
+
+char* iupgtkStrConvertFromFilename(const char* str) /* From Filename to IUP */
+{
+ if (!str || *str == 0)
+ return (char*)str;
+
+ if (iupgtk_utf8autoconvert) /* this means str is in current locale */
+ return (char*)str;
+ else
+ {
+ const char *charset = NULL;
+ if (gtkGetFilenameCharset(&charset)==TRUE) /* current locale is already UTF-8 */
+ {
+ if (g_utf8_validate(str, -1, NULL))
+ return (char*)str;
+ else
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrToUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ else
+ {
+ if (gtkStrIsAscii(str) || !charset)
+ return (char*)str;
+ else if (charset)
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrToUTF8(str, charset);
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ }
+ return (char*)str;
+}
+
+gboolean iupgtkMotionNotifyEvent(GtkWidget *widget, GdkEventMotion *evt, Ihandle *ih)
+{
+ IFniis cb = (IFniis)IupGetCallback(ih,"MOTION_CB");
+ if (cb)
+ {
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ iupgtkButtonKeySetStatus(evt->state, 0, status, 0);
+ cb(ih, (int)evt->x, (int)evt->y, status);
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+gboolean iupgtkButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ IFniiiis cb = (IFniiiis)IupGetCallback(ih,"BUTTON_CB");
+ if (cb)
+ {
+ int doubleclick = 0, ret, press = 1;
+ int b = IUP_BUTTON1+(evt->button-1);
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+
+ if (evt->type == GDK_BUTTON_RELEASE)
+ press = 0;
+
+ if (evt->type == GDK_2BUTTON_PRESS)
+ doubleclick = 1;
+
+ iupgtkButtonKeySetStatus(evt->state, evt->button, status, doubleclick);
+
+ ret = cb(ih, b, press, (int)evt->x, (int)evt->y, status);
+ if (ret==IUP_CLOSE)
+ IupExitLoop();
+ else if (ret==IUP_IGNORE)
+ return TRUE;
+ }
+
+ (void)widget;
+ return FALSE;
+}
diff --git a/iup/src/gtk/iupgtk_dialog.c b/iup/src/gtk/iupgtk_dialog.c
new file mode 100755
index 0000000..46c0ce1
--- /dev/null
+++ b/iup/src/gtk/iupgtk_dialog.c
@@ -0,0 +1,1023 @@
+/** \file
+ * \brief IupDialog class
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#ifdef HILDON
+#include <hildon/hildon-program.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <time.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_class.h"
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_dlglist.h"
+#include "iup_attrib.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_drvinfo.h"
+#include "iup_focus.h"
+#include "iup_str.h"
+#define _IUPDLG_PRIVATE
+#include "iup_dialog.h"
+#include "iup_image.h"
+
+#include "iupgtk_drv.h"
+
+
+static void gtkDialogSetMinMax(Ihandle* ih, int min_w, int min_h, int max_w, int max_h);
+
+/****************************************************************
+ Utilities
+****************************************************************/
+
+int iupdrvDialogIsVisible(Ihandle* ih)
+{
+ return iupdrvIsVisible(ih);
+}
+
+void iupdrvDialogUpdateSize(Ihandle* ih)
+{
+ int width, height;
+ gtk_window_get_size((GtkWindow*)ih->handle, &width, &height);
+ ih->currentwidth = width;
+ ih->currentheight = height;
+}
+
+void iupdrvDialogGetSize(InativeHandle* handle, int *w, int *h)
+{
+ int width, height;
+ gtk_window_get_size((GtkWindow*)handle, &width, &height);
+ if (w) *w = width;
+ if (h) *h = height;
+}
+
+void iupdrvDialogSetVisible(Ihandle* ih, int visible)
+{
+ if (visible)
+ gtk_widget_show(ih->handle);
+ else
+ gtk_widget_hide(ih->handle);
+}
+
+void iupdrvDialogGetPosition(InativeHandle* handle, int *x, int *y)
+{
+ gtk_window_get_position((GtkWindow*)handle, x, y);
+}
+
+void iupdrvDialogSetPosition(Ihandle *ih, int x, int y)
+{
+ gtk_window_move((GtkWindow*)ih->handle, x, y);
+}
+
+static int gtkDialogGetMenuSize(Ihandle* ih)
+{
+#ifdef HILDON
+ return 0;
+#else
+ if (ih->data->menu)
+ return iupdrvMenuGetMenuBarSize(ih->data->menu);
+ else
+ return 0;
+#endif
+}
+
+static int gtkDialogGetWindowDecor(Ihandle* ih, int *win_border, int *win_caption)
+{
+ int x, y, frame_x, frame_y;
+ gdk_window_get_origin(ih->handle->window, &x, &y);
+ gdk_window_get_root_origin(ih->handle->window, &frame_x, &frame_y);
+ *win_border = x-frame_x;
+ *win_caption = y-frame_y-*win_border;
+ return 1; /* just for compatibility with iupdrvGetWindowDecor */
+}
+
+void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu)
+{
+#ifdef HILDON
+ /* In Hildon, borders have fixed dimensions, but are drawn as part
+ of the client area! */
+ if (border)
+ *border = (iupAttribGetBoolean(ih, "HILDONWINDOW") && !iupAttribGetBoolean(ih, "FULLSCREEN")) ? 12 : 0;
+ if (caption)
+ *caption = 0;
+ if (menu)
+ *menu = 0;
+#else
+ 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_border = has_caption ||
+ iupAttribGetBoolean(ih, "RESIZE") ||
+ iupAttribGetBoolean(ih, "BORDER");
+
+ *menu = gtkDialogGetMenuSize(ih);
+
+ if (ih->handle && iupdrvIsVisible(ih))
+ {
+ int win_border, win_caption;
+
+ if (gtkDialogGetWindowDecor(ih, &win_border, &win_caption))
+ {
+#ifdef WIN32
+ if (*menu)
+ win_caption -= *menu;
+#endif
+
+ *border = 0;
+ if (has_border)
+ *border = win_border;
+
+ *caption = 0;
+ if (has_caption)
+ *caption = win_caption;
+
+ if (!native_border && *border)
+ native_border = win_border;
+
+ if (!native_caption && *caption)
+ native_caption = win_caption;
+ }
+ }
+
+ /* I could not set the size of the window including the decorations when the dialog is hidden */
+ /* So we have to estimate the size of borders and caption when the dialog is hidden */
+
+ *border = 0;
+ if (has_border)
+ {
+ if (native_border)
+ *border = native_border;
+ else
+ *border = 5;
+ }
+
+ *caption = 0;
+ if (has_caption)
+ {
+ if (native_caption)
+ *caption = native_caption;
+ else
+ *caption = 20;
+ }
+#endif
+}
+
+int iupdrvDialogSetPlacement(Ihandle* ih)
+{
+ char* placement;
+ int old_state = ih->data->show_state;
+ ih->data->show_state = IUP_SHOW;
+
+ if (iupAttribGetBoolean(ih, "FULLSCREEN"))
+ {
+ gtk_window_fullscreen((GtkWindow*)ih->handle);
+ return 1;
+ }
+
+ placement = iupAttribGet(ih, "PLACEMENT");
+ if (!placement)
+ {
+ if (old_state == IUP_MAXIMIZE || old_state == IUP_MINIMIZE)
+ ih->data->show_state = IUP_RESTORE;
+
+ gtk_window_unmaximize((GtkWindow*)ih->handle);
+ gtk_window_deiconify((GtkWindow*)ih->handle);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(placement, "MINIMIZED"))
+ {
+ ih->data->show_state = IUP_MINIMIZE;
+ gtk_window_iconify((GtkWindow*)ih->handle);
+ }
+ else if (iupStrEqualNoCase(placement, "MAXIMIZED"))
+ {
+ ih->data->show_state = IUP_MAXIMIZE;
+ gtk_window_maximize((GtkWindow*)ih->handle);
+ }
+ else if (iupStrEqualNoCase(placement, "FULL"))
+ {
+ int width, height, x, y;
+ int border, caption, menu;
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ /* position the decoration outside the screen */
+ x = -(border);
+ y = -(border+caption+menu);
+
+ /* the dialog client area will cover the task bar */
+ iupdrvGetFullSize(&width, &height);
+
+ height += menu; /* menu is inside the client area. */
+
+ /* set the new size and position */
+ /* The resize evt will update the layout */
+ gtk_window_move((GtkWindow*)ih->handle, x, y);
+ gtk_window_resize((GtkWindow*)ih->handle, width, height);
+
+ if (old_state == IUP_MAXIMIZE || old_state == IUP_MINIMIZE)
+ ih->data->show_state = IUP_RESTORE;
+ }
+
+ iupAttribSetStr(ih, "PLACEMENT", NULL); /* reset to NORMAL */
+
+ return 1;
+}
+
+
+/****************************************************************
+ Callbacks and Events
+****************************************************************/
+
+
+gboolean iupgtkDialogDeleteEvent(GtkWidget *widget, GdkEvent *evt, Ihandle *ih)
+{
+ Icallback cb;
+ (void)widget;
+ (void)evt;
+
+ /* even when ACTIVE=NO the dialog gets this evt */
+ if (!iupdrvIsActive(ih))
+ return TRUE;
+
+ cb = IupGetCallback(ih, "CLOSE_CB");
+ if (cb)
+ {
+ int ret = cb(ih);
+ if (ret == IUP_IGNORE)
+ return TRUE;
+ if (ret == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ IupHide(ih); /* default: close the window */
+
+ return TRUE; /* do not propagate */
+}
+
+static gboolean gtkDialogConfigureEvent(GtkWidget *widget, GdkEventConfigure *evt, Ihandle *ih)
+{
+ int old_width, old_height, old_x, old_y;
+ gint x, y;
+ (void)widget;
+
+#ifndef HILDON
+ /* In hildon the menu is not a menubar */
+ if (ih->data->menu && ih->data->menu->handle)
+ gtk_widget_set_size_request(ih->data->menu->handle, evt->width, -1);
+#endif
+
+ if (ih->data->ignore_resize) return FALSE;
+
+ old_width = iupAttribGetInt(ih, "_IUPGTK_OLD_WIDTH");
+ old_height = iupAttribGetInt(ih, "_IUPGTK_OLD_HEIGHT");
+
+ /* Check the size change, because configure is called also for position changes */
+ if (evt->width != old_width || evt->height != old_height)
+ {
+ IFnii cb;
+ int border, caption, menu;
+ iupAttribSetInt(ih, "_IUPGTK_OLD_WIDTH", evt->width);
+ iupAttribSetInt(ih, "_IUPGTK_OLD_HEIGHT", evt->height);
+
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ /* update dialog size */
+#ifdef HILDON
+ /* In Hildon, the configure event contains the window size, not the client area size */
+ ih->currentwidth = evt->width;
+ ih->currentheight = evt->height;
+#else
+ ih->currentwidth = evt->width + 2*border;
+ ih->currentheight = evt->height + 2*border + caption; /* menu is inside the window client area */
+#endif
+
+ cb = (IFnii)IupGetCallback(ih, "RESIZE_CB");
+ if (!cb || cb(ih, evt->width, evt->height - menu)!=IUP_IGNORE) /* width and height here are for the client area */
+ {
+ ih->data->ignore_resize = 1;
+ IupRefresh(ih);
+ ih->data->ignore_resize = 0;
+ }
+ }
+
+ old_x = iupAttribGetInt(ih, "_IUPGTK_OLD_X");
+ old_y = iupAttribGetInt(ih, "_IUPGTK_OLD_Y");
+ gtk_window_get_position((GtkWindow*)ih->handle, &x, &y); /* ignore evt->x and evt->y because they are the clientpos and not X/Y */
+
+ /* Check the position change, because configure is called also for size changes */
+ if (x != old_x || y != old_y)
+ {
+ IFnii cb;
+ iupAttribSetInt(ih, "_IUPGTK_OLD_X", x);
+ iupAttribSetInt(ih, "_IUPGTK_OLD_Y", y);
+
+ cb = (IFnii)IupGetCallback(ih, "MOVE_CB");
+ if (cb)
+ cb(ih, x, y);
+ }
+
+ return FALSE;
+}
+
+static gboolean gtkDialogWindowStateEvent(GtkWidget *widget, GdkEventWindowState *evt, Ihandle *ih)
+{
+ int state = -1;
+ (void)widget;
+
+ if ((evt->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) && /* if flag changed and */
+ (evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && /* is now set */
+ !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)) /* is visible */
+ state = IUP_MAXIMIZE;
+ else if ((evt->changed_mask & GDK_WINDOW_STATE_ICONIFIED) &&
+ (evt->new_window_state & GDK_WINDOW_STATE_ICONIFIED) &&
+ !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN))
+ state = IUP_MINIMIZE;
+ else if ((evt->changed_mask & GDK_WINDOW_STATE_ICONIFIED) &&
+ (evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
+ !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN))
+ state = IUP_MAXIMIZE;
+ else if (((evt->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) && /* maximized changed */
+ !(evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && /* not maximized */
+ !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) && /* is visible */
+ !(evt->new_window_state & GDK_WINDOW_STATE_ICONIFIED)) /* not minimized */
+ || /* OR */
+ ((evt->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && /* minimized changed */
+ !(evt->new_window_state & GDK_WINDOW_STATE_ICONIFIED) && /* not minimized */
+ !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) && /* is visible */
+ !(evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED))) /* not maximized */
+ state = IUP_RESTORE;
+
+ if (state < 0)
+ return FALSE;
+
+ if (ih->data->show_state != state)
+ {
+ IFni cb;
+ ih->data->show_state = state;
+
+ cb = (IFni)IupGetCallback(ih, "SHOW_CB");
+ if (cb && cb(ih, state) == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ return FALSE;
+}
+
+static gboolean gtkDialogChildDestroyEvent(GtkWidget *widget, Ihandle *ih)
+{
+ /* It seems that the documentation for this callback is not correct */
+ /* The second parameter must be the user_data or it will fail. */
+ (void)widget;
+
+ /* If the IUP dialog was not destroyed, destroy it here. */
+ if (iupObjectCheck(ih))
+ IupDestroy(ih);
+
+ /* this callback is usefull to destroy children dialogs when the parent is destroyed. */
+ /* The application is responsable for destroying the children before this happen. */
+
+ return FALSE;
+}
+
+
+/****************************************************************
+ Idialog Methods
+****************************************************************/
+
+
+/* replace the common dialog SetChildrenPosition method because of
+ the menu that it is inside the dialog. */
+static void gtkDialogSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ int menu_h = gtkDialogGetMenuSize(ih);
+ (void)x;
+ (void)y;
+
+ /* Child coordinates are relative to client left-top corner. */
+ iupBaseSetPosition(ih->firstchild, 0, menu_h);
+}
+
+static void* gtkDialogGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child)
+{
+ (void)child;
+ return (void*)gtk_bin_get_child((GtkBin*)ih->handle);
+}
+
+static int gtkDialogMapMethod(Ihandle* ih)
+{
+ int decorations = 0;
+ int functions = 0;
+ InativeHandle* parent;
+ GtkWidget* fixed;
+
+#ifdef HILDON
+ if (iupAttribGetBoolean(ih, "HILDONWINDOW"))
+ {
+ HildonProgram *program = HILDON_PROGRAM(hildon_program_get_instance());
+ ih->handle = hildon_window_new();
+ if (ih->handle)
+ hildon_program_add_window(program, HILDON_WINDOW(ih->handle));
+ }
+ else
+ {
+ iupAttribSetStr(ih, "DIALOGHINT", "YES"); /* otherwise not displayed correctly */
+ ih->handle = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ }
+#else
+ ih->handle = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+#endif
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ parent = iupDialogGetNativeParent(ih);
+ if (parent)
+ {
+ gtk_window_set_transient_for((GtkWindow*)ih->handle, (GtkWindow*)parent);
+
+ /* manually remove child windows when parent is destroyed */
+ g_signal_connect(G_OBJECT(parent), "destroy", G_CALLBACK(gtkDialogChildDestroyEvent), ih);
+ }
+
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ /* The iupgtkKeyPressEvent of the control with the focus will propagate the key up to the dialog. */
+ /* Inside iupgtkKeyPressEvent we test this to avoid duplicate calls. */
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "configure-event", G_CALLBACK(gtkDialogConfigureEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "window-state-event", G_CALLBACK(gtkDialogWindowStateEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "delete-event", G_CALLBACK(iupgtkDialogDeleteEvent), ih);
+
+ gtk_window_set_default_size((GtkWindow*)ih->handle, 100, 100); /* set this to avoid size calculation problems */
+
+ if (iupAttribGetBoolean(ih, "DIALOGHINT"))
+ gtk_window_set_type_hint(GTK_WINDOW(ih->handle), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ /* the container that will receive the child element. */
+ fixed = gtk_fixed_new();
+ gtk_container_add((GtkContainer*)ih->handle, fixed);
+ gtk_widget_show(fixed);
+
+ /* initialize the widget */
+ gtk_widget_realize(ih->handle);
+
+ if (iupAttribGetBoolean(ih, "DIALOGFRAME")) {
+ iupAttribSetStr(ih, "RESIZE", "NO");
+ }
+
+ if (!iupAttribGetBoolean(ih, "RESIZE")) {
+ iupAttribSetStr(ih, "MAXBOX", "NO"); /* Must also remove these, so RESIZE=NO can work */
+ 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")) {
+ functions |= GDK_FUNC_CLOSE;
+ decorations |= GDK_DECOR_MENU;
+ }
+
+ if (iupAttribGetBoolean(ih, "MINBOX")) {
+ functions |= GDK_FUNC_MINIMIZE;
+ decorations |= GDK_DECOR_MINIMIZE;
+ }
+
+ if (iupAttribGetBoolean(ih, "MAXBOX")) {
+ functions |= GDK_FUNC_MAXIMIZE;
+ decorations |= GDK_DECOR_MAXIMIZE;
+ }
+
+ if (iupAttribGetBoolean(ih, "RESIZE")) {
+ functions |= GDK_FUNC_RESIZE;
+ decorations |= GDK_DECOR_RESIZEH;
+ }
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ decorations |= GDK_DECOR_BORDER;
+
+ if (decorations == 0)
+ gtk_window_set_decorated((GtkWindow*)ih->handle, FALSE);
+ else
+ {
+ GdkWindow* window = ih->handle->window;
+ if (window)
+ {
+ gdk_window_set_decorations(window, (GdkWMDecoration)decorations);
+ gdk_window_set_functions(window, (GdkWMFunction)functions);
+ }
+ }
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ {
+ /* Reset the DLGBGCOLOR global attribute
+ if it is the first time a dialog is created.
+ The value returned by gtk_style_new is not accurate. */
+ GtkStyle* style = gtk_widget_get_style(ih->handle);
+ if (style && IupGetGlobal("_IUP_RESET_GLOBALCOLORS"))
+ {
+ iupgtkUpdateGlobalColors(style);
+ IupSetGlobal("_IUP_RESET_GLOBALCOLORS", NULL);
+ }
+ }
+
+ /* configure the size range */
+ gtkDialogSetMinMax(ih, 1, 1, 65535, 65535); /* MINSIZE and MAXSIZE default values */
+
+ /* Ignore VISIBLE before mapping */
+ iupAttribSetStr(ih, "VISIBLE", NULL);
+
+ return IUP_NOERROR;
+}
+
+static void gtkDialogUnMapMethod(Ihandle* ih)
+{
+ GtkWidget* fixed;
+#if GTK_CHECK_VERSION(2, 10, 0)
+ GtkStatusIcon* status_icon;
+#endif
+
+ if (ih->data->menu)
+ {
+ ih->data->menu->handle = NULL; /* the dialog will destroy the native menu */
+ IupDestroy(ih->data->menu);
+ }
+
+#if GTK_CHECK_VERSION(2, 10, 0)
+ status_icon = (GtkStatusIcon*)iupAttribGet(ih, "_IUPDLG_STATUSICON");
+ if (status_icon)
+ g_object_unref(status_icon);
+#endif
+
+ fixed = gtk_bin_get_child((GtkBin*)ih->handle);
+ gtk_widget_unrealize(fixed);
+ gtk_widget_destroy(fixed);
+
+ gtk_widget_unrealize(ih->handle); /* To match the call to gtk_widget_realize */
+ gtk_widget_destroy(ih->handle); /* To match the call to gtk_window_new */
+}
+
+static void gtkDialogLayoutUpdateMethod(Ihandle *ih)
+{
+ int border, caption, menu;
+ int width, height;
+
+ if (ih->data->ignore_resize ||
+ iupAttribGet(ih, "_IUPGTK_FS_STYLE"))
+ return;
+
+ /* for dialogs the position is not updated here */
+ ih->data->ignore_resize = 1;
+
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ /* set size excluding the border */
+ width = ih->currentwidth - 2*border;
+ height = ih->currentheight - 2*border - caption; /* menu is inside the client area. */
+ gtk_window_resize((GtkWindow*)ih->handle, width, height);
+
+ if (!iupAttribGetBoolean(ih, "RESIZE"))
+ {
+ GdkGeometry geometry;
+ geometry.min_width = width;
+ geometry.min_height = height;
+ geometry.max_width = width;
+ geometry.max_height = height;
+ gtk_window_set_geometry_hints((GtkWindow*)ih->handle, ih->handle,
+ &geometry, (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
+ }
+
+ ih->data->ignore_resize = 0;
+}
+
+
+/****************************************************************************
+ Attributes
+****************************************************************************/
+
+static void gtkDialogSetMinMax(Ihandle* ih, int min_w, int min_h, int max_w, int max_h)
+{
+ /* The minmax size restricts the client area */
+ GdkGeometry geometry;
+ int decorwidth = 0, decorheight = 0;
+ iupDialogGetDecorSize(ih, &decorwidth, &decorheight);
+
+ geometry.min_width = 1;
+ if (min_w > decorwidth)
+ geometry.min_width = min_w-decorwidth;
+
+ geometry.min_height = 1;
+ if (min_h > decorheight)
+ geometry.min_height = min_h-decorheight;
+
+ geometry.max_width = 65535;
+ if (max_w > decorwidth && max_w > geometry.min_width)
+ geometry.max_width = max_w-decorwidth;
+
+ geometry.max_height = 65535;
+ if (max_h > decorheight && max_w > geometry.min_height)
+ geometry.max_height = max_h-decorheight;
+
+ gtk_window_set_geometry_hints((GtkWindow*)ih->handle, ih->handle,
+ &geometry, (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
+}
+
+static int gtkDialogSetMinSizeAttrib(Ihandle* ih, const char* value)
+{
+ int min_w = 1, min_h = 1; /* MINSIZE default value */
+ int max_w = 65535, max_h = 65535; /* MAXSIZE default value */
+ iupStrToIntInt(value, &min_w, &min_h, 'x');
+
+ /* if MAXSIZE also set, must be also updated here */
+ iupStrToIntInt(iupAttribGet(ih, "MAXSIZE"), &max_w, &max_h, 'x');
+
+ gtkDialogSetMinMax(ih, min_w, min_h, max_w, max_h);
+ return 1;
+}
+
+static int gtkDialogSetMaxSizeAttrib(Ihandle* ih, const char* value)
+{
+ int min_w = 1, min_h = 1; /* MINSIZE default value */
+ int max_w = 65535, max_h = 65535; /* MAXSIZE default value */
+ iupStrToIntInt(value, &max_w, &max_h, 'x');
+
+ /* if MINSIZE also set, must be also updated here */
+ iupStrToIntInt(iupAttribGet(ih, "MINSIZE"), &min_w, &min_h, 'x');
+
+ gtkDialogSetMinMax(ih, min_w, min_h, max_w, max_h);
+ return 1;
+}
+
+static char* gtkDialogGetXAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+
+ gint x = 0;
+ gtk_window_get_position((GtkWindow*)ih->handle, &x, NULL);
+
+ sprintf(str, "%d", x);
+ return str;
+}
+
+static char* gtkDialogGetYAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+
+ gint y = 0;
+ gtk_window_get_position((GtkWindow*)ih->handle, NULL, &y);
+
+ sprintf(str, "%d", y);
+ return str;
+}
+
+static int gtkDialogSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ value = "";
+ gtk_window_set_title((GtkWindow*)ih->handle, iupgtkStrConvertToUTF8(value));
+ return 0;
+}
+
+static char* gtkDialogGetTitleAttrib(Ihandle* ih)
+{
+ const char* title = gtk_window_get_title((GtkWindow*)ih->handle);
+
+ if (!title || title[0] == 0)
+ return NULL;
+ else
+ return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(title));
+}
+
+static char* gtkDialogGetClientSizeAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+
+ int width, height;
+ gtk_window_get_size((GtkWindow*)ih->handle, &width, &height);
+ height -= gtkDialogGetMenuSize(ih);
+
+ sprintf(str, "%dx%d", width, height);
+ return str;
+}
+
+static int gtkDialogSetFullScreenAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ {
+ if (!iupAttribGet(ih, "_IUPGTK_FS_STYLE"))
+ {
+ /* save the previous decoration attributes */
+ /* during fullscreen these attributes can be consulted by the application */
+ iupAttribStoreStr(ih, "_IUPGTK_FS_MAXBOX", iupAttribGet(ih, "MAXBOX"));
+ iupAttribStoreStr(ih, "_IUPGTK_FS_MINBOX", iupAttribGet(ih, "MINBOX"));
+ iupAttribStoreStr(ih, "_IUPGTK_FS_MENUBOX",iupAttribGet(ih, "MENUBOX"));
+ iupAttribStoreStr(ih, "_IUPGTK_FS_RESIZE", iupAttribGet(ih, "RESIZE"));
+ iupAttribStoreStr(ih, "_IUPGTK_FS_BORDER", iupAttribGet(ih, "BORDER"));
+ iupAttribStoreStr(ih, "_IUPGTK_FS_TITLE", IupGetAttribute(ih, "TITLE")); /* must use IupGetAttribute to check from the native implementation */
+
+ /* remove the decorations attributes */
+ iupAttribSetStr(ih, "MAXBOX", "NO");
+ iupAttribSetStr(ih, "MINBOX", "NO");
+ iupAttribSetStr(ih, "MENUBOX", "NO");
+ IupSetAttribute(ih, "TITLE", NULL); iupAttribSetStr(ih, "TITLE", NULL); /* remove from the hash table if we are during IupMap */
+ iupAttribSetStr(ih, "RESIZE", "NO");
+ iupAttribSetStr(ih, "BORDER", "NO");
+
+ if (iupdrvIsVisible(ih))
+ gtk_window_fullscreen((GtkWindow*)ih->handle);
+
+ iupAttribSetStr(ih, "_IUPGTK_FS_STYLE", "YES");
+ }
+ }
+ else
+ {
+ char* fs_style = iupAttribGet(ih, "_IUPGTK_FS_STYLE");
+ if (fs_style)
+ {
+ iupAttribSetStr(ih, "_IUPGTK_FS_STYLE", NULL);
+
+ /* restore the decorations attributes */
+ iupAttribStoreStr(ih, "MAXBOX", iupAttribGet(ih, "_IUPGTK_FS_MAXBOX"));
+ iupAttribStoreStr(ih, "MINBOX", iupAttribGet(ih, "_IUPGTK_FS_MINBOX"));
+ iupAttribStoreStr(ih, "MENUBOX",iupAttribGet(ih, "_IUPGTK_FS_MENUBOX"));
+ IupSetAttribute(ih, "TITLE", iupAttribGet(ih, "_IUPGTK_FS_TITLE")); /* must use IupSetAttribute to update the native implementation */
+ iupAttribStoreStr(ih, "RESIZE", iupAttribGet(ih, "_IUPGTK_FS_RESIZE"));
+ iupAttribStoreStr(ih, "BORDER", iupAttribGet(ih, "_IUPGTK_FS_BORDER"));
+
+ if (iupdrvIsVisible(ih))
+ gtk_window_unfullscreen((GtkWindow*)ih->handle);
+
+ /* remove auxiliar attributes */
+ iupAttribSetStr(ih, "_IUPGTK_FS_MAXBOX", NULL);
+ iupAttribSetStr(ih, "_IUPGTK_FS_MINBOX", NULL);
+ iupAttribSetStr(ih, "_IUPGTK_FS_MENUBOX",NULL);
+ iupAttribSetStr(ih, "_IUPGTK_FS_RESIZE", NULL);
+ iupAttribSetStr(ih, "_IUPGTK_FS_BORDER", NULL);
+ iupAttribSetStr(ih, "_IUPGTK_FS_TITLE", NULL);
+ }
+ }
+ return 1;
+}
+
+static int gtkDialogSetTopMostAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ gtk_window_set_keep_above((GtkWindow*)ih->handle, TRUE);
+ else
+ gtk_window_set_keep_above((GtkWindow*)ih->handle, FALSE);
+ return 1;
+}
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+static int gtkDialogSetOpacityAttrib(Ihandle *ih, const char *value)
+{
+ int opacity;
+ if (!iupStrToInt(value, &opacity))
+ return 0;
+
+ gtk_window_set_opacity((GtkWindow*)ih->handle, (double)opacity/255.0);
+ return 1;
+}
+#endif
+
+static int gtkDialogSetIconAttrib(Ihandle* ih, const char *value)
+{
+ if (!value)
+ gtk_window_set_icon((GtkWindow*)ih->handle, NULL);
+ else
+ {
+ GdkPixbuf* icon = (GdkPixbuf*)iupImageGetIcon(value);
+ if (icon)
+ gtk_window_set_icon((GtkWindow*)ih->handle, icon);
+ }
+ return 1;
+}
+
+static int gtkDialogSetBackgroundAttrib(Ihandle* ih, const char* value)
+{
+ if (iupdrvBaseSetBgColorAttrib(ih, value))
+ {
+ GtkStyle *style = gtk_widget_get_style(ih->handle);
+ if (style->bg_pixmap[GTK_STATE_NORMAL])
+ {
+ style = gtk_style_copy(style);
+ style->bg_pixmap[GTK_STATE_NORMAL] = NULL;
+ gtk_widget_set_style(ih->handle, style);
+ }
+ return 1;
+ }
+ else
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(value, ih, 0);
+ if (pixbuf)
+ {
+ GdkPixmap* pixmap;
+ GtkStyle *style;
+
+ gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap, NULL, 255);
+
+ style = gtk_style_copy(gtk_widget_get_style(ih->handle));
+ style->bg_pixmap[GTK_STATE_NORMAL] = pixmap;
+ gtk_widget_set_style(ih->handle, style);
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#if GTK_CHECK_VERSION(2, 10, 0)
+static int gtkDialogTaskDoubleClick(int button)
+{
+ static int last_button = -1;
+ static GTimer* timer = NULL;
+ if (last_button == -1 || last_button != button)
+ {
+ last_button = button;
+ if (timer)
+ g_timer_destroy(timer);
+ timer = g_timer_new();
+ return 0;
+ }
+ else
+ {
+ double seconds;
+
+ if (!timer) /* just in case */
+ return 0;
+
+ seconds = g_timer_elapsed(timer, NULL);
+ if (seconds < 0.4)
+ {
+ /* reset state */
+ g_timer_destroy(timer);
+ timer = NULL;
+ last_button = -1;
+ return 1;
+ }
+ else
+ {
+ g_timer_reset(timer);
+ return 0;
+ }
+ }
+}
+
+static void gtkDialogTaskAction(GtkStatusIcon *status_icon, Ihandle *ih)
+{
+ /* from GTK source code it is called only when button==1 and pressed==1 */
+ int button = 1;
+ int pressed = 1;
+ int dclick = gtkDialogTaskDoubleClick(button);
+ IFniii cb = (IFniii)IupGetCallback(ih, "TRAYCLICK_CB");
+ if (cb && cb(ih, button, pressed, dclick) == IUP_CLOSE)
+ IupExitLoop();
+ (void)status_icon;
+}
+
+static void gtkDialogTaskPopupMenu(GtkStatusIcon *status_icon, guint gbutton, guint activate_time, Ihandle *ih)
+{
+ /* from GTK source code it is called only when button==3 and pressed==1 */
+ int button = 3;
+ int pressed = 1;
+ int dclick = gtkDialogTaskDoubleClick(button);
+ IFniii cb = (IFniii)IupGetCallback(ih, "TRAYCLICK_CB");
+ if (cb && cb(ih, button, pressed, dclick) == IUP_CLOSE)
+ IupExitLoop();
+ (void)activate_time;
+ (void)gbutton;
+ (void)status_icon;
+}
+
+static GtkStatusIcon* gtkDialogGetStatusIcon(Ihandle *ih)
+{
+ GtkStatusIcon* status_icon = (GtkStatusIcon*)iupAttribGet(ih, "_IUPDLG_STATUSICON");
+ if (!status_icon)
+ {
+ status_icon = gtk_status_icon_new();
+
+ g_signal_connect(G_OBJECT(status_icon), "activate", G_CALLBACK(gtkDialogTaskAction), ih);
+ g_signal_connect(G_OBJECT(status_icon), "popup-menu", G_CALLBACK(gtkDialogTaskPopupMenu), ih);
+
+ iupAttribSetStr(ih, "_IUPDLG_STATUSICON", (char*)status_icon);
+ }
+ return status_icon;
+}
+
+static int gtkDialogSetTrayAttrib(Ihandle *ih, const char *value)
+{
+ GtkStatusIcon* status_icon = gtkDialogGetStatusIcon(ih);
+ gtk_status_icon_set_visible(status_icon, iupStrBoolean(value));
+ return 1;
+}
+
+static int gtkDialogSetTrayTipAttrib(Ihandle *ih, const char *value)
+{
+ GtkStatusIcon* status_icon = gtkDialogGetStatusIcon(ih);
+#if GTK_CHECK_VERSION(2, 16, 0)
+ if (value)
+ {
+ gtk_status_icon_set_has_tooltip(status_icon, TRUE);
+ gtk_status_icon_set_tooltip_text(status_icon, value);
+ }
+ else
+ gtk_status_icon_set_has_tooltip(status_icon, FALSE);
+#else
+ gtk_status_icon_set_tooltip(status_icon, value);
+#endif
+ return 1;
+}
+
+static int gtkDialogSetTrayImageAttrib(Ihandle *ih, const char *value)
+{
+ GtkStatusIcon* status_icon = gtkDialogGetStatusIcon(ih);
+ GdkPixbuf* icon = (GdkPixbuf*)iupImageGetIcon(value);
+ gtk_status_icon_set_from_pixbuf(status_icon, icon);
+ return 1;
+}
+#endif /* GTK_CHECK_VERSION(2, 10, 0) */
+
+void iupdrvDialogInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class methods */
+ ic->Map = gtkDialogMapMethod;
+ ic->UnMap = gtkDialogUnMapMethod;
+ ic->LayoutUpdate = gtkDialogLayoutUpdateMethod;
+ ic->GetInnerNativeContainerHandle = gtkDialogGetInnerNativeContainerHandleMethod;
+ ic->SetChildrenPosition = gtkDialogSetChildrenPositionMethod;
+
+ /* Callback Windows and GTK Only */
+ 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);
+#endif
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, "DLGBGCOLOR", NULL, IUPAF_DEFAULT); /* force new default value */
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "X", gtkDialogGetXAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "Y", gtkDialogGetYAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", gtkDialogGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "TITLE", gtkDialogGetTitleAttrib, gtkDialogSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupDialog only */
+ iupClassRegisterAttribute(ic, "BACKGROUND", NULL, gtkDialogSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ICON", NULL, gtkDialogSetIconAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FULLSCREEN", NULL, gtkDialogSetFullScreenAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MINSIZE", NULL, gtkDialogSetMinSizeAttrib, IUPAF_SAMEASSYSTEM, "1x1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MAXSIZE", NULL, gtkDialogSetMaxSizeAttrib, IUPAF_SAMEASSYSTEM, "65535x65535", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SAVEUNDER", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); /* saveunder not supported in GTK */
+
+ /* IupDialog Windows and GTK Only */
+ iupClassRegisterAttribute(ic, "TOPMOST", NULL, gtkDialogSetTopMostAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DIALOGHINT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+#if GTK_CHECK_VERSION(2, 12, 0)
+ iupClassRegisterAttribute(ic, "OPACITY", NULL, gtkDialogSetOpacityAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+#endif
+#if GTK_CHECK_VERSION(2, 10, 0)
+ iupClassRegisterAttribute(ic, "TRAY", NULL, gtkDialogSetTrayAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TRAYIMAGE", NULL, gtkDialogSetTrayImageAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TRAYTIP", NULL, gtkDialogSetTrayTipAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+#endif
+}
diff --git a/iup/src/gtk/iupgtk_drv.h b/iup/src/gtk/iupgtk_drv.h
new file mode 100755
index 0000000..ade2a4a
--- /dev/null
+++ b/iup/src/gtk/iupgtk_drv.h
@@ -0,0 +1,82 @@
+/** \file
+ * \brief GTK Driver
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPGTK_DRV_H
+#define __IUPGTK_DRV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* global variables, declared in iupgtk_globalattrib.c */
+extern int iupgtk_utf8autoconvert;
+
+
+/* common */
+gboolean iupgtkEnterLeaveEvent(GtkWidget *widget, GdkEventCrossing *evt, Ihandle* ih);
+gboolean iupgtkShowHelp(GtkWidget *widget, GtkWidgetHelpType *arg1, Ihandle* ih);
+GtkFixed* iupgtkBaseGetFixed(Ihandle* ih);
+void iupgtkBaseAddToParent(Ihandle* ih);
+void iupgdkColorSet(GdkColor* color, unsigned char r, unsigned char g, unsigned char b);
+int iupgtkSetDragDropAttrib(Ihandle* ih, const char* value);
+int iupgtkSetMnemonicTitle(Ihandle* ih, GtkLabel* label, const char* value);
+char* iupgtkStrConvertToUTF8(const char* str);
+char* iupgtkStrConvertFromUTF8(const char* str);
+void iupgtkReleaseConvertUTF8(void);
+char* iupgtkStrConvertFromFilename(const char* str);
+char* iupgtkStrConvertToFilename(const char* str);
+void iupgtkUpdateMnemonic(Ihandle* ih);
+gboolean iupgtkMotionNotifyEvent(GtkWidget *widget, GdkEventMotion *evt, Ihandle *ih);
+gboolean iupgtkButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih);
+void iupgtkBaseSetBgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b);
+void iupgtkBaseSetFgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b);
+void iupgtkBaseSetFgGdkColor(InativeHandle* handle, GdkColor *color);
+
+
+/* focus */
+gboolean iupgtkFocusInOutEvent(GtkWidget *widget, GdkEventFocus *evt, Ihandle* ih);
+
+
+/* key */
+gboolean iupgtkKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle* ih);
+gboolean iupgtkKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle* ih);
+void iupgtkButtonKeySetStatus(guint state, unsigned int but, char* status, int doubleclick);
+void iupgtkKeyEncode(int key, guint *keyval, guint *state);
+
+
+/* font */
+char* iupgtkGetPangoFontDescAttrib(Ihandle *ih);
+char* iupgtkGetFontIdAttrib(Ihandle *ih);
+PangoFontDescription* iupgtkGetPangoFontDesc(const char* value);
+char* iupgtkFindPangoFontDesc(PangoFontDescription* fontdesc);
+void iupgtkFontUpdatePangoLayout(Ihandle* ih, PangoLayout* layout);
+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)
+
+
+/* open */
+char* iupgtkGetNativeWindowHandle(Ihandle* ih);
+void iupgtkPushVisualAndColormap(void* visual, void* colormap);
+void* iupgtkGetNativeGraphicsContext(GtkWidget* widget);
+void iupgtkReleaseNativeGraphicsContext(GtkWidget* widget, void* gc);
+void iupgtkUpdateGlobalColors(GtkStyle* style);
+
+
+/* dialog */
+gboolean iupgtkDialogDeleteEvent(GtkWidget *widget, GdkEvent *evt, Ihandle *ih);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/gtk/iupgtk_filedlg.c b/iup/src/gtk/iupgtk_filedlg.c
new file mode 100755
index 0000000..5426910
--- /dev/null
+++ b/iup/src/gtk/iupgtk_filedlg.c
@@ -0,0 +1,536 @@
+/** \file
+ * \brief IupFileDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <stdio.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drvinfo.h"
+#include "iup_dialog.h"
+#include "iup_strmessage.h"
+#include "iup_array.h"
+#include "iup_drvinfo.h"
+
+#include "iupgtk_drv.h"
+
+
+static void iupStrRemoveChar(char* str, char c)
+{
+ char* p = str;
+ while (*str)
+ {
+ if (*str != c)
+ {
+ *p = *str;
+ p++;
+ }
+
+ str++;
+ }
+ *p = 0;
+}
+
+static void gtkFileDlgGetNextFilter(char** str, char** name, char** pattern)
+{
+ int len;
+ *name = *str;
+
+ len = strlen(*name);
+ *pattern = (*name)+len+1;
+
+ len = strlen(*pattern);
+ *str = (*pattern)+len+1;
+
+ iupStrReplace(*pattern, ';', 0); /* remove other patterns */
+}
+
+static void gtkFileDlgGetMultipleFiles(Ihandle* ih, GSList* list)
+{
+ int len, cur_len, dir_len = -1;
+ char *filename, *all_names;
+ Iarray* names_array = iupArrayCreate(1024, 1); /* just set an initial size, but count is 0 */
+
+ while (list)
+ {
+ filename = (char*)list->data;
+ len = strlen(filename);
+
+ if (dir_len == -1)
+ {
+ dir_len = len;
+
+ while (dir_len && (filename[dir_len] != '/' && filename[dir_len] != '\\'))
+ dir_len--;
+
+ 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] = '|';
+
+ dir_len++; /* skip separator */
+ }
+ len -= dir_len; /* remove directory */
+
+ cur_len = iupArrayCount(names_array);
+ all_names = iupArrayAdd(names_array, len+1);
+ memcpy(all_names+cur_len, filename+dir_len, len);
+ all_names[cur_len+len] = '|';
+
+ g_free(filename);
+ list = list->next;
+ }
+
+ cur_len = iupArrayCount(names_array);
+ all_names = iupArrayInc(names_array);
+ all_names[cur_len+1] = 0;
+
+ iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(all_names));
+
+ iupArrayDestroy(names_array);
+}
+
+#ifdef WIN32
+#include <gdk/gdkwin32.h>
+#else
+#include <gdk/gdkx.h>
+#endif
+
+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"));
+#endif
+ glcanvas->iclass->Map(glcanvas);
+ }
+}
+
+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());
+#endif
+ gtkFileDlgUpdatePreviewGLCanvas(ih);
+}
+
+static void gtkFileDlgRealize(GtkWidget *widget, Ihandle *ih)
+{
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ cb(ih, NULL, "INIT");
+
+ (void)widget;
+}
+
+static gboolean gtkFileDlgPreviewConfigureEvent(GtkWidget *widget, GdkEventConfigure *evt, Ihandle *ih)
+{
+ iupAttribSetInt(ih, "PREVIEWWIDTH", evt->width);
+ iupAttribSetInt(ih, "PREVIEWHEIGHT", evt->height);
+
+ (void)widget;
+ return FALSE;
+}
+
+static gboolean gtkFileDlgPreviewExposeEvent(GtkWidget *widget, GdkEventExpose *evt, Ihandle *ih)
+{
+ GtkFileChooser *file_chooser = (GtkFileChooser*)iupAttribGet(ih, "_IUPDLG_FILE_CHOOSER");
+ char *filename = gtk_file_chooser_get_preview_filename(file_chooser);
+
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (iupdrvIsFile(filename))
+ cb(ih, iupgtkStrConvertFromFilename(filename), "PAINT");
+ else
+ cb(ih, NULL, "PAINT");
+
+ g_free (filename);
+
+ (void)evt;
+ (void)widget;
+ return TRUE; /* stop other handlers */
+}
+
+static void gtkFileDlgUpdatePreview(GtkFileChooser *file_chooser, Ihandle* ih)
+{
+ char *filename = gtk_file_chooser_get_preview_filename(file_chooser);
+
+ if (iupdrvIsFile(filename))
+ {
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ cb(ih, iupgtkStrConvertFromFilename(filename), "SELECT");
+ }
+
+ g_free (filename);
+
+ gtk_file_chooser_set_preview_widget_active(file_chooser, TRUE);
+}
+
+static int gtkFileDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ GtkWidget* dialog;
+ GtkWidget* preview_canvas = NULL;
+ GtkFileChooserAction action;
+ IFnss file_cb;
+ char* value;
+ int response, filter_count = 0;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ value = iupAttribGetStr(ih, "DIALOGTYPE");
+ if (iupStrEqualNoCase(value, "SAVE"))
+ action = GTK_FILE_CHOOSER_ACTION_SAVE;
+ else if (iupStrEqualNoCase(value, "DIR"))
+ action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+ else
+ action = GTK_FILE_CHOOSER_ACTION_OPEN;
+
+ value = iupAttribGet(ih, "TITLE");
+ if (!value)
+ {
+ GtkStockItem item;
+
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ value = GTK_STOCK_SAVE_AS;
+ else
+ value = GTK_STOCK_OPEN;
+
+ gtk_stock_lookup(value, &item);
+ value = item.label;
+
+ iupAttribStoreStr(ih, "TITLE", iupgtkStrConvertFromUTF8(value));
+ value = iupAttribGet(ih, "TITLE");
+ iupStrRemoveChar(value, '_');
+ }
+
+ dialog = gtk_file_chooser_dialog_new(iupgtkStrConvertToUTF8(value), (GtkWindow*)parent, action,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ NULL);
+ if (!dialog)
+ return IUP_ERROR;
+
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_SAVE, GTK_RESPONSE_OK);
+ else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OPEN, GTK_RESPONSE_OK);
+ else
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_HELP, GTK_RESPONSE_HELP);
+
+#if GTK_CHECK_VERSION(2, 6, 0)
+ if (iupAttribGetBoolean(ih, "SHOWHIDDEN"))
+ gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog), TRUE);
+#endif
+
+ if (iupAttribGetBoolean(ih, "MULTIPLEFILES") && action == GTK_FILE_CHOOSER_ACTION_OPEN)
+ gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ if (!iupAttribGetBoolean(ih, "NOOVERWRITEPROMPT") && action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
+#endif
+
+ /* just check for the path inside FILE */
+ value = iupAttribGet(ih, "FILE");
+ if (value && (value[0] == '/' || value[1] == ':'))
+ {
+ char* dir = iupStrFileGetPath(value);
+ int len = strlen(dir);
+ iupAttribStoreStr(ih, "DIRECTORY", dir);
+ free(dir);
+ iupAttribStoreStr(ih, "FILE", value+len);
+ }
+
+ value = iupAttribGet(ih, "DIRECTORY");
+ if (value)
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), iupgtkStrConvertToFilename(value));
+
+ value = iupAttribGet(ih, "FILE");
+ if (value)
+ {
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), iupgtkStrConvertToFilename(value));
+ else
+ {
+ if (iupdrvIsFile(value)) /* check if file exists */
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), iupgtkStrConvertToFilename(value));
+ }
+ }
+
+ value = iupAttribGet(ih, "EXTFILTER");
+ if (value)
+ {
+ char *name, *pattern, *filters = iupStrDup(value), *p;
+ char atrib[30];
+ int i;
+ int filter_index = iupAttribGetInt(ih, "FILTERUSED");
+ if (!filter_index)
+ filter_index = 1;
+
+ filter_count = iupStrReplace(filters, '|', 0) / 2;
+
+ p = filters;
+ for (i=0; i<filter_count; i++)
+ {
+ GtkFileFilter *filter = gtk_file_filter_new();
+
+ gtkFileDlgGetNextFilter(&p, &name, &pattern);
+
+ gtk_file_filter_set_name(filter, iupgtkStrConvertToUTF8(name));
+ gtk_file_filter_add_pattern(filter, pattern);
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
+
+ sprintf(atrib, "_IUPDLG_FILTER%d", i+1);
+ iupAttribSetStr(ih, atrib, (char*)filter);
+
+ if (i+1 == filter_index)
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
+ }
+
+ free(filters);
+ }
+ else
+ {
+ value = iupAttribGet(ih, "FILTER");
+ if (value)
+ {
+ GtkFileFilter *filter = gtk_file_filter_new();
+ char* info = iupAttribGet(ih, "FILTERINFO");
+ if (!info)
+ info = value;
+
+ gtk_file_filter_set_name(filter, iupgtkStrConvertToUTF8(info));
+ gtk_file_filter_add_pattern(filter, value);
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
+ }
+ }
+
+ file_cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (file_cb && action != GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ {
+ g_signal_connect(GTK_FILE_CHOOSER(dialog), "update-preview", G_CALLBACK(gtkFileDlgUpdatePreview), ih);
+ g_signal_connect(dialog, "realize", G_CALLBACK(gtkFileDlgRealize), ih);
+
+ if (iupAttribGetBoolean(ih, "SHOWPREVIEW"))
+ {
+ GtkWidget* frame = gtk_frame_new(NULL);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
+ gtk_widget_set_size_request(frame, 180, 150);
+
+ preview_canvas = gtk_drawing_area_new();
+ gtk_widget_set_double_buffered(preview_canvas, FALSE);
+ gtk_container_add(GTK_CONTAINER(frame), preview_canvas);
+ gtk_widget_show(preview_canvas);
+
+ g_signal_connect(preview_canvas, "configure-event", G_CALLBACK(gtkFileDlgPreviewConfigureEvent), ih);
+ g_signal_connect(preview_canvas, "expose-event", G_CALLBACK(gtkFileDlgPreviewExposeEvent), ih);
+ g_signal_connect(preview_canvas, "realize", G_CALLBACK(gtkFileDlgPreviewRealize), ih);
+
+ iupAttribSetStr(ih, "_IUPDLG_FILE_CHOOSER", (char*)dialog);
+
+ gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), frame);
+ }
+ }
+
+ /* initialize the widget */
+ gtk_widget_realize(GTK_WIDGET(dialog));
+
+ ih->handle = GTK_WIDGET(dialog);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+
+ do
+ {
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+ if (response == GTK_RESPONSE_HELP)
+ {
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ response = GTK_RESPONSE_CANCEL;
+ }
+ else if (response == GTK_RESPONSE_OK)
+ {
+ char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ int file_exist = iupdrvIsFile(filename);
+ int dir_exist = iupdrvIsDirectory(filename);
+ g_free(filename);
+
+ if (action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ {
+ if (!dir_exist)
+ {
+ iupStrMessageShowError(ih, "IUP_INVALIDDIR");
+ response = GTK_RESPONSE_HELP; /* to leave the dialog open */
+ continue;
+ }
+ }
+ else if (!iupAttribGetBoolean(ih, "MULTIPLEFILES"))
+ {
+ if (dir_exist)
+ {
+ iupStrMessageShowError(ih, "IUP_FILEISDIR");
+ response = GTK_RESPONSE_HELP; /* to leave the dialog open */
+ continue;
+ }
+
+ if (!file_exist) /* if do not exist check ALLOWNEW */
+ {
+ value = iupAttribGet(ih, "ALLOWNEW");
+ if (!value)
+ {
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ value = "YES";
+ else
+ value = "NO";
+ }
+
+ if (!iupStrBoolean(value))
+ {
+ iupStrMessageShowError(ih, "IUP_FILENOTEXIST");
+ response = GTK_RESPONSE_HELP; /* to leave the dialog open */
+ continue;
+ }
+ }
+
+ if (file_cb)
+ {
+ char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ int ret = file_cb(ih, iupgtkStrConvertFromFilename(filename), "OK");
+ g_free(filename);
+
+ if (ret == IUP_IGNORE)
+ {
+ response = GTK_RESPONSE_HELP; /* to leave the dialog open */
+ continue;
+ }
+ }
+ }
+ }
+ } while (response == GTK_RESPONSE_HELP);
+
+ if (file_cb)
+ {
+ if (iupAttribGetBoolean(ih, "SHOWPREVIEW"))
+ iupgtkReleaseNativeGraphicsContext(preview_canvas, (void*)iupAttribGet(ih, "PREVIEWDC"));
+
+ file_cb(ih, NULL, "FINISH");
+ }
+
+ if (response == GTK_RESPONSE_OK)
+ {
+ int file_exist, dir_exist;
+
+ if (filter_count)
+ {
+ int i;
+ char atrib[30];
+ GtkFileFilter* filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog));
+
+ for (i=0; i<filter_count; i++)
+ {
+ sprintf(atrib, "_IUPDLG_FILTER%d", i+1);
+ if (filter == (GtkFileFilter*)iupAttribGet(ih, atrib))
+ iupAttribSetInt(ih, "FILTERUSED", i+1);
+ }
+ }
+
+ if (iupAttribGetBoolean(ih, "MULTIPLEFILES"))
+ {
+ GSList* file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
+
+ if (file_list->next) /* if more than one file */
+ gtkFileDlgGetMultipleFiles(ih, file_list);
+ else
+ {
+ char* filename = (char*)file_list->data;
+ iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(filename));
+ g_free(filename);
+ }
+
+ g_slist_free(file_list);
+ file_exist = 1;
+ dir_exist = 0;
+ }
+ else
+ {
+ char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(filename));
+ file_exist = iupdrvIsFile(filename);
+ dir_exist = iupdrvIsDirectory(filename);
+ g_free(filename);
+ }
+
+ if (dir_exist)
+ {
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "STATUS", "0");
+ }
+ else
+ {
+ if (file_exist) /* check if file exists */
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "YES");
+ iupAttribSetStr(ih, "STATUS", "0");
+ }
+ else
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "NO");
+ iupAttribSetStr(ih, "STATUS", "1");
+ }
+ }
+
+ if (action != GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER && !iupAttribGetBoolean(ih, "NOCHANGEDIR")) /* do change the current directory */
+ {
+ /* 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);
+ }
+ }
+ else
+ {
+ iupAttribSetStr(ih, "FILTERUSED", NULL);
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "STATUS", "-1");
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFileDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = gtkFileDlgPopup;
+
+ /* IupFileDialog Windows and GTK Only */
+ iupClassRegisterAttribute(ic, "EXTFILTER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTERINFO", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTERUSED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MULTIPLEFILES", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_focus.c b/iup/src/gtk/iupgtk_focus.c
new file mode 100755
index 0000000..fa596ba
--- /dev/null
+++ b/iup/src/gtk/iupgtk_focus.c
@@ -0,0 +1,44 @@
+/** \file
+ * \brief GTK Focus
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_focus.h"
+#include "iup_attrib.h"
+#include "iup_drv.h"
+#include "iup_assert.h"
+#include "iup_drv.h"
+
+#include "iupgtk_drv.h"
+
+
+void iupdrvSetFocus(Ihandle *ih)
+{
+ gtk_widget_grab_focus(ih->handle);
+}
+
+gboolean iupgtkFocusInOutEvent(GtkWidget *widget, GdkEventFocus *evt, Ihandle *ih)
+{
+ (void)widget;
+
+ if (evt->in)
+ {
+ /* even when ACTIVE=NO the dialog gets this evt */
+ if (!iupdrvIsActive(ih))
+ return TRUE;
+
+ iupCallGetFocusCb(ih);
+ }
+ else
+ iupCallKillFocusCb(ih);
+
+ return FALSE;
+}
diff --git a/iup/src/gtk/iupgtk_font.c b/iup/src/gtk/iupgtk_font.c
new file mode 100755
index 0000000..f7ff348
--- /dev/null
+++ b/iup/src/gtk/iupgtk_font.c
@@ -0,0 +1,413 @@
+/** \file
+ * \brief GTK Font mapping
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_attrib.h"
+#include "iup_array.h"
+#include "iup_object.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_assert.h"
+
+#include "iupgtk_drv.h"
+
+
+typedef struct _IgtkFont
+{
+ char standardfont[200];
+ PangoFontDescription* fontdesc;
+ PangoAttribute* strikethrough;
+ PangoAttribute* underline;
+ PangoLayout* layout;
+ int charwidth, charheight;
+} IgtkFont;
+
+static Iarray* gtk_fonts = NULL;
+static PangoContext *gtk_fonts_context = NULL;
+
+static void gtkFontUpdate(IgtkFont* gtkfont)
+{
+ PangoAttrList *attrs;
+
+ pango_layout_set_font_description(gtkfont->layout, gtkfont->fontdesc);
+
+ attrs = pango_layout_get_attributes(gtkfont->layout);
+ if (!attrs)
+ {
+ attrs = pango_attr_list_new();
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->underline));
+ pango_layout_set_attributes(gtkfont->layout, attrs);
+ }
+ else
+ {
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->underline));
+ }
+}
+
+static IgtkFont* gtkFindFont(const char *standardfont)
+{
+ PangoFontMetrics* metrics;
+ PangoFontDescription* fontdesc;
+ int i,
+ is_underline = 0,
+ is_strikeout = 0,
+ count = iupArrayCount(gtk_fonts);
+
+ IgtkFont* fonts = (IgtkFont*)iupArrayGetData(gtk_fonts);
+
+ /* Check if the standardfont already exists in cache */
+ for (i = 0; i < count; i++)
+ {
+ if (iupStrEqualNoCase(standardfont, fonts[i].standardfont))
+ return &fonts[i];
+ }
+
+ /* not found, create a new one */
+ {
+ int size = 0, is_pango = 0;
+ int is_bold = 0,
+ is_italic = 0;
+ char typeface[1024];
+ const char* mapped_name;
+
+ /* parse the old Windows format first */
+ if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return NULL;
+ else
+ is_pango = 1;
+ }
+ }
+
+ mapped_name = iupFontGetPangoName(typeface);
+ if (mapped_name)
+ strcpy(typeface, mapped_name);
+
+ if (is_pango && !is_underline && !is_strikeout && size>0)
+ fontdesc = pango_font_description_from_string(standardfont);
+ else
+ {
+ char new_standardfont[200];
+ if (size<0)
+ {
+ double res = ((double)gdk_screen_get_width(gdk_screen_get_default()) / (double)gdk_screen_get_width_mm(gdk_screen_get_default())); /* pixels/mm */
+ /* 1 point = 1/72 inch 1 inch = 25.4 mm */
+ /* pixel = ((point/72)*25.4)*pixel/mm */
+ size = (int)((-size/res)*2.83464567 + 0.5); /* from pixels to points */
+ }
+
+ sprintf(new_standardfont, "%s, %s%s%d", typeface, is_bold?"Bold ":"", is_italic?"Italic ":"", size);
+
+ fontdesc = pango_font_description_from_string(new_standardfont);
+ }
+ }
+
+ if (!fontdesc)
+ return NULL;
+
+ /* create room in the array */
+ fonts = (IgtkFont*)iupArrayInc(gtk_fonts);
+
+ strcpy(fonts[i].standardfont, standardfont);
+ fonts[i].fontdesc = fontdesc;
+ fonts[i].strikethrough = pango_attr_strikethrough_new(is_strikeout? TRUE: FALSE);
+ fonts[i].underline = pango_attr_underline_new(is_underline? PANGO_UNDERLINE_SINGLE: PANGO_UNDERLINE_NONE);
+ fonts[i].layout = pango_layout_new(gtk_fonts_context);
+
+ 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].charwidth = pango_font_metrics_get_approximate_char_width(metrics);
+ fonts[i].charwidth = IUPGTK_PANGOUNITS2PIXELS(fonts[i].charwidth);
+ pango_font_metrics_unref(metrics);
+
+ gtkFontUpdate(&(fonts[i]));
+
+ return &fonts[i];
+}
+
+static PangoLayout* gtkFontGetWidgetPangoLayout(Ihandle *ih)
+{
+ int inherit;
+ char *def_value;
+ /* only check the native implementation */
+ return (PangoLayout*)iupClassObjectGetAttribute(ih, "PANGOLAYOUT", &def_value, &inherit);
+}
+
+static IgtkFont* gtkFontCreateNativeFont(Ihandle* ih, const char* value)
+{
+ IgtkFont *gtkfont = gtkFindFont(value);
+ if (!gtkfont)
+ {
+ iupERROR1("Failed to create Font: %s", value);
+ return NULL;
+ }
+
+ iupAttribSetStr(ih, "_IUP_GTKFONT", (char*)gtkfont);
+ return gtkfont;
+}
+
+static IgtkFont* gtkFontGet(Ihandle *ih)
+{
+ IgtkFont* gtkfont = (IgtkFont*)iupAttribGet(ih, "_IUP_GTKFONT");
+ if (!gtkfont)
+ gtkfont = gtkFontCreateNativeFont(ih, iupGetFontAttrib(ih));
+ return gtkfont;
+}
+
+void iupgtkFontUpdatePangoLayout(Ihandle* ih, PangoLayout* layout)
+{
+ IgtkFont* gtkfont;
+ PangoAttrList *attrs;
+
+ if (!layout)
+ return;
+
+ gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ return;
+
+ attrs = pango_layout_get_attributes(layout);
+ if (!attrs)
+ {
+ attrs = pango_attr_list_new();
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->underline));
+ pango_layout_set_attributes(layout, attrs);
+ }
+ else
+ {
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->underline));
+ }
+}
+
+void iupgtkFontUpdateObjectPangoLayout(Ihandle* ih, gpointer object)
+{
+ PangoAttrList *attrs;
+
+ IgtkFont* gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ return;
+
+ g_object_get(object, "attributes", &attrs, NULL);
+ if (!attrs)
+ {
+ attrs = pango_attr_list_new();
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->underline));
+ g_object_set(object, "attributes", attrs, NULL);
+ }
+ else
+ {
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->underline));
+ }
+}
+
+char* iupdrvGetSystemFont(void)
+{
+ static char systemfont[200] = "";
+ GtkStyle* style;
+ GtkWidget* widget = gtk_invisible_new();
+ gtk_widget_realize(widget);
+ style = gtk_widget_get_style(widget);
+ if (!style || !style->font_desc)
+ strcpy(systemfont, "Sans, 10");
+ else
+ {
+ char* desc = pango_font_description_to_string(style->font_desc);
+ strcpy(systemfont, desc);
+ g_free(desc);
+ }
+ gtk_widget_unrealize(widget);
+ gtk_widget_destroy(widget);
+ return systemfont;
+}
+
+char* iupgtkFindPangoFontDesc(PangoFontDescription* fontdesc)
+{
+ int i, count = iupArrayCount(gtk_fonts);
+ IgtkFont* fonts = (IgtkFont*)iupArrayGetData(gtk_fonts);
+
+ /* Check if the standardfont already exists in cache */
+ for (i = 0; i < count; i++)
+ {
+ if (pango_font_description_equal(fontdesc, fonts[i].fontdesc))
+ return fonts[i].standardfont;
+ }
+
+ return NULL;
+}
+
+PangoFontDescription* iupgtkGetPangoFontDesc(const char* value)
+{
+ IgtkFont *gtkfont = gtkFindFont(value);
+ if (!gtkfont)
+ {
+ iupERROR1("Failed to create Font: %s", value);
+ return NULL;
+ }
+ return gtkfont->fontdesc;
+}
+
+char* iupgtkGetPangoFontDescAttrib(Ihandle *ih)
+{
+ IgtkFont* gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ return NULL;
+ else
+ return (char*)gtkfont->fontdesc;
+}
+
+char* iupgtkGetFontIdAttrib(Ihandle *ih)
+{
+ IgtkFont* gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ return NULL;
+ else
+ {
+ GdkFont* gdk_font = gdk_font_from_description(gtkfont->fontdesc);
+ return (char*)gdk_font_id(gdk_font); /* In UNIX will return an X Font ID, in Win32 will return an HFONT */
+ }
+}
+
+int iupdrvSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ IgtkFont* gtkfont = gtkFontCreateNativeFont(ih, value);
+ if (!gtkfont)
+ return 1;
+
+ /* If FONT is changed, must update the SIZE attribute */
+ iupBaseUpdateSizeFromFont(ih);
+
+ /* FONT attribute must be able to be set before mapping,
+ so the font is enable for size calculation. */
+ if (ih->handle && (ih->iclass->nativetype != IUP_TYPEVOID))
+ {
+ gtk_widget_modify_font(ih->handle, gtkfont->fontdesc);
+ iupgtkFontUpdatePangoLayout(ih, gtkFontGetWidgetPangoLayout(ih));
+ }
+
+ return 1;
+}
+
+void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h)
+{
+ int max_w;
+
+ IgtkFont* gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ {
+ if (w) *w = 0;
+ if (h) *h = 0;
+ return;
+ }
+
+ if (!str)
+ {
+ if (w) *w = 0;
+ if (h) *h = gtkfont->charheight * 1;
+ return;
+ }
+
+ max_w = 0;
+ if (str[0])
+ {
+ int dummy_h;
+
+ pango_layout_set_attributes(gtkfont->layout, NULL);
+
+ if (iupAttribGetBoolean(ih, "MARKUP"))
+ pango_layout_set_markup(gtkfont->layout, iupgtkStrConvertToUTF8(str), -1);
+ else
+ pango_layout_set_text(gtkfont->layout, iupgtkStrConvertToUTF8(str), -1);
+
+ pango_layout_get_pixel_size(gtkfont->layout, &max_w, &dummy_h);
+ }
+
+ if (w) *w = max_w;
+ if (h) *h = gtkfont->charheight * iupStrLineCount(str);
+}
+
+int iupdrvFontGetStringWidth(Ihandle* ih, const char* str)
+{
+ IgtkFont* gtkfont;
+ int len, w;
+ char* line_end;
+
+ if (!str || str[0]==0)
+ return 0;
+
+ gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ return 0;
+
+ line_end = strchr(str, '\n');
+ if (line_end)
+ len = line_end-str;
+ else
+ len = strlen(str);
+
+ if (iupAttribGetBoolean(ih, "MARKUP"))
+ pango_layout_set_markup(gtkfont->layout, iupgtkStrConvertToUTF8(str), len);
+ else
+ pango_layout_set_text(gtkfont->layout, iupgtkStrConvertToUTF8(str), len);
+
+ pango_layout_get_pixel_size(gtkfont->layout, &w, NULL);
+ return w;
+}
+
+void iupdrvFontGetCharSize(Ihandle* ih, int *charwidth, int *charheight)
+{
+ IgtkFont* gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ {
+ if (charwidth) *charwidth = 0;
+ if (charheight) *charheight = 0;
+ return;
+ }
+
+ if (charheight)
+ *charheight = gtkfont->charheight;
+
+ if (charwidth)
+ *charwidth = gtkfont->charwidth;
+}
+
+void iupdrvFontInit(void)
+{
+ gtk_fonts = iupArrayCreate(50, sizeof(IgtkFont));
+ gtk_fonts_context = gdk_pango_context_get();
+ pango_context_set_language(gtk_fonts_context, gtk_get_default_language());
+}
+
+void iupdrvFontFinish(void)
+{
+ int i, count = iupArrayCount(gtk_fonts);
+ IgtkFont* fonts = (IgtkFont*)iupArrayGetData(gtk_fonts);
+ for (i = 0; i < count; i++)
+ {
+ pango_font_description_free(fonts[i].fontdesc);
+ pango_attribute_destroy(fonts[i].strikethrough);
+ pango_attribute_destroy(fonts[i].underline);
+ }
+ iupArrayDestroy(gtk_fonts);
+ g_object_unref(gtk_fonts_context);
+}
diff --git a/iup/src/gtk/iupgtk_fontdlg.c b/iup/src/gtk/iupgtk_fontdlg.c
new file mode 100755
index 0000000..5769cbc
--- /dev/null
+++ b/iup/src/gtk/iupgtk_fontdlg.c
@@ -0,0 +1,91 @@
+/** \file
+ * \brief IupFontDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <string.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+
+#include "iupgtk_drv.h"
+
+
+static int gtkFontDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ GtkFontSelectionDialog* dialog;
+ int response;
+ char* preview_text;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ dialog = (GtkFontSelectionDialog*)gtk_font_selection_dialog_new(iupgtkStrConvertToUTF8(iupAttribGet(ih, "TITLE")));
+ if (!dialog)
+ return IUP_ERROR;
+
+ if (parent)
+ gtk_window_set_transient_for((GtkWindow*)dialog, (GtkWindow*)parent);
+
+ gtk_font_selection_dialog_set_font_name(dialog, iupAttribGet(ih, "VALUE"));
+
+ preview_text = iupAttribGet(ih, "PREVIEWTEXT");
+ if (preview_text)
+ gtk_font_selection_dialog_set_preview_text(dialog, preview_text);
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_HELP, GTK_RESPONSE_HELP);
+
+ /* initialize the widget */
+ gtk_widget_realize(GTK_WIDGET(dialog));
+
+ ih->handle = GTK_WIDGET(dialog);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL;
+
+ do
+ {
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+ if (response == GTK_RESPONSE_HELP)
+ {
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ response = GTK_RESPONSE_CANCEL;
+ }
+ } while (response == GTK_RESPONSE_HELP);
+
+ if (response == GTK_RESPONSE_OK)
+ {
+ char* fontname = gtk_font_selection_dialog_get_font_name(dialog);
+ iupAttribStoreStr(ih, "VALUE", fontname);
+ g_free(fontname);
+ iupAttribSetStr(ih, "STATUS", "1");
+ }
+ else
+ {
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "STATUS", NULL);
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFontDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = gtkFontDlgPopup;
+
+ /* IupFontDialog GTK Only */
+ iupClassRegisterAttribute(ic, "PREVIEWTEXT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_frame.c b/iup/src/gtk/iupgtk_frame.c
new file mode 100755
index 0000000..022c6c7
--- /dev/null
+++ b/iup/src/gtk/iupgtk_frame.c
@@ -0,0 +1,155 @@
+/** \file
+ * \brief Frame Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+
+#include "iupgtk_drv.h"
+
+
+void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y)
+{
+ (void)ih;
+ *x = 0;
+ *y = 0;
+}
+
+static char* gtkFrameGetTitleAttrib(Ihandle* ih)
+{
+ GtkFrame* frame = (GtkFrame*)ih->handle;
+ return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_frame_get_label(frame)));
+}
+
+static int gtkFrameSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ GtkFrame* frame = (GtkFrame*)ih->handle;
+ gtk_frame_set_label(frame, iupgtkStrConvertToUTF8(value));
+ return 0;
+}
+
+static int gtkFrameSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ GtkWidget* label = gtk_frame_get_label_widget((GtkFrame*)ih->handle);
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ if (label)
+ iupgtkBaseSetBgColor(label, r, g, b);
+
+ iupgtkBaseSetBgColor(ih->handle, r, g, b);
+
+ return 1;
+}
+
+static int gtkFrameSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ GtkWidget* label = gtk_frame_get_label_widget((GtkFrame*)ih->handle);
+ if (!label) return 0;
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(label, r, g, b);
+
+ return 1;
+}
+
+static int gtkFrameSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+
+ if (ih->handle)
+ {
+ GtkWidget* label = gtk_frame_get_label_widget((GtkFrame*)ih->handle);
+ if (!label) return 1;
+
+ gtk_widget_modify_font(label, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih));
+ iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)label));
+ }
+ return 1;
+}
+
+static void* gtkFrameGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child)
+{
+ (void)child;
+ return (void*)gtk_bin_get_child((GtkBin*)ih->handle);
+}
+
+static int gtkFrameMapMethod(Ihandle* ih)
+{
+ char *value, *title;
+ GtkWidget *fixed;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ title = iupAttribGet(ih, "TITLE");
+
+ ih->handle = gtk_frame_new(NULL);
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ if (title)
+ iupAttribSetStr(ih, "_IUPFRAME_HAS_TITLE", "1");
+ else
+ {
+ value = iupAttribGetStr(ih, "SUNKEN");
+ if (iupStrBoolean(value))
+ gtk_frame_set_shadow_type((GtkFrame*)ih->handle, GTK_SHADOW_IN);
+ else
+ gtk_frame_set_shadow_type((GtkFrame*)ih->handle, GTK_SHADOW_ETCHED_IN);
+ }
+
+ /* the container that will receive the child element. */
+ fixed = gtk_fixed_new();
+ gtk_container_add((GtkContainer*)ih->handle, fixed);
+ gtk_widget_show(fixed);
+
+ /* Add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ gtk_widget_realize(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFrameInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkFrameMapMethod;
+ ic->GetInnerNativeContainerHandle = gtkFrameGetInnerNativeContainerHandleMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkFrameSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkFrameSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkFrameSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", gtkFrameGetTitleAttrib, gtkFrameSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_globalattrib.c b/iup/src/gtk/iupgtk_globalattrib.c
new file mode 100755
index 0000000..eebe799
--- /dev/null
+++ b/iup/src/gtk/iupgtk_globalattrib.c
@@ -0,0 +1,211 @@
+/** \file
+ * \brief GTK Driver iupdrvSetGlobal
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_strmessage.h"
+
+#include "iupgtk_drv.h"
+
+
+int iupgtk_utf8autoconvert = 1;
+
+static void gtkGlobalSendKey(int key, int press)
+{
+ Ihandle* focus;
+ gint nkeys = 0;
+ GdkKeymapKey *keys;
+ GdkEventKey evt;
+ memset(&evt, 0, sizeof(GdkEventKey));
+ evt.send_event = TRUE;
+
+ focus = IupGetFocus();
+ if (!focus)
+ return;
+ evt.window = focus->handle->window;
+
+ iupgtkKeyEncode(key, &evt.keyval, &evt.state);
+ if (!evt.keyval)
+ return;
+
+ if (!gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), evt.keyval, &keys, &nkeys))
+ return;
+ evt.hardware_keycode = (guint16)keys[0].keycode;
+ evt.group = (guint8)keys[0].group;
+
+ if (press & 0x01)
+ {
+ evt.type = GDK_KEY_PRESS;
+ gdk_display_put_event(gdk_display_get_default(), (GdkEvent*)&evt);
+ }
+
+ if (press & 0x02)
+ {
+ evt.type = GDK_KEY_RELEASE;
+ gdk_display_put_event(gdk_display_get_default(), (GdkEvent*)&evt);
+ }
+}
+
+int iupdrvSetGlobal(const char *name, const char *value)
+{
+ if (iupStrEqual(name, "LANGUAGE"))
+ {
+ iupStrMessageUpdateLanguage(value);
+ return 1;
+ }
+ if (iupStrEqual(name, "CURSORPOS"))
+ {
+#if GTK_CHECK_VERSION(2, 8, 0)
+ int x, y;
+ if (iupStrToIntInt(value, &x, &y, 'x') == 2)
+ gdk_display_warp_pointer(gdk_display_get_default(), gdk_screen_get_default(), x, y);
+#endif
+ return 0;
+ }
+ if (iupStrEqual(name, "UTF8AUTOCONVERT"))
+ {
+ if (!value || iupStrBoolean(value))
+ iupgtk_utf8autoconvert = 1;
+ else
+ iupgtk_utf8autoconvert = 0;
+ return 0;
+ }
+ if (iupStrEqual(name, "KEYPRESS"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ gtkGlobalSendKey(key, 0x01);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEYRELEASE"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ gtkGlobalSendKey(key, 0x02);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEY"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ gtkGlobalSendKey(key, 0x03);
+ return 0;
+ }
+ return 1;
+}
+
+char *iupdrvGetGlobal(const char *name)
+{
+ if (iupStrEqual(name, "CURSORPOS"))
+ {
+ char *str = iupStrGetMemory(50);
+ int x, y;
+ iupdrvGetCursorPos(&x, &y);
+ sprintf(str, "%dx%d", (int)x, (int)y);
+ return str;
+ }
+ if (iupStrEqual(name, "SHIFTKEY"))
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[0] == 'S')
+ return "ON";
+ else
+ return "OFF";
+ }
+ if (iupStrEqual(name, "CONTROLKEY"))
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[1] == 'C')
+ return "ON";
+ else
+ return "OFF";
+ }
+ if (iupStrEqual(name, "MODKEYSTATE"))
+ {
+ char *str = iupStrGetMemory(5);
+ iupdrvGetKeyState(str);
+ return str;
+ }
+ if (iupStrEqual(name, "SCREENSIZE"))
+ {
+ char *str = iupStrGetMemory(50);
+ int w, h;
+ iupdrvGetScreenSize(&w, &h);
+ sprintf(str, "%dx%d", w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "FULLSIZE"))
+ {
+ char *str = iupStrGetMemory(50);
+ int w, h;
+ iupdrvGetFullSize(&w, &h);
+ sprintf(str, "%dx%d", w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "SCREENDEPTH"))
+ {
+ char *str = iupStrGetMemory(50);
+ int bpp = iupdrvGetScreenDepth();
+ sprintf(str, "%d", bpp);
+ return str;
+ }
+ if (iupStrEqual(name, "VIRTUALSCREEN"))
+ {
+ char *str = iupStrGetMemory(50);
+ GdkScreen *screen = gdk_screen_get_default();
+ GdkWindow *root = gdk_screen_get_root_window(gdk_screen_get_default());
+ int x = 0;
+ int y = 0;
+ int w = gdk_screen_get_width(screen);
+ int h = gdk_screen_get_height(screen);
+ gdk_window_get_root_origin(root, &x, &y);
+ sprintf(str, "%d %d %d %d", x, y, w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "MONITORSINFO"))
+ {
+ int i;
+ GdkScreen *screen = gdk_screen_get_default();
+ int monitors_count = gdk_screen_get_n_monitors(screen);
+ char *str = iupStrGetMemory(monitors_count*50);
+ char* pstr = str;
+ GdkRectangle rect;
+
+ for (i=0; i < monitors_count; i++)
+ {
+ gdk_screen_get_monitor_geometry(screen, i, &rect);
+ pstr += sprintf(pstr, "%d %d %d %d\n", rect.x, rect.y, rect.width, rect.height);
+ }
+
+ return str;
+ }
+ if (iupStrEqual(name, "TRUECOLORCANVAS"))
+ {
+ if (gdk_visual_get_best_depth() > 8)
+ return "YES";
+ else
+ return "NO";
+ }
+ if (iupStrEqual(name, "UTF8AUTOCONVERT"))
+ {
+ if (iupgtk_utf8autoconvert)
+ return "YES";
+ else
+ return "NO";
+ }
+ return NULL;
+}
diff --git a/iup/src/gtk/iupgtk_help.c b/iup/src/gtk/iupgtk_help.c
new file mode 100755
index 0000000..270677f
--- /dev/null
+++ b/iup/src/gtk/iupgtk_help.c
@@ -0,0 +1,52 @@
+/** \file
+ * \brief GTK Driver IupHelp for non Windows systems
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+
+int IupHelp(const char *url)
+{
+ GError *error = NULL;
+ gchar *argv[3];
+ int ret;
+ char *browser = getenv("IUP_HELPAPP");
+ if (!browser)
+ browser = IupGetGlobal("HELPAPP");
+
+ if (!browser)
+ {
+ char* system = IupGetGlobal("SYSTEM");
+ if (iupStrEqualNoCase(system, "Linux") ||
+ iupStrEqualNoCase(system, "FreeBSD"))
+ browser = "firefox";
+ else if (iupStrEqualNoCase(system, "Darwin"))
+ browser = "safari";
+ else if (iupStrEqualPartial(system, "CYGWIN"))
+ browser = "iexplore";
+ else
+ browser = "netscape";
+ }
+
+ argv[0] = browser;
+ argv[1] = (gchar*)url;
+ argv[2] = NULL;
+
+ ret = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
+
+ if (error)
+ g_error_free(error);
+
+ if (!ret)
+ return -1;
+ return 1;
+}
diff --git a/iup/src/gtk/iupgtk_image.c b/iup/src/gtk/iupgtk_image.c
new file mode 100755
index 0000000..b261974
--- /dev/null
+++ b/iup/src/gtk/iupgtk_image.c
@@ -0,0 +1,430 @@
+/** \file
+ * \brief Image Resource.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_drvinfo.h"
+
+#include "iupgtk_drv.h"
+
+
+void iupdrvImageGetRawData(void* handle, unsigned char* imgdata)
+{
+ GdkPixbuf* pixbuf = (GdkPixbuf*)handle;
+ int w, h, y, x, bpp;
+ guchar *pixdata, *pixline_data;
+ int rowstride, channels, planesize;
+ unsigned char *r, *g, *b, *a;
+
+ if (!iupdrvImageGetInfo(handle, &w, &h, &bpp))
+ return;
+
+ if (bpp==8)
+ return;
+
+ pixdata = gdk_pixbuf_get_pixels(pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+ channels = gdk_pixbuf_get_n_channels(pixbuf);
+
+ /* planes are separated in imgdata */
+ planesize = w*h;
+ r = imgdata;
+ g = imgdata+planesize;
+ b = imgdata+2*planesize;
+ a = imgdata+3*planesize;
+ for (y=0; y<h; y++)
+ {
+ int lineoffset = (h-1 - y)*w; /* imgdata is bottom up */
+ pixline_data = pixdata + y * rowstride;
+ for(x=0;x<w;x++)
+ {
+ int pos = x*channels;
+ r[lineoffset+x] = pixline_data[pos];
+ g[lineoffset+x] = pixline_data[pos+1];
+ b[lineoffset+x] = pixline_data[pos+2];
+
+ if (bpp == 32)
+ a[lineoffset+x] = pixline_data[pos+3];
+ }
+ }
+}
+
+void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata)
+{
+ GdkPixbuf* pixbuf;
+ guchar *pixdata, *pixline_data;
+ int rowstride, channels;
+ unsigned char *line_data;
+ int x, y, has_alpha = (bpp==32);
+ (void)colors_count;
+
+ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, width, height);
+ if (!pixbuf)
+ return NULL;
+
+ pixdata = gdk_pixbuf_get_pixels(pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+ channels = gdk_pixbuf_get_n_channels(pixbuf);
+
+ /* GdkPixbuf is top-bottom */
+ /* imgdata is bottom up */
+
+ if (bpp == 8)
+ {
+ for (y=0; y<height; y++)
+ {
+ pixline_data = pixdata + y * rowstride;
+ line_data = imgdata + (height-1 - y) * width; /* imgdata is bottom up */
+
+ for (x=0; x<width; x++)
+ {
+ unsigned char index = line_data[x];
+ iupColor* c = &colors[index];
+ guchar *r = &pixline_data[channels*x],
+ *g = r+1,
+ *b = g+1;
+
+ *r = c->r;
+ *g = c->g;
+ *b = c->b;
+ }
+ }
+ }
+ else /* bpp == 32 or bpp == 24 */
+ {
+ /* planes are separated in imgdata */
+ int planesize = width*height;
+ unsigned char *r = imgdata,
+ *g = imgdata+planesize,
+ *b = imgdata+2*planesize,
+ *a = imgdata+3*planesize;
+ for (y=0; y<height; y++)
+ {
+ int lineoffset = (height-1 - y)*width; /* imgdata is bottom up */
+ pixline_data = pixdata + y * rowstride;
+ for(x=0;x<width;x++)
+ {
+ int pos = x*channels;
+ pixline_data[pos] = r[lineoffset+x];
+ pixline_data[pos+1] = g[lineoffset+x];
+ pixline_data[pos+2] = b[lineoffset+x];
+
+ if (bpp == 32)
+ pixline_data[pos+3] = a[lineoffset+x];
+ }
+ }
+ }
+
+ return pixbuf;
+}
+
+void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive)
+{
+ GdkPixbuf* pixbuf;
+ guchar *pixdata, *pixline_data;
+ int rowstride, channels;
+ unsigned char *imgdata, *line_data, bg_r=0, bg_g=0, bg_b=0;
+ int x, y, i, bpp, colors_count = 0, has_alpha = 0;
+ iupColor colors[256];
+
+ bpp = iupAttribGetInt(ih, "BPP");
+
+ if (bpp == 8)
+ has_alpha = iupImageInitColorTable(ih, colors, &colors_count);
+ else if (bpp == 32)
+ has_alpha = 1;
+
+ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, ih->currentwidth, ih->currentheight);
+ if (!pixbuf)
+ return NULL;
+
+ pixdata = gdk_pixbuf_get_pixels(pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+ channels = gdk_pixbuf_get_n_channels(pixbuf);
+ imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+
+ if (make_inactive)
+ iupStrToRGB(bgcolor, &bg_r, &bg_g, &bg_b);
+
+ if (bpp == 8)
+ {
+ if (make_inactive)
+ {
+ for (i=0;i<colors_count;i++)
+ {
+ if (colors[i].a == 0)
+ {
+ colors[i].r = bg_r;
+ colors[i].g = bg_g;
+ colors[i].b = bg_b;
+ colors[i].a = 255;
+ }
+
+ iupImageColorMakeInactive(&(colors[i].r), &(colors[i].g), &(colors[i].b),
+ bg_r, bg_g, bg_b);
+ }
+ }
+
+ for (y=0; y<ih->currentheight; y++)
+ {
+ pixline_data = pixdata + y * rowstride;
+ line_data = imgdata + y * ih->currentwidth;
+
+ for (x=0; x<ih->currentwidth; x++)
+ {
+ unsigned char index = line_data[x];
+ iupColor* c = &colors[index];
+ guchar *r = &pixline_data[channels*x],
+ *g = r+1,
+ *b = g+1,
+ *a = b+1;
+
+ *r = c->r;
+ *g = c->g;
+ *b = c->b;
+
+ if (has_alpha)
+ *a = c->a;
+ }
+ }
+ }
+ else /* bpp == 32 or bpp == 24 */
+ {
+ for (y=0; y<ih->currentheight; y++)
+ {
+ pixline_data = pixdata + y * rowstride;
+ line_data = imgdata + y * ih->currentwidth*channels;
+
+ memcpy(pixline_data, line_data, ih->currentwidth*channels);
+
+ if (make_inactive)
+ {
+ for (x=0; x<ih->currentwidth; x++)
+ {
+ guchar *r = &pixline_data[channels*x],
+ *g = r+1,
+ *b = g+1,
+ *a = b+1;
+
+ if (has_alpha)
+ {
+ if (*a != 255)
+ {
+ *r = iupALPHABLEND(*r, bg_r, *a);
+ *g = iupALPHABLEND(*g, bg_g, *a);
+ *b = iupALPHABLEND(*b, bg_b, *a);
+ }
+ else
+ *a = 255;
+ }
+
+ iupImageColorMakeInactive(r, g, b,
+ bg_r, bg_g, bg_b);
+ }
+ }
+ }
+ }
+
+ return pixbuf;
+}
+
+void* iupdrvImageCreateIcon(Ihandle *ih)
+{
+ return iupdrvImageCreateImage(ih, NULL, 0);
+}
+
+void* iupdrvImageCreateCursor(Ihandle *ih)
+{
+ GdkCursor *cursor;
+ int hx, hy, bpp;
+
+ hx=0; hy=0;
+ iupStrToIntInt(iupAttribGet(ih, "HOTSPOT"), &hx, &hy, ':');
+
+ bpp = iupAttribGetInt(ih, "BPP");
+
+ if (bpp == 8 && !iupAttribGet(ih, "3"))
+ {
+ GdkPixmap *source, *mask;
+ GdkColor fg, bg;
+ unsigned char r, g, b;
+ char *sbits, *mbits, *sb, *mb;
+ int y, x, line_size = (ih->currentwidth+7)/8;
+ int size_bytes = line_size*ih->currentheight;
+ unsigned char* imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+
+ r = 255; g = 255; b = 255;
+ iupStrToRGB(iupAttribGet(ih, "1"), &r, &g, &b );
+ iupgdkColorSet(&fg, r, g, b);
+
+ r = 0; g = 0; b = 0;
+ iupStrToRGB(iupAttribGet(ih, "2"), &r, &g, &b );
+ iupgdkColorSet(&bg, r, g, b);
+
+ sbits = (char*)malloc(2*size_bytes);
+ if (!sbits) return NULL;
+ memset(sbits, 0, 2*size_bytes);
+ mbits = sbits + size_bytes;
+
+ sb = sbits;
+ mb = mbits;
+ for (y=0; y<ih->currentheight; y++)
+ {
+ for (x=0; x<ih->currentwidth; x++)
+ {
+ int byte = x/8;
+ int bit = x%8;
+ int index = (int)imgdata[y*ih->currentwidth+x];
+ /* index==0 is transparent */
+ if (index == 1)
+ sb[byte] = (char)(sb[byte] | (1<<bit));
+ if (index != 0)
+ mb[byte] = (char)(mb[byte] | (1<<bit));
+ }
+
+ sb += line_size;
+ mb += line_size;
+ }
+
+ source = gdk_bitmap_create_from_data(NULL, sbits, ih->currentwidth, ih->currentheight);
+ mask = gdk_bitmap_create_from_data(NULL, mbits, ih->currentwidth, ih->currentheight);
+
+ cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, hx, hy);
+
+ gdk_pixmap_unref(source);
+ gdk_pixmap_unref(mask);
+ free(sbits);
+ }
+ else
+ {
+ GdkPixbuf* pixbuf = iupdrvImageCreateImage(ih, NULL, 0);
+ cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf, hx, hy);
+ g_object_unref(pixbuf);
+ }
+
+ return cursor;
+}
+
+void* iupdrvImageCreateMask(Ihandle *ih)
+{
+ int bpp;
+ GdkPixmap *mask;
+ char *bits, *sb;
+ int y, x, line_size = (ih->currentwidth+7)/8;
+ int size_bytes = line_size*ih->currentheight;
+ unsigned char* imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+ unsigned char colors[256];
+
+ bpp = iupAttribGetInt(ih, "BPP");
+ if (bpp > 8)
+ return NULL;
+
+ bits = (char*)malloc(size_bytes);
+ if (!bits) return NULL;
+ memset(bits, 0, size_bytes);
+
+ iupImageInitNonBgColors(ih, colors);
+
+ sb = bits;
+ for (y=0; y<ih->currentheight; y++)
+ {
+ for (x=0; x<ih->currentwidth; x++)
+ {
+ int byte = x/8;
+ int bit = x%8;
+ int index = (int)imgdata[y*ih->currentwidth+x];
+ if (colors[index])
+ sb[byte] = (char)(sb[byte] | (1<<bit));
+ }
+
+ sb += line_size;
+ }
+
+ mask = gdk_bitmap_create_from_data(NULL, bits, ih->currentwidth, ih->currentheight);
+
+ free(bits);
+
+ return mask;
+}
+
+void* iupdrvImageLoad(const char* name, int type)
+{
+ if (type == IUPIMAGE_CURSOR)
+#if GTK_CHECK_VERSION(2, 8, 0)
+ return gdk_cursor_new_from_name(gdk_display_get_default(), name);
+#else
+ return NULL;
+#endif
+ else
+ {
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *pixbuf = NULL;
+
+ icon_theme = gtk_icon_theme_get_default();
+ if (gtk_icon_theme_has_icon(icon_theme, name))
+ {
+ GError *error = NULL;
+ pixbuf = gtk_icon_theme_load_icon(icon_theme, name,
+ 24, /* size */
+ 0, /* flags */
+ &error);
+ if (error)
+ g_error_free(error);
+ }
+
+ if (!pixbuf)
+ {
+ GError *error = NULL;
+ pixbuf = gdk_pixbuf_new_from_file(name, &error);
+ if (error)
+ g_error_free(error);
+ }
+
+ return pixbuf;
+ }
+}
+
+int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp)
+{
+ GdkPixbuf* pixbuf = (GdkPixbuf*)handle;
+ if (!GDK_IS_PIXBUF(pixbuf))
+ {
+ if (w) *w = 0;
+ if (h) *h = 0;
+ if (bpp) *bpp = 0;
+ return 0;
+ }
+ if (w) *w = gdk_pixbuf_get_width(pixbuf);
+ if (h) *h = gdk_pixbuf_get_height(pixbuf);
+ if (bpp) *bpp = iupImageNormBpp(gdk_pixbuf_get_bits_per_sample(pixbuf)*gdk_pixbuf_get_n_channels(pixbuf));
+ return 1;
+}
+
+int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count)
+{
+ /* GdkPixbuf are only 24 bpp or 32 bpp */
+ (void)colors;
+ (void)colors_count;
+ return iupdrvImageGetInfo(handle, w, h, bpp);
+}
+
+void iupdrvImageDestroy(void* handle, int type)
+{
+ if (type == IUPIMAGE_CURSOR)
+ gdk_cursor_unref((GdkCursor*)handle);
+ else
+ g_object_unref(handle);
+}
diff --git a/iup/src/gtk/iupgtk_key.c b/iup/src/gtk/iupgtk_key.c
new file mode 100755
index 0000000..5aec919
--- /dev/null
+++ b/iup/src/gtk/iupgtk_key.c
@@ -0,0 +1,422 @@
+/** \file
+ * \brief GTK Driver keyboard mapping
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+#include "iupkey.h"
+
+#include "iup_object.h"
+#include "iup_key.h"
+
+#include "iupgtk_drv.h"
+
+
+typedef struct _Igtk2iupkey
+{
+ guint gtkcode;
+ int iupcode;
+ int s_iupcode;
+ int c_iupcode;
+ int m_iupcode;
+ int y_iupcode;
+} Igtk2iupkey;
+
+static Igtk2iupkey gtkkey_map[] = {
+
+{ GDK_Escape, K_ESC, K_sESC, K_cESC, K_mESC ,K_yESC },
+{ GDK_Pause, K_PAUSE, K_sPAUSE, K_cPAUSE, K_mPAUSE ,K_yPAUSE },
+{ GDK_Print, K_Print, K_sPrint, K_cPrint, K_mPrint ,K_yPrint },
+{ GDK_Menu, K_Menu, K_sMenu, K_cMenu, K_mMenu ,K_yMenu },
+
+{ GDK_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME ,K_yHOME },
+{ GDK_Up, K_UP, K_sUP, K_cUP, K_mUP ,K_yUP },
+{ GDK_Prior, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP ,K_yPGUP },
+{ GDK_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT ,K_yLEFT },
+{ GDK_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE},
+{ GDK_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT ,K_yRIGHT },
+{ GDK_End, K_END, K_sEND, K_cEND, K_mEND ,K_yEND },
+{ GDK_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN ,K_yDOWN },
+{ GDK_Next, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN ,K_yPGDN },
+{ GDK_Insert, K_INS, K_sINS, K_cINS, K_mINS ,K_yINS },
+{ GDK_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL ,K_yDEL },
+{ GDK_space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP },
+{ GDK_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB },
+{ GDK_Return, K_CR, K_sCR, K_cCR, K_mCR ,K_yCR },
+{ GDK_BackSpace, K_BS, K_sBS, K_cBS, K_mBS ,K_yBS },
+
+{ GDK_1, K_1, K_exclam, K_c1, K_m1, K_y1 },
+{ GDK_2, K_2, K_at, K_c2, K_m2, K_y2 },
+{ GDK_3, K_3, K_numbersign, K_c3, K_m3, K_y3 },
+{ GDK_4, K_4, K_dollar, K_c4, K_m4, K_y4 },
+{ GDK_5, K_5, K_percent, K_c5, K_m5, K_y5 },
+{ GDK_6, K_6, K_circum, K_c6, K_m6, K_y6 },
+{ GDK_7, K_7, K_ampersand, K_c7, K_m7, K_y7 },
+{ GDK_8, K_8, K_asterisk, K_c8, K_m8, K_y8 },
+{ GDK_9, K_9, K_parentleft, K_c9, K_m9, K_y9 },
+{ GDK_0, K_0, K_parentright, K_c0, K_m0, K_y0 },
+
+/* Shift will be flaged so s_iupcode will contain the right code */
+{ GDK_exclam, K_1, K_exclam, K_c1, K_m1, K_y1 },
+{ GDK_at, K_2, K_at, K_c2, K_m2, K_y2 },
+{ GDK_numbersign, K_3, K_numbersign, K_c3, K_m3, K_y3 },
+{ GDK_dollar, K_4, K_dollar, K_c4, K_m4, K_y4 },
+{ GDK_percent, K_5, K_percent, K_c5, K_m5, K_y5 },
+{ GDK_dead_diaeresis, K_6, K_circum, K_c6, K_m6, K_y6 },
+{ GDK_ampersand, K_7, K_ampersand, K_c7, K_m7, K_y7 },
+{ GDK_asterisk, K_8, K_asterisk, K_c8, K_m8, K_y8 },
+{ GDK_parenleft, K_9, K_parentleft, K_c9, K_m9, K_y9 },
+{ GDK_parenright, K_0, K_parentright, K_c0, K_m0, K_y0 },
+
+{ GDK_a, K_a, K_A, K_cA, K_mA, K_yA },
+{ GDK_b, K_b, K_B, K_cB, K_mB, K_yB },
+{ GDK_c, K_c, K_C, K_cC, K_mC, K_yC },
+{ GDK_d, K_d, K_D, K_cD, K_mD, K_yD },
+{ GDK_e, K_e, K_E, K_cE, K_mE, K_yE },
+{ GDK_f, K_f, K_F, K_cF, K_mF, K_yF },
+{ GDK_g, K_g, K_G, K_cG, K_mG, K_yG },
+{ GDK_h, K_h, K_H, K_cH, K_mH, K_yH },
+{ GDK_i, K_i, K_I, K_cI, K_mI, K_yI },
+{ GDK_j, K_j, K_J, K_cJ, K_mJ, K_yJ },
+{ GDK_k, K_k, K_K, K_cK, K_mK, K_yK },
+{ GDK_l, K_l, K_L, K_cL, K_mL, K_yL },
+{ GDK_m, K_m, K_M, K_cM, K_mM, K_yM },
+{ GDK_n, K_n, K_N, K_cN, K_mN, K_yN },
+{ GDK_o, K_o, K_O, K_cO, K_mO, K_yO },
+{ GDK_p, K_p, K_P, K_cP, K_mP, K_yP },
+{ GDK_q, K_q, K_Q, K_cQ, K_mQ, K_yQ },
+{ GDK_r, K_r, K_R, K_cR, K_mR, K_yR },
+{ GDK_s, K_s, K_S, K_cS, K_mS, K_yS },
+{ GDK_t, K_t, K_T, K_cT, K_mT, K_yT },
+{ GDK_u, K_u, K_U, K_cU, K_mU, K_yU },
+{ GDK_v, K_v, K_V, K_cV, K_mV, K_yV },
+{ GDK_w, K_w, K_W, K_cW, K_mW, K_yW },
+{ GDK_x, K_x, K_X, K_cX, K_mX, K_yX },
+{ GDK_y, K_y, K_Y, K_cY, K_mY, K_yY },
+{ GDK_z, K_z, K_Z, K_cZ, K_mZ, K_yZ },
+
+/* Shift will be flaged so s_iupcode will contain the right code */
+{ GDK_A, K_a, K_A, K_cA, K_mA, K_yA },
+{ GDK_B, K_b, K_B, K_cB, K_mB, K_yB },
+{ GDK_C, K_c, K_C, K_cC, K_mC, K_yC },
+{ GDK_D, K_d, K_D, K_cD, K_mD, K_yD },
+{ GDK_E, K_e, K_E, K_cE, K_mE, K_yE },
+{ GDK_F, K_f, K_F, K_cF, K_mF, K_yF },
+{ GDK_G, K_g, K_G, K_cG, K_mG, K_yG },
+{ GDK_H, K_h, K_H, K_cH, K_mH, K_yH },
+{ GDK_I, K_i, K_I, K_cI, K_mI, K_yI },
+{ GDK_J, K_j, K_J, K_cJ, K_mJ, K_yJ },
+{ GDK_K, K_k, K_K, K_cK, K_mK, K_yK },
+{ GDK_L, K_l, K_L, K_cL, K_mL, K_yL },
+{ GDK_M, K_m, K_M, K_cM, K_mM, K_yM },
+{ GDK_N, K_n, K_N, K_cN, K_mN, K_yN },
+{ GDK_O, K_o, K_O, K_cO, K_mO, K_yO },
+{ GDK_P, K_p, K_P, K_cP, K_mP, K_yP },
+{ GDK_Q, K_q, K_Q, K_cQ, K_mQ, K_yQ },
+{ GDK_R, K_r, K_R, K_cR, K_mR, K_yR },
+{ GDK_S, K_s, K_S, K_cS, K_mS, K_yS },
+{ GDK_T, K_t, K_T, K_cT, K_mT, K_yT },
+{ GDK_U, K_u, K_U, K_cU, K_mU, K_yU },
+{ GDK_V, K_v, K_V, K_cV, K_mV, K_yV },
+{ GDK_W, K_w, K_W, K_cW, K_mW, K_yW },
+{ GDK_X, K_x, K_X, K_cX, K_mX, K_yX },
+{ GDK_Y, K_y, K_Y, K_cY, K_mY, K_yY },
+{ GDK_Z, K_z, K_Z, K_cZ, K_mZ, K_yZ },
+
+{ GDK_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 },
+{ GDK_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 },
+{ GDK_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 },
+{ GDK_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 },
+{ GDK_F5, K_F5, K_sF5, K_cF5, K_mF5, K_yF5 },
+{ GDK_F6, K_F6, K_sF6, K_cF6, K_mF6, K_yF6 },
+{ GDK_F7, K_F7, K_sF7, K_cF7, K_mF7, K_yF7 },
+{ GDK_F8, K_F8, K_sF8, K_cF8, K_mF8, K_yF8 },
+{ GDK_F9, K_F9, K_sF9, K_cF9, K_mF9, K_yF9 },
+{ GDK_F10, K_F10, K_sF10, K_cF10, K_mF10, K_yF10 },
+{ GDK_F11, K_F11, K_sF11, K_cF11, K_mF11, K_yF11 },
+{ GDK_F12, K_F12, K_sF12, K_cF12, K_mF12, K_yF12 },
+
+{ GDK_semicolon, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon },
+{ GDK_equal, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual },
+{ GDK_comma, K_comma, K_less, K_cComma, K_mComma, K_yComma },
+{ GDK_minus, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus },
+{ GDK_period, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod },
+{ GDK_slash, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash },
+{ GDK_grave, K_grave, K_tilde, 0, 0, 0 },
+{ GDK_bracketleft, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft },
+{ GDK_backslash, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash },
+{ GDK_bracketright,K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright },
+{ GDK_apostrophe, K_apostrophe, K_quotedbl, 0, 0, 0 },
+
+/* Shift will be flaged so s_iupcode will contain the right code */
+{ GDK_colon, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon },
+{ GDK_plus, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual },
+{ GDK_less, K_comma, K_less, K_cComma, K_mComma, K_yComma },
+{ GDK_underscore, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus },
+{ GDK_greater, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod },
+{ GDK_question, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash },
+{ GDK_braceleft, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft },
+{ GDK_bar, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash },
+{ GDK_braceright, K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright },
+{ GDK_quotedbl, K_apostrophe, K_quotedbl, 0, 0, 0 },
+
+{ GDK_KP_0, K_0, K_0, K_c0, K_m0, K_y0 },
+{ GDK_KP_1, K_1, K_1, K_c1, K_m1, K_y1 },
+{ GDK_KP_2, K_2, K_2, K_c2, K_m2, K_y2 },
+{ GDK_KP_3, K_3, K_3, K_c3, K_m3, K_y3 },
+{ GDK_KP_4, K_4, K_4, K_c4, K_m4, K_y4 },
+{ GDK_KP_5, K_5, K_5, K_c5, K_m5, K_y5 },
+{ GDK_KP_6, K_6, K_6, K_c6, K_m6, K_y6 },
+{ GDK_KP_7, K_7, K_7, K_c7, K_m7, K_y7 },
+{ GDK_KP_8, K_8, K_8, K_c8, K_m8, K_y8 },
+{ GDK_KP_9, K_9, K_9, K_c9, K_m9, K_y9 },
+{ GDK_KP_Multiply, K_asterisk, K_sAsterisk, K_cAsterisk, K_mAsterisk, K_yAsterisk },
+{ GDK_KP_Add, K_plus, K_sPlus, K_cPlus, K_mPlus, K_yPlus },
+{ GDK_KP_Subtract, K_minus, K_sMinus, K_cMinus, K_mMinus, K_yMinus },
+{ GDK_KP_Decimal, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod },
+{ GDK_KP_Divide, K_slash, K_sSlash, K_cSlash, K_mSlash, K_ySlash },
+{ GDK_KP_Separator, K_comma, K_sComma, K_cComma, K_mComma, K_yComma },
+
+{ GDK_ccedilla, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla },
+{ GDK_Ccedilla, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla },
+
+{ GDK_dead_tilde, K_tilde, K_circum, 0, 0, 0 },
+{ GDK_dead_acute, K_acute, K_grave, 0, 0, 0 },
+{ GDK_dead_grave, K_grave, K_tilde, 0, 0, 0 },
+{ GDK_dead_circumflex, K_tilde, K_circum, 0, 0, 0 },
+
+{ GDK_KP_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 },
+{ GDK_KP_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 },
+{ GDK_KP_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 },
+{ GDK_KP_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 },
+{ GDK_KP_Space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP },
+{ GDK_KP_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB },
+{ GDK_KP_Equal, K_equal, 0, K_cEqual, K_mEqual, K_yEqual },
+
+{ GDK_KP_Enter, K_CR, K_sCR, K_cCR, K_mCR, K_yCR },
+{ GDK_KP_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME, K_yHOME },
+{ GDK_KP_Up, K_UP, K_sUP, K_cUP, K_mUP, K_yUP },
+{ GDK_KP_Page_Up, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP, K_yPGUP },
+{ GDK_KP_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT, K_yLEFT },
+{ GDK_KP_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE},
+{ GDK_KP_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT, K_yRIGHT },
+{ GDK_KP_End, K_END, K_sEND, K_cEND, K_mEND, K_yEND },
+{ GDK_KP_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN, K_yDOWN },
+{ GDK_KP_Page_Down, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN, K_yPGDN },
+{ GDK_KP_Insert, K_INS, K_sINS, K_cINS, K_mINS, K_yINS },
+{ GDK_KP_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL, K_yDEL }
+
+};
+
+void iupgtkKeyEncode(int key, guint *keyval, guint *state)
+{
+ int i, iupcode = key & 0xFF; /* 0-255 interval */
+ int count = sizeof(gtkkey_map)/sizeof(gtkkey_map[0]);
+ for (i = 0; i < count; i++)
+ {
+ Igtk2iupkey* key_map = &(gtkkey_map[i]);
+ if (key_map->iupcode == iupcode)
+ {
+ *keyval = key_map->gtkcode;
+ *state = 0;
+
+ if (iupcode != key)
+ {
+ if (key_map->c_iupcode == key)
+ *state = GDK_CONTROL_MASK;
+ else if (key_map->m_iupcode == key)
+ *state = GDK_MOD1_MASK;
+ else if (key_map->y_iupcode == key)
+ *state = GDK_MOD4_MASK;
+ else if (key_map->s_iupcode == key)
+ *state = GDK_SHIFT_MASK;
+ }
+ return;
+ }
+ else if (key_map->s_iupcode == key) /* There are Shift keys bellow 256 */
+ {
+ *keyval = key_map->gtkcode;
+ *state = GDK_SHIFT_MASK;
+
+ if ((*keyval >= GDK_a) &&
+ (*keyval <= GDK_z))
+ {
+ /* remap to upper case */
+ *keyval -= GDK_a-GDK_A;
+ }
+ return;
+ }
+ }
+}
+
+static int gtkKeyMap2Iup(int state, int i)
+{
+ int code = 0;
+ if (state & GDK_CONTROL_MASK) /* Ctrl */
+ code = gtkkey_map[i].c_iupcode;
+ else if (state & GDK_MOD1_MASK ||
+ state & GDK_MOD5_MASK) /* Alt */
+ code = gtkkey_map[i].m_iupcode;
+ else if (state & GDK_MOD4_MASK) /* Apple/Win */
+ code = gtkkey_map[i].y_iupcode;
+ else if (state & GDK_LOCK_MASK) /* CapsLock */
+ {
+ if ((state & GDK_SHIFT_MASK) || !iupKeyCanCaps(gtkkey_map[i].iupcode))
+ return gtkkey_map[i].iupcode;
+ else
+ code = gtkkey_map[i].s_iupcode;
+ }
+ else if (state & GDK_SHIFT_MASK) /* Shift */
+ code = gtkkey_map[i].s_iupcode;
+ else
+ return gtkkey_map[i].iupcode;
+
+ if (!code)
+ code = gtkkey_map[i].iupcode;
+
+ return code;
+}
+
+static int gtkKeyDecode(GdkEventKey *evt)
+{
+ int i;
+ int count = sizeof(gtkkey_map)/sizeof(gtkkey_map[0]);
+ guint keyval = evt->keyval;
+
+ if ((evt->state & GDK_MOD2_MASK) && /* NumLock */
+ (keyval >= GDK_KP_Home) &&
+ (keyval <= GDK_KP_Delete))
+ {
+ /* remap to numeric keys */
+ guint remap_numkey[] = {GDK_KP_7, GDK_KP_4, GDK_KP_8, GDK_KP_6, GDK_KP_2, GDK_KP_9, GDK_KP_3, GDK_KP_1, GDK_KP_5, GDK_KP_0, GDK_KP_Decimal};
+ keyval = remap_numkey[keyval-GDK_KP_Home];
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (gtkkey_map[i].gtkcode == keyval)
+ return gtkKeyMap2Iup(evt->state, i);
+ }
+
+ return 0;
+}
+
+gboolean iupgtkKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ int result;
+ int code = gtkKeyDecode(evt);
+ 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())
+ return FALSE;
+
+ result = iupKeyCallKeyCb(ih, code);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return FALSE;
+ }
+ if (result == IUP_IGNORE)
+ return TRUE;
+
+ /* in the previous callback the dialog could be destroyed */
+ if (iupObjectCheck(ih))
+ {
+ /* this is called only for canvas */
+ if (ih->iclass->nativetype == IUP_TYPECANVAS)
+ {
+ result = iupKeyCallKeyPressCb(ih, code, 1);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return FALSE;
+ }
+ if (result == IUP_IGNORE)
+ return TRUE;
+ }
+
+ if (!iupKeyProcessNavigation(ih, code, evt->state & GDK_SHIFT_MASK))
+ return TRUE;
+
+ /* compensate the show-help limitation.
+ * It is not called on F1, only on Shift+F1 and Ctrl+F1. */
+ if (code == K_F1)
+ {
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb)
+ {
+ if (cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+ }
+ }
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+gboolean iupgtkKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ /* this is called only for canvas */
+ int result;
+ int code = gtkKeyDecode(evt);
+ if (code == 0)
+ return FALSE;
+
+ result = iupKeyCallKeyPressCb(ih, code, 0);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return FALSE;
+ }
+ if (result == IUP_IGNORE)
+ return TRUE;
+
+ (void)widget;
+ return FALSE;
+}
+
+void iupgtkButtonKeySetStatus(guint state, unsigned int but, char* status, int doubleclick)
+{
+ if (state & GDK_SHIFT_MASK)
+ iupKEYSETSHIFT(status);
+
+ if (state & GDK_CONTROL_MASK)
+ iupKEYSETCONTROL(status);
+
+ if ((state & GDK_BUTTON1_MASK) || but==1)
+ iupKEYSETBUTTON1(status);
+
+ if ((state & GDK_BUTTON2_MASK) || but==2)
+ iupKEYSETBUTTON2(status);
+
+ if ((state & GDK_BUTTON3_MASK) || but==3)
+ iupKEYSETBUTTON3(status);
+
+ if ((state & GDK_BUTTON4_MASK) || but==4)
+ iupKEYSETBUTTON4(status);
+
+ if ((state & GDK_BUTTON5_MASK) || but==5)
+ iupKEYSETBUTTON5(status);
+
+ if (state & GDK_MOD1_MASK || state & GDK_MOD5_MASK) /* Alt */
+ iupKEYSETALT(status);
+
+ if (state & GDK_MOD4_MASK) /* Apple/Win */
+ iupKEYSETSYS(status);
+
+ if (doubleclick)
+ iupKEYSETDOUBLE(status);
+}
+
diff --git a/iup/src/gtk/iupgtk_label.c b/iup/src/gtk/iupgtk_label.c
new file mode 100755
index 0000000..49d5c6d
--- /dev/null
+++ b/iup/src/gtk/iupgtk_label.c
@@ -0,0 +1,318 @@
+/** \file
+ * \brief Label Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_label.h"
+#include "iup_drv.h"
+#include "iup_image.h"
+#include "iup_focus.h"
+
+#include "iupgtk_drv.h"
+
+
+static int gtkLabelSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ {
+ GtkLabel* label = (GtkLabel*)ih->handle;
+ if (iupgtkSetMnemonicTitle(ih, label, value))
+ {
+ Ihandle* next = iupFocusNextInteractive(ih);
+ if (next)
+ {
+ if (next->handle)
+ gtk_label_set_mnemonic_widget(label, next->handle);
+ else
+ iupAttribSetStr(next, "_IUPGTK_LABELMNEMONIC", (char*)label); /* used by iupgtkUpdateMnemonic */
+ }
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+static int gtkLabelSetWordWrapAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ {
+ GtkLabel* label = (GtkLabel*)ih->handle;
+ if (iupStrBoolean(value))
+ gtk_label_set_line_wrap(label, TRUE);
+ else
+ gtk_label_set_line_wrap(label, FALSE);
+ return 1;
+ }
+ return 0;
+}
+
+static int gtkLabelSetEllipsisAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ {
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GtkLabel* label = (GtkLabel*)ih->handle;
+ if (iupStrBoolean(value))
+ gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_END);
+ else
+ gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_NONE);
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+static int gtkLabelSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ GtkMisc* misc = (GtkMisc*)ih->handle;
+ PangoAlignment alignment;
+ float xalign, yalign;
+ char value1[30]="", value2[30]="";
+
+ iupStrToStrStr(value, value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ {
+ xalign = 1.0f;
+ alignment = PANGO_ALIGN_RIGHT;
+ }
+ else if (iupStrEqualNoCase(value1, "ACENTER"))
+ {
+ xalign = 0.5f;
+ alignment = PANGO_ALIGN_CENTER;
+ }
+ else /* "ALEFT" */
+ {
+ xalign = 0;
+ alignment = PANGO_ALIGN_LEFT;
+ }
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ yalign = 1.0f;
+ else if (iupStrEqualNoCase(value2, "ATOP"))
+ yalign = 0;
+ else /* ACENTER (default) */
+ yalign = 0.5f;
+
+ gtk_misc_set_alignment(misc, xalign, yalign);
+
+ if (ih->data->type == IUP_LABEL_TEXT)
+ pango_layout_set_alignment(gtk_label_get_layout((GtkLabel*)ih->handle), alignment);
+
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkLabelSetPaddingAttrib(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)
+ {
+ GtkMisc* misc = (GtkMisc*)ih->handle;
+ gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding);
+ }
+ return 0;
+}
+
+static char* gtkLabelGetPangoLayoutAttrib(Ihandle* ih)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ return (char*)gtk_label_get_layout((GtkLabel*)ih->handle);
+ else
+ return NULL;
+}
+
+static void gtkLabelSetPixbuf(Ihandle* ih, const char* name, int make_inactive)
+{
+ GtkImage* image_label = (GtkImage*)ih->handle;
+
+ if (name)
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(name, ih, make_inactive);
+ GdkPixbuf* old_pixbuf = gtk_image_get_pixbuf(image_label);
+ if (pixbuf != old_pixbuf)
+ gtk_image_set_from_pixbuf(image_label, pixbuf);
+ return;
+ }
+
+ /* if not defined */
+#if GTK_CHECK_VERSION(2, 8, 0)
+ gtk_image_clear(image_label);
+#endif
+}
+
+static int gtkLabelSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_IMAGE)
+ {
+ if (iupdrvIsActive(ih))
+ gtkLabelSetPixbuf(ih, value, 0);
+ else
+ {
+ if (!iupAttribGet(ih, "IMINACTIVE"))
+ {
+ /* if not active and IMINACTIVE is not defined
+ then automaticaly create one based on IMAGE */
+ gtkLabelSetPixbuf(ih, value, 1); /* make_inactive */
+ }
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkLabelSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_IMAGE)
+ {
+ if (!iupdrvIsActive(ih))
+ {
+ if (value)
+ gtkLabelSetPixbuf(ih, value, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ char* name = iupAttribGet(ih, "IMAGE");
+ gtkLabelSetPixbuf(ih, name, 1); /* make_inactive */
+ }
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkLabelSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ /* update the inactive image if necessary */
+ if (ih->data->type == IUP_LABEL_IMAGE)
+ {
+ if (!iupStrBoolean(value))
+ {
+ char* name = iupAttribGet(ih, "IMINACTIVE");
+ if (name)
+ gtkLabelSetPixbuf(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ gtkLabelSetPixbuf(ih, name, 1); /* make_inactive */
+ }
+ }
+ else
+ {
+ /* must restore the normal image */
+ char* name = iupAttribGet(ih, "IMAGE");
+ gtkLabelSetPixbuf(ih, name, 0);
+ }
+ }
+
+ return iupBaseSetActiveAttrib(ih, value);
+}
+
+static int gtkLabelMapMethod(Ihandle* ih)
+{
+ char* value;
+ GtkWidget *label;
+
+ value = iupAttribGet(ih, "SEPARATOR");
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "HORIZONTAL"))
+ {
+ ih->data->type = IUP_LABEL_SEP_HORIZ;
+ label = gtk_hseparator_new();
+ }
+ else /* "VERTICAL" */
+ {
+ ih->data->type = IUP_LABEL_SEP_VERT;
+ label = gtk_vseparator_new();
+ }
+ }
+ else
+ {
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ {
+ ih->data->type = IUP_LABEL_IMAGE;
+ label = gtk_image_new();
+ }
+ else
+ {
+ ih->data->type = IUP_LABEL_TEXT;
+ label = gtk_label_new(NULL);
+ }
+ }
+
+ if (!label)
+ return IUP_ERROR;
+
+ ih->handle = label;
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ gtk_widget_realize(label);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvLabelInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkLabelMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Common GTK only (when text is in a secondary element) */
+ iupClassRegisterAttribute(ic, "PANGOLAYOUT", gtkLabelGetPangoLayoutAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, gtkLabelSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, gtkLabelSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupLabel only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkLabelSetAlignmentAttrib, "ALEFT:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkLabelSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PADDING", iupLabelGetPaddingAttrib, gtkLabelSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+
+ /* IupLabel GTK and Motif only */
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, gtkLabelSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupLabel Windows and GTK only */
+ iupClassRegisterAttribute(ic, "WORDWRAP", NULL, gtkLabelSetWordWrapAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "ELLIPSIS", NULL, gtkLabelSetEllipsisAttrib, NULL, NULL, IUPAF_DEFAULT);
+
+ /* IupLabel GTK only */
+ iupClassRegisterAttribute(ic, "MARKUP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
+}
diff --git a/iup/src/gtk/iupgtk_list.c b/iup/src/gtk/iupgtk_list.c
new file mode 100755
index 0000000..80f6cce
--- /dev/null
+++ b/iup/src/gtk/iupgtk_list.c
@@ -0,0 +1,1439 @@
+/** \file
+ * \brief List Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_mask.h"
+#include "iup_key.h"
+#include "iup_list.h"
+
+#include "iupgtk_drv.h"
+
+
+static void gtkListSelectionChanged(GtkTreeSelection* selection, Ihandle* ih);
+static void gtkListComboBoxChanged(GtkComboBox* widget, Ihandle* ih);
+
+
+void iupdrvListAddItemSpace(Ihandle* ih, int *h)
+{
+ (void)ih;
+ *h += 3;
+}
+
+void iupdrvListAddBorders(Ihandle* ih, int *x, int *y)
+{
+ int border_size = 2*5;
+ (*x) += border_size;
+ (*y) += border_size;
+
+ if (ih->data->is_dropdown)
+ {
+#ifdef HILDON
+ (*x) += 9; /* extra space for the dropdown button */
+#else
+ (*x) += 5; /* extra space for the dropdown button */
+#endif
+
+ if (ih->data->has_editbox)
+ (*x) += 5; /* another extra space for the dropdown button */
+ else
+ {
+ (*y) += 4; /* extra padding space */
+ (*x) += 4; /* extra padding space */
+ }
+ }
+ else
+ {
+ if (ih->data->has_editbox)
+ (*y) += 2*3; /* internal border between editbox and list */
+ }
+}
+
+static int gtkListConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ if (!ih->data->is_dropdown)
+ {
+ GtkTreePath* path;
+ if (gtk_tree_view_get_dest_row_at_pos((GtkTreeView*)ih->handle, x, y, &path, NULL))
+ {
+ int* indices = gtk_tree_path_get_indices(path);
+ int pos = indices[0]+1; /* IUP starts at 1 */
+ gtk_tree_path_free (path);
+ return pos;
+ }
+ }
+
+ return -1;
+}
+
+static GtkTreeModel* gtkListGetModel(Ihandle* ih)
+{
+ if (ih->data->is_dropdown)
+ return gtk_combo_box_get_model((GtkComboBox*)ih->handle);
+ else
+ return gtk_tree_view_get_model((GtkTreeView*)ih->handle);
+}
+
+int iupdrvListGetCount(Ihandle* ih)
+{
+ GtkTreeModel *model = gtkListGetModel(ih);
+ return gtk_tree_model_iter_n_children(model, NULL);
+}
+
+void iupdrvListAppendItem(Ihandle* ih, const char* value)
+{
+ GtkTreeModel *model = gtkListGetModel(ih);
+ GtkTreeIter iter;
+ gtk_list_store_append(GTK_LIST_STORE(model), &iter);
+ gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, iupgtkStrConvertToUTF8(value), -1);
+}
+
+void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value)
+{
+ GtkTreeModel *model = gtkListGetModel(ih);
+ 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);
+}
+
+void iupdrvListRemoveItem(Ihandle* ih, int pos)
+{
+ GtkTreeModel *model = gtkListGetModel(ih);
+ GtkTreeIter iter;
+ if (gtk_tree_model_iter_nth_child(model, &iter, NULL, pos))
+ {
+ if (ih->data->is_dropdown && !ih->data->has_editbox)
+ {
+ /* must check if removing the current item */
+ int curpos = gtk_combo_box_get_active((GtkComboBox*)ih->handle);
+ if (pos == curpos)
+ {
+ if (curpos > 0) curpos--;
+ else curpos++;
+
+ gtk_combo_box_set_active((GtkComboBox*)ih->handle, curpos);
+ }
+ }
+
+ gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
+ }
+}
+
+void iupdrvListRemoveAllItems(Ihandle* ih)
+{
+ GtkTreeModel *model = gtkListGetModel(ih);
+ gtk_list_store_clear(GTK_LIST_STORE(model));
+}
+
+
+/*********************************************************************************/
+
+
+static int gtkListSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+
+ if (ih->handle)
+ {
+ if (ih->data->is_dropdown)
+ {
+ GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER");
+ if (renderer)
+ {
+ g_object_set(G_OBJECT(renderer), "font-desc", (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih), NULL);
+ iupgtkFontUpdateObjectPangoLayout(ih, G_OBJECT(renderer));
+ }
+ }
+
+ if (ih->data->has_editbox)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_widget_modify_font((GtkWidget*)entry, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih));
+ iupgtkFontUpdatePangoLayout(ih, gtk_entry_get_layout(entry));
+ }
+ }
+ return 1;
+}
+
+static char* gtkListGetIdValueAttrib(Ihandle* ih, const char* name_id)
+{
+ int pos = iupListGetPos(ih, name_id);
+ if (pos != -1)
+ {
+ GtkTreeIter iter;
+ GtkTreeModel* model = gtkListGetModel(ih);
+ if (gtk_tree_model_iter_nth_child(model, &iter, NULL, pos))
+ {
+ gchar *text = NULL;
+ gtk_tree_model_get(model, &iter, 0, &text, -1);
+ if (text)
+ {
+ char* ret_str = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(text));
+ g_free(text);
+ return ret_str;
+ }
+ }
+ }
+ return NULL;
+}
+
+static int gtkListSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+
+ GtkScrolledWindow* scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (scrolled_window && !ih->data->is_dropdown)
+ {
+ /* ignore given value, must use only from parent for the scrollbars */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ if (iupStrToRGB(parent_value, &r, &g, &b))
+ {
+ GtkWidget* sb;
+
+ if (!GTK_IS_SCROLLED_WINDOW(scrolled_window))
+ scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUPGTK_SCROLLED_WINDOW");
+
+ iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ sb = gtk_scrolled_window_get_hscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+
+ sb = gtk_scrolled_window_get_vscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+#endif
+ }
+ }
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ if (ih->data->has_editbox)
+ {
+ GtkWidget* entry = (GtkWidget*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ iupgtkBaseSetBgColor(entry, r, g, b);
+ }
+
+ {
+ GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER");
+ if (renderer)
+ {
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(renderer), "cell-background-gdk", &color, NULL);
+ }
+ }
+
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+}
+
+static int gtkListSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(ih->handle, r, g, b);
+
+ if (ih->data->has_editbox)
+ {
+ GtkWidget* entry = (GtkWidget*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ iupgtkBaseSetFgColor(entry, r, g, b);
+ }
+
+ {
+ GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER");
+ if (renderer)
+ {
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(renderer), "foreground-gdk", &color, NULL);
+ }
+ }
+
+ return 1;
+}
+
+static char* gtkListGetValueAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_entry_get_text(entry)));
+ }
+ else
+ {
+ if (ih->data->is_dropdown)
+ {
+ int pos = gtk_combo_box_get_active((GtkComboBox*)ih->handle);
+ char* str = iupStrGetMemory(50);
+ sprintf(str, "%d", pos+1); /* IUP starts at 1 */
+ return str;
+ }
+ else
+ {
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ if (!ih->data->is_multiple)
+ {
+ GtkTreeIter iter;
+ GtkTreeModel* tree_model;
+ if (gtk_tree_selection_get_selected(selection, &tree_model, &iter))
+ {
+ char* str;
+ GtkTreePath *path = gtk_tree_model_get_path(tree_model, &iter);
+ int* indices = gtk_tree_path_get_indices(path);
+ str = iupStrGetMemory(50);
+ sprintf(str, "%d", indices[0]+1); /* IUP starts at 1 */
+ gtk_tree_path_free (path);
+ return str;
+ }
+ }
+ else
+ {
+ GList *il, *list = gtk_tree_selection_get_selected_rows(selection, NULL);
+ int count = iupdrvListGetCount(ih);
+ char* str = iupStrGetMemory(count+1);
+ memset(str, '-', count);
+ str[count]=0;
+ for (il=list; il; il=il->next)
+ {
+ GtkTreePath* path = (GtkTreePath*)il->data;
+ int* indices = gtk_tree_path_get_indices(path);
+ str[indices[0]] = '+';
+ gtk_tree_path_free(path);
+ }
+ g_list_free(list);
+ return str;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int gtkListSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->has_editbox)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (!value) value = "";
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_entry_set_text(entry, iupgtkStrConvertToUTF8(value));
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ else
+ {
+ if (ih->data->is_dropdown)
+ {
+ int pos;
+ 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 && 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);
+ }
+ else
+ {
+ gtk_combo_box_set_active((GtkComboBox*)ih->handle, -1); /* none */
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ }
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkListComboBoxChanged), ih);
+ }
+ else
+ {
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ if (!ih->data->is_multiple)
+ {
+ int pos;
+ g_signal_handlers_block_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+ if (iupStrToInt(value, &pos)==1)
+ {
+ GtkTreePath* path = gtk_tree_path_new_from_indices(pos-1, -1); /* IUP starts at 1 */
+ gtk_tree_selection_select_path(selection, path);
+ gtk_tree_path_free(path);
+ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos);
+ }
+ else
+ {
+ gtk_tree_selection_unselect_all(selection);
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ }
+ g_signal_handlers_unblock_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+ }
+ else
+ {
+ /* User has changed a multiple selection on a simple list. */
+ int i, len, count;
+
+ g_signal_handlers_block_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+
+ /* Clear all selections */
+ gtk_tree_selection_unselect_all(selection);
+
+ if (!value)
+ {
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ return 0;
+ }
+
+ len = strlen(value);
+ count = iupdrvListGetCount(ih);
+ if (len < count)
+ count = len;
+
+ /* update selection list */
+ for (i = 0; i<count; i++)
+ {
+ if (value[i]=='+')
+ {
+ GtkTreePath* path = gtk_tree_path_new_from_indices(i, -1);
+ gtk_tree_selection_select_path(selection, path);
+ gtk_tree_path_free(path);
+ }
+ }
+ iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value);
+ g_signal_handlers_unblock_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int gtkListSetShowDropdownAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_dropdown)
+ {
+ if (iupStrBoolean(value))
+ gtk_combo_box_popup((GtkComboBox*)ih->handle);
+ else
+ gtk_combo_box_popdown((GtkComboBox*)ih->handle);
+ }
+ return 0;
+}
+
+static int gtkListSetTopItemAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->is_dropdown)
+ {
+ int pos = 1;
+ if (iupStrToInt(value, &pos))
+ {
+ GtkTreePath* path = gtk_tree_path_new_from_indices(pos-1, -1); /* IUP starts at 1 */
+ gtk_tree_view_scroll_to_cell((GtkTreeView*)ih->handle, path, NULL, FALSE, 0, 0);
+ gtk_tree_path_free(path);
+ }
+ }
+ return 0;
+}
+
+static int gtkListSetSpacingAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_dropdown)
+ return 0;
+
+ if (!iupStrToInt(value, &ih->data->spacing))
+ ih->data->spacing = 0;
+
+ if (ih->handle)
+ {
+ GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER");
+ if (renderer)
+ g_object_set(G_OBJECT(renderer), "xpad", ih->data->spacing,
+ "ypad", ih->data->spacing,
+ NULL);
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int gtkListSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle)
+ {
+#if GTK_CHECK_VERSION(2, 10, 0)
+ GtkEntry* entry;
+ GtkBorder border;
+ border.bottom = border.top = ih->data->vert_padding;
+ border.left = border.right = ih->data->horiz_padding;
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_entry_set_inner_border(entry, &border);
+#endif
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int gtkListSetSelectionAttrib(Ihandle* ih, const char* value)
+{
+ int start=1, end=1;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ gtk_editable_select_region(GTK_EDITABLE(entry), 0, 0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<1 || end<1)
+ return 0;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ gtk_editable_select_region(GTK_EDITABLE(entry), start, end);
+
+ return 0;
+}
+
+static char* gtkListGetSelectionAttrib(Ihandle* ih)
+{
+ char *str;
+ int start, end;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end))
+ {
+ start++; /* IUP starts at 1 */
+ end++;
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", (int)start, (int)end);
+ return str;
+ }
+
+ return NULL;
+}
+
+static int gtkListSetSelectionPosAttrib(Ihandle* ih, const char* value)
+{
+ int start=0, end=0;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ gtk_editable_select_region(GTK_EDITABLE(entry), 0, 0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<0 || end<0)
+ return 0;
+
+ gtk_editable_select_region(GTK_EDITABLE(entry), start, end);
+
+ return 0;
+}
+
+static char* gtkListGetSelectionPosAttrib(Ihandle* ih)
+{
+ int start, end;
+ char *str;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end))
+ {
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", (int)start, (int)end);
+ return str;
+ }
+
+ return NULL;
+}
+
+static int gtkListSetSelectedTextAttrib(Ihandle* ih, const char* value)
+{
+ int start, end;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end))
+ {
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_editable_delete_selection(GTK_EDITABLE(entry));
+ gtk_editable_insert_text(GTK_EDITABLE(entry), iupgtkStrConvertToUTF8(value), -1, &start);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+
+ return 0;
+}
+
+static char* gtkListGetSelectedTextAttrib(Ihandle* ih)
+{
+ int start, end;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end))
+ {
+ char* selectedtext = gtk_editable_get_chars(GTK_EDITABLE(entry), start, end);
+ char* str = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(selectedtext));
+ g_free(selectedtext);
+ return str;
+ }
+
+ return NULL;
+}
+
+static int gtkListSetCaretAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ pos--; /* IUP starts at 1 */
+ if (pos < 0) pos = 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_editable_set_position(GTK_EDITABLE(entry), pos);
+
+ return 0;
+}
+
+static char* gtkListGetCaretAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char* str = iupStrGetMemory(50);
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ int pos = gtk_editable_get_position(GTK_EDITABLE(entry));
+ pos++; /* IUP starts at 1 */
+ sprintf(str, "%d", (int)pos);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int gtkListSetCaretPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_editable_set_position(GTK_EDITABLE(entry), pos);
+
+ return 0;
+}
+
+static char* gtkListGetCaretPosAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char* str = iupStrGetMemory(50);
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ int pos = gtk_editable_get_position(GTK_EDITABLE(entry));
+ sprintf(str, "%d", (int)pos);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int gtkListSetScrollToAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+ pos--; /* return to GTK referece */
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_editable_set_position(GTK_EDITABLE(entry), pos);
+
+ return 0;
+}
+
+static int gtkListSetScrollToPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_editable_set_position(GTK_EDITABLE(entry), pos);
+
+ return 0;
+}
+
+static int gtkListSetInsertAttrib(Ihandle* ih, const char* value)
+{
+ gint pos;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); /* disable callbacks */
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ pos = gtk_editable_get_position(GTK_EDITABLE(entry));
+ gtk_editable_insert_text(GTK_EDITABLE(entry), iupgtkStrConvertToUTF8(value), -1, &pos);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ return 0;
+}
+
+static int gtkListSetAppendAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->has_editbox)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gint pos = strlen(gtk_entry_get_text(entry))+1;
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); /* disable callbacks */
+ gtk_editable_insert_text(GTK_EDITABLE(entry), iupgtkStrConvertToUTF8(value), -1, &pos);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ return 0;
+}
+
+static int gtkListSetNCAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!iupStrToInt(value, &ih->data->nc))
+ ih->data->nc = INT_MAX;
+
+ if (ih->handle)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_entry_set_max_length(entry, ih->data->nc);
+ }
+
+ return 0;
+}
+
+static int gtkListSetClipboardAttrib(Ihandle *ih, const char *value)
+{
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (iupStrEqualNoCase(value, "COPY"))
+ gtk_editable_copy_clipboard(GTK_EDITABLE(entry));
+ else if (iupStrEqualNoCase(value, "CUT"))
+ gtk_editable_cut_clipboard(GTK_EDITABLE(entry));
+ else if (iupStrEqualNoCase(value, "PASTE"))
+ gtk_editable_paste_clipboard(GTK_EDITABLE(entry));
+ else if (iupStrEqualNoCase(value, "CLEAR"))
+ gtk_editable_delete_selection(GTK_EDITABLE(entry));
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ return 0;
+}
+
+static int gtkListSetReadOnlyAttrib(Ihandle* ih, const char* value)
+{
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_editable_set_editable(GTK_EDITABLE(entry), !iupStrBoolean(value));
+ return 0;
+}
+
+static char* gtkListGetReadOnlyAttrib(Ihandle* ih)
+{
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return NULL;
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (!gtk_editable_get_editable(GTK_EDITABLE(entry)))
+ return "YES";
+ else
+ return "NO";
+}
+
+
+/*********************************************************************************/
+
+
+static void gtkListEditMoveCursor(GtkWidget* entry, GtkMovementStep step, gint count, gboolean extend_selection, Ihandle* ih)
+{
+ int pos;
+
+ IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB");
+ if (!cb) return;
+
+ pos = gtk_editable_get_position(GTK_EDITABLE(entry));
+
+ if (pos != ih->data->last_caret_pos)
+ {
+ ih->data->last_caret_pos = pos;
+
+ cb(ih, 1, pos+1, pos);
+ }
+
+ (void)step;
+ (void)count;
+ (void)extend_selection;
+}
+
+static gboolean gtkListEditKeyPressEvent(GtkWidget* entry, GdkEventKey *evt, Ihandle *ih)
+{
+ if (iupgtkKeyPressEvent(entry, evt, ih) == TRUE)
+ return TRUE;
+
+ if ((evt->keyval == GDK_Up || evt->keyval == GDK_KP_Up) ||
+ (evt->keyval == GDK_Prior || evt->keyval == GDK_KP_Page_Up) ||
+ (evt->keyval == GDK_Down || evt->keyval == GDK_KP_Down) ||
+ (evt->keyval == GDK_Next || evt->keyval == GDK_KP_Page_Down))
+ {
+ int pos = -1;
+ GtkTreeIter iter;
+ GtkTreeModel* model = NULL;
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ if (gtk_tree_selection_get_selected(selection, &model, &iter))
+ {
+ GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
+ int* indices = gtk_tree_path_get_indices(path);
+ pos = indices[0];
+ gtk_tree_path_free(path);
+ }
+
+ if (pos == -1)
+ pos = 0;
+ else if (evt->keyval == GDK_Up || evt->keyval == GDK_KP_Up)
+ {
+ pos--;
+ if (pos < 0) pos = 0;
+ }
+ else if (evt->keyval == GDK_Prior || evt->keyval == GDK_KP_Page_Up)
+ {
+ pos -= 5;
+ if (pos < 0) pos = 0;
+ }
+ else if (evt->keyval == GDK_Down || evt->keyval == GDK_KP_Down)
+ {
+ int count = gtk_tree_model_iter_n_children(model, NULL);
+ pos++;
+ if (pos > count-1) pos = count-1;
+ }
+ else if (evt->keyval == GDK_Next || evt->keyval == GDK_KP_Page_Down)
+ {
+ int count = gtk_tree_model_iter_n_children(model, NULL);
+ pos += 5;
+ if (pos > count-1) pos = count-1;
+ }
+
+ if (pos != -1)
+ {
+ GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1);
+ g_signal_handlers_block_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+ gtk_tree_selection_select_path(selection, path);
+ g_signal_handlers_unblock_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+ gtk_tree_path_free(path);
+ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos);
+
+ if (!model) model = gtkListGetModel(ih);
+
+ if (gtk_tree_model_iter_nth_child(model, &iter, NULL, pos))
+ {
+ gchar *text = NULL;
+ gtk_tree_model_get(model, &iter, 0, &text, -1);
+ if (text)
+ {
+ gtk_entry_set_text((GtkEntry*)entry, text);
+ g_free(text);
+ }
+ }
+
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean gtkListEditKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ gtkListEditMoveCursor(widget, 0, 0, 0, ih);
+ (void)evt;
+ return FALSE;
+}
+
+static gboolean gtkListEditButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ gtkListEditMoveCursor(widget, 0, 0, 0, ih);
+ (void)evt;
+ return FALSE;
+}
+
+static int gtkListCallEditCb(Ihandle* ih, GtkEditable *editable, const char* insert_value, int len, int start, int end)
+{
+ char *new_value, *value;
+ int ret = -1, key = 0;
+
+ IFnis cb = (IFnis)IupGetCallback(ih, "EDIT_CB");
+ if (!cb && !ih->data->mask)
+ return -1; /* continue */
+
+ value = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_entry_get_text(GTK_ENTRY(editable))));
+
+ if (!insert_value)
+ {
+ new_value = iupStrDup(value);
+ if (end<0) end = strlen(value)+1;
+ iupStrRemove(new_value, start, end, 1);
+ }
+ else
+ {
+ if (!value)
+ new_value = iupStrDup(insert_value);
+ else
+ {
+ if (len < end-start)
+ {
+ new_value = iupStrDup(value);
+ new_value = iupStrInsert(new_value, insert_value, start, end);
+ }
+ else
+ new_value = iupStrInsert(value, insert_value, start, end);
+ }
+ }
+
+ if (insert_value && insert_value[0]!=0 && insert_value[1]==0)
+ key = insert_value[0];
+
+ if (!new_value)
+ return -1; /* continue */
+
+ if (ih->data->nc && (int)strlen(new_value) > ih->data->nc)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (cb)
+ {
+ int cb_ret = cb(ih, key, (char*)new_value);
+ if (cb_ret==IUP_IGNORE)
+ ret = 0; /* abort */
+ else if (cb_ret==IUP_CLOSE)
+ {
+ IupExitLoop();
+ ret = 0; /* abort */
+ }
+ else if (cb_ret!=0 && key!=0 &&
+ cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE)
+ ret = cb_ret; /* abort and replace */
+ }
+
+ if (new_value != value) free(new_value);
+ return ret; /* continue */
+}
+
+static void gtkListEditDeleteText(GtkEditable *editable, int start, int end, Ihandle* ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ if (gtkListCallEditCb(ih, editable, NULL, 0, start, end)==0)
+ g_signal_stop_emission_by_name(editable, "delete_text");
+}
+
+static void gtkListEditInsertText(GtkEditable *editable, char *insert_value, int len, int *pos, Ihandle* ih)
+{
+ int ret;
+
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ ret = gtkListCallEditCb(ih, editable, iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(insert_value)), len, *pos, *pos);
+ if (ret == 0)
+ g_signal_stop_emission_by_name(editable, "insert_text");
+ else if (ret != -1)
+ {
+ insert_value[0] = (char)ret; /* replace key */
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_editable_insert_text(editable, insert_value, 1, pos);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ g_signal_stop_emission_by_name(editable, "insert_text");
+ }
+}
+
+static void gtkListEditChanged(void* dummy, Ihandle* ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ iupBaseCallValueChangedCb(ih);
+ (void)dummy;
+}
+
+static void gtkListComboBoxPopupShownChanged(GtkComboBox* widget, GParamSpec *pspec, Ihandle* ih)
+{
+ IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB");
+ if (cb)
+ {
+ gboolean popup_shown;
+ g_object_get(widget, "popup-shown", &popup_shown, NULL);
+ cb(ih, popup_shown);
+ }
+ (void)pspec;
+}
+
+static void gtkListComboBoxChanged(GtkComboBox* widget, Ihandle* ih)
+{
+ IFnsii cb = (IFnsii)IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ int pos = gtk_combo_box_get_active((GtkComboBox*)ih->handle);
+ pos++; /* IUP starts at 1 */
+ iupListSingleCallActionCallback(ih, cb, pos);
+ }
+
+ if (!ih->data->has_editbox)
+ iupBaseCallValueChangedCb(ih);
+
+ (void)widget;
+}
+
+static gboolean gtkListSimpleKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (iupgtkKeyPressEvent(widget, evt, ih) == TRUE)
+ return TRUE;
+
+ if (evt->keyval == GDK_Return || evt->keyval == GDK_KP_Enter)
+ return TRUE; /* used to avoid the call to DBLCLICK_CB in the default processing */
+ return FALSE;
+}
+
+static void gtkListRowActivated(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, Ihandle* ih)
+{
+ IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB");
+ if (cb)
+ {
+ int* indices = gtk_tree_path_get_indices(path);
+ iupListSingleCallDblClickCallback(ih, cb, indices[0]+1); /* IUP starts at 1 */
+ }
+ (void)column;
+ (void)tree_view;
+}
+
+static void gtkListSelectionChanged(GtkTreeSelection* selection, Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ /* must manually update its contents */
+ GtkTreeIter iter;
+ GtkTreeModel* tree_model;
+ if (gtk_tree_selection_get_selected(selection, &tree_model, &iter))
+ {
+ GtkTreePath *path = gtk_tree_model_get_path(tree_model, &iter);
+ char* value = NULL;
+ gtk_tree_model_get(tree_model, &iter, 0, &value, -1);
+ if (value)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_entry_set_text(entry, value);
+ g_free(value);
+ }
+ gtk_tree_path_free(path);
+ }
+ }
+
+ if (!ih->data->is_multiple)
+ {
+ IFnsii cb = (IFnsii)IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iter;
+ GtkTreeModel* tree_model;
+ if (gtk_tree_selection_get_selected(selection, &tree_model, &iter))
+ {
+ GtkTreePath *path = gtk_tree_model_get_path(tree_model, &iter);
+ int* indices = gtk_tree_path_get_indices(path);
+ iupListSingleCallActionCallback(ih, cb, indices[0]+1); /* IUP starts at 1 */
+ gtk_tree_path_free (path);
+ }
+ }
+ }
+ else
+ {
+ IFns multi_cb = (IFns)IupGetCallback(ih, "MULTISELECT_CB");
+ IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION");
+ if (multi_cb || cb)
+ {
+ GList *il, *list = gtk_tree_selection_get_selected_rows(selection, NULL);
+ int i, sel_count = g_list_length(list);
+ int* pos = malloc(sizeof(int)*sel_count);
+ for (il=list, i=0; il; il=il->next, i++)
+ {
+ GtkTreePath* path = (GtkTreePath*)il->data;
+ int* indices = gtk_tree_path_get_indices(path);
+ pos[i] = indices[0];
+ gtk_tree_path_free(path);
+ }
+ g_list_free(list);
+
+ iupListMultipleCallActionCallback(ih, cb, multi_cb, pos, sel_count);
+ free(pos);
+ }
+ }
+
+ if (!ih->data->has_editbox)
+ iupBaseCallValueChangedCb(ih);
+}
+
+
+/*********************************************************************************/
+
+
+static int gtkListMapMethod(Ihandle* ih)
+{
+ GtkScrolledWindow* scrolled_window = NULL;
+ GtkListStore *store;
+
+ store = gtk_list_store_new(1, G_TYPE_STRING);
+
+ if (ih->data->is_dropdown)
+ {
+ GtkCellRenderer *renderer = NULL;
+
+ if (ih->data->has_editbox)
+ ih->handle = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(store), 0);
+ else
+ ih->handle = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
+ g_object_unref(store);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ g_object_set(G_OBJECT(ih->handle), "has-frame", TRUE, NULL);
+
+ if (ih->data->has_editbox)
+ {
+ GtkWidget *entry;
+#if GTK_CHECK_VERSION(2, 12, 0)
+ GList* list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(ih->handle));
+ renderer = list->data;
+ g_list_free(list);
+#endif
+
+ entry = gtk_bin_get_child(GTK_BIN(ih->handle));
+ iupAttribSetStr(ih, "_IUPGTK_ENTRY", (char*)entry);
+
+ g_signal_connect(G_OBJECT(entry), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+ g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+
+ g_signal_connect(G_OBJECT(entry), "delete-text", G_CALLBACK(gtkListEditDeleteText), ih);
+ g_signal_connect(G_OBJECT(entry), "insert-text", G_CALLBACK(gtkListEditInsertText), ih);
+ /* g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(gtkListEditChanged), ih); */
+ g_signal_connect_after(G_OBJECT(entry), "move-cursor", G_CALLBACK(gtkListEditMoveCursor), ih); /* only report some caret movements */
+ g_signal_connect_after(G_OBJECT(entry), "key-release-event", G_CALLBACK(gtkListEditKeyReleaseEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "button-press-event", G_CALLBACK(gtkListEditButtonEvent), ih); /* if connected "after" then it is ignored */
+ g_signal_connect(G_OBJECT(entry), "button-release-event",G_CALLBACK(gtkListEditButtonEvent), ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+ }
+ else
+ {
+ /* had to add an event box just to get get/killfocus,enter/leave events */
+ GtkWidget *box = gtk_event_box_new();
+ gtk_container_add((GtkContainer*)box, ih->handle);
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)box);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(ih->handle), renderer, TRUE);
+ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(ih->handle), renderer, "text", 0, NULL);
+
+ g_signal_connect(G_OBJECT(box), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(box), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(box), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(box), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+ else
+ GTK_WIDGET_FLAGS(box) |= GTK_CAN_FOCUS;
+ }
+
+ g_signal_connect(ih->handle, "changed", G_CALLBACK(gtkListComboBoxChanged), ih);
+ g_signal_connect(ih->handle, "notify::popup-shown", G_CALLBACK(gtkListComboBoxPopupShownChanged), ih);
+
+ if (renderer)
+ {
+ renderer->xpad = 0;
+ renderer->ypad = 0;
+ iupAttribSetStr(ih, "_IUPGTK_RENDERER", (char*)renderer);
+ }
+ }
+ else
+ {
+ GtkCellRenderer *renderer;
+ GtkTreeSelection* selection;
+ GtkTreeViewColumn *column;
+ GtkPolicyType scrollbar_policy;
+
+ ih->handle = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+ g_object_unref(store);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL);
+
+ if (ih->data->has_editbox)
+ {
+ GtkBox* vbox = (GtkBox*)gtk_vbox_new(FALSE, 0);
+
+ GtkWidget *entry = gtk_entry_new();
+ gtk_widget_show(entry);
+ gtk_box_pack_start(vbox, entry, FALSE, FALSE, 0);
+ iupAttribSetStr(ih, "_IUPGTK_ENTRY", (char*)entry);
+
+ gtk_widget_show((GtkWidget*)vbox);
+ gtk_box_pack_end(vbox, (GtkWidget*)scrolled_window, TRUE, TRUE, 0);
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)vbox);
+ iupAttribSetStr(ih, "_IUPGTK_SCROLLED_WINDOW", (char*)scrolled_window);
+
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; /* focus goes only to the edit box */
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(entry) &= ~GTK_CAN_FOCUS;
+
+ g_signal_connect(G_OBJECT(entry), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(entry), "delete-text", G_CALLBACK(gtkListEditDeleteText), ih);
+ g_signal_connect(G_OBJECT(entry), "insert-text", G_CALLBACK(gtkListEditInsertText), ih);
+ g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(gtkListEditChanged), ih);
+ g_signal_connect_after(G_OBJECT(entry), "move-cursor", G_CALLBACK(gtkListEditMoveCursor), ih); /* only report some caret movements */
+ g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(gtkListEditKeyPressEvent), ih);
+ g_signal_connect_after(G_OBJECT(entry), "key-release-event", G_CALLBACK(gtkListEditKeyReleaseEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "button-press-event", G_CALLBACK(gtkListEditButtonEvent), ih); /* if connected "after" then it is ignored */
+ g_signal_connect(G_OBJECT(entry), "button-release-event",G_CALLBACK(gtkListEditButtonEvent), ih);
+ }
+ else
+ {
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkListSimpleKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+ }
+
+ column = gtk_tree_view_column_new();
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), renderer, TRUE);
+ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(column), renderer, "text", 0, NULL);
+
+ iupAttribSetStr(ih, "_IUPGTK_RENDERER", (char*)renderer);
+ g_object_set(G_OBJECT(renderer), "xpad", 0, NULL);
+ g_object_set(G_OBJECT(renderer), "ypad", 0, NULL);
+
+ gtk_tree_view_append_column(GTK_TREE_VIEW(ih->handle), column);
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ih->handle), FALSE);
+ gtk_tree_view_set_enable_search(GTK_TREE_VIEW(ih->handle), FALSE); /* TODO: check "start-interactive-search" signal */
+
+ gtk_container_add((GtkContainer*)scrolled_window, ih->handle);
+ gtk_widget_show((GtkWidget*)scrolled_window);
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN);
+
+ if (ih->data->sb)
+ {
+ if (iupAttribGetBoolean(ih, "AUTOHIDE"))
+ scrollbar_policy = GTK_POLICY_AUTOMATIC;
+ else
+ scrollbar_policy = GTK_POLICY_ALWAYS;
+ }
+ else
+ scrollbar_policy = GTK_POLICY_NEVER;
+
+ gtk_scrolled_window_set_policy(scrolled_window, scrollbar_policy, scrollbar_policy);
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ 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)
+ gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(ih->handle), TRUE);
+#endif
+ }
+ else
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
+
+ g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(gtkListSelectionChanged), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "row-activated", G_CALLBACK(gtkListRowActivated), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(iupgtkButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(iupgtkButtonEvent), ih);
+ }
+
+ if (iupAttribGetBoolean(ih, "SORT"))
+ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), 0, GTK_SORT_ASCENDING);
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (scrolled_window)
+ gtk_widget_realize((GtkWidget*)scrolled_window);
+ gtk_widget_realize(ih->handle);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkListConvertXYToPos);
+
+ iupListSetInitialItems(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvListInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkListMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkListSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkListSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkListSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT);
+
+ /* IupList only */
+ iupClassRegisterAttributeId(ic, "IDVALUE", gtkListGetIdValueAttrib, iupListSetIdValueAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE", gtkListGetValueAttrib, gtkListSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWDROPDOWN", NULL, gtkListSetShowDropdownAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TOPITEM", NULL, gtkListSetTopItemAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPACING", iupListGetSpacingAttrib, gtkListSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupListGetPaddingAttrib, gtkListSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "SELECTEDTEXT", gtkListGetSelectedTextAttrib, gtkListSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTION", gtkListGetSelectionAttrib, gtkListSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTIONPOS", gtkListGetSelectionPosAttrib, gtkListSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARET", gtkListGetCaretAttrib, gtkListSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARETPOS", gtkListGetCaretPosAttrib, gtkListSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INSERT", NULL, gtkListSetInsertAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPEND", NULL, gtkListSetAppendAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "READONLY", gtkListGetReadOnlyAttrib, gtkListSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "NC", iupListGetNCAttrib, gtkListSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, gtkListSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTO", NULL, gtkListSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, gtkListSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_loop.c b/iup/src/gtk/iupgtk_loop.c
new file mode 100755
index 0000000..e349a45
--- /dev/null
+++ b/iup/src/gtk/iupgtk_loop.c
@@ -0,0 +1,93 @@
+/** \file
+ * \brief GTK Message Loop
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+
+/* local variables */
+static IFidle gtk_idle_cb = NULL;
+static guint gtk_idle_id;
+
+static gboolean gtkIdleFunc(gpointer data)
+{
+ (void)data;
+ if (gtk_idle_cb)
+ {
+ int ret = gtk_idle_cb();
+ if (ret == IUP_CLOSE)
+ {
+ gtk_idle_cb = NULL;
+ IupExitLoop();
+ return FALSE; /* removes the idle */
+ }
+ if (ret == IUP_IGNORE)
+ {
+ gtk_idle_cb = NULL;
+ return FALSE; /* removes the idle */
+ }
+
+ return TRUE; /* keeps the idle */
+ }
+
+ return FALSE; /* removes the idle */
+}
+
+void iupdrvSetIdleFunction(Icallback f)
+{
+ if (gtk_idle_cb)
+ g_source_remove(gtk_idle_id);
+
+ gtk_idle_cb = (IFidle)f;
+
+ if (gtk_idle_cb)
+ gtk_idle_id = g_idle_add(gtkIdleFunc, NULL);
+}
+
+void IupExitLoop(void)
+{
+ if (gtk_main_iteration_do(FALSE)==FALSE)
+ gtk_main_quit();
+}
+
+int IupMainLoopLevel(void)
+{
+ return gtk_main_level();
+}
+
+int IupMainLoop(void)
+{
+ gtk_main();
+ return IUP_NOERROR;
+}
+
+int IupLoopStep(void)
+{
+ if (gtk_main_iteration_do(FALSE))
+ return IUP_CLOSE;
+ return IUP_DEFAULT;
+}
+
+void IupFlush(void)
+{
+ IFidle old_gtk_idle_cb = NULL;
+ if (gtk_idle_cb)
+ {
+ old_gtk_idle_cb = gtk_idle_cb;
+ iupdrvSetIdleFunction(NULL);
+ }
+
+ while (gtk_events_pending())
+ gtk_main_iteration();
+
+ if (old_gtk_idle_cb)
+ iupdrvSetIdleFunction((Icallback)old_gtk_idle_cb);
+}
diff --git a/iup/src/gtk/iupgtk_menu.c b/iup/src/gtk/iupgtk_menu.c
new file mode 100755
index 0000000..c12fbea
--- /dev/null
+++ b/iup/src/gtk/iupgtk_menu.c
@@ -0,0 +1,525 @@
+/** \file
+ * \brief Menu Resources
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#ifdef HILDON
+#include <hildon/hildon-window.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_label.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+#include "iup_menu.h"
+
+#include "iupgtk_drv.h"
+
+
+typedef struct _ImenuPos
+{
+ int x, y;
+} ImenuPos;
+
+static void gtkMenuPositionFunc(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, ImenuPos *menupos)
+{
+ *x = menupos->x;
+ *y = menupos->y;
+ *push_in = FALSE;
+ (void)menu;
+}
+
+int iupdrvMenuPopup(Ihandle* ih, int x, int y)
+{
+ ImenuPos menupos;
+ menupos.x = x;
+ menupos.y = y;
+ gtk_menu_popup((GtkMenu*)ih->handle, NULL, NULL, (GtkMenuPositionFunc)gtkMenuPositionFunc,
+ (gpointer)&menupos, 0, gtk_get_current_event_time());
+ gtk_main();
+ return IUP_NOERROR;
+}
+
+int iupdrvMenuGetMenuBarSize(Ihandle* ih)
+{
+ int ch;
+ iupdrvFontGetCharSize(ih, NULL, &ch);
+#ifdef WIN32
+ return 3 + ch + 3;
+#else
+ return 4 + ch + 4;
+#endif
+}
+
+static void gtkItemUpdateImage(Ihandle* ih, const char* value, const char* image, const char* impress)
+{
+ GdkPixbuf* pixbuf;
+
+ if (!impress || !iupStrBoolean(value))
+ pixbuf = iupImageGetImage(image, ih, 0);
+ else
+ pixbuf = iupImageGetImage(impress, ih, 0);
+
+ if (pixbuf)
+ {
+ GtkWidget* image_label = gtk_image_menu_item_get_image((GtkImageMenuItem*)ih->handle);
+ if (!image_label)
+ {
+ image_label = gtk_image_new();
+ gtk_image_menu_item_set_image((GtkImageMenuItem*)ih->handle, image_label);
+ }
+
+ if (pixbuf != gtk_image_get_pixbuf((GtkImage*)image_label))
+ gtk_image_set_from_pixbuf((GtkImage*)image_label, pixbuf);
+ }
+ else
+ gtk_image_menu_item_set_image((GtkImageMenuItem*)ih->handle, NULL);
+}
+
+
+/*******************************************************************************************/
+
+
+static void gtkMenuMap(GtkWidget *widget, Ihandle* ih)
+{
+ Icallback cb = IupGetCallback(ih, "OPEN_CB");
+ if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "OPEN_CB"); /* check also in the Submenu */
+ if (cb) cb(ih);
+
+ (void)widget;
+}
+
+static void gtkMenuUnMap(GtkWidget *widget, Ihandle* ih)
+{
+ Icallback cb = IupGetCallback(ih, "MENUCLOSE_CB");
+ if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "MENUCLOSE_CB"); /* check also in the Submenu */
+ if (cb) cb(ih);
+
+ (void)widget;
+}
+
+static void gtkPopupMenuUnMap(GtkWidget *widget, Ihandle* ih)
+{
+ gtkMenuUnMap(widget, ih);
+
+ /* quit the popup loop */
+ gtk_main_quit();
+}
+
+static void gtkItemSelect(GtkWidget *widget, Ihandle* ih)
+{
+ Icallback cb = IupGetCallback(ih, "HIGHLIGHT_CB");
+ if (cb)
+ cb(ih);
+
+ cb = IupGetCallback(ih, "HELP_CB");
+ if (cb)
+ gtk_menu_set_active((GtkMenu*)ih->parent->handle, IupGetChildPos(ih->parent, ih));
+
+ (void)widget;
+}
+
+static void gtkItemActivate(GtkWidget *widget, Ihandle* ih)
+{
+ Icallback cb;
+
+ if (GTK_IS_CHECK_MENU_ITEM(ih->handle) && !iupAttribGetBoolean(ih, "AUTOTOGGLE") && !iupAttribGetBoolean(ih->parent, "RADIO"))
+ {
+ /* GTK by default will do autotoggle */
+ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
+ gtk_check_menu_item_set_active((GtkCheckMenuItem*)ih->handle, !gtk_check_menu_item_get_active((GtkCheckMenuItem*)ih->handle));
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
+ }
+
+ if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ if (iupAttribGetBoolean(ih, "AUTOTOGGLE"))
+ {
+ if (iupAttribGetBoolean(ih, "VALUE"))
+ iupAttribSetStr(ih, "VALUE", "OFF");
+ else
+ iupAttribSetStr(ih, "VALUE", "ON");
+
+ gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), iupAttribGet(ih, "IMAGE"), iupAttribGet(ih, "IMPRESS"));
+ }
+ }
+
+ cb = IupGetCallback(ih, "ACTION");
+ if (cb && cb(ih)==IUP_CLOSE)
+ IupExitLoop();
+
+ (void)widget;
+}
+
+static gboolean gtkMenuKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (evt->keyval == GDK_F1)
+ {
+ Ihandle* child;
+ GtkWidget* active = gtk_menu_get_active((GtkMenu*)widget);
+ for (child=ih->firstchild; child; child=child->brother)
+ {
+ if (child->handle == active)
+ iupgtkShowHelp(NULL, NULL, child);
+ }
+ }
+
+ (void)widget;
+ (void)evt;
+ return FALSE;
+}
+
+
+/*******************************************************************************************/
+
+
+static int gtkMenuMapMethod(Ihandle* ih)
+{
+ if (iupMenuIsMenuBar(ih))
+ {
+ /* top level menu used for MENU attribute in IupDialog (a menu bar) */
+#ifdef HILDON
+ Ihandle *pih;
+ ih->handle = gtk_menu_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ pih = iupChildTreeGetNativeParent(ih);
+ hildon_window_set_menu(HILDON_WINDOW(pih->handle), GTK_MENU(ih->handle));
+#else
+ ih->handle = gtk_menu_bar_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ iupgtkBaseAddToParent(ih);
+#endif
+ }
+ else
+ {
+ ih->handle = gtk_menu_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ if (ih->parent)
+ {
+ /* parent is a submenu */
+ gtk_menu_item_set_submenu((GtkMenuItem*)ih->parent->handle, ih->handle);
+
+ g_signal_connect(G_OBJECT(ih->handle), "map", G_CALLBACK(gtkMenuMap), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "unmap", G_CALLBACK(gtkMenuUnMap), ih);
+ }
+ else
+ {
+ /* top level menu used for IupPopup */
+ iupAttribSetStr(ih, "_IUPGTK_POPUP_MENU", "1");
+
+ g_signal_connect(G_OBJECT(ih->handle), "map", G_CALLBACK(gtkMenuMap), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "unmap", G_CALLBACK(gtkPopupMenuUnMap), ih);
+ }
+ }
+
+ gtk_widget_add_events(ih->handle, GDK_KEY_PRESS_MASK);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkMenuKeyPressEvent), ih);
+
+ ih->serial = iupMenuGetChildId(ih);
+ gtk_widget_show(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvMenuInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkMenuMapMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Used by iupdrvMenuGetMenuBarSize */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, NULL, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_DEFAULT); /* use inheritance to retrieve standard fonts */
+
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, NULL, NULL, IUPAF_DEFAULT);
+}
+
+
+/*******************************************************************************************/
+
+static int gtkItemSetTitleImageAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ gtkItemUpdateImage(ih, NULL, value, NULL);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkItemSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), value, iupAttribGet(ih, "IMPRESS"));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkItemSetImpressAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), iupAttribGet(ih, "IMAGE"), value);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkItemSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ char *str;
+ GtkWidget* label;
+
+ if (!value)
+ {
+ str = " ";
+ value = str;
+ }
+ else
+ str = iupMenuProcessTitle(ih, value);
+
+ label = gtk_bin_get_child((GtkBin*)ih->handle);
+
+ iupgtkSetMnemonicTitle(ih, (GtkLabel*)label, str);
+
+ if (str != value) free(str);
+ return 1;
+}
+
+static int gtkItemSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_CHECK_MENU_ITEM(ih->handle))
+ {
+ if (iupAttribGetBoolean(ih->parent, "RADIO"))
+ value = "ON";
+
+ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
+ gtk_check_menu_item_set_active((GtkCheckMenuItem*)ih->handle, iupStrBoolean(value));
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
+ return 0;
+ }
+ else if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ gtkItemUpdateImage(ih, value, iupAttribGet(ih, "IMAGE"), iupAttribGet(ih, "IMPRESS"));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+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";
+ }
+ else
+ return NULL;
+}
+
+static int gtkItemMapMethod(Ihandle* ih)
+{
+ int pos;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+#ifndef HILDON
+ if (iupMenuIsMenuBar(ih->parent))
+ ih->handle = gtk_menu_item_new_with_label("");
+ else
+#endif
+ {
+ if (iupAttribGet(ih, "IMAGE")||iupAttribGet(ih, "TITLEIMAGE"))
+ ih->handle = gtk_image_menu_item_new_with_label("");
+ else if (iupAttribGetBoolean(ih->parent, "RADIO"))
+ {
+ GtkRadioMenuItem* last_tg = (GtkRadioMenuItem*)iupAttribGet(ih->parent, "_IUPGTK_LASTRADIOITEM");
+ if (last_tg)
+ ih->handle = gtk_radio_menu_item_new_with_label_from_widget(last_tg, "");
+ else
+ ih->handle = gtk_radio_menu_item_new_with_label(NULL, "");
+ iupAttribSetStr(ih->parent, "_IUPGTK_LASTRADIOITEM", (char*)ih->handle);
+ }
+ else
+ {
+ char* hidemark = iupAttribGetStr(ih, "HIDEMARK");
+ if (!hidemark && gtk_check_version(2, 14, 0) == NULL)
+ {
+ /* force HIDEMARK if VALUE is defined before Map, after GTK 2.14 */
+ if (!iupAttribGet(ih, "VALUE"))
+ hidemark = "YES";
+ }
+
+ if (iupStrBoolean(hidemark))
+ ih->handle = gtk_menu_item_new_with_label("");
+ else
+ ih->handle = gtk_check_menu_item_new_with_label("");
+ }
+ }
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupMenuGetChildId(ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "select", G_CALLBACK(gtkItemSelect), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "activate", G_CALLBACK(gtkItemActivate), ih);
+
+ pos = IupGetChildPos(ih->parent, ih);
+ gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos);
+ gtk_widget_show(ih->handle);
+
+ iupUpdateStandardFontAttrib(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvItemInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkItemMapMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* IupItem only */
+ iupClassRegisterAttribute(ic, "VALUE", gtkItemGetValueAttrib, gtkItemSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, gtkItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TITLEIMAGE", NULL, gtkItemSetTitleImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkItemSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, gtkItemSetImpressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupItem GTK and Motif only */
+ iupClassRegisterAttribute(ic, "HIDEMARK", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED);
+}
+
+
+/*******************************************************************************************/
+
+
+static int gtkSubmenuSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ gtkItemUpdateImage(ih, NULL, value, NULL);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int motSubmenuMapMethod(Ihandle* ih)
+{
+ int pos;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+#ifndef HILDON
+ if (iupMenuIsMenuBar(ih->parent))
+ ih->handle = gtk_menu_item_new_with_label("");
+ else
+#endif
+ ih->handle = gtk_image_menu_item_new_with_label("");
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupMenuGetChildId(ih);
+
+ pos = IupGetChildPos(ih->parent, ih);
+ gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos);
+ gtk_widget_show(ih->handle);
+
+ g_signal_connect(G_OBJECT(ih->handle), "select", G_CALLBACK(gtkItemSelect), ih);
+
+ iupUpdateStandardFontAttrib(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvSubmenuInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motSubmenuMapMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* IupSubmenu only */
+ iupClassRegisterAttribute(ic, "TITLE", NULL, gtkItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkSubmenuSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+}
+
+
+/*******************************************************************************************/
+
+
+static int gtkSeparatorMapMethod(Ihandle* ih)
+{
+ int pos;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ ih->handle = gtk_separator_menu_item_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupMenuGetChildId(ih);
+
+ pos = IupGetChildPos(ih->parent, ih);
+ gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos);
+ gtk_widget_show(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvSeparatorInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkSeparatorMapMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+}
diff --git a/iup/src/gtk/iupgtk_messagedlg.c b/iup/src/gtk/iupgtk_messagedlg.c
new file mode 100755
index 0000000..a036af6
--- /dev/null
+++ b/iup/src/gtk/iupgtk_messagedlg.c
@@ -0,0 +1,128 @@
+/** \file
+ * \brief GTK IupMessageDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+
+#include "iupgtk_drv.h"
+
+/* Sometimes GTK decides to invert the buttons position because of the GNOME Guidelines.
+ To avoid that we define different Ids for the buttons. */
+#define IUP_RESPONSE_1 -100
+#define IUP_RESPONSE_2 -200
+#define IUP_RESPONSE_HELP -300
+
+#ifndef GTK_MESSAGE_OTHER
+#define GTK_MESSAGE_OTHER GTK_MESSAGE_INFO
+#endif
+
+static int gtkMessageDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ GtkMessageType type = GTK_MESSAGE_OTHER;
+ GtkWidget* dialog;
+ char *icon, *buttons, *title;
+ int response, num_but = 2;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ icon = iupAttribGetStr(ih, "DIALOGTYPE");
+ if (iupStrEqualNoCase(icon, "ERROR"))
+ type = GTK_MESSAGE_ERROR;
+ else if (iupStrEqualNoCase(icon, "WARNING"))
+ type = GTK_MESSAGE_WARNING;
+ else if (iupStrEqualNoCase(icon, "INFORMATION"))
+ type = GTK_MESSAGE_INFO;
+ else if (iupStrEqualNoCase(icon, "QUESTION"))
+ type = GTK_MESSAGE_QUESTION;
+
+ dialog = gtk_message_dialog_new((GtkWindow*)parent,
+ 0,
+ type,
+ GTK_BUTTONS_NONE,
+ iupgtkStrConvertToUTF8(iupAttribGet(ih, "VALUE")));
+ if (!dialog)
+ return IUP_ERROR;
+
+ title = iupAttribGet(ih, "TITLE");
+ if (title)
+ gtk_window_set_title(GTK_WINDOW(dialog), iupgtkStrConvertToUTF8(title));
+
+ buttons = iupAttribGetStr(ih, "BUTTONS");
+ if (iupStrEqualNoCase(buttons, "OKCANCEL"))
+ {
+ gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_OK,
+ IUP_RESPONSE_1);
+ gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_CANCEL,
+ IUP_RESPONSE_2);
+ }
+ else if (iupStrEqualNoCase(buttons, "YESNO"))
+ {
+ gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_YES,
+ IUP_RESPONSE_1);
+ gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_NO,
+ IUP_RESPONSE_2);
+ }
+ else /* OK */
+ {
+ gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_OK,
+ IUP_RESPONSE_1);
+ num_but = 1;
+ }
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_HELP, IUP_RESPONSE_HELP);
+
+ if (num_but == 2 && iupAttribGetInt(ih, "BUTTONDEFAULT") == 2)
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), IUP_RESPONSE_2);
+ else
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), IUP_RESPONSE_1);
+
+ /* initialize the widget */
+ gtk_widget_realize(dialog);
+
+ ih->handle = dialog;
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL;
+
+ do
+ {
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+ if (response == IUP_RESPONSE_HELP)
+ {
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ response = (num_but == 2)? IUP_RESPONSE_2: IUP_RESPONSE_1;
+ }
+ } while (response == IUP_RESPONSE_HELP);
+
+ if (response == IUP_RESPONSE_1)
+ IupSetAttribute(ih, "BUTTONRESPONSE", "1");
+ else
+ IupSetAttribute(ih, "BUTTONRESPONSE", "2");
+
+ gtk_widget_destroy(dialog);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvMessageDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = gtkMessageDlgPopup;
+}
diff --git a/iup/src/gtk/iupgtk_open.c b/iup/src/gtk/iupgtk_open.c
new file mode 100755
index 0000000..66e46e8
--- /dev/null
+++ b/iup/src/gtk/iupgtk_open.c
@@ -0,0 +1,172 @@
+/** \file
+ * \brief GTK Driver Core
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_object.h"
+#include "iup_globalattrib.h"
+
+#include "iupgtk_drv.h"
+
+
+#ifdef WIN32 /******************************** WIN32 ************************************/
+#include <gdk/gdkwin32.h>
+
+char* iupgtkGetNativeWindowHandle(Ihandle* ih)
+{
+ GdkWindow* window = ih->handle->window;
+ if (window)
+ return (char*)GDK_WINDOW_HWND(window);
+ else
+ return NULL;
+}
+
+void* iupgtkGetNativeGraphicsContext(GtkWidget* widget)
+{
+ return GetDC(GDK_WINDOW_HWND(widget->window));
+}
+
+void iupgtkReleaseNativeGraphicsContext(GtkWidget* widget, void* gc)
+{
+ ReleaseDC(GDK_WINDOW_HWND(widget->window), (HDC)gc);
+}
+
+void* iupdrvGetDisplay(void)
+{
+ return NULL;
+}
+
+void iupgtkPushVisualAndColormap(void* visual, void* colormap)
+{
+ (void)visual;
+ (void)colormap;
+}
+
+static void gtkSetDrvGlobalAttrib(void)
+{
+}
+
+#else /******************************** X11 ************************************/
+#include <gdk/gdkx.h>
+
+char* iupgtkGetNativeWindowHandle(Ihandle* ih)
+{
+ GdkWindow* window = ih->handle->window;
+ if (window)
+ return (char*)GDK_WINDOW_XID(window);
+ else
+ return NULL;
+}
+
+void* iupgtkGetNativeGraphicsContext(GtkWidget* widget)
+{
+ GdkDisplay* display = gdk_display_get_default();
+ return (void*)XCreateGC(GDK_DISPLAY_XDISPLAY(display), GDK_WINDOW_XID(widget->window), 0, NULL);
+}
+
+void iupgtkReleaseNativeGraphicsContext(GtkWidget* widget, void* gc)
+{
+ GdkDisplay* display = gdk_display_get_default();
+ XFreeGC(GDK_DISPLAY_XDISPLAY(display), (GC)gc);
+ (void)widget;
+}
+
+void* iupdrvGetDisplay(void)
+{
+ GdkDisplay* display = gdk_display_get_default();
+ return GDK_DISPLAY_XDISPLAY(display);
+}
+
+void iupgtkPushVisualAndColormap(void* visual, void* colormap)
+{
+ GdkColormap* gdk_colormap;
+ GdkVisual *gdk_visual = gdkx_visual_get(XVisualIDFromVisual((Visual*)visual));
+ if (colormap)
+ gdk_colormap = gdk_x11_colormap_foreign_new(gdk_visual, (Colormap)colormap);
+ else
+ 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)
+{
+ GdkDisplay* display = gdk_display_get_default();
+ Display* xdisplay = GDK_DISPLAY_XDISPLAY(display);
+ IupSetGlobal("XDISPLAY", (char*)xdisplay);
+ IupSetGlobal("XSCREEN", (char*)XDefaultScreen(xdisplay));
+ IupSetGlobal("XSERVERVENDOR", ServerVendor(xdisplay));
+ IupSetfAttribute(NULL, "XVENDORRELEASE", "%d", VendorRelease(xdisplay));
+}
+
+#endif
+
+static void gtkSetGlobalColorAttrib(const char* name, GdkColor *color)
+{
+ iupGlobalSetDefaultColorAttrib(name, (int)iupCOLOR16TO8(color->red),
+ (int)iupCOLOR16TO8(color->green),
+ (int)iupCOLOR16TO8(color->blue));
+}
+
+void iupgtkUpdateGlobalColors(GtkStyle* style)
+{
+ GdkColor color = style->bg[GTK_STATE_NORMAL];
+ gtkSetGlobalColorAttrib("DLGBGCOLOR", &color);
+
+ color = style->fg[GTK_STATE_NORMAL];
+ gtkSetGlobalColorAttrib("DLGFGCOLOR", &color);
+
+ color = style->base[GTK_STATE_NORMAL];
+ gtkSetGlobalColorAttrib("TXTBGCOLOR", &color);
+
+ color = style->text[GTK_STATE_NORMAL];
+ gtkSetGlobalColorAttrib("TXTFGCOLOR", &color);
+}
+
+int iupdrvOpen(int *argc, char ***argv)
+{
+ GtkStyle* style;
+
+ if (!gtk_init_check(argc, argv))
+ return IUP_ERROR;
+
+ IupSetGlobal("DRIVER", "GTK");
+
+ IupStoreGlobal("SYSTEMLANGUAGE", pango_language_to_string(gtk_get_default_language()));
+
+ /* driver system version */
+ IupSetfAttribute(NULL, "GTKVERSION", "%d.%d.%d", gtk_major_version,
+ gtk_minor_version,
+ gtk_micro_version);
+ IupSetfAttribute(NULL, "GTKDEVVERSION", "%d.%d.%d", GTK_MAJOR_VERSION,
+ GTK_MINOR_VERSION,
+ GTK_MICRO_VERSION);
+
+ gtkSetDrvGlobalAttrib();
+
+ style = gtk_style_new();
+ iupgtkUpdateGlobalColors(style);
+ IupSetGlobal("_IUP_RESET_GLOBALCOLORS", "YES"); /* will update the global colors when the first dialog is mapped */
+ g_object_unref(style);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvClose(void)
+{
+ iupgtkReleaseConvertUTF8();
+}
diff --git a/iup/src/gtk/iupgtk_progressbar.c b/iup/src/gtk/iupgtk_progressbar.c
new file mode 100755
index 0000000..7bc6cbb
--- /dev/null
+++ b/iup/src/gtk/iupgtk_progressbar.c
@@ -0,0 +1,131 @@
+/** \file
+* \brief Progress bar Control
+*
+* See Copyright Notice in "iup.h"
+*/
+
+#undef GTK_DISABLE_DEPRECATED
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_progressbar.h"
+#include "iup_drv.h"
+
+#include "iupgtk_drv.h"
+
+
+static int gtkProgressBarSetMarqueeAttrib(Ihandle* ih, const char* value)
+{
+ GtkProgress* progress = (GtkProgress*)ih->handle;
+
+ if (iupStrBoolean(value))
+ {
+ ih->data->marquee = 1;
+ gtk_progress_set_activity_mode(progress, TRUE);
+ }
+ else
+ {
+ gtk_progress_set_activity_mode(progress, FALSE);
+ ih->data->marquee = 0;
+ }
+
+ return 1;
+}
+
+static int gtkProgressBarSetValueAttrib(Ihandle* ih, const char* value)
+{
+ GtkProgressBar* pbar = (GtkProgressBar*)ih->handle;
+
+ if (!value)
+ ih->data->value = 0;
+ else
+ ih->data->value = atof(value);
+ iProgressBarCropValue(ih);
+
+ if (ih->data->marquee)
+ gtk_progress_bar_pulse(pbar);
+ else
+ gtk_progress_bar_set_fraction(pbar, (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin));
+
+ return 0;
+}
+
+static int gtkProgressBarSetDashedAttrib(Ihandle* ih, const char* value)
+{
+ GtkProgressBar* pbar = (GtkProgressBar*)ih->handle;
+
+ /* gtk_progress_bar_set_bar_style is deprecated */
+ if (iupStrBoolean(value))
+ {
+ ih->data->dashed = 1;
+ gtk_progress_bar_set_bar_style(pbar, GTK_PROGRESS_DISCRETE);
+ }
+ else /* Default */
+ {
+ ih->data->dashed = 0;
+ gtk_progress_bar_set_bar_style(pbar, GTK_PROGRESS_CONTINUOUS);
+ }
+
+ return 0;
+}
+
+static int gtkProgressBarMapMethod(Ihandle* ih)
+{
+ ih->handle = gtk_progress_bar_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ gtk_widget_realize(ih->handle);
+
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL"))
+ {
+ gtk_progress_bar_set_orientation((GtkProgressBar*)ih->handle, GTK_PROGRESS_BOTTOM_TO_TOP);
+
+ if (ih->currentheight < ih->currentwidth)
+ {
+ int tmp = ih->currentheight;
+ ih->currentheight = ih->currentwidth;
+ ih->currentwidth = tmp;
+ }
+ }
+ else
+ gtk_progress_bar_set_orientation((GtkProgressBar*)ih->handle, GTK_PROGRESS_LEFT_TO_RIGHT);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvProgressBarInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkProgressBarMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
+
+ /* IupProgressBar only */
+ iupClassRegisterAttribute(ic, "VALUE", iProgressBarGetValueAttrib, gtkProgressBarSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DASHED", iProgressBarGetDashedAttrib, gtkProgressBarSetDashedAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MARQUEE", NULL, gtkProgressBarSetMarqueeAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DASHED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_tabs.c b/iup/src/gtk/iupgtk_tabs.c
new file mode 100755
index 0000000..8029826
--- /dev/null
+++ b/iup/src/gtk/iupgtk_tabs.c
@@ -0,0 +1,444 @@
+/** \file
+* \brief Tabs Control
+*
+* See Copyright Notice in "iup.h"
+*/
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_image.h"
+#include "iup_tabs.h"
+
+#include "iupgtk_drv.h"
+
+
+int iupdrvTabsExtraDecor(Ihandle* ih)
+{
+ (void)ih;
+ return 0;
+}
+
+int iupdrvTabsGetLineCountAttrib(Ihandle* ih)
+{
+ (void)ih;
+ return 1;
+}
+
+void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos)
+{
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", "1");
+ gtk_notebook_set_current_page((GtkNotebook*)ih->handle, pos);
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", NULL);
+}
+
+int iupdrvTabsGetCurrentTab(Ihandle* ih)
+{
+ return gtk_notebook_get_current_page((GtkNotebook*)ih->handle);
+}
+
+static void gtkTabsUpdatePageFont(Ihandle* ih)
+{
+ Ihandle* child;
+ PangoFontDescription* fontdesc = (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih);
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL");
+ if (tab_label)
+ {
+ gtk_widget_modify_font(tab_label, fontdesc);
+ iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)tab_label));
+ }
+ }
+}
+
+static void gtkTabsUpdatePageBgColor(Ihandle* ih, unsigned char r, unsigned char g, unsigned char b)
+{
+ Ihandle* child;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ if (tab_page)
+ {
+ GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL");
+ if (tab_label)
+ iupgtkBaseSetBgColor(tab_label, r, g, b);
+ iupgtkBaseSetBgColor(tab_page, r, g, b);
+ }
+ }
+}
+
+static void gtkTabsUpdatePageFgColor(Ihandle* ih, unsigned char r, unsigned char g, unsigned char b)
+{
+ Ihandle* child;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL");
+ if (tab_label)
+ iupgtkBaseSetFgColor(tab_label, r, g, b);
+ }
+}
+
+static void gtkTabsUpdatePagePadding(Ihandle* ih)
+{
+ Ihandle* child;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL");
+ if (tab_label)
+ gtk_misc_set_padding((GtkMisc*)tab_label, ih->data->horiz_padding, ih->data->vert_padding);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* gtkTabs - Sets and Gets accessors */
+/* ------------------------------------------------------------------------- */
+
+
+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;
+}
+
+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]);
+}
+
+static int gtkTabsSetTabTypeAttrib(Ihandle* ih, const char* value)
+{
+ if(iupStrEqualNoCase(value, "BOTTOM"))
+ ih->data->type = ITABS_BOTTOM;
+ else if(iupStrEqualNoCase(value, "LEFT"))
+ ih->data->type = ITABS_LEFT;
+ else if(iupStrEqualNoCase(value, "RIGHT"))
+ ih->data->type = ITABS_RIGHT;
+ else /* "TOP" */
+ ih->data->type = ITABS_TOP;
+
+ if (ih->handle)
+ gtkTabsUpdateTabType(ih);
+
+ return 0;
+}
+
+static int gtkTabsSetTabOrientationAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->handle) /* allow to set only before mapping */
+ return 0;
+
+ if(iupStrEqualNoCase(value, "VERTICAL"))
+ ih->data->orientation = ITABS_VERTICAL;
+ else /* HORIZONTAL */
+ ih->data->orientation = ITABS_HORIZONTAL;
+
+ return 0;
+}
+
+static int gtkTabsSetTabTitleAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int pos;
+ if (value && iupStrToInt(name_id, &pos)==1)
+ {
+ Ihandle* child = IupGetChild(ih, pos);
+ GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL");
+ if (tab_label)
+ {
+ GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ 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));
+ }
+ }
+ return 1;
+}
+
+static int gtkTabsSetTabImageAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int pos;
+ if (value && iupStrToInt(name_id, &pos)==1)
+ {
+ Ihandle* child = IupGetChild(ih, pos);
+ GtkWidget* tab_image = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABIMAGE");
+ if (tab_image)
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(value, ih, 0);
+ if (pixbuf)
+ gtk_image_set_from_pixbuf((GtkImage*)tab_image, pixbuf);
+ }
+ }
+ return 1;
+}
+
+static int gtkTabsSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+ if (ih->handle)
+ gtkTabsUpdatePageFont(ih);
+ return 1;
+}
+
+static int gtkTabsSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(ih->handle, r, g, b);
+ gtkTabsUpdatePageFgColor(ih, r, g, b);
+
+ return 1;
+}
+
+static int gtkTabsSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetBgColor(ih->handle, r, g, b);
+ gtkTabsUpdatePageBgColor(ih, r, g, b);
+
+ return 1;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* gtkTabs - Callbacks */
+/* ------------------------------------------------------------------------- */
+
+void gtkTabSwitchPage(GtkNotebook* notebook, GtkNotebookPage *page, int pos, Ihandle* ih)
+{
+ IFnnn cb;
+ Ihandle* child = IupGetChild(ih, pos);
+ Ihandle* prev_child = IupGetChild(ih, iupdrvTabsGetCurrentTab(ih));
+ IupSetAttribute(child, "VISIBLE", "YES");
+ IupSetAttribute(prev_child, "VISIBLE", "NO");
+
+ if (iupAttribGet(ih, "_IUPGTK_IGNORE_CHANGE"))
+ return;
+
+ cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB");
+ if (cb)
+ cb(ih, child, prev_child);
+
+ (void)notebook;
+ (void)page;
+}
+
+/* ------------------------------------------------------------------------- */
+/* gtkTabs - Methods and Init Class */
+/* ------------------------------------------------------------------------- */
+
+static void gtkTabsChildAddedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (IupGetName(child) == NULL)
+ iupAttribSetHandleName(child);
+
+ if (ih->handle)
+ {
+ GtkWidget* tab_page;
+ GtkWidget *tab_label = NULL, *tab_image = NULL;
+ char *tabtitle, *tabimage;
+ int pos;
+ unsigned char r, g, b;
+
+ pos = IupGetChildPos(ih, child);
+
+ tab_page = gtk_fixed_new();
+ gtk_widget_show(tab_page);
+
+ tabtitle = iupAttribGet(child, "TABTITLE");
+ if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos);
+ tabimage = iupAttribGet(child, "TABIMAGE");
+ if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos);
+ if (!tabtitle && !tabimage)
+ tabtitle = " ";
+
+ if (tabtitle)
+ {
+ tab_label = gtk_label_new(iupgtkStrConvertToUTF8(tabtitle));
+
+#if GTK_CHECK_VERSION(2, 6, 0)
+ if (ih->data->orientation == ITABS_VERTICAL)
+ gtk_label_set_angle((GtkLabel*)tab_label, 90);
+#endif
+ }
+
+ if (tabimage)
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(tabimage, ih, 0);
+
+ tab_image = gtk_image_new();
+
+ if (pixbuf)
+ gtk_image_set_from_pixbuf((GtkImage*)tab_image, pixbuf);
+ }
+
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", "1");
+
+ if (tabimage && tabtitle)
+ {
+ GtkWidget* box;
+ if (ih->data->orientation == ITABS_VERTICAL)
+ box = gtk_vbox_new(FALSE, 2);
+ else
+ box = gtk_hbox_new(FALSE, 2);
+ gtk_widget_show(box);
+
+ gtk_container_add((GtkContainer*)box, tab_image);
+ gtk_container_add((GtkContainer*)box, tab_label);
+
+ gtk_notebook_insert_page((GtkNotebook*)ih->handle, tab_page, box, pos);
+ gtk_notebook_set_menu_label_text((GtkNotebook*)ih->handle, tab_page, gtk_label_get_text((GtkLabel*)tab_label));
+ }
+ else if (tabimage)
+ gtk_notebook_insert_page((GtkNotebook*)ih->handle, tab_page, tab_image, pos);
+ else
+ gtk_notebook_insert_page((GtkNotebook*)ih->handle, tab_page, tab_label, pos);
+
+ gtk_widget_realize(tab_page);
+
+ 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);
+ iupStrToRGB(IupGetAttribute(ih, "BGCOLOR"), &r, &g, &b);
+ iupgtkBaseSetBgColor(tab_page, r, g, b);
+
+ if (tabtitle)
+ {
+ PangoFontDescription* fontdesc = (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih);
+ gtk_widget_modify_font(tab_label, fontdesc);
+ iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)tab_label));
+
+ iupgtkBaseSetBgColor(tab_label, r, g, b);
+
+ iupStrToRGB(IupGetAttribute(ih, "FGCOLOR"), &r, &g, &b);
+ iupgtkBaseSetFgColor(tab_label, r, g, b);
+
+ gtk_widget_show(tab_label);
+ gtk_widget_realize(tab_label);
+ }
+
+ if (tabimage)
+ {
+ gtk_widget_show(tab_image);
+ gtk_widget_realize(tab_image);
+ }
+
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", NULL);
+
+ if (pos == iupdrvTabsGetCurrentTab(ih))
+ IupSetAttribute(child, "VISIBLE", "YES");
+ else
+ IupSetAttribute(child, "VISIBLE", "NO");
+ }
+}
+
+static void gtkTabsChildRemovedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (ih->handle)
+ {
+ GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ if (tab_page)
+ {
+ int pos = gtk_notebook_page_num((GtkNotebook*)ih->handle, tab_page);
+
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", "1");
+ gtk_notebook_remove_page((GtkNotebook*)ih->handle, pos);
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", NULL);
+
+ iupAttribSetStr(child, "_IUPGTK_TABIMAGE", NULL);
+ iupAttribSetStr(child, "_IUPGTK_TABLABEL", NULL);
+ iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL);
+ }
+ }
+}
+
+static int gtkTabsMapMethod(Ihandle* ih)
+{
+ ih->handle = gtk_notebook_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ gtk_notebook_set_scrollable((GtkNotebook*)ih->handle, TRUE);
+ gtk_notebook_popup_enable((GtkNotebook*)ih->handle);
+
+ gtkTabsUpdateTabType(ih);
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ gtk_widget_add_events(ih->handle, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK);
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "switch-page", G_CALLBACK(gtkTabSwitchPage), ih);
+
+ gtk_widget_realize(ih->handle);
+
+ /* Create pages and tabs */
+ if (ih->firstchild)
+ {
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ gtkTabsChildAddedMethod(ih, child);
+ }
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTabsInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkTabsMapMethod;
+ ic->ChildAdded = gtkTabsChildAddedMethod;
+ ic->ChildRemoved = gtkTabsChildRemovedMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkTabsSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTabsSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkTabsSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+
+ /* IupTabs only */
+ iupClassRegisterAttribute(ic, "TABTYPE", iupTabsGetTabTypeAttrib, gtkTabsSetTabTypeAttrib, IUPAF_SAMEASSYSTEM, "TOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ 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);
+}
diff --git a/iup/src/gtk/iupgtk_text.c b/iup/src/gtk/iupgtk_text.c
new file mode 100755
index 0000000..4c2906a
--- /dev/null
+++ b/iup/src/gtk/iupgtk_text.c
@@ -0,0 +1,1716 @@
+/** \file
+ * \brief Text Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_mask.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+#include "iup_key.h"
+#include "iup_array.h"
+#include "iup_text.h"
+
+#include "iupgtk_drv.h"
+
+#ifndef PANGO_WEIGHT_SEMIBOLD
+#define PANGO_WEIGHT_SEMIBOLD 600
+#endif
+
+void iupdrvTextAddSpin(int *w, int h)
+{
+ int spin_size = 16;
+ *w += spin_size;
+ (void)h;
+}
+
+void iupdrvTextAddBorders(int *x, int *y)
+{
+ int border_size = 2*5;
+ (*x) += border_size;
+ (*y) += border_size;
+}
+
+static void gtkTextParseParagraphFormat(Ihandle* formattag, GtkTextTag* tag)
+{
+ int val;
+ char* format;
+
+ format = iupAttribGet(formattag, "INDENT");
+ if (format && iupStrToInt(format, &val))
+ g_object_set(G_OBJECT(tag), "indent", val, NULL);
+
+ format = iupAttribGet(formattag, "ALIGNMENT");
+ if (format)
+ {
+ if (iupStrEqualNoCase(format, "JUSTIFY"))
+ val = GTK_JUSTIFY_FILL;
+ else if (iupStrEqualNoCase(format, "RIGHT"))
+ val = GTK_JUSTIFY_RIGHT;
+ else if (iupStrEqualNoCase(format, "CENTER"))
+ val = GTK_JUSTIFY_CENTER;
+ else /* "LEFT" */
+ val = GTK_JUSTIFY_LEFT;
+
+ g_object_set(G_OBJECT(tag), "justification", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "TABSARRAY");
+ {
+ PangoTabArray *tabs;
+ int pos, i = 0;
+ PangoTabAlign align;
+ char* str;
+
+ tabs = pango_tab_array_new(32, FALSE);
+
+ while (format)
+ {
+ str = iupStrCopyUntil((char**)&format, ' ');
+ if (!str) break;
+ pos = atoi(str);
+ free(str);
+
+ str = iupStrCopyUntil((char**)&format, ' ');
+ if (!str) break;
+
+/* if (iupStrEqualNoCase(str, "DECIMAL")) unsupported for now
+ align = PANGO_TAB_NUMERIC;
+ else if (iupStrEqualNoCase(str, "RIGHT"))
+ align = PANGO_TAB_RIGHT;
+ else if (iupStrEqualNoCase(str, "CENTER"))
+ align = PANGO_TAB_CENTER;
+ else */ /* "LEFT" */
+ align = PANGO_TAB_LEFT;
+ free(str);
+
+ pango_tab_array_set_tab(tabs, i, align, IUPGTK_PIXELS2PANGOUNITS(pos));
+ i++;
+ if (i == 32) break;
+ }
+
+ g_object_set(G_OBJECT(tag), "tabs", tabs, NULL);
+ pango_tab_array_free(tabs);
+ }
+
+ format = iupAttribGet(formattag, "SPACEBEFORE");
+ if (format && iupStrToInt(format, &val))
+ g_object_set(G_OBJECT(tag), "pixels-above-lines", val, NULL);
+
+ format = iupAttribGet(formattag, "SPACEAFTER");
+ if (format && iupStrToInt(format, &val))
+ g_object_set(G_OBJECT(tag), "pixels-below-lines", val, NULL);
+
+ format = iupAttribGet(formattag, "LINESPACING");
+ if (format && iupStrToInt(format, &val))
+ g_object_set(G_OBJECT(tag), "pixels-inside-wrap", val, NULL);
+}
+
+static void gtkTextParseCharacterFormat(Ihandle* formattag, GtkTextTag* tag)
+{
+ int val;
+ char* format;
+
+ format = iupAttribGet(formattag, "LANGUAGE");
+ if (format)
+ g_object_set(G_OBJECT(tag), "language", format, NULL);
+
+ format = iupAttribGet(formattag, "STRETCH");
+ if (format)
+ {
+ if (iupStrEqualNoCase(format, "EXTRA_CONDENSED"))
+ val = PANGO_STRETCH_EXTRA_CONDENSED;
+ else if (iupStrEqualNoCase(format, "CONDENSED"))
+ val = PANGO_STRETCH_CONDENSED;
+ else if (iupStrEqualNoCase(format, "SEMI_CONDENSED"))
+ val = PANGO_STRETCH_SEMI_CONDENSED;
+ else if (iupStrEqualNoCase(format, "SEMI_EXPANDED"))
+ val = PANGO_STRETCH_SEMI_EXPANDED;
+ else if (iupStrEqualNoCase(format, "EXPANDED"))
+ val = PANGO_STRETCH_EXPANDED;
+ else if (iupStrEqualNoCase(format, "EXTRA_EXPANDED"))
+ val = PANGO_STRETCH_EXTRA_EXPANDED;
+ else /* "NORMAL" */
+ val = PANGO_STRETCH_NORMAL;
+
+ g_object_set(G_OBJECT(tag), "stretch", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "RISE");
+ if (format)
+ {
+ val = 0;
+
+ if (iupStrEqualNoCase(format, "SUPERSCRIPT"))
+ {
+ g_object_set(G_OBJECT(tag), "scale", PANGO_SCALE_X_SMALL, NULL);
+ val = 10; /* 10 pixels up */
+ }
+ else if (iupStrEqualNoCase(format, "SUBSCRIPT"))
+ {
+ g_object_set(G_OBJECT(tag), "scale", PANGO_SCALE_X_SMALL, NULL);
+ val = -10; /* 10 pixels down */
+ }
+ else
+ iupStrToInt(format, &val);
+
+ val = IUPGTK_PIXELS2PANGOUNITS(val);
+ g_object_set(G_OBJECT(tag), "rise", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "SMALLCAPS");
+ if (format)
+ {
+ if (iupStrBoolean(format))
+ val = PANGO_VARIANT_SMALL_CAPS;
+ else
+ val = PANGO_VARIANT_NORMAL;
+ g_object_set(G_OBJECT(tag), "variant", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "ITALIC");
+ if (format)
+ {
+ if (iupStrBoolean(format))
+ val = PANGO_STYLE_ITALIC;
+ else
+ val = PANGO_STYLE_NORMAL;
+ g_object_set(G_OBJECT(tag), "style", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "STRIKEOUT");
+ if (format)
+ {
+ val = iupStrBoolean(format);
+ g_object_set(G_OBJECT(tag), "strikethrough", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "PROTECTED");
+ if (format)
+ {
+ val = iupStrBoolean(format);
+ g_object_set(G_OBJECT(tag), "editable", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "FONTSIZE");
+ if (format && iupStrToInt(format, &val))
+ {
+ if (val < 0) /* in pixels */
+ {
+ val = IUPGTK_PIXELS2PANGOUNITS(-val);
+ g_object_set(G_OBJECT(tag), "size", val, NULL);
+ }
+ else /* in points */
+ g_object_set(G_OBJECT(tag), "size-points", (double)val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "FONTSCALE");
+ if (format)
+ {
+ float fval = 0;
+ if (iupStrEqualNoCase(format, "XX-SMALL"))
+ fval = (float)PANGO_SCALE_XX_SMALL;
+ else if (iupStrEqualNoCase(format, "X-SMALL"))
+ fval = (float)PANGO_SCALE_X_SMALL;
+ else if (iupStrEqualNoCase(format, "SMALL"))
+ fval = (float)PANGO_SCALE_SMALL;
+ else if (iupStrEqualNoCase(format, "MEDIUM"))
+ fval = (float)PANGO_SCALE_MEDIUM;
+ else if (iupStrEqualNoCase(format, "LARGE"))
+ fval = (float)PANGO_SCALE_LARGE;
+ else if (iupStrEqualNoCase(format, "X-LARGE"))
+ fval = (float)PANGO_SCALE_X_LARGE;
+ else if (iupStrEqualNoCase(format, "XX-LARGE"))
+ fval = (float)PANGO_SCALE_XX_LARGE;
+ else
+ iupStrToFloat(format, &fval);
+
+ if (fval > 0)
+ g_object_set(G_OBJECT(tag), "scale", (double)fval, NULL);
+ }
+
+ format = iupAttribGet(formattag, "FONTFACE");
+ if (format)
+ g_object_set(G_OBJECT(tag), "family", format, NULL);
+
+ format = iupAttribGet(formattag, "FGCOLOR");
+ if (format)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(format, &r, &g, &b))
+ {
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(tag), "foreground-gdk", &color, NULL);
+ }
+ }
+
+ format = iupAttribGet(formattag, "BGCOLOR");
+ if (format)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(format, &r, &g, &b))
+ {
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(tag), "background-gdk", &color, NULL);
+ }
+ }
+
+ format = iupAttribGet(formattag, "UNDERLINE");
+ if (format)
+ {
+ if (iupStrEqualNoCase(format, "SINGLE"))
+ val = PANGO_UNDERLINE_SINGLE;
+ else if (iupStrEqualNoCase(format, "DOUBLE"))
+ val = PANGO_UNDERLINE_DOUBLE;
+ else /* "NONE" */
+ val = PANGO_UNDERLINE_NONE;
+
+ g_object_set(G_OBJECT(tag), "underline", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "WEIGHT");
+ if (format)
+ {
+ if (iupStrEqualNoCase(format, "EXTRALIGHT"))
+ val = PANGO_WEIGHT_ULTRALIGHT;
+ else if (iupStrEqualNoCase(format, "LIGHT"))
+ val = PANGO_WEIGHT_LIGHT;
+ else if (iupStrEqualNoCase(format, "SEMIBOLD"))
+ val = PANGO_WEIGHT_SEMIBOLD;
+ else if (iupStrEqualNoCase(format, "BOLD"))
+ val = PANGO_WEIGHT_BOLD;
+ else if (iupStrEqualNoCase(format, "EXTRABOLD"))
+ val = PANGO_WEIGHT_ULTRABOLD;
+ else if (iupStrEqualNoCase(format, "HEAVY"))
+ val = PANGO_WEIGHT_HEAVY;
+ else /* "NORMAL" */
+ val = PANGO_WEIGHT_NORMAL;
+
+ g_object_set(G_OBJECT(tag), "weight", val, NULL);
+ }
+}
+
+static void gtkTextMoveIterToLinCol(GtkTextBuffer *buffer, GtkTextIter *iter, int lin, int col)
+{
+ int line_count, line_length;
+
+ lin--; /* IUP starts at 1 */
+ col--;
+
+ line_count = gtk_text_buffer_get_line_count(buffer);
+ if (lin < 0) lin = 0;
+ if (lin >= line_count)
+ lin = line_count-1;
+
+ gtk_text_buffer_get_iter_at_line(buffer, iter, lin);
+ line_length = gtk_text_iter_get_chars_in_line(iter);
+
+ if (col < 0) col = 0;
+ if (col > line_length)
+ col = line_length; /* after the last character */
+
+ gtk_text_iter_set_line_offset(iter, col);
+}
+
+static void gtkTextGetLinColFromPosition(const GtkTextIter *iter, int *lin, int *col)
+{
+ *lin = gtk_text_iter_get_line(iter);
+ *col = gtk_text_iter_get_line_offset(iter);
+
+ (*lin)++; /* IUP starts at 1 */
+ (*col)++;
+}
+
+static int gtkTextGetCharSize(Ihandle* ih)
+{
+ int charwidth;
+ PangoFontMetrics* metrics;
+ PangoContext* context;
+ PangoFontDescription* fontdesc = (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih);
+ if (!fontdesc)
+ return 0;
+
+ context = gdk_pango_context_get();
+ metrics = pango_context_get_metrics(context, fontdesc, pango_context_get_language(context));
+ charwidth = pango_font_metrics_get_approximate_char_width(metrics);
+ pango_font_metrics_unref(metrics);
+ return charwidth;
+}
+
+void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos)
+{
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtkTextMoveIterToLinCol(buffer, &iter, lin, col);
+ *pos = gtk_text_iter_get_offset(&iter);
+}
+
+void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col)
+{
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos);
+ gtkTextGetLinColFromPosition(&iter, lin, col);
+}
+
+static int gtkTextConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter iter;
+ gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(ih->handle), GTK_TEXT_WINDOW_WIDGET, x, y, &x, &y);
+ gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(ih->handle), &iter, x, y);
+ return gtk_text_iter_get_offset(&iter);
+ }
+ else
+ {
+ int trailing, off_x, off_y, pos;
+
+ /* 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);
+
+ pango_layout_xy_to_index(gtk_entry_get_layout(GTK_ENTRY(ih->handle)), x, y, &pos, &trailing);
+ return pos;
+ }
+}
+
+static void gtkTextScrollToVisible(Ihandle* ih)
+{
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ GtkTextMark* mark = gtk_text_buffer_get_insert(buffer);
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(ih->handle), mark);
+}
+
+
+/*******************************************************************************************/
+
+
+static int gtkTextSetSelectionAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ return 0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_start_iter(buffer, &start_iter);
+ gtk_text_buffer_select_range(buffer, &start_iter, &start_iter);
+ }
+ else
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, 0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_start_iter(buffer, &start_iter);
+ gtk_text_buffer_get_end_iter(buffer, &end_iter);
+ gtk_text_buffer_select_range(buffer, &start_iter, &end_iter);
+ }
+ else
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, -1);
+ return 0;
+ }
+
+ if (ih->data->is_multiline)
+ {
+ int lin_start=1, col_start=1, lin_end=1, col_end=1;
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+
+ if (sscanf(value, "%d,%d:%d,%d", &lin_start, &col_start, &lin_end, &col_end)!=4) return 0;
+ if (lin_start<1 || col_start<1 || lin_end<1 || col_end<1) return 0;
+
+ gtkTextMoveIterToLinCol(buffer, &start_iter, lin_start, col_start);
+ gtkTextMoveIterToLinCol(buffer, &end_iter, lin_end, col_end);
+
+ gtk_text_buffer_select_range(buffer, &start_iter, &end_iter);
+ }
+ else
+ {
+ int start=1, end=1;
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<1 || end<1)
+ return 0;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), start, end);
+ }
+
+ return 0;
+}
+
+static char* gtkTextGetSelectionAttrib(Ihandle* ih)
+{
+ char *str;
+
+ if (ih->data->is_multiline)
+ {
+ int start_col, start_lin, end_col, end_lin;
+
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ {
+ gtkTextGetLinColFromPosition(&start_iter, &start_lin, &start_col);
+ gtkTextGetLinColFromPosition(&end_iter, &end_lin, &end_col);
+
+ str = iupStrGetMemory(100);
+ sprintf(str,"%d,%d:%d,%d", start_lin, start_col, end_lin, end_col);
+ return str;
+ }
+ }
+ else
+ {
+ int start, end;
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end))
+ {
+ start++; /* IUP starts at 1 */
+ end++;
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", (int)start, (int)end);
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+static int gtkTextSetSelectionPosAttrib(Ihandle* ih, const char* value)
+{
+ int start=0, end=0;
+
+ if (!value)
+ return 0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_start_iter(buffer, &start_iter);
+ gtk_text_buffer_select_range(buffer, &start_iter, &start_iter);
+ }
+ else
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, 0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_start_iter(buffer, &start_iter);
+ gtk_text_buffer_get_end_iter(buffer, &end_iter);
+ gtk_text_buffer_select_range(buffer, &start_iter, &end_iter);
+ }
+ else
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, -1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<0 || end<0)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+
+ gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, start);
+ gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, end);
+
+ gtk_text_buffer_select_range(buffer, &start_iter, &end_iter);
+ }
+ else
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), start, end);
+
+ return 0;
+}
+
+static char* gtkTextGetSelectionPosAttrib(Ihandle* ih)
+{
+ int start, end;
+ char *str;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ {
+ start = gtk_text_iter_get_offset(&start_iter);
+ end = gtk_text_iter_get_offset(&end_iter);
+
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", (int)start, (int)end);
+ return str;
+ }
+ }
+ else
+ {
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end))
+ {
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", (int)start, (int)end);
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+static int gtkTextSetSelectedTextAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ {
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
+ gtk_text_buffer_insert(buffer, &start_iter, iupgtkStrConvertToUTF8(value), -1);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ }
+ else
+ {
+ int start, end;
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end))
+ {
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_editable_delete_selection(GTK_EDITABLE(ih->handle));
+ gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &start);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ }
+
+ return 0;
+}
+
+static char* gtkTextGetSelectedTextAttrib(Ihandle* ih)
+{
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, TRUE)));
+ }
+ else
+ {
+ int start, end;
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end))
+ {
+ char* selectedtext = gtk_editable_get_chars(GTK_EDITABLE(ih->handle), start, end);
+ char* str = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(selectedtext));
+ g_free(selectedtext);
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+static int gtkTextSetCaretAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ int lin = 1, col = 1;
+ GtkTextIter iter;
+
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+
+ iupStrToIntInt(value, &lin, &col, ',');
+
+ gtkTextMoveIterToLinCol(buffer, &iter, lin, col);
+
+ gtk_text_buffer_place_cursor(buffer, &iter);
+ gtkTextScrollToVisible(ih);
+ }
+ else
+ {
+ sscanf(value,"%i",&pos);
+ pos--; /* IUP starts at 1 */
+ if (pos < 0) pos = 0;
+
+ gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos);
+ }
+
+ return 0;
+}
+
+static char* gtkTextGetCaretAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(50);
+
+ if (ih->data->is_multiline)
+ {
+ int col, lin;
+ GtkTextIter iter;
+
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer));
+ gtkTextGetLinColFromPosition(&iter, &lin, &col);
+
+ sprintf(str, "%d,%d", lin, col);
+ }
+ else
+ {
+ int pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle));
+ pos++; /* IUP starts at 1 */
+ sprintf(str, "%d", (int)pos);
+ }
+
+ return str;
+}
+
+static int gtkTextSetCaretPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos);
+ gtk_text_buffer_place_cursor(buffer, &iter);
+ gtkTextScrollToVisible(ih);
+ }
+ else
+ gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos);
+
+ return 0;
+}
+
+static char* gtkTextGetCaretPosAttrib(Ihandle* ih)
+{
+ int pos;
+ char* str = iupStrGetMemory(50);
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer));
+ pos = gtk_text_iter_get_offset(&iter);
+ }
+ else
+ pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle));
+
+ sprintf(str, "%d", (int)pos);
+ return str;
+}
+
+static int gtkTextSetScrollToAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ int lin = 1, col = 1;
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+
+ iupStrToIntInt(value, &lin, &col, ',');
+ if (lin < 1) lin = 1;
+ if (col < 1) col = 1;
+
+ gtkTextMoveIterToLinCol(buffer, &iter, lin, col);
+ gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ih->handle), &iter, 0, FALSE, 0, 0);
+ }
+ else
+ {
+ int pos = 1;
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+ pos--; /* return to GTK referece */
+ gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos);
+ }
+
+ return 0;
+}
+
+static int gtkTextSetScrollToPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos);
+ gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ih->handle), &iter, 0, FALSE, 0, 0);
+ }
+ else
+ gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos);
+
+ return 0;
+}
+
+static int gtkTextSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (!value) value = "";
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_set_text(buffer, iupgtkStrConvertToUTF8(value), -1);
+ }
+ else
+ gtk_entry_set_text(GTK_ENTRY(ih->handle), iupgtkStrConvertToUTF8(value));
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ return 0;
+}
+
+static char* gtkTextGetValueAttrib(Ihandle* ih)
+{
+ char* value;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_start_iter(buffer, &start_iter);
+ gtk_text_buffer_get_end_iter(buffer, &end_iter);
+ value = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, TRUE)));
+ }
+ else
+ value = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_entry_get_text(GTK_ENTRY(ih->handle))));
+
+ if (!value) value = "";
+
+ return value;
+}
+
+static int gtkTextSetInsertAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (!value)
+ return 0;
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_insert_at_cursor(buffer, iupgtkStrConvertToUTF8(value), -1);
+ }
+ else
+ {
+ gint pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle));
+ gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &pos);
+ }
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ return 0;
+}
+
+static int gtkTextSetAppendAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ if (ih->data->is_multiline)
+ {
+ 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)
+ 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;
+ gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &pos);
+ }
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ return 0;
+}
+
+static int gtkTextSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ float xalign;
+ GtkJustification justification;
+
+ if (iupStrEqualNoCase(value, "ARIGHT"))
+ {
+ xalign = 1.0f;
+ justification = GTK_JUSTIFY_RIGHT;
+ }
+ else if (iupStrEqualNoCase(value, "ACENTER"))
+ {
+ xalign = 0.5f;
+ justification = GTK_JUSTIFY_CENTER;
+ }
+ else /* "ALEFT" */
+ {
+ xalign = 0;
+ justification = GTK_JUSTIFY_LEFT;
+ }
+
+ if (ih->data->is_multiline)
+ gtk_text_view_set_justification(GTK_TEXT_VIEW(ih->handle), justification);
+ else
+ gtk_entry_set_alignment(GTK_ENTRY(ih->handle), xalign);
+
+ return 1;
+}
+
+static int gtkTextSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle)
+ {
+ if (ih->data->is_multiline)
+ {
+ gtk_text_view_set_left_margin(GTK_TEXT_VIEW(ih->handle), ih->data->horiz_padding);
+ gtk_text_view_set_right_margin(GTK_TEXT_VIEW(ih->handle), ih->data->horiz_padding);
+ ih->data->vert_padding = 0;
+ }
+ else
+ {
+#if GTK_CHECK_VERSION(2, 10, 0)
+ GtkBorder border;
+ border.bottom = border.top = ih->data->vert_padding;
+ border.left = border.right = ih->data->horiz_padding;
+ gtk_entry_set_inner_border(GTK_ENTRY(ih->handle), &border);
+#endif
+ }
+ }
+ return 0;
+}
+
+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;
+}
+
+static int gtkTextSetClipboardAttrib(Ihandle *ih, const char *value)
+{
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ if (iupStrEqualNoCase(value, "COPY"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE));
+ gtk_text_buffer_copy_clipboard(buffer, clipboard);
+ }
+ else
+ gtk_editable_copy_clipboard(GTK_EDITABLE(ih->handle));
+ }
+ else if (iupStrEqualNoCase(value, "CUT"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE));
+ gtk_text_buffer_cut_clipboard(buffer, clipboard, TRUE);
+ }
+ else
+ gtk_editable_cut_clipboard(GTK_EDITABLE(ih->handle));
+ }
+ else if (iupStrEqualNoCase(value, "PASTE"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE));
+ gtk_text_buffer_paste_clipboard(buffer, clipboard, NULL, TRUE);
+ }
+ else
+ gtk_editable_paste_clipboard(GTK_EDITABLE(ih->handle));
+ }
+ else if (iupStrEqualNoCase(value, "CLEAR"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_delete_selection(buffer, FALSE, TRUE);
+ }
+ else
+ gtk_editable_delete_selection(GTK_EDITABLE(ih->handle));
+ }
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ return 0;
+}
+
+static int gtkTextSetReadOnlyAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_multiline)
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(ih->handle), !iupStrBoolean(value));
+ else
+ gtk_editable_set_editable(GTK_EDITABLE(ih->handle), !iupStrBoolean(value));
+ return 0;
+}
+
+static char* gtkTextGetReadOnlyAttrib(Ihandle* ih)
+{
+ int editable;
+ if (ih->data->is_multiline)
+ editable = gtk_text_view_get_editable(GTK_TEXT_VIEW(ih->handle));
+ else
+ editable = gtk_editable_get_editable(GTK_EDITABLE(ih->handle));
+ if (!editable)
+ return "YES";
+ else
+ return "NO";
+}
+
+static char* gtkTextGetPangoLayoutAttrib(Ihandle* ih)
+{
+ if (ih->data->is_multiline)
+ return NULL;
+ else
+ return (char*)gtk_entry_get_layout(GTK_ENTRY(ih->handle));
+}
+
+static int gtkTextSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_multiline)
+ {
+ GtkScrolledWindow* scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ unsigned char r, g, b;
+
+ /* ignore given value, must use only from parent for the scrollbars */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ if (iupStrToRGB(parent_value, &r, &g, &b))
+ {
+ GtkWidget* sb;
+
+ iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ sb = gtk_scrolled_window_get_hscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+
+ sb = gtk_scrolled_window_get_vscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+#endif
+ }
+ }
+
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+}
+
+static int gtkTextSetTabSizeAttrib(Ihandle* ih, const char* value)
+{
+ PangoTabArray *tabs;
+ int tabsize, charwidth;
+ if (!ih->data->is_multiline)
+ return 0;
+
+ iupStrToInt(value, &tabsize);
+ charwidth = gtkTextGetCharSize(ih);
+ tabsize *= charwidth;
+ tabs = pango_tab_array_new_with_positions(1, FALSE, PANGO_TAB_LEFT, tabsize);
+ gtk_text_view_set_tabs(GTK_TEXT_VIEW(ih->handle), tabs);
+ pango_tab_array_free(tabs);
+ return 1;
+}
+
+static int gtkTextSetOverwriteAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->is_multiline)
+ return 0;
+ gtk_text_view_set_overwrite(GTK_TEXT_VIEW(ih->handle), iupStrBoolean(value));
+ return 0;
+}
+
+static char* gtkTextGetOverwriteAttrib(Ihandle* ih)
+{
+ if (!ih->data->is_multiline)
+ return "NO";
+ if (gtk_text_view_get_overwrite(GTK_TEXT_VIEW(ih->handle)))
+ return "YES";
+ else
+ return "NO";
+}
+
+void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter start_iter, end_iter;
+ GtkTextTag* tag;
+ char *selection;
+
+ if (!ih->data->is_multiline)
+ return;
+
+ selection = iupAttribGet(formattag, "SELECTION");
+ if (selection)
+ {
+ /* simulate Windows behavior and change the current selection */
+ gtkTextSetSelectionAttrib(ih, selection);
+ iupAttribSetStr(ih, "SELECTION", NULL);
+ }
+ else
+ {
+ char* selectionpos = iupAttribGet(formattag, "SELECTIONPOS");
+ if (selectionpos)
+ {
+ /* simulate Windows behavior and change the current selection */
+ gtkTextSetSelectionPosAttrib(ih, selectionpos);
+ iupAttribSetStr(ih, "SELECTIONPOS", NULL);
+ }
+ }
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (!gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ {
+ GtkTextMark* mark = gtk_text_buffer_get_insert(buffer);
+ gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, mark);
+ gtk_text_buffer_get_iter_at_mark(buffer, &end_iter, mark);
+ }
+
+ tag = gtk_text_buffer_create_tag(buffer, NULL, NULL);
+ gtkTextParseParagraphFormat(formattag, tag);
+ gtkTextParseCharacterFormat(formattag, tag);
+ gtk_text_buffer_apply_tag(buffer, tag, &start_iter, &end_iter);
+
+ /* reset the selection */
+ gtkTextSetSelectionAttrib(ih, NULL);
+}
+
+static int gtkTextSetRemoveFormattingAttrib(Ihandle* ih, const char* value)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter start_iter, end_iter;
+
+ if (!ih->data->is_multiline)
+ return 0;
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ gtk_text_buffer_remove_all_tags(buffer, &start_iter, &end_iter);
+
+ (void)value;
+ return 0;
+}
+
+
+/************************************************************************************************/
+
+static gboolean gtkTextSpinOutput(GtkSpinButton *spin, Ihandle* ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO"))
+ {
+ iupAttribSetInt(ih, "_IUPGTK_SPIN_VALUE", (int)spin->adjustment->value);
+ return TRUE; /* disable output update */
+ }
+ else
+ {
+ iupAttribSetStr(ih, "_IUPGTK_SPIN_OLDVALUE", gtk_entry_get_text(GTK_ENTRY(ih->handle)));
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ return FALSE;
+ }
+}
+
+static gint gtkTextSpinInput(GtkSpinButton *spin, gdouble *val, Ihandle* ih)
+{
+ (void)spin;
+ *val = (double)iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE");
+ /* called only when SPINAUTO=NO */
+ return TRUE; /* disable input update */
+}
+
+static void gtkTextSpinValueChanged(GtkSpinButton* spin, Ihandle* ih)
+{
+ IFni cb;
+
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ cb = (IFni)IupGetCallback(ih, "SPIN_CB");
+ if (cb)
+ {
+ int pos, ret;
+ if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO"))
+ pos = iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE");
+ else
+ pos = gtk_spin_button_get_value_as_int((GtkSpinButton*)ih->handle);
+
+ ret = cb(ih, pos);
+ if (ret == IUP_IGNORE)
+ {
+ /* this is not working: g_signal_stop_emission_by_name(spin, "value_changed"); */
+ }
+ }
+
+ (void)spin;
+}
+
+static int gtkTextSetSpinMinAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ int min;
+ if (iupStrToInt(value, &min))
+ {
+ int max = iupAttribGetInt(ih, "SPINMAX");
+
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+
+ gtk_spin_button_set_range((GtkSpinButton*)ih->handle, (double)min, (double)max);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ }
+ return 1;
+}
+
+static int gtkTextSetSpinMaxAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ int max;
+ if (iupStrToInt(value, &max))
+ {
+ int min = iupAttribGetInt(ih, "SPINMIN");
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+
+ gtk_spin_button_set_range((GtkSpinButton*)ih->handle, (double)min, (double)max);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ }
+ return 1;
+}
+
+static int gtkTextSetSpinIncAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ int inc;
+ if (iupStrToInt(value, &inc))
+ gtk_spin_button_set_increments((GtkSpinButton*)ih->handle, (double)inc, (double)(inc*10));
+ }
+ return 1;
+}
+
+static int gtkTextSetSpinValueAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ int pos;
+ if (iupStrToInt(value, &pos))
+ {
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+
+ gtk_spin_button_set_value((GtkSpinButton*)ih->handle, (double)pos);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO"))
+ iupAttribSetInt(ih, "_IUPGTK_SPIN_VALUE", pos);
+ }
+ }
+ return 1;
+}
+
+static char* gtkTextGetSpinValueAttrib(Ihandle* ih)
+{
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ int pos;
+ char *str = iupStrGetMemory(50);
+
+ if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO"))
+ pos = iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE");
+ else
+ pos = gtk_spin_button_get_value_as_int((GtkSpinButton*)ih->handle);
+
+ sprintf(str, "%d", pos);
+ return str;
+ }
+ return NULL;
+}
+
+
+/**********************************************************************************************************/
+
+
+static void gtkTextMoveCursor(GtkWidget *w, GtkMovementStep step, gint count, gboolean extend_selection, Ihandle* ih)
+{
+ int col, lin, pos;
+
+ IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB");
+ if (!cb) return;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter iter;
+
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer));
+ gtkTextGetLinColFromPosition(&iter, &lin, &col);
+ pos = gtk_text_iter_get_offset(&iter);
+ }
+ else
+ {
+ pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle));
+ col = pos;
+ col++; /* IUP starts at 1 */
+ lin = 1;
+ }
+
+ if (pos != ih->data->last_caret_pos)
+ {
+ ih->data->last_caret_pos = pos;
+
+ cb(ih, lin, col, pos);
+ }
+
+ (void)w;
+ (void)step;
+ (void)count;
+ (void)extend_selection;
+}
+
+static gboolean gtkTextKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ gtkTextMoveCursor(NULL, 0, 0, 0, ih);
+ (void)widget;
+ (void)evt;
+ return FALSE;
+}
+
+static gboolean gtkTextButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ gtkTextMoveCursor(NULL, 0, 0, 0, ih);
+ return iupgtkButtonEvent(widget, evt, ih);
+}
+
+static int gtkTextCallActionCb(Ihandle* ih, const char* insert_value, int len, int start, int end)
+{
+ char *new_value, *value;
+ int ret = -1, key = 0;
+
+ IFnis cb = (IFnis)IupGetCallback(ih, "ACTION");
+ if (!cb && !ih->data->mask)
+ return -1; /* continue */
+
+ value = gtkTextGetValueAttrib(ih); /* new_value is the internal buffer */
+
+ if (!insert_value)
+ {
+ new_value = iupStrDup(value);
+ if (end<0) end = strlen(value)+1;
+ iupStrRemove(new_value, start, end, 1);
+ }
+ else
+ {
+ if (value[0]==0)
+ new_value = iupStrDup(insert_value);
+ else
+ {
+ if (len < end-start)
+ {
+ new_value = iupStrDup(value);
+ new_value = iupStrInsert(new_value, insert_value, start, end);
+ }
+ else
+ new_value = iupStrInsert(value, insert_value, start, end);
+ }
+ }
+
+ if (insert_value && insert_value[0]!=0 && insert_value[1]==0)
+ key = insert_value[0];
+
+ if (!new_value)
+ return -1; /* continue */
+
+ if (ih->data->nc && (int)strlen(new_value) > ih->data->nc)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (cb)
+ {
+ int cb_ret = cb(ih, key, (char*)new_value);
+ if (cb_ret==IUP_IGNORE)
+ ret = 0; /* abort */
+ else if (cb_ret==IUP_CLOSE)
+ {
+ IupExitLoop();
+ ret = 0; /* abort */
+ }
+ else if (cb_ret!=0 && key!=0 &&
+ cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE)
+ ret = cb_ret; /* abort and replace */
+ }
+
+ if (new_value != value) free(new_value);
+ return ret; /* continue */
+}
+
+static void gtkTextEntryDeleteText(GtkEditable *editable, int start, int end, Ihandle* ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ if (gtkTextCallActionCb(ih, NULL, 0, start, end)==0)
+ g_signal_stop_emission_by_name (editable, "delete_text");
+}
+
+static void gtkTextEntryInsertText(GtkEditable *editable, char *insert_value, int len, int *pos, Ihandle* ih)
+{
+ int ret;
+
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ ret = gtkTextCallActionCb(ih, iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(insert_value)), len, *pos, *pos);
+ if (ret == 0)
+ g_signal_stop_emission_by_name(editable, "insert_text");
+ else if (ret != -1)
+ {
+ insert_value[0] = (char)ret; /* replace key */
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_editable_insert_text(editable, insert_value, 1, pos);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ g_signal_stop_emission_by_name(editable, "insert_text");
+ }
+}
+
+static void gtkTextBufferDeleteRange(GtkTextBuffer *textbuffer, GtkTextIter *start_iter, GtkTextIter *end_iter, Ihandle* ih)
+{
+ int start, end;
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ start = gtk_text_iter_get_offset(start_iter);
+ end = gtk_text_iter_get_offset(end_iter);
+
+ if (gtkTextCallActionCb(ih, NULL, 0, start, end)==0)
+ g_signal_stop_emission_by_name (textbuffer, "delete_range");
+}
+
+static void gtkTextBufferInsertText(GtkTextBuffer *textbuffer, GtkTextIter *pos_iter, gchar *insert_value, gint len, Ihandle* ih)
+{
+ int ret, pos;
+
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ pos = gtk_text_iter_get_offset(pos_iter);
+
+ ret = gtkTextCallActionCb(ih, iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(insert_value)), len, pos, pos);
+ if (ret == 0)
+ g_signal_stop_emission_by_name(textbuffer, "insert_text");
+ else if (ret != -1)
+ {
+ insert_value[0] = (char)ret; /* replace key */
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_text_buffer_insert(textbuffer, pos_iter, insert_value, 1);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ g_signal_stop_emission_by_name(textbuffer, "insert_text");
+ }
+}
+
+static void gtkTextChanged(void* dummy, Ihandle* ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ iupBaseCallValueChangedCb(ih);
+ (void)dummy;
+}
+
+/**********************************************************************************************************/
+
+
+static int gtkTextMapMethod(Ihandle* ih)
+{
+ GtkScrolledWindow* scrolled_window = NULL;
+
+ if (ih->data->is_multiline)
+ {
+ GtkPolicyType hscrollbar_policy, vscrollbar_policy;
+ int wordwrap = 0;
+
+ ih->handle = gtk_text_view_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL);
+ if (!scrolled_window)
+ return IUP_ERROR;
+
+ gtk_container_add((GtkContainer*)scrolled_window, ih->handle);
+ gtk_widget_show((GtkWidget*)scrolled_window);
+
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window);
+
+ /* formatting is always supported when MULTILINE=YES */
+ ih->data->has_formatting = 1;
+
+ if (iupAttribGetBoolean(ih, "WORDWRAP"))
+ {
+ wordwrap = 1;
+ ih->data->sb &= ~IUP_SB_HORIZ; /* must remove the horizontal scroolbar */
+ }
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN);
+ else
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_NONE);
+
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ if (iupAttribGetBoolean(ih, "AUTOHIDE"))
+ hscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ else
+ hscrollbar_policy = GTK_POLICY_ALWAYS;
+ }
+ else
+ hscrollbar_policy = GTK_POLICY_NEVER;
+
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ if (iupAttribGetBoolean(ih, "AUTOHIDE"))
+ vscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ else
+ vscrollbar_policy = GTK_POLICY_ALWAYS;
+ }
+ else
+ vscrollbar_policy = GTK_POLICY_NEVER;
+
+ gtk_scrolled_window_set_policy(scrolled_window, hscrollbar_policy, vscrollbar_policy);
+
+ if (wordwrap)
+ gtk_text_view_set_wrap_mode((GtkTextView*)ih->handle, GTK_WRAP_WORD);
+
+ gtk_widget_add_events(ih->handle, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK);
+ }
+ else
+ {
+ if (iupAttribGetBoolean(ih, "SPIN"))
+ ih->handle = gtk_spin_button_new_with_range(0, 100, 1);
+ else
+ ih->handle = gtk_entry_new();
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* formatting is never supported when MULTILINE=NO */
+ ih->data->has_formatting = 0;
+
+ gtk_entry_set_has_frame((GtkEntry*)ih->handle, IupGetInt(ih, "BORDER"));
+
+ if (iupAttribGetBoolean(ih, "PASSWORD"))
+ gtk_entry_set_visibility((GtkEntry*)ih->handle, FALSE);
+
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ gtk_spin_button_set_numeric((GtkSpinButton*)ih->handle, FALSE);
+ gtk_spin_button_set_digits((GtkSpinButton*)ih->handle, 0);
+
+ gtk_spin_button_set_wrap((GtkSpinButton*)ih->handle, iupAttribGetBoolean(ih, "SPINWRAP"));
+
+ g_signal_connect(G_OBJECT(ih->handle), "value-changed", G_CALLBACK(gtkTextSpinValueChanged), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "output", G_CALLBACK(gtkTextSpinOutput), ih);
+
+ if (!iupAttribGetBoolean(ih, "SPINAUTO"))
+ {
+ g_signal_connect(G_OBJECT(ih->handle), "input", G_CALLBACK(gtkTextSpinInput), ih);
+ iupAttribSetStr(ih, "_IUPGTK_SPIN_NOAUTO", "1");
+ }
+ }
+ }
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect_after(G_OBJECT(ih->handle), "move-cursor", G_CALLBACK(gtkTextMoveCursor), ih); /* only report some caret movements */
+ g_signal_connect_after(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(gtkTextKeyReleaseEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkTextButtonEvent), ih); /* if connected "after" then it is ignored */
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkTextButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih);
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ g_signal_connect(G_OBJECT(buffer), "delete-range", G_CALLBACK(gtkTextBufferDeleteRange), ih);
+ g_signal_connect(G_OBJECT(buffer), "insert-text", G_CALLBACK(gtkTextBufferInsertText), ih);
+ g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(gtkTextChanged), ih);
+ }
+ else
+ {
+ g_signal_connect(G_OBJECT(ih->handle), "delete-text", G_CALLBACK(gtkTextEntryDeleteText), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "insert-text", G_CALLBACK(gtkTextEntryInsertText), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "changed", G_CALLBACK(gtkTextChanged), ih);
+ }
+
+ if (scrolled_window)
+ gtk_widget_realize((GtkWidget*)scrolled_window);
+ gtk_widget_realize(ih->handle);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ /* update a mnemonic in a label if necessary */
+ iupgtkUpdateMnemonic(ih);
+
+ if (ih->data->formattags)
+ iupTextUpdateFormatTags(ih);
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkTextConvertXYToPos);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTextInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkTextMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Common GTK only (when text is in a secondary element) */
+ iupClassRegisterAttribute(ic, "PANGOLAYOUT", gtkTextGetPangoLayoutAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT);
+
+ /* IupText only */
+ iupClassRegisterAttribute(ic, "PADDING", iupTextGetPaddingAttrib, gtkTextSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "VALUE", gtkTextGetValueAttrib, gtkTextSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTEDTEXT", gtkTextGetSelectedTextAttrib, gtkTextSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTION", gtkTextGetSelectionAttrib, gtkTextSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTIONPOS", gtkTextGetSelectionPosAttrib, gtkTextSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARET", gtkTextGetCaretAttrib, gtkTextSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARETPOS", gtkTextGetCaretPosAttrib, gtkTextSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INSERT", NULL, gtkTextSetInsertAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPEND", NULL, gtkTextSetAppendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "READONLY", gtkTextGetReadOnlyAttrib, gtkTextSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "NC", iupTextGetNCAttrib, gtkTextSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, gtkTextSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTO", NULL, gtkTextSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, gtkTextSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINMIN", NULL, gtkTextSetSpinMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINMAX", NULL, gtkTextSetSpinMaxAttrib, IUPAF_SAMEASSYSTEM, "100", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPININC", NULL, gtkTextSetSpinIncAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINVALUE", gtkTextGetSpinValueAttrib, gtkTextSetSpinValueAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT);
+
+ /* IupText Windows and GTK only */
+ iupClassRegisterAttribute(ic, "ADDFORMATTAG", NULL, iupTextSetAddFormatTagAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ADDFORMATTAG_HANDLE", NULL, iupTextSetAddFormatTagHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkTextSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FORMATTING", iupTextGetFormattingAttrib, iupTextSetFormattingAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "OVERWRITE", gtkTextGetOverwriteAttrib, gtkTextSetOverwriteAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "REMOVEFORMATTING", NULL, gtkTextSetRemoveFormattingAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TABSIZE", NULL, gtkTextSetTabSizeAttrib, "8", NULL, IUPAF_DEFAULT); /* force new default value */
+ iupClassRegisterAttribute(ic, "PASSWORD", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_timer.c b/iup/src/gtk/iupgtk_timer.c
new file mode 100755
index 0000000..ecbefa3
--- /dev/null
+++ b/iup/src/gtk/iupgtk_timer.c
@@ -0,0 +1,61 @@
+/** \file
+ * \brief Timer for the GTK Driver.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_assert.h"
+#include "iup_timer.h"
+
+
+static gboolean gtkTimerProc(gpointer data)
+{
+ Ihandle *ih = (Ihandle*)data;
+ Icallback cb;
+
+ if (!iupObjectCheck(ih)) /* control could be destroyed before timer callback */
+ return FALSE;
+
+ cb = IupGetCallback(ih, "ACTION_CB");
+ if (cb && cb(ih)==IUP_CLOSE)
+ IupExitLoop();
+
+ return TRUE;
+}
+
+void iupdrvTimerRun(Ihandle *ih)
+{
+ unsigned int time_ms;
+
+ if (ih->serial > 0) /* timer already started */
+ return;
+
+ time_ms = iupAttribGetInt(ih, "TIME");
+ if (time_ms > 0)
+ ih->serial = g_timeout_add(time_ms, gtkTimerProc, (gpointer)ih);
+}
+
+void iupdrvTimerStop(Ihandle* ih)
+{
+ if (ih->serial > 0)
+ {
+ g_source_remove(ih->serial);
+ ih->serial = -1;
+ }
+}
+
+void iupdrvTimerInitClass(Iclass* ic)
+{
+ (void)ic;
+}
diff --git a/iup/src/gtk/iupgtk_tips.c b/iup/src/gtk/iupgtk_tips.c
new file mode 100755
index 0000000..6289d70
--- /dev/null
+++ b/iup/src/gtk/iupgtk_tips.c
@@ -0,0 +1,100 @@
+/** \file
+ * \brief Windows Driver TIPS management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_str.h"
+#include "iup_attrib.h"
+#include "iup_image.h"
+
+#include "iupgtk_drv.h"
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+#else
+static GtkTooltips* gtk_tips = NULL; /* old TIPS */
+#endif
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+static gboolean gtkQueryTooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, Ihandle* ih)
+{
+ char* value = iupAttribGet(ih, "TIPRECT");
+ if (value && !keyboard_mode)
+ {
+ GdkRectangle rect;
+ int x1, x2, y1, y2;
+ sscanf(value, "%d %d %d %d", &x1, &y1, &x2, &y2);
+ rect.x = x1;
+ rect.y = y1;
+ rect.width = x2-x1+1;
+ rect.height = y2-y1+1;
+ gtk_tooltip_set_tip_area(tooltip, &rect);
+ }
+ else
+ gtk_tooltip_set_tip_area(tooltip, NULL);
+
+ value = iupAttribGet(ih, "TIPICON");
+ if (!value)
+ gtk_tooltip_set_icon(tooltip, NULL);
+ else
+ {
+ GdkPixbuf* icon = (GdkPixbuf*)iupImageGetIcon(value);
+ if (icon)
+ gtk_tooltip_set_icon(tooltip, icon);
+ }
+
+ (void)y;
+ (void)x;
+ (void)widget;
+ return FALSE;
+}
+#endif
+
+int iupdrvBaseSetTipAttrib(Ihandle* ih, const char* value)
+{
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget)
+ widget = ih->handle;
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+ if (iupAttribGetBoolean(ih, "TIPMARKUP"))
+ gtk_widget_set_tooltip_markup(widget, iupgtkStrConvertToUTF8(value));
+ else
+ gtk_widget_set_tooltip_text(widget, iupgtkStrConvertToUTF8(value));
+
+ g_signal_connect(widget, "query-tooltip", G_CALLBACK(gtkQueryTooltip), ih);
+#else
+ if (gtk_tips == NULL)
+ gtk_tips = gtk_tooltips_new();
+
+ gtk_tooltips_set_tip(gtk_tips, widget, iupgtkStrConvertToUTF8(value), NULL);
+#endif
+
+ return 1;
+}
+
+int iupdrvBaseSetTipVisibleAttrib(Ihandle* ih, const char* value)
+{
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget)
+ widget = ih->handle;
+ (void)value;
+
+ /* must use IupGetAttribute to use inheritance */
+ if (!IupGetAttribute(ih, "TIP"))
+ return 0;
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+ gtk_widget_trigger_tooltip_query(widget);
+#endif
+
+ return 0;
+}
+
diff --git a/iup/src/gtk/iupgtk_toggle.c b/iup/src/gtk/iupgtk_toggle.c
new file mode 100755
index 0000000..8ff7df5
--- /dev/null
+++ b/iup/src/gtk/iupgtk_toggle.c
@@ -0,0 +1,519 @@
+/** \file
+ * \brief Toggle Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+#include "iup_key.h"
+#include "iup_toggle.h"
+
+#include "iupgtk_drv.h"
+
+
+#if !GTK_CHECK_VERSION(2, 6, 0)
+static void gtk_button_set_image(GtkButton *button, GtkWidget *image)
+{
+}
+static GtkWidget* gtk_button_get_image(GtkButton *button)
+{
+ return NULL;
+}
+#endif
+
+void iupdrvToggleAddCheckBox(int *x, int *y)
+{
+#ifdef HILDON
+ (*x) += 30+4;
+ if ((*y) < 30) (*y) = 30; /* minimum height */
+#else
+ (*x) += 16+4;
+ if ((*y) < 16) (*y) = 16; /* minimum height */
+#endif
+ (*y) += 4;
+}
+
+static int gtkToggleGetCheck(Ihandle* ih)
+{
+ if (gtk_toggle_button_get_inconsistent((GtkToggleButton*)ih->handle))
+ return -1;
+ if (gtk_toggle_button_get_active((GtkToggleButton*)ih->handle))
+ return 1;
+ else
+ return 0;
+}
+
+static void gtkToggleSetPixbuf(Ihandle* ih, const char* name, int make_inactive)
+{
+ GtkButton* button = (GtkButton*)ih->handle;
+ GtkImage* image = (GtkImage*)gtk_button_get_image(button);
+
+ if (name)
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(name, ih, make_inactive);
+ GdkPixbuf* old_pixbuf = gtk_image_get_pixbuf(image);
+ if (pixbuf != old_pixbuf)
+ gtk_image_set_from_pixbuf(image, pixbuf);
+ return;
+ }
+
+ /* if not defined */
+#if GTK_CHECK_VERSION(2, 8, 0)
+ gtk_image_clear(image);
+#endif
+}
+
+static void gtkToggleUpdateImage(Ihandle* ih, int active, int check)
+{
+ char* name;
+
+ if (!active)
+ {
+ name = iupAttribGet(ih, "IMINACTIVE");
+ if (name)
+ gtkToggleSetPixbuf(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ gtkToggleSetPixbuf(ih, name, 1); /* make_inactive */
+ }
+ }
+ else
+ {
+ /* must restore the normal image */
+ if (check)
+ {
+ name = iupAttribGet(ih, "IMPRESS");
+ if (name)
+ gtkToggleSetPixbuf(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ gtkToggleSetPixbuf(ih, name, 0);
+ }
+ }
+ else
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ if (name)
+ gtkToggleSetPixbuf(ih, name, 0);
+ }
+ }
+}
+
+
+/*************************************************************************/
+
+
+static int gtkToggleSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrEqualNoCase(value,"NOTDEF"))
+ gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, TRUE);
+ else
+ {
+ gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, FALSE);
+
+ /* This action causes the toggled signal to be emitted. */
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_TOGGLE", "1");
+
+ if (iupStrBoolean(value))
+ gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, TRUE);
+ else
+ gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, FALSE);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih));
+
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_TOGGLE", NULL);
+ }
+
+ return 0;
+}
+
+static char* gtkToggleGetValueAttrib(Ihandle* ih)
+{
+ int check = gtkToggleGetCheck(ih);
+ if (check == -1)
+ return "NOTDEF";
+ else if (check == 1)
+ return "ON";
+ else
+ return "OFF";
+}
+
+static int gtkToggleSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ {
+ GtkButton* button = (GtkButton*)ih->handle;
+ GtkLabel* label = (GtkLabel*)gtk_button_get_image(button);
+ iupgtkSetMnemonicTitle(ih, label, value);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int gtkToggleSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ GtkButton* button = (GtkButton*)ih->handle;
+ float xalign, yalign;
+ char value1[30]="", value2[30]="";
+
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ return 0;
+
+ iupStrToStrStr(value, value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ xalign = 1.0f;
+ else if (iupStrEqualNoCase(value1, "ACENTER"))
+ xalign = 0.5f;
+ else /* "ALEFT" */
+ xalign = 0;
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ yalign = 1.0f;
+ else if (iupStrEqualNoCase(value2, "ATOP"))
+ yalign = 0;
+ else /* ACENTER (default) */
+ yalign = 0.5f;
+
+ gtk_button_set_alignment(button, xalign, yalign);
+
+ return 1;
+}
+
+static int gtkToggleSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle && ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ 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;
+}
+
+static int gtkToggleSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ GtkWidget* label = (GtkWidget*)gtk_button_get_image((GtkButton*)ih->handle);
+ if (!label) return 0;
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(label, r, g, b);
+
+ return 1;
+}
+
+static int gtkToggleSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+
+ if (ih->handle)
+ {
+ GtkWidget* label = gtk_button_get_image((GtkButton*)ih->handle);
+ if (!label) return 1;
+
+ gtk_widget_modify_font(label, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih));
+
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)label));
+ }
+ return 1;
+}
+
+static int gtkToggleSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMAGE"))
+ iupAttribSetStr(ih, "IMAGE", (char*)value);
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkToggleSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMINACTIVE"))
+ iupAttribSetStr(ih, "IMINACTIVE", (char*)value);
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkToggleSetImPressAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMPRESS"))
+ iupAttribSetStr(ih, "IMPRESS", (char*)value);
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkToggleSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ /* update the inactive image if necessary */
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ gtkToggleUpdateImage(ih, iupStrBoolean(value), gtkToggleGetCheck(ih));
+
+ return iupBaseSetActiveAttrib(ih, value);
+}
+
+/****************************************************************************************************/
+
+static void gtkToggleToggled(GtkToggleButton *widget, Ihandle* ih)
+{
+ IFni cb;
+ int check;
+
+ if (iupAttribGet(ih, "_IUPGTK_IGNORE_TOGGLE"))
+ return;
+
+ check = gtkToggleGetCheck(ih);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), check);
+
+ cb = (IFni)IupGetCallback(ih, "ACTION");
+ if (cb && cb(ih, check) == IUP_CLOSE)
+ IupExitLoop();
+
+ iupBaseCallValueChangedCb(ih);
+
+ (void)widget;
+}
+
+static int gtkToggleUpdate3StateCheck(Ihandle *ih, int keyb)
+{
+ int check = gtkToggleGetCheck(ih);
+ if (check == 1) /* GOTO check == -1 */
+ {
+ gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, TRUE);
+ gtkToggleToggled((GtkToggleButton*)ih->handle, ih);
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ else if (check == -1) /* GOTO check == 0 */
+ {
+ gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, FALSE);
+ if (keyb)
+ {
+ gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, FALSE);
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ }
+ else /* (check == 0) GOTO check == 1 */
+ {
+ gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, FALSE);
+ if (keyb)
+ {
+ gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, TRUE);
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean gtkToggleButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_IGNORE_TOGGLE"))
+ return FALSE;
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ char* name = iupAttribGet(ih, "IMPRESS");
+ if (name)
+ {
+ if (evt->type == GDK_BUTTON_PRESS)
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), 1);
+ else
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), 0);
+ }
+ }
+ else
+ {
+ if (evt->type == GDK_BUTTON_RELEASE)
+ {
+ if (gtkToggleUpdate3StateCheck(ih, 0))
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+static gboolean gtkToggleKeyEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (evt->type == GDK_KEY_PRESS)
+ {
+ if (evt->keyval == GDK_space || evt->keyval == GDK_Return)
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ else
+ {
+ if (evt->keyval == GDK_space || evt->keyval == GDK_Return)
+ {
+ if (gtkToggleUpdate3StateCheck(ih, 1))
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+static int gtkToggleMapMethod(Ihandle* ih)
+{
+ Ihandle* radio = iupRadioFindToggleParent(ih);
+ char *value;
+ int is3state = 0;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (radio)
+ ih->data->radio = 1;
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ ih->data->type = IUP_TOGGLE_IMAGE;
+ else
+ ih->data->type = IUP_TOGGLE_TEXT;
+
+ if (radio)
+ {
+ GtkRadioButton* last_tg = (GtkRadioButton*)iupAttribGet(radio, "_IUPGTK_LASTRADIOBUTTON");
+ if (last_tg)
+ ih->handle = gtk_radio_button_new_from_widget(last_tg);
+ else
+ ih->handle = gtk_radio_button_new(NULL);
+ iupAttribSetStr(radio, "_IUPGTK_LASTRADIOBUTTON", (char*)ih->handle);
+ }
+ else
+ {
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ {
+ ih->handle = gtk_check_button_new();
+
+ if (iupAttribGetBoolean(ih, "3STATE"))
+ is3state = 1;
+ }
+ else
+ ih->handle = gtk_toggle_button_new();
+ }
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ {
+ gtk_button_set_image((GtkButton*)ih->handle, gtk_label_new(NULL));
+ gtk_toggle_button_set_mode((GtkToggleButton*)ih->handle, TRUE);
+ }
+ else
+ {
+ gtk_button_set_image((GtkButton*)ih->handle, gtk_image_new());
+ gtk_toggle_button_set_mode((GtkToggleButton*)ih->handle, FALSE);
+ }
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "toggled", G_CALLBACK(gtkToggleToggled), ih);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE || is3state)
+ {
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkToggleButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkToggleButtonEvent), ih);
+ }
+
+ if (is3state)
+ {
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkToggleKeyEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(gtkToggleKeyEvent), ih);
+ }
+
+ gtk_widget_realize(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvToggleInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkToggleMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkToggleSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, gtkToggleSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkToggleSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); /* black */
+ iupClassRegisterAttribute(ic, "TITLE", NULL, gtkToggleSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupToggle only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkToggleSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkToggleSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, gtkToggleSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, gtkToggleSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE", gtkToggleGetValueAttrib, gtkToggleSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupToggleGetPaddingAttrib, gtkToggleSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "MARKUP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
+}
diff --git a/iup/src/gtk/iupgtk_tree.c b/iup/src/gtk/iupgtk_tree.c
new file mode 100755
index 0000000..d408f27
--- /dev/null
+++ b/iup/src/gtk/iupgtk_tree.c
@@ -0,0 +1,2369 @@
+/** \file
+ * \brief Tree Control
+ *
+ * See Copyright Notice in iup.h
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_key.h"
+#include "iup_image.h"
+#include "iup_array.h"
+#include "iup_tree.h"
+
+#include "iup_drvinfo.h"
+#include "iupgtk_drv.h"
+
+enum
+{
+ IUPGTK_TREE_IMAGE,
+ IUPGTK_TREE_HAS_IMAGE,
+ IUPGTK_TREE_IMAGE_EXPANDED,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED,
+ IUPGTK_TREE_TITLE,
+ IUPGTK_TREE_KIND,
+ IUPGTK_TREE_COLOR,
+ IUPGTK_TREE_FONT,
+ IUPGTK_TREE_USERDATA
+};
+
+static GtkTreeIter gtkTreeInvalidIter = {0,0,0,0};
+
+/*****************************************************************************/
+/* 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)
+{
+ 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;
+
+ gtk_tree_model_get(GTK_TREE_MODEL(store), iterItem, IUPGTK_TREE_IMAGE, &image,
+ IUPGTK_TREE_HAS_IMAGE, &has_image,
+ IUPGTK_TREE_IMAGE_EXPANDED, &image_expanded,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED, &has_image_expanded,
+ IUPGTK_TREE_TITLE, &title,
+ IUPGTK_TREE_KIND, &kind,
+ IUPGTK_TREE_COLOR, &color,
+ IUPGTK_TREE_FONT, &font,
+ IUPGTK_TREE_USERDATA, &userdata,
+ -1);
+
+ if (position == 2)
+ gtk_tree_store_append(store, iterNewItem, iterParent);
+ else if (position == 1) /* copy as first child of expanded branch */
+ gtk_tree_store_insert(store, iterNewItem, iterParent, 0); /* iterParent is parent of the new item (firstchild of it) */
+ 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,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED, has_image_expanded,
+ IUPGTK_TREE_TITLE, title,
+ IUPGTK_TREE_KIND, kind,
+ IUPGTK_TREE_COLOR, color,
+ IUPGTK_TREE_FONT, font,
+ IUPGTK_TREE_USERDATA, userdata,
+ -1);
+}
+
+static void gtkTreeCopyChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, int full_copy)
+{
+ 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 */
+
+ /* Recursively transfer all the items */
+ gtkTreeCopyChildren(ih, model, &iterChildSrc, &iterNewItem, full_copy);
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterChildSrc);
+ }
+}
+
+/* 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)
+{
+ int kind, position = 0; /* insert after iterItemDst */
+ gtk_tree_model_get(model, iterItemDst, IUPGTK_TREE_KIND, &kind, -1);
+
+ if (kind == ITREE_BRANCH)
+ {
+ 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 */
+ gtk_tree_path_free(path);
+ }
+
+ gtkTreeCopyItem(model, iterItemSrc, iterItemDst, position, iterNewItem, full_copy);
+
+ gtkTreeCopyChildren(ih, model, iterItemSrc, iterNewItem, full_copy);
+}
+
+/*****************************************************************************/
+/* FINDING ITEMS */
+/*****************************************************************************/
+
+static void gtkTreeInvertAllNodeMarking(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter* iterItem)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+
+ while(hasItem)
+ {
+ if(gtk_tree_selection_iter_is_selected(selection, iterItem))
+ gtk_tree_selection_unselect_iter(selection, iterItem);
+ else
+ gtk_tree_selection_select_iter(selection, iterItem);
+
+ /* 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);
+ }
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, iterItem);
+ }
+}
+
+static GtkTreeIter gtkTreeFindVisibleNodeId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode)
+{
+ GtkTreeIter iterChild;
+ GtkTreePath* path;
+ int hasItem = TRUE;
+
+ while(hasItem)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control++; /* not the real id since it counts only the visible ones */
+
+ /* StateID founded! */
+ if(iterItem.user_data == iterNode.user_data)
+ return iterItem;
+
+ 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))
+ {
+ gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */
+ iterChild = gtkTreeFindVisibleNodeId(ih, model, iterChild, iterNode);
+
+ /* StateID founded! */
+ if(iterChild.user_data)
+ {
+ gtk_tree_path_free(path);
+ return iterChild;
+ }
+ }
+
+ gtk_tree_path_free(path);
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterItem);
+ }
+
+ return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */
+}
+
+static GtkTreeIter gtkTreeFindVisibleNodeFromId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem)
+{
+ GtkTreeIter iterChild;
+ GtkTreePath* path;
+ int hasItem = TRUE;
+
+ while(hasItem)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control--; /* not the real id since it counts only the visible ones */
+
+ /* StateID founded! */
+ if(ih->data->id_control < 0)
+ return iterItem;
+
+ 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))
+ {
+ 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;
+ }
+ }
+
+ gtk_tree_path_free(path);
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterItem);
+ }
+
+ return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */
+}
+
+static GtkTreeIter gtkTreeGetLastVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem)
+{
+ 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 */
+
+ while(hasItem)
+ {
+ iterPrev = iterChild;
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterChild);
+ }
+
+ iterItem = gtkTreeGetLastVisibleNode(ih, model, iterPrev);
+ }
+ gtk_tree_path_free(path);
+
+ return iterItem;
+}
+
+static GtkTreeIter gtkTreeFindNodeID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+
+ while(hasItem)
+ {
+ /* 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))
+ {
+ 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;
+ }
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterItem);
+ }
+
+ return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */
+}
+
+static int gtkTreeGetNodeId(Ihandle* ih, GtkTreeIter iterItem)
+{
+ 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;
+}
+
+static GtkTreeIter gtkTreeFindUserData(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, void* userdata)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+ void* node_userdata;
+
+ while(hasItem)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control++;
+
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &node_userdata, -1);
+
+ /* userdata founded! */
+ if (node_userdata == userdata)
+ return iterItem;
+
+ /* 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);
+
+ /* userdata founded! */
+ if (iterChild.user_data)
+ return iterChild;
+ }
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterItem);
+ }
+
+ return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */
+}
+
+static int gtkTreeGetUserDataId(Ihandle* ih, GtkTreeModel* model, void* userdata)
+{
+ 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;
+}
+
+static void gtkTreeCallNodeRemovedRec(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, IFnis cb)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+ void* node_userdata;
+
+ 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 to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterItem);
+ }
+}
+
+static void gtkTreeCallNodeRemoved(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem)
+{
+ IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB");
+ if (cb)
+ {
+ ih->data->id_control = gtkTreeGetNodeId(ih, *iterItem)-1;
+ gtkTreeCallNodeRemovedRec(ih, model, *iterItem, cb);
+ }
+}
+
+static gboolean gtkTreeFindNodeFromID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, int *id)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+
+ while(hasItem)
+ {
+ /* 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))
+ {
+ gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */
+
+ if (gtkTreeFindNodeFromID(ih, model, &iterChild, id))
+ {
+ *iterItem = iterChild;
+ return TRUE;
+ }
+ }
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, iterItem);
+ }
+
+ return FALSE;
+}
+
+static gboolean gtkTreeFindNodeFromString(Ihandle* ih, GtkTreeModel* model, 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;
+}
+
+/*****************************************************************************/
+/* MANIPULATING IMAGES */
+/*****************************************************************************/
+static void gtkTreeUpdateImages(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, int mode)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+ int kind;
+
+ while(hasItem)
+ {
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+
+ if (kind == ITREE_BRANCH)
+ {
+ if (mode == ITREE_UPDATEIMAGE_EXPANDED)
+ {
+ gboolean has_image_expanded = FALSE;
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE_EXPANDED, &has_image_expanded, -1);
+ if (!has_image_expanded)
+ gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, -1);
+ }
+ else if(mode == ITREE_UPDATEIMAGE_COLLAPSED)
+ {
+ gboolean has_image = FALSE;
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE, &has_image, -1);
+ 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
+ {
+ if (mode == ITREE_UPDATEIMAGE_LEAF)
+ {
+ gboolean has_image = FALSE;
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE, &has_image, -1);
+ if (!has_image)
+ 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);
+ }
+}
+
+static void gtkTreeExpandItem(Ihandle* ih, GtkTreePath* path, int expand)
+{
+ if (expand == -1)
+ expand = !gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); /* toggle */
+
+ if (expand)
+ gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE);
+ else
+ gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path);
+}
+
+int iupgtkGetColor(const char* value, GdkColor *color)
+{
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ iupgdkColorSet(color, r, g, b);
+ return 1;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* ADDING ITEMS */
+/*****************************************************************************/
+void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add)
+{
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ 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;
+
+ 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) */
+ else
+ gtk_tree_store_insert_after(store, &iterNewItem, NULL, &iterPrev); /* iterPrev is sibling of the new item */
+
+ iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color);
+
+ /* 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);
+
+ if (kind == ITREE_LEAF)
+ gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, -1);
+ else
+ 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 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)
+ {
+ 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 */
+ {
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB", "1");
+ gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE);
+ }
+ else
+ gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path);
+ gtk_tree_path_free(path);
+ }
+}
+
+static void gtkTreeAddRootNode(Ihandle* ih)
+{
+ 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};
+
+ iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color);
+
+ 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);
+
+ path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterRoot);
+ /* MarkStart node */
+ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)path);
+
+ /* Set the default VALUE */
+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE);
+}
+
+/*****************************************************************************/
+/* AUXILIAR FUNCTIONS */
+/*****************************************************************************/
+static void gtkTreeOpenCloseEvent(Ihandle* ih)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ GtkTreePath* path;
+ int kind;
+
+ if (!gtkTreeFindNodeFromString(ih, model, "", &iterItem))
+ return;
+
+ path = gtk_tree_model_get_path(model, &iterItem);
+ if (path)
+ {
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+
+ if (kind == ITREE_LEAF) /* leafs */
+ gtk_tree_view_row_activated(GTK_TREE_VIEW(ih->handle), path, (GtkTreeViewColumn*)iupAttribGet(ih, "_IUPGTK_COLUMN"));
+ else /* branches */
+ gtkTreeExpandItem(ih, path, -1); /* toggle */
+
+ gtk_tree_path_free(path);
+ }
+}
+
+static gboolean gtkTreeSelected_Foreach_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list)
+{
+ GtkTreeRowReference *rowref;
+
+ rowref = gtk_tree_row_reference_new(model, path);
+ *rowref_list = g_list_append(*rowref_list, rowref);
+
+ (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)
+{
+ 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);
+
+ return FALSE; /* do not stop walking the store, call us with next row */
+}
+
+/*****************************************************************************/
+/* CALLBACKS */
+/*****************************************************************************/
+static void gtkTreeCallMultiSelectionCb(Ihandle* ih)
+{
+ IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB");
+ IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB");
+ if (cbMulti || cbSelec)
+ {
+ 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;
+
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+
+ 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);
+
+ for(node = rr_list; node != NULL; node = node->next)
+ {
+ 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);
+ }
+ }
+
+ g_list_foreach(rr_list, (GFunc) gtk_tree_row_reference_free, NULL);
+ g_list_free(rr_list);
+
+ if (cbMulti)
+ cbMulti(ih, id_rowItem, count_selected_rows);
+ else
+ {
+ for (i=0; i<count_selected_rows; i++)
+ cbSelec(ih, id_rowItem[i], 1);
+ }
+
+ free(id_rowItem);
+ }
+}
+
+
+/*****************************************************************************/
+/* GET AND SET ATTRIBUTES */
+/*****************************************************************************/
+
+
+static char* gtkTreeGetIndentationAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(255);
+#if GTK_CHECK_VERSION(2, 12, 0)
+ int indent = gtk_tree_view_get_level_indentation(GTK_TREE_VIEW(ih->handle));
+#else
+ int indent = 0;
+#endif
+ sprintf(str, "%d", indent);
+ return str;
+}
+
+static int gtkTreeSetIndentationAttrib(Ihandle* ih, const char* value)
+{
+#if GTK_CHECK_VERSION(2, 12, 0)
+ int indent;
+ if (iupStrToInt(value, &indent))
+ gtk_tree_view_set_level_indentation(GTK_TREE_VIEW(ih->handle), indent);
+#endif
+ return 0;
+}
+
+static int gtkTreeSetTopItemAttrib(Ihandle* ih, const char* value)
+{
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ GtkTreeIter iterItem;
+ GtkTreePath* path;
+
+ if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), 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_view_expand_to_path(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 */
+
+ gtk_tree_path_free(path);
+
+ return 0;
+}
+
+static int gtkTreeSetSpacingAttrib(Ihandle* ih, const char* value)
+{
+ if(!iupStrToInt(value, &ih->data->spacing))
+ ih->data->spacing = 1;
+
+ if(ih->data->spacing < 1)
+ ih->data->spacing = 1;
+
+ if (ih->handle)
+ {
+ GtkCellRenderer *renderer_img = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_IMG");
+ GtkCellRenderer *renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT");
+ g_object_set(G_OBJECT(renderer_img), "ypad", ih->data->spacing, NULL);
+ g_object_set(G_OBJECT(renderer_txt), "ypad", ih->data->spacing, NULL);
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+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;
+ 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 NULL;
+
+ depth = iupStrGetMemory(10);
+ sprintf(depth, "%d", gtk_tree_store_iter_depth(store, &iterItem));
+ return depth;
+}
+
+static int gtkTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeModel* model;
+ GtkTreeIter iterItemSrc, iterItemDst, iterNewItem;
+ GtkTreeIter iterParent, iterNextParent;
+
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc))
+ return 0;
+
+ if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst))
+ return 0;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ iterParent = iterItemDst;
+ while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent))
+ {
+ if (iterNextParent.user_data == iterItemSrc.user_data)
+ return 0;
+ 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);
+
+ return 0;
+}
+
+static int gtkTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeModel* model;
+ GtkTreeIter iterItemSrc, iterItemDst, iterNewItem;
+ GtkTreeIter iterParent, iterNextParent;
+
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc))
+ return 0;
+
+ if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst))
+ return 0;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ iterParent = iterItemDst;
+ while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent))
+ {
+ if (iterNextParent.user_data == iterItemSrc.user_data)
+ return 0;
+ iterParent = iterNextParent;
+ }
+
+ /* Copying the node and its children to the new position */
+ gtkTreeCopyNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 1);
+
+ return 0;
+}
+
+static char* gtkTreeGetColorAttrib(Ihandle* ih, const char* name_id)
+{
+ char* str;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ GdkColor *color;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return NULL;
+
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_COLOR, &color, -1);
+ if (!color)
+ return NULL;
+
+ str = iupStrGetMemory(20);
+ sprintf(str, "%d %d %d", iupCOLOR16TO8(color->red),
+ iupCOLOR16TO8(color->green),
+ iupCOLOR16TO8(color->blue));
+ return str;
+}
+
+static int gtkTreeSetColorAttrib(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;
+ GdkColor color;
+ unsigned char r, g, b;
+
+ if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem))
+ return 0;
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgdkColorSet(&color, r, g, b);
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_COLOR, &color, -1);
+
+ return 0;
+}
+
+static char* gtkTreeGetParentAttrib(Ihandle* ih, const char* name_id)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ GtkTreeIter iterParent;
+ char* str;
+
+ if (!gtkTreeFindNodeFromString(ih, model, 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));
+ return str;
+}
+
+static char* gtkTreeGetChildCountAttrib(Ihandle* ih, const char* name_id)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ char* str;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return NULL;
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", gtk_tree_model_iter_n_children(model, &iterItem));
+ 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))
+ return NULL;
+
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+
+ if(!kind)
+ return "BRANCH";
+ else
+ return "LEAF";
+}
+
+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))
+ return NULL;
+
+ if (gtk_tree_model_iter_has_child(model, &iterItem))
+ {
+ GtkTreePath* path = gtk_tree_model_get_path(model, &iterItem);
+ int expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path);
+ gtk_tree_path_free(path);
+
+ if (expanded)
+ return "EXPANDED";
+ else
+ return "COLLAPSED";
+ }
+
+ return NULL;
+}
+
+static int gtkTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ GtkTreePath* path;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return 0;
+
+ path = gtk_tree_model_get_path(model, &iterItem);
+ gtkTreeExpandItem(ih, path, iupStrEqualNoCase(value, "EXPANDED"));
+ gtk_tree_path_free(path);
+
+ return 0;
+}
+
+static char* gtkTreeGetTitle(GtkTreeModel* model, GtkTreeIter iterItem)
+{
+ char* title;
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_TITLE, &title, -1);
+ return iupgtkStrConvertFromUTF8(title);
+}
+
+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))
+ return NULL;
+ return gtkTreeGetTitle(model, iterItem);
+}
+
+static int gtkTreeSetTitleAttrib(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_TITLE, iupgtkStrConvertToUTF8(value), -1);
+ return 0;
+}
+
+static int gtkTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ 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))
+ return 0;
+ if (value)
+ fontdesc = iupgtkGetPangoFontDesc(value);
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_FONT, fontdesc, -1);
+ return 0;
+}
+
+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))
+ 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));
+ GtkTreePath* path = NULL;
+ char* str;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL);
+ if (path)
+ {
+ GtkTreeIter iterItem;
+ gtk_tree_model_get_iter(model, &iterItem, path);
+ gtk_tree_path_free(path);
+
+ str = iupStrGetMemory(16);
+ sprintf(str, "%d", gtkTreeGetNodeId(ih, iterItem));
+ return str;
+ }
+
+ return "0"; /* default VALUE is root */
+}
+
+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"))
+ {
+ 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_path_free(pathFocus);
+ }
+ else if(iupStrEqualNoCase(value, "CLEARALL"))
+ gtk_tree_selection_unselect_all(selection);
+ else if(iupStrEqualNoCase(value, "MARKALL"))
+ gtk_tree_selection_select_all(selection);
+ else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */
+ gtkTreeInvertAllNodeMarking(ih, model, selection, &iterRoot);
+ else if(iupStrEqualPartial(value, "INVERT"))
+ {
+ /* iupStrEqualPartial allows the use of "INVERTid" form */
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, model, &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);
+ }
+ 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))
+ return 0;
+ if (!gtkTreeFindNodeFromString(ih, model, 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);
+ }
+
+ return 1;
+}
+
+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;
+ GtkTreePath* path;
+
+ if (gtkTreeSetMarkAttrib(ih, value))
+ return 0;
+
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+
+ if (iupStrEqualNoCase(value, "ROOT"))
+ iterItem = iterRoot;
+ else if(iupStrEqualNoCase(value, "LAST"))
+ iterItem = gtkTreeGetLastVisibleNode(ih, model, iterRoot);
+ 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_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);
+ }
+ 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_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;
+ }
+ 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_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;
+ }
+ 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_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;
+ }
+ else
+ {
+ if (!gtkTreeFindNodeFromString(ih, model, 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);
+ }
+
+ path = gtk_tree_model_get_path(model, &iterItem);
+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE, 0, 0); /* scroll to visible */
+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); /* set focus */
+ gtk_tree_path_free(path);
+
+ iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", gtkTreeGetNodeId(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))
+ 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);
+
+ 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));
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, model, 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))
+ return "YES";
+ else
+ return "NO";
+}
+
+static int gtkTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeSelection* selection;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return 0;
+
+ iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", "1");
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ if (iupStrBoolean(value))
+ gtk_tree_selection_select_iter(selection, &iterItem);
+ else
+ gtk_tree_selection_unselect_iter(selection, &iterItem);
+
+ return 0;
+}
+
+static int gtkTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */
+ {
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ GtkTreeIter iterParent;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return 0;
+
+ if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem)) /* the root node can't be deleted */
+ return 0;
+
+ gtkTreeCallNodeRemoved(ih, model, &iterItem);
+
+ /* deleting the specified node (and it's children) */
+ gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem);
+ }
+ else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */
+ {
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem, iterChild;
+ int hasChildren;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return 0;
+
+ hasChildren = gtk_tree_model_iter_children(model, &iterChild, &iterItem);
+
+ /* deleting the selected node's children */
+ while(hasChildren)
+ {
+ gtkTreeCallNodeRemoved(ih, model, &iterChild);
+ hasChildren = gtk_tree_store_remove(GTK_TREE_STORE(model), &iterChild);
+ }
+ }
+ else if(iupStrEqualNoCase(value, "MARKED")) /* Delete the array of marked nodes */
+ {
+ 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;
+
+ gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Iter_Func, &rr_list);
+
+ for(node = rr_list; node != NULL; node = node->next)
+ {
+ GtkTreePath* path = gtk_tree_row_reference_get_path(node->data);
+ if (path)
+ {
+ 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);
+ }
+ gtk_tree_row_reference_free(node->data);
+ }
+ g_list_free(rr_list);
+ }
+
+ return 0;
+}
+
+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;
+}
+
+static int gtkTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int kind;
+ 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))
+ return 0;
+
+ gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+
+ if (kind == ITREE_BRANCH)
+ {
+ if (pixExpand)
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, pixExpand,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED, TRUE, -1);
+ else
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, -1);
+ }
+
+ return 1;
+}
+
+static int gtkTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ 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))
+ return 0;
+
+ if (pixImage)
+ {
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, pixImage,
+ IUPGTK_TREE_HAS_IMAGE, TRUE, -1);
+ }
+ else
+ {
+ int kind;
+ gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+ if (kind == ITREE_BRANCH)
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed,
+ IUPGTK_TREE_HAS_IMAGE, FALSE, -1);
+ else
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf,
+ IUPGTK_TREE_HAS_IMAGE, FALSE, -1);
+ }
+
+ return 1;
+}
+
+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);
+
+ 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);
+
+ 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);
+
+ return 1;
+}
+
+static int gtkTreeSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+
+ GtkScrolledWindow* scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (scrolled_window)
+ {
+ /* ignore given value, must use only from parent for the scrollbars */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ if (iupStrToRGB(parent_value, &r, &g, &b))
+ {
+ GtkWidget* sb;
+
+ if (!GTK_IS_SCROLLED_WINDOW(scrolled_window))
+ scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUPGTK_SCROLLED_WINDOW");
+
+ iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ sb = gtk_scrolled_window_get_hscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+
+ sb = gtk_scrolled_window_get_vscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+#endif
+ }
+ }
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ {
+ GtkCellRenderer* renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT");
+ GtkCellRenderer* renderer_img = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_IMG");
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(renderer_txt), "cell-background-gdk", &color, NULL);
+ g_object_set(G_OBJECT(renderer_img), "cell-background-gdk", &color, NULL);
+ }
+
+ iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */
+
+ /* no need to update internal image cache in GTK */
+
+ return 1;
+}
+
+static int gtkTreeSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(ih->handle, r, g, b);
+
+ {
+ GtkCellRenderer* renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT");
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(renderer_txt), "foreground-gdk", &color, NULL);
+ g_object_get(G_OBJECT(renderer_txt), "foreground-gdk", &color, NULL);
+ color.blue = 0;
+ }
+
+ return 1;
+}
+
+void iupdrvTreeUpdateMarkMode(Ihandle *ih)
+{
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ gtk_tree_selection_set_mode(selection, (ih->data->mark_mode==ITREE_MARK_SINGLE)? GTK_SELECTION_SINGLE: GTK_SELECTION_MULTIPLE);
+
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && !ih->data->show_dragdrop)
+ {
+#if GTK_CHECK_VERSION(2, 10, 0)
+ gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(ih->handle), TRUE);
+#endif
+ }
+}
+
+
+/***********************************************************************************************/
+
+
+static void gtkTreeSetRenameCaretPos(GtkCellEditable *editable, const char* value)
+{
+ int pos = 1;
+
+ if (iupStrToInt(value, &pos))
+ {
+ if (pos < 1) pos = 1;
+ pos--; /* IUP starts at 1 */
+
+ gtk_editable_set_position(GTK_EDITABLE(editable), pos);
+ }
+}
+
+static void gtkTreeSetRenameSelectionPos(GtkCellEditable *editable, const char* value)
+{
+ int start = 1, end = 1;
+
+ if (iupStrToIntInt(value, &start, &end, ':') != 2)
+ return;
+
+ if(start < 1 || end < 1)
+ return;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ gtk_editable_select_region(GTK_EDITABLE(editable), start, end);
+}
+
+/*****************************************************************************/
+/* SIGNALS */
+/*****************************************************************************/
+
+static void gtkTreeCellTextEditingStarted(GtkCellRenderer *cell, GtkCellEditable *editable, const gchar *path_string, Ihandle *ih)
+{
+ char* value;
+ GtkTreeIter iterItem;
+ PangoFontDescription* fontdesc = NULL;
+ GdkColor *color = NULL;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+
+ value = iupAttribGetStr(ih, "RENAMECARET");
+ if (value)
+ gtkTreeSetRenameCaretPos(editable, value);
+
+ value = iupAttribGetStr(ih, "RENAMESELECTION");
+ 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);
+
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_COLOR, &color, -1);
+ if (color)
+ iupgtkBaseSetFgGdkColor(GTK_WIDGET(editable), color);
+
+ (void)cell;
+}
+
+static void gtkTreeCellTextEdited(GtkCellRendererText *cell, gchar *path_string, gchar *new_text, Ihandle* ih)
+{
+ GtkTreeModel* model;
+ GtkTreeIter iterItem;
+ IFnis cbRename;
+
+ if (!new_text)
+ return;
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ if (!gtk_tree_model_get_iter_from_string(model, &iterItem, path_string))
+ return;
+
+ cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB");
+ if (cbRename)
+ {
+ if (cbRename(ih, gtkTreeGetNodeId(ih, iterItem), iupgtkStrConvertFromUTF8(new_text)) == IUP_IGNORE)
+ return;
+ }
+
+ /* It is the responsibility of the application to update the model and store new_text at the position indicated by path. */
+ gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_TITLE, new_text, -1);
+
+ (void)cell;
+}
+
+static int gtkTreeCallDragDropCb(Ihandle* ih, GtkTreeIter *iterDrag, GtkTreeIter *iterDrop, int *is_ctrl)
+{
+ IFniiii cbDragDrop = (IFniiii)IupGetCallback(ih, "DRAGDROP_CB");
+ int is_shift = 0;
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[0] == 'S')
+ is_shift = 1;
+ if (key[1] == 'C')
+ *is_ctrl = 1;
+ else
+ *is_ctrl = 0;
+
+ if (cbDragDrop)
+ {
+ int drag_id = gtkTreeGetNodeId(ih, *iterDrag);
+ int drop_id = gtkTreeGetNodeId(ih, *iterDrop);
+ return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl);
+ }
+
+ return IUP_CONTINUE; /* allow to move by default if callback not defined */
+}
+
+static void gtkTreeDragDataReceived(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
+ GtkSelectionData *selection_data, guint info, guint time, Ihandle* ih)
+{
+ GtkTreePath* pathDrag = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM");
+ GtkTreePath* pathDrop = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DROPITEM");
+ int accepted = FALSE;
+ int is_ctrl;
+
+ if (pathDrag && pathDrop)
+ {
+ GtkTreeIter iterDrag, iterDrop, iterParent, iterNextParent;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+
+ gtk_tree_model_get_iter(model, &iterDrag, pathDrag);
+ gtk_tree_model_get_iter(model, &iterDrop, pathDrop);
+
+ iterParent = iterDrop;
+ while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent))
+ {
+ if (iterNextParent.user_data == iterDrag.user_data)
+ goto gtkTreeDragDataReceived_FINISH;
+ iterParent = iterNextParent;
+ }
+
+ accepted = TRUE;
+
+ if (gtkTreeCallDragDropCb(ih, &iterDrag, &iterDrop, &is_ctrl) == IUP_CONTINUE)
+ {
+ 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);
+ }
+
+ /* set focus and selection */
+ {
+ 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);
+
+ 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);
+
+ gtk_tree_path_free(pathNew);
+ }
+ }
+ }
+
+gtkTreeDragDataReceived_FINISH:
+ if (pathDrag) gtk_tree_path_free(pathDrag);
+ if (pathDrop) gtk_tree_path_free(pathDrop);
+
+ iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", NULL);
+ iupAttribSetStr(ih, "_IUPTREE_DROPITEM", NULL);
+
+ gtk_drag_finish(context, accepted, (context->action == GDK_ACTION_MOVE), time);
+
+ (void)widget;
+ (void)info;
+ (void)x;
+ (void)y;
+ (void)selection_data;
+}
+
+static gboolean gtkTreeDragDrop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, Ihandle* ih)
+{
+ GtkTreePath* path;
+ GtkTreeViewDropPosition pos;
+ GdkAtom target = GDK_NONE;
+
+ /* unset any highlight row */
+ gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW(widget), NULL, GTK_TREE_VIEW_DROP_BEFORE);
+
+ if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos))
+ {
+ if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) &&
+ (gtk_tree_path_compare(path, (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM")) != 0))
+ {
+ target = gtk_drag_dest_find_target(widget, context, gtk_drag_dest_get_target_list(widget));
+ if (target != GDK_NONE)
+ {
+ iupAttribSetStr(ih, "_IUPTREE_DROPITEM", (char*)path);
+ gtk_drag_get_data(widget, context, target, time);
+ return TRUE;
+ }
+ }
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+static void gtkTreeDragLeave(GtkWidget *widget, GdkDragContext *context, guint time)
+{
+ /* unset any highlight row */
+ gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), NULL, GTK_TREE_VIEW_DROP_BEFORE);
+ (void)context;
+ (void)time;
+}
+
+static gboolean gtkTreeDragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, Ihandle* ih)
+{
+ GtkTreePath* path;
+ GtkTreeViewDropPosition pos;
+ GtkTreePath* pathDrag = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM");
+ if (pathDrag && gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos))
+ {
+ if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) &&
+ (gtk_tree_path_compare(path, pathDrag) != 0))
+ {
+ gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), path, pos);
+ gdk_drag_status(context, context->actions, time);
+ return TRUE;
+ }
+
+ gtk_tree_path_free(path);
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+static void gtkTreeDragBegin(GtkWidget *widget, GdkDragContext *context, Ihandle* ih)
+{
+ int x = iupAttribGetInt(ih, "_IUPTREE_DRAG_X");
+ int y = iupAttribGetInt(ih, "_IUPTREE_DRAG_Y");
+ GtkTreePath* path;
+ GtkTreeViewDropPosition pos;
+ if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos))
+ {
+ if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER))
+ {
+ GdkPixmap* pixmap;
+ iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", (char*)path);
+
+ pixmap = gtk_tree_view_create_row_drag_icon(GTK_TREE_VIEW(ih->handle), path);
+ gtk_drag_source_set_icon(widget, gtk_widget_get_colormap(widget), pixmap, NULL);
+ g_object_unref(pixmap);
+ return;
+ }
+ }
+
+ (void)context;
+ (void)widget;
+}
+
+static void gtkTreeSelectionChanged(GtkTreeSelection* selection, Ihandle* ih)
+{
+ IFnii cbSelec;
+ int is_ctrl = 0;
+
+ if (ih->data->mark_mode == ITREE_MARK_MULTIPLE)
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[0] == 'S')
+ return;
+ else if (key[1] == 'C')
+ is_ctrl = 1;
+
+ if (iupAttribGetInt(ih, "_IUPTREE_EXTENDSELECT")==2 && !is_ctrl)
+ {
+ iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", NULL);
+ gtkTreeCallMultiSelectionCb(ih);
+ return;
+ }
+ }
+
+ cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB");
+ if (cbSelec)
+ {
+ int curpos = -1, is_selected = 0;
+
+ if (iupAttribGet(ih, "_IUP_IGNORE_SELECTION"))
+ {
+ iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", NULL);
+ return;
+ }
+
+ {
+ 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);
+ }
+ }
+
+ if (curpos == -1)
+ return;
+
+ if (is_ctrl)
+ cbSelec(ih, curpos, is_selected);
+ else
+ {
+ int oldpos = iupAttribGetInt(ih, "_IUPTREE_OLDVALUE");
+ if(oldpos != curpos)
+ {
+ cbSelec(ih, oldpos, 0); /* unselected */
+ cbSelec(ih, curpos, 1); /* selected */
+
+ iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", curpos);
+ }
+ }
+ }
+}
+
+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);
+ return FALSE;
+ }
+
+ if (cbBranchOpen(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE)
+ return TRUE; /* prevent the change */
+ }
+
+ (void)path;
+ (void)tree_view;
+ return FALSE;
+}
+
+static gboolean gtkTreeTestCollapseRow(GtkTreeView* tree_view, GtkTreeIter *iterItem, GtkTreePath *path, Ihandle* ih)
+{
+ IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB");
+ if (cbBranchClose)
+ {
+ if (cbBranchClose(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE)
+ return TRUE;
+ }
+
+ (void)path;
+ (void)tree_view;
+ return FALSE;
+}
+
+static void gtkTreeRowActived(GtkTreeView* tree_view, GtkTreePath *path, GtkTreeViewColumn *column, Ihandle* ih)
+{
+ GtkTreeIter iterItem;
+ GtkTreeModel* model;
+ int kind; /* used for nodes defined as branches, but do not have children */
+ IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB");
+ if (!cbExecuteLeaf)
+ return;
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ gtk_tree_model_get_iter(model, &iterItem, path);
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+
+ /* just to leaf nodes */
+ if(gtk_tree_model_iter_has_child(model, &iterItem) == 0 && kind == ITREE_LEAF)
+ cbExecuteLeaf(ih, gtkTreeGetNodeId(ih, iterItem));
+
+ (void)column;
+ (void)tree_view;
+}
+
+static int gtkTreeConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ GtkTreePath* path;
+ if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, NULL))
+ {
+ 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 gtkTreeGetNodeId(ih, iterItem);
+ }
+ return -1;
+}
+
+static gboolean gtkTreeButtonEvent(GtkWidget *treeview, GdkEventButton *evt, Ihandle* ih)
+{
+ if (iupgtkButtonEvent(treeview, evt, ih) == TRUE)
+ return TRUE;
+
+ if (evt->type == GDK_BUTTON_PRESS && evt->button == 3) /* right single click */
+ {
+ IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB");
+ if (cbRightClick)
+ {
+ int id = gtkTreeConvertXYToPos(ih, (int)evt->x, (int)evt->y);
+ if (id != -1)
+ cbRightClick(ih, id);
+ return TRUE;
+ }
+ }
+ else if (evt->type == GDK_2BUTTON_PRESS && evt->button == 1) /* left double click */
+ {
+ GtkTreePath *path;
+
+ if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), (gint) evt->x, (gint) evt->y, &path, NULL, NULL, NULL))
+ {
+ GtkTreeIter iter;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ int kind; /* used for nodes defined as branches, but do not have children */
+
+ gtk_tree_model_get_iter(model, &iter, path);
+ gtk_tree_model_get(model, &iter, IUPGTK_TREE_KIND, &kind, -1);
+
+ if (kind == ITREE_BRANCH)
+ gtkTreeExpandItem(ih, path, -1); /* toggle */
+
+ gtk_tree_path_free(path);
+ }
+ }
+ 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))
+ gtkTreeCallMultiSelectionCb(ih); /* Multi Selection Callback */
+
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE &&
+ !(evt->state & GDK_SHIFT_MASK) && !(evt->state & GDK_CONTROL_MASK))
+ {
+ if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT"))
+ 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;
+}
+
+static gboolean gtkTreeKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & GDK_SHIFT_MASK))
+ {
+ if (evt->keyval == GDK_Up || evt->keyval == GDK_Down || evt->keyval == GDK_Home || evt->keyval == GDK_End)
+ gtkTreeCallMultiSelectionCb(ih); /* Multi Selection Callback */
+ }
+
+ (void)widget;
+ return TRUE;
+}
+
+static gboolean gtkTreeKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (iupgtkKeyPressEvent(widget, evt, ih) == TRUE)
+ return TRUE;
+
+ if (evt->keyval == GDK_F2)
+ {
+ gtkTreeSetRenameAttrib(ih, NULL);
+ return TRUE;
+ }
+ else if (evt->keyval == GDK_Return || evt->keyval == GDK_KP_Enter)
+ {
+ gtkTreeOpenCloseEvent(ih);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void gtkTreeEnableDragDrop(Ihandle* ih)
+{
+ const GtkTargetEntry row_targets[] = {
+ { "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);
+
+ 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);
+ }
+}
+
+/*****************************************************************************/
+
+static int gtkTreeMapMethod(Ihandle* ih)
+{
+ GtkScrolledWindow* scrolled_window = NULL;
+ GtkTreeStore *store;
+ GtkCellRenderer *renderer_img, *renderer_txt;
+ 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);
+
+ ih->handle = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+
+ g_object_unref(store);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL);
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window);
+
+ /* Column and renderers */
+ column = gtk_tree_view_column_new();
+ iupAttribSetStr(ih, "_IUPGTK_COLUMN", (char*)column);
+
+ renderer_img = gtk_cell_renderer_pixbuf_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), renderer_img, FALSE);
+ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(column), renderer_img, "pixbuf", IUPGTK_TREE_IMAGE,
+ "pixbuf-expander-open", IUPGTK_TREE_IMAGE_EXPANDED,
+ "pixbuf-expander-closed", IUPGTK_TREE_IMAGE,
+ NULL);
+ iupAttribSetStr(ih, "_IUPGTK_RENDERER_IMG", (char*)renderer_img);
+
+ renderer_txt = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), renderer_txt, TRUE);
+ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(column), renderer_txt, "text", IUPGTK_TREE_TITLE,
+ "is-expander", IUPGTK_TREE_KIND,
+ "font-desc", IUPGTK_TREE_FONT,
+ "foreground-gdk", IUPGTK_TREE_COLOR,
+ NULL);
+ iupAttribSetStr(ih, "_IUPGTK_RENDERER_TEXT", (char*)renderer_txt);
+
+ if (ih->data->show_rename)
+ g_object_set(G_OBJECT(renderer_txt), "editable", TRUE, NULL);
+
+ g_object_set(G_OBJECT(renderer_txt), "xpad", 0, NULL);
+ g_object_set(G_OBJECT(renderer_txt), "ypad", 0, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(ih->handle), column);
+
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ih->handle), FALSE);
+ gtk_tree_view_set_enable_search(GTK_TREE_VIEW(ih->handle), FALSE);
+
+#if GTK_CHECK_VERSION(2, 10, 0)
+ if (iupAttribGetBoolean(ih, "HIDELINES"))
+ gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(ih->handle), FALSE);
+ else
+ gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(ih->handle), TRUE);
+#endif
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+ if (iupAttribGetBoolean(ih, "HIDEBUTTONS"))
+ gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(ih->handle), FALSE);
+ else
+ gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(ih->handle), TRUE);
+#endif
+
+ if (ih->data->show_dragdrop)
+ gtkTreeEnableDragDrop(ih);
+
+ gtk_container_add((GtkContainer*)scrolled_window, ih->handle);
+ gtk_widget_show((GtkWidget*)scrolled_window);
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN);
+
+ 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_view_set_reorderable(GTK_TREE_VIEW(ih->handle), FALSE);
+
+ /* callbacks */
+ g_signal_connect(selection, "changed", G_CALLBACK(gtkTreeSelectionChanged), ih);
+
+ g_signal_connect(renderer_txt, "editing-started", G_CALLBACK(gtkTreeCellTextEditingStarted), ih);
+ g_signal_connect(renderer_txt, "edited", G_CALLBACK(gtkTreeCellTextEdited), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), 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), "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);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkTreeKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(gtkTreeKeyReleaseEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkTreeButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkTreeButtonEvent), ih);
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ gtk_widget_realize((GtkWidget*)scrolled_window);
+ gtk_widget_realize(ih->handle);
+
+ /* Initialize the default images */
+ ih->data->def_image_leaf = iupImageGetImage("IMGLEAF", ih, 0);
+ ih->data->def_image_collapsed = iupImageGetImage("IMGCOLLAPSED", ih, 0);
+ ih->data->def_image_expanded = iupImageGetImage("IMGEXPANDED", ih, 0);
+
+ gtkTreeAddRootNode(ih);
+
+ /* configure for DRAG&DROP of files */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkTreeConvertXYToPos);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTreeInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkTreeMapMethod;
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTreeSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkTreeSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT);
+
+ /* 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);
+
+ /* IupTree Attributes - IMAGES */
+ iupClassRegisterAttributeId(ic, "IMAGE", NULL, gtkTreeSetImageAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "IMAGEEXPANDED", NULL, gtkTreeSetImageExpandedAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "IMAGELEAF", NULL, gtkTreeSetImageLeafAttrib, IUPAF_SAMEASSYSTEM, "IMGLEAF", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEBRANCHCOLLAPSED", NULL, gtkTreeSetImageBranchCollapsedAttrib, IUPAF_SAMEASSYSTEM, "IMGCOLLAPSED", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEBRANCHEXPANDED", NULL, gtkTreeSetImageBranchExpandedAttrib, IUPAF_SAMEASSYSTEM, "IMGEXPANDED", IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - NODES */
+ iupClassRegisterAttributeId(ic, "STATE", gtkTreeGetStateAttrib, gtkTreeSetStateAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "DEPTH", gtkTreeGetDepthAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "KIND", gtkTreeGetKindAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "PARENT", gtkTreeGetParentAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ 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);
+
+ /* IupTree Attributes - MARKS */
+ iupClassRegisterAttributeId(ic, "MARKED", gtkTreeGetMarkedAttrib, gtkTreeSetMarkedAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ 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, "VALUE", gtkTreeGetValueAttrib, gtkTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - ACTION */
+ iupClassRegisterAttributeId(ic, "DELNODE", NULL, gtkTreeSetDelNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ 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);
+}
diff --git a/iup/src/gtk/iupgtk_val.c b/iup/src/gtk/iupgtk_val.c
new file mode 100755
index 0000000..018af83
--- /dev/null
+++ b/iup/src/gtk/iupgtk_val.c
@@ -0,0 +1,208 @@
+/** \file
+ * \brief Valuator Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_val.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_key.h"
+
+#include "iupgtk_drv.h"
+
+
+void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h)
+{
+ if (ih->data->type == IVAL_HORIZONTAL)
+ {
+ *w = 20;
+ *h = 35;
+ }
+ else
+ {
+ *w = 35;
+ *h = 20;
+ }
+}
+
+static int gtkValSetStepAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->step = atof(value);
+ gtk_range_set_increments(GTK_RANGE(ih->handle), ih->data->step, ih->data->pagestep);
+ return 0; /* do not store value in hash table */
+}
+
+static int gtkValSetPageStepAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->pagestep = atof(value);
+ gtk_range_set_increments(GTK_RANGE(ih->handle), ih->data->step, ih->data->pagestep);
+ return 0; /* do not store value in hash table */
+}
+
+static int gtkValSetValueAttrib(Ihandle* ih, const char* value)
+{
+ double fval;
+ ih->data->val = atof(value);
+ fval = (ih->data->val-ih->data->vmin)/(ih->data->vmax - ih->data->vmin);
+ gtk_range_set_value(GTK_RANGE(ih->handle), fval);
+ return 0; /* do not store value in hash table */
+}
+
+
+/*********************************************************************************************/
+
+
+static gboolean gtkValChangeValue(GtkRange *range, GtkScrollType scroll, double fval, Ihandle *ih)
+{
+ double old_val = ih->data->val;
+ IFn cb;
+
+ if (fval < 0.0)
+ gtk_range_set_value(GTK_RANGE(ih->handle), 0.0);
+ if (fval > 1.0)
+ gtk_range_set_value(GTK_RANGE(ih->handle), 1.0);
+
+ ih->data->val = fval*(ih->data->vmax - ih->data->vmin) + ih->data->vmin;
+ iupValCropValue(ih);
+
+ cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB");
+ if (cb)
+ {
+ if (ih->data->val == old_val)
+ return FALSE;
+
+ cb(ih);
+ }
+ else
+ {
+ IFnd cb_old;
+ if (scroll == GTK_SCROLL_JUMP) /* scroll == 1 */
+ cb_old = (IFnd)IupGetCallback(ih, "MOUSEMOVE_CB");
+ else if((scroll >= GTK_SCROLL_STEP_BACKWARD) && (scroll <= GTK_SCROLL_END))
+ cb_old = (IFnd)IupGetCallback(ih, "BUTTON_PRESS_CB");
+ else
+ cb_old = (IFnd)IupGetCallback(ih, "BUTTON_RELEASE_CB");
+ if (cb_old)
+ cb_old(ih, ih->data->val);
+ }
+
+ if (fval < 0.0 || fval > 1.0)
+ return TRUE;
+
+ (void)range;
+ return FALSE;
+}
+
+static gboolean gtkValKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (iupgtkKeyPressEvent(widget, evt, ih) == TRUE)
+ return TRUE;
+
+ /* change Home and End default behaviour */
+ if (ih->data->inverted)
+ {
+ if (evt->keyval==GDK_Home || evt->keyval==GDK_KP_Home)
+ {
+ /* set to maximum */
+ gtk_range_set_value(GTK_RANGE(ih->handle), 1.0);
+ gtkValChangeValue(GTK_RANGE(ih->handle), GTK_SCROLL_START, 1.0, ih);
+ return TRUE;
+ }
+ if (evt->keyval==GDK_End || evt->keyval==GDK_KP_End)
+ {
+ /* set to minimum */
+ gtk_range_set_value(GTK_RANGE(ih->handle), 0.0);
+ gtkValChangeValue(GTK_RANGE(ih->handle), GTK_SCROLL_END, 0.0, ih);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*********************************************************************************************/
+
+
+static int gtkValMapMethod(Ihandle* ih)
+{
+ GtkObject *adjustment;
+
+ /* value, lower, upper, step_increment, page_increment, page_size */
+ /* page_size value only makes a difference for scrollbar widgets */
+ adjustment = gtk_adjustment_new (0, 0, 1.0, 0.01, 0.1, 0);
+ if (!adjustment)
+ return IUP_ERROR;
+
+ if (ih->data->type == IVAL_HORIZONTAL)
+ ih->handle = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
+ else
+ ih->handle = gtk_vscale_new(GTK_ADJUSTMENT(adjustment));
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkValKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "change-value", G_CALLBACK(gtkValChangeValue), ih);
+
+ /* configure the scale */
+ gtk_scale_set_draw_value(GTK_SCALE(ih->handle), FALSE);
+ gtk_range_set_range(GTK_RANGE(ih->handle), 0.0, 1.0);
+
+ if (ih->data->inverted)
+ gtk_range_set_inverted(GTK_RANGE(ih->handle), TRUE);
+
+ gtk_widget_realize(ih->handle);
+
+ /* update a mnemonic in a label if necessary */
+ iupgtkUpdateMnemonic(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvValInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkValMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+
+ /* IupVal only */
+ iupClassRegisterAttribute(ic, "VALUE", iupValGetValueAttrib, gtkValSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PAGESTEP", iupValGetPageStepAttrib, gtkValSetPageStepAttrib, IUPAF_SAMEASSYSTEM, "0.1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "STEP", iupValGetStepAttrib, gtkValSetStepAttrib, IUPAF_SAMEASSYSTEM, "0.01", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWTICKS", NULL, NULL, NULL, NULL, IUPAF_WRITEONLY|IUPAF_READONLY); /* showticks is not supported in GTK */
+}
diff --git a/iup/src/iup.c b/iup/src/iup.c
new file mode 100755
index 0000000..df4bf34
--- /dev/null
+++ b/iup/src/iup.c
@@ -0,0 +1,86 @@
+/** \file
+ * \brief miscelaneous functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+/*! \mainpage IUP
+ *
+ * \section intro Introduction
+ *
+ * Internal SDK documentation of the IUP library, automatically generated using Doxygen (<A HREF="http://www.doxygen.org/">http://www.doxygen.org/</A>).
+ *
+ * \section codestd Code Standards
+ *
+ * \subsection func Function Names (prefix format)
+ * - IupFunc - User API, implemented in the core
+ * - iupFunc - Internal Core API, implemented in the core, used in the core or in driver
+ * - iupxxxFunc - Windows Internal API, implemented in driver xxx, used in driver xxx
+ * - iupdrvFunc - Driver API, implemented in driver, used in the core or driver
+ * - xxxFunc - Driver xxx local functions
+ *
+ * \subsection glob Globais Variables (lower case format)
+ * - iupxxx_var
+ *
+ * \subsection loc Local Variables (lower case format, using module name)
+ * - iyyy_var
+ *
+ * \subsection fil File Names
+ * - iupyyy.h - public headers
+ * - iup_yyy.h/c - core
+ * - iupxxx_yyy.h/c - driver
+ *
+ * \subsection strc Structures
+ * - Iyyy
+ *
+ * \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 doc Documentation
+ * - In the header, using Doxygen commands.
+ * - Check an existant header for example.
+ *
+ */
+
+/** \defgroup util Utilities
+ */
+
+/** \defgroup cpi Control SDK
+ * \par
+ * <H3><A HREF="../en/cpi.html">Control Creation Guide</A></H3>
+ */
+
+#include <stdlib.h>
+
+#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_NUMBER 0
+
+const char iup_ident[] =
+ "$IUP: " IUP_VERSION IUP_VERSION_FIX " " IUP_COPYRIGHT " $\n"
+ "$URL: www.tecgraf.puc-rio.br/iup $\n";
+
+/* Using this, if you look for the string TECVER, you will find also the library version. */
+const char *iup_tecver = "TECVERID.str:Iup:LIB:" IUP_VERSION IUP_VERSION_FIX;
+
+char* IupVersion(void)
+{
+ (void)iup_tecver;
+ (void)iup_ident;
+ return IUP_VERSION IUP_VERSION_FIX;
+}
+
+char* IupVersionDate(void)
+{
+ return IUP_VERSION_DATE;
+}
+
+int IupVersionNumber(void)
+{
+ return IUP_VERSION_NUMBER+IUP_VERSION_FIX_NUMBER;
+}
diff --git a/iup/src/iup.def b/iup/src/iup.def
new file mode 100755
index 0000000..d0dcfbd
--- /dev/null
+++ b/iup/src/iup.def
@@ -0,0 +1,353 @@
+EXPORTS
+IupAlarm
+IupAppend
+IupButton
+IupCanvas
+IupClose
+IupCreate
+IupCreatep
+IupCreatev
+IupDestroy
+IupDetach
+IupDialog
+IupFileDlg
+IupFill
+IupFlush
+IupFrame
+IupGetActionName
+IupGetAllDialogs
+IupGetAllNames
+IupGetAttribute
+IupGetAttributes
+IupGetDialog
+IupGetFile
+IupGetFloat
+IupGetFocus
+IupGetFunction
+IupGetGlobal
+IupGetHandle
+IupGetInt
+IupGetLanguage
+IupGetName
+IupHbox
+IupHelp
+IupImage
+IupHide
+IupItem
+IupLabel
+IupList
+IupListDialog
+IupLoad
+IupLoadBuffer
+IupLoopStep
+IupMainLoop
+IupMap
+IupMapFont
+IupMenu
+IupMessage
+IupMessagef
+IupMultiLine
+IupNextField
+IupOpen
+IupPopup
+IupPreviousField
+IupRadio
+IupScanf
+IupSeparator
+IupSetAttribute
+IupSetAttributes
+IupSetfAttribute
+IupSetAtt
+IupSetFocus
+IupSetFunction
+IupSetGlobal
+IupSetHandle
+IupSetLanguage
+IupShow
+IupShowXY
+IupStoreAttribute
+IupStoreGlobal
+IupSubmenu
+IupText
+IupToggle
+IupUnMapFont
+IupUser
+IupVbox
+IupVersion
+IupVersionDate
+IupZbox
+IupTimer
+IupClipboard
+IupGetNextChild
+IupGetBrother
+IupGetParent
+IupVersionNumber
+IupRefresh
+IupGetText
+IupVboxv
+IupZboxv
+IupHboxv
+IupMenuv
+IupSetCallback
+IupGetCallback
+IupGetChild
+IupGetChildPos
+IupGetChildCount
+IupGetAllAttributes
+IupSetAttributeHandle
+IupGetAttributeHandle
+IupExitLoop
+IupUpdate
+IupRedraw
+IupImageRGB
+IupImageRGBA
+IupUnmap
+IupReparent
+IupMessageDlg
+IupColorDlg
+IupFontDlg
+IupSbox
+IupSpin
+IupSpinbox
+IupCboxv
+IupCbox
+IupVal
+IupProgressBar
+IupTabs
+IupTabsv
+IupGetClassAttributes
+IupSetClassDefaultAttribute
+IupSaveClassAttributes
+IupGetColor
+IupGetParam
+IupGetParamv
+iupGetParamType
+iupGetParamCount
+IupNormalizer
+IupNormalizerv
+IupGetClassType
+IupGetClassName
+IupInsert
+IupMainLoopLevel
+IupGetDialogChild
+IupConvertXYToPos
+IupTextConvertLinColToPos
+IupTextConvertPosToLinCol
+IupUpdateChildren
+IupTreeSetAttribute
+IupTreeStoreAttribute
+IupTreeGetAttribute
+IupTreeGetInt
+IupTreeGetFloat
+IupTreeSetfAttribute
+IupTree
+IupTreeGetId
+IupTreeGetUserId
+IupTreeSetUserId
+IupSaveImageAsText
+
+iupdrvSetVisible
+iupdrvSetStandardFontAttrib
+iupdrvSetCurrentDirectory
+iupdrvSetActive
+iupdrvScreenToClient
+iupdrvReparent
+iupdrvMakeDirectory
+iupdrvIsVisible
+iupdrvIsFile
+iupdrvIsDirectory
+iupdrvIsActive
+iupdrvGetWindowDecor
+iupdrvGetUserName
+iupdrvGetSystemVersion
+iupdrvGetSystemName
+iupdrvGetSystemFont
+iupdrvGetScrollbarSize
+iupdrvGetScreenSize
+iupdrvGetScreenDepth
+iupdrvGetKeyState
+iupdrvGetFullSize
+iupdrvGetDisplay
+iupdrvGetCursorPos
+iupdrvGetCurrentDirectory
+iupdrvGetComputerName
+iupdrvFontGetStringWidth
+iupdrvFontGetMultiLineStringSize
+iupdrvFontGetCharSize
+iupdrvDrawFocusRect
+iupdrvDisplayUpdate
+iupdrvDisplayRedraw
+iupdrvBaseUnMapMethod
+iupdrvBaseSetZorderAttrib
+iupdrvBaseSetTipVisibleAttrib
+iupdrvBaseSetTipAttrib
+iupdrvBaseSetCursorAttrib
+iupdrvBaseLayoutUpdateMethod
+iupdrvBaseGetYAttrib
+iupdrvBaseGetXAttrib
+iupdrvBaseGetClientSizeAttrib
+iupdrvActivate
+iupdrvImageCreateImageRaw
+iupdrvImageGetRawInfo
+iupdrvImageGetRawData
+iupdrvImageDestroy
+iupVersionDlg
+iupTableSetFunc
+iupTableSet
+iupTableRemoveCurr
+iupTableRemove
+iupTableNext
+iupTableGetTyped
+iupTableGetFunc
+iupTableGetCurr
+iupTableGet
+iupTableFirst
+iupTableDestroy
+iupTableCreateSized
+iupTableCreate
+iupTableCount
+iupTableClear
+iupStrToUnix
+iupStrToStrStr
+iupStrToRGB
+iupStrToRGBA
+iupStrToMac
+iupStrToIntInt
+iupStrToInt
+iupStrToFloatFloat
+iupStrToFloat
+iupStrToDos
+iupStrReplace
+iupStrRemove
+iupStrProcessMnemonic
+iupStrNextLine
+iupStrMessageShowError
+iupStrMessageGet
+iupStrLower
+iupStrLineCount
+iupStrInsert
+iupStrGetMemoryCopy
+iupStrGetMemory
+iupStrFileMakeFileName
+iupStrFileGetTitle
+iupStrFileGetPath
+iupStrFileGetExt
+iupStrEqualPartial
+iupStrEqualNoCase
+iupStrEqual
+iupStrDup
+iupStrCountChar
+iupStrCopyUntil
+iupStrCopyN
+iupStrBoolean
+iupSetFontStyleAttrib
+iupSetFontSizeAttrib
+iupSetFontAttrib
+iupRegisterFindClass
+iupRegisterClass
+iupObjectGetParamList
+iupObjectCheck
+iupMaskDestroy
+iupMaskCreateInt
+iupMaskCreateFloat
+iupMaskCreate
+iupMaskCheck
+iupKeyNameToCode
+iupKeyForEach
+iupKeyCodeToName
+iupKeyCanCaps
+iupKeyCallKeyPressCb
+iupKeyCallKeyCb
+iupKeyProcessNavigation
+iupImageStockSet
+iupImageStockLoad
+iupImageColorMakeInactive
+iupGetFontStyleAttrib
+iupGetFontSizeAttrib
+iupGetFontFaceAttrib
+iupGetFontAttrib
+iupFontParseX
+iupFontParseWin
+iupFontParsePango
+iupFocusCanAccept
+iupError
+iupGlobalIsPointer
+iupDlgListVisibleInc
+iupDlgListVisibleDec
+iupDlgListVisibleCount
+iupDlgListRemove
+iupDlgListNext
+iupDlgListFirst
+iupDlgListAdd
+iupDialogGetClass
+iupDataEntry
+iupClassRelease
+iupClassRegisterCallback
+iupClassRegisterAttributeId
+iupClassRegisterAttribute
+iupClassRegisterGetAttribute
+iupClassObjectUnMap
+iupClassObjectSetChildrenPosition
+iupClassObjectSetChildrenCurrentSize
+iupClassObjectSetAttribute
+iupClassObjectMap
+iupClassObjectLayoutUpdate
+iupClassObjectGetInnerContainer
+iupClassObjectGetAttribute
+iupClassObjectGetAttributeInfo
+iupClassObjectAttribIsNotString
+iupClassObjectDlgPopup
+iupClassObjectDestroy
+iupClassObjectCreate
+iupClassObjectComputeNaturalSize
+iupClassObjectChildRemoved
+iupClassObjectChildAdded
+iupClassNew
+iupClassCallbackGetFormat
+iupChildTreeGetNativeParentHandle
+iupChildTreeGetNativeParent
+iupChildTreeAppend
+iupCanvasGetClass
+iupCallKillFocusCb
+iupCallGetFocusCb
+iupBaseSetVisibleAttrib
+iupBaseSetSizeAttrib
+iupBaseSetRasterSizeAttrib
+iupBaseSetActiveAttrib
+iupBaseRegisterVisualAttrib
+iupBaseRegisterCommonAttrib
+iupBaseGetWidAttrib
+iupBaseGetVisibleAttrib
+iupBaseGetSizeAttrib
+iupBaseGetScrollbar
+iupBaseGetRasterSizeAttrib
+iupBaseGetActiveAttrib
+iupBaseContainerUpdateExpand
+iupBaseContainerGetExpandAttrib
+iupBaseTypeVoidMapMethod
+iupBaseSetPosition
+iupBaseComputeNaturalSize
+iupBaseSetCurrentSize
+iupBaseCallValueChangedCb
+iupAttribStoreStr
+iupAttribSetStrf
+iupAttribSetStr
+iupAttribSetInt
+iupAttribSetHandleName
+iupAttribSetFloat
+iupAttribIsPointer
+iupAttribGet
+iupAttribGetInherit
+iupAttribGetInheritNativeParent
+iupAttribGetStr
+iupAttribGetInt
+iupAttribGetBoolean
+iupAttribGetFloat
+iupAssert
+iupArrayInc
+iupArrayGetData
+iupArrayDestroy
+iupArrayCreate
+iupArrayCount
+iupArrayAdd
+iupSaveImageAsText
diff --git a/iup/src/iup.dep b/iup/src/iup.dep
new file mode 100644
index 0000000..63394d5
--- /dev/null
+++ b/iup/src/iup.dep
@@ -0,0 +1,334 @@
+$(OBJDIR)/iup_array.o: iup_array.c iup_array.h iup_assert.h
+$(OBJDIR)/iup_callback.o: iup_callback.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_assert.h
+$(OBJDIR)/iup_dlglist.o: iup_dlglist.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_dlglist.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_assert.h
+$(OBJDIR)/iup_attrib.o: iup_attrib.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_childtree.h iup_str.h iup_ledlex.h iup_attrib.h \
+ iup_assert.h
+$(OBJDIR)/iup_focus.o: iup_focus.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_focus.h iup_assert.h iup_attrib.h \
+ iup_str.h iup_drv.h
+$(OBJDIR)/iup_font.o: iup_font.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h iup_drvfont.h iup_assert.h iup_attrib.h \
+ iup_class.h iup_table.h iup_classbase.h
+$(OBJDIR)/iup_globalattrib.o: iup_globalattrib.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h iup_table.h iup_globalattrib.h \
+ iup_drv.h iup_drvfont.h iup_assert.h iup_str.h
+$(OBJDIR)/iup_object.o: iup_object.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_assert.h iup_register.h iup_names.h
+$(OBJDIR)/iup_key.o: iup_key.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_key.h iup_str.h \
+ iup_object.h iup_class.h iup_table.h iup_classbase.h iup_drv.h \
+ iup_focus.h
+$(OBJDIR)/iup_layout.o: iup_layout.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_drv.h iup_attrib.h iup_str.h iup_layout.h \
+ iup_assert.h
+$(OBJDIR)/iup_ledlex.o: iup_ledlex.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_class.h iup_table.h iup_classbase.h \
+ iup_ledlex.h iup_str.h iup_register.h
+$(OBJDIR)/iup_names.o: iup_names.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h iup_table.h iup_names.h iup_object.h \
+ iup_class.h iup_classbase.h iup_assert.h
+$(OBJDIR)/iup_open.o: iup_open.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h iup_globalattrib.h iup_names.h iup_func.h \
+ iup_drv.h iup_drvinfo.h iup_drvfont.h iup_predial.h iup_class.h \
+ iup_table.h iup_classbase.h iup_register.h iup_key.h iup_image.h \
+ iup_dlglist.h iup_assert.h iup_strmessage.h
+$(OBJDIR)/iup_ledparse.o: iup_ledparse.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_ledlex.h iup_str.h iup_assert.h
+$(OBJDIR)/iup_predial.o: iup_predial.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_predial.h iup_attrib.h iup_str.h \
+ iup_strmessage.h
+$(OBJDIR)/iup_register.o: iup_register.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_register.h iup_stdcontrols.h
+$(OBJDIR)/iup_scanf.o: iup_scanf.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_predial.h iup_str.h iup_assert.h
+$(OBJDIR)/iup_show.o: iup_show.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_layout.h iup_attrib.h iup_dialog.h iup_menu.h \
+ iup_assert.h iup_str.h iup_drv.h iup_drvfont.h
+$(OBJDIR)/iup_str.o: iup_str.c iup_str.h
+$(OBJDIR)/iup_table.o: iup_table.c iup_table.h iup_str.h iup_assert.h
+$(OBJDIR)/iup_func.o: iup_func.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h iup_table.h iup_func.h iup_drv.h \
+ iup_assert.h
+$(OBJDIR)/iup_childtree.o: iup_childtree.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_dlglist.h iup_childtree.h iup_attrib.h iup_assert.h \
+ iup_str.h iup_drv.h
+$(OBJDIR)/iup.o: iup.c ../include/iup.h ../include/iupkey.h ../include/iupdef.h
+$(OBJDIR)/iup_classattrib.o: iup_classattrib.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h iup_attrib.h \
+ iup_assert.h iup_register.h iup_globalattrib.h
+$(OBJDIR)/iup_dialog.o: iup_dialog.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_class.h iup_table.h \
+ iup_classbase.h iup_object.h iup_dlglist.h iup_layout.h iup_attrib.h \
+ iup_drv.h iup_drvinfo.h iup_drvfont.h iup_focus.h iup_str.h \
+ iup_dialog.h
+$(OBJDIR)/iup_assert.o: iup_assert.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_assert.h iup_attrib.h iup_str.h \
+ iup_strmessage.h
+$(OBJDIR)/iup_canvas.o: iup_canvas.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_canvas.h
+$(OBJDIR)/iup_messagedlg.o: iup_messagedlg.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_stdcontrols.h
+$(OBJDIR)/iup_timer.o: iup_timer.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_str.h iup_stdcontrols.h iup_timer.h
+$(OBJDIR)/iup_image.o: iup_image.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_image.h iup_assert.h \
+ iup_stdcontrols.h
+$(OBJDIR)/iup_label.o: iup_label.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_label.h iup_image.h
+$(OBJDIR)/iup_fill.o: iup_fill.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h
+$(OBJDIR)/iup_zbox.o: iup_zbox.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h
+$(OBJDIR)/iup_colordlg.o: iup_colordlg.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h
+$(OBJDIR)/iup_fontdlg.o: iup_fontdlg.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h
+$(OBJDIR)/iup_filedlg.o: iup_filedlg.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h
+$(OBJDIR)/iup_strmessage.o: iup_strmessage.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_attrib.h iup_str.h iup_strmessage.h iup_table.h
+$(OBJDIR)/iup_menu.o: iup_menu.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_dialog.h iup_str.h iup_assert.h \
+ iup_key.h iup_stdcontrols.h iup_drvinfo.h iup_menu.h
+$(OBJDIR)/iup_frame.o: iup_frame.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_frame.h
+$(OBJDIR)/iup_user.o: iup_user.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_stdcontrols.h
+$(OBJDIR)/iup_button.o: iup_button.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_button.h iup_image.h
+$(OBJDIR)/iup_radio.o: iup_radio.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h
+$(OBJDIR)/iup_toggle.o: iup_toggle.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_toggle.h iup_image.h
+$(OBJDIR)/iup_progressbar.o: iup_progressbar.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_progressbar.h
+$(OBJDIR)/iup_text.o: iup_text.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_mask.h iup_array.h \
+ iup_text.h iup_assert.h
+$(OBJDIR)/iup_val.o: iup_val.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h ../include/iupcontrols.h \
+ iup_object.h iup_class.h iup_table.h iup_classbase.h iup_attrib.h \
+ iup_str.h iup_drv.h iup_stdcontrols.h iup_layout.h iup_val.h
+$(OBJDIR)/iup_box.o: iup_box.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h
+$(OBJDIR)/iup_hbox.o: iup_hbox.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h
+$(OBJDIR)/iup_vbox.o: iup_vbox.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h
+$(OBJDIR)/iup_cbox.o: iup_cbox.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h
+$(OBJDIR)/iup_class.o: iup_class.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h iup_attrib.h \
+ iup_assert.h
+$(OBJDIR)/iup_classbase.o: iup_classbase.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h \
+ iup_attrib.h iup_assert.h
+$(OBJDIR)/iup_maskmatch.o: iup_maskmatch.c iup_maskparse.h iup_maskmatch.h
+$(OBJDIR)/iup_mask.o: iup_mask.c iup_maskparse.h iup_mask.h iup_str.h
+$(OBJDIR)/iup_maskparse.o: iup_maskparse.c iup_maskparse.h iup_maskmatch.h
+$(OBJDIR)/iup_tabs.o: iup_tabs.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_image.h iup_tabs.h
+$(OBJDIR)/iup_spin.o: iup_spin.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h \
+ iup_childtree.h
+$(OBJDIR)/iup_list.o: iup_list.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_assert.h iup_object.h \
+ iup_class.h iup_table.h iup_classbase.h iup_attrib.h iup_str.h \
+ iup_drv.h iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_mask.h \
+ iup_list.h
+$(OBJDIR)/iup_getparam.o: iup_getparam.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_attrib.h iup_str.h iup_strmessage.h \
+ iup_drvfont.h
+$(OBJDIR)/iup_sbox.o: iup_sbox.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_stdcontrols.h iup_layout.h iup_childtree.h
+$(OBJDIR)/iup_normalizer.o: iup_normalizer.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_array.h iup_stdcontrols.h
+$(OBJDIR)/iup_tree.o: iup_tree.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_tree.h iup_assert.h
+$(OBJDIR)/iupmot_common.o: mot/iupmot_common.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_childtree.h iup_key.h iup_str.h \
+ iup_class.h iup_attrib.h iup_focus.h iup_drv.h iup_image.h \
+ mot/iupmot_color.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_color.o: mot/iupmot_color.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_drvinfo.h mot/iupmot_drv.h \
+ mot/iupmot_color.h
+$(OBJDIR)/iupmot_focus.o: mot/iupmot_focus.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_focus.h iup_attrib.h iup_assert.h iup_drv.h \
+ mot/iupmot_drv.h
+$(OBJDIR)/iupmot_font.o: mot/iupmot_font.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h iup_attrib.h iup_array.h iup_object.h \
+ iup_class.h iup_table.h iup_classbase.h iup_drv.h iup_drvfont.h \
+ iup_assert.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_key.o: mot/iupmot_key.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_key.h iup_str.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_loop.o: mot/iupmot_loop.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_open.o: mot/iupmot_open.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_str.h iup_drv.h iup_globalattrib.h mot/iupmot_drv.h \
+ mot/iupmot_color.h
+$(OBJDIR)/iupmot_tips.o: mot/iupmot_tips.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_attrib.h iup_str.h iup_drv.h iup_drvfont.h \
+ mot/iupmot_drv.h mot/iupmot_color.h
+$(OBJDIR)/iupmot_globalattrib.o: mot/iupmot_globalattrib.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h iup_str.h iup_drv.h \
+ iup_drvinfo.h iup_strmessage.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_dialog.o: mot/iupmot_dialog.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_class.h iup_table.h \
+ iup_classbase.h iup_object.h iup_class.h iup_childtree.h iup_dlglist.h \
+ iup_attrib.h iup_drv.h iup_drvfont.h iup_drvinfo.h iup_focus.h \
+ iup_str.h iup_dialog.h iup_image.h mot/iupmot_drv.h mot/iupmot_color.h
+$(OBJDIR)/iupmot_messagedlg.o: mot/iupmot_messagedlg.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drvinfo.h \
+ iup_dialog.h iup_strmessage.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_timer.o: mot/iupmot_timer.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_assert.h \
+ iup_timer.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_image.o: mot/iupmot_image.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_image.h iup_drvinfo.h \
+ mot/iupmot_drv.h mot/iupmot_color.h
+$(OBJDIR)/iupmot_label.o: mot/iupmot_label.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \
+ iup_str.h iup_label.h iup_drv.h iup_image.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_canvas.o: mot/iupmot_canvas.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \
+ iup_str.h iup_drv.h iup_drvfont.h iup_canvas.h iup_key.h \
+ mot/iupmot_drv.h mot/iupmot_color.h
+$(OBJDIR)/iupmot_colordlg.o: mot/iupmot_colordlg.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drvinfo.h \
+ iup_dialog.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_fontdlg.o: mot/iupmot_fontdlg.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drvinfo.h \
+ iup_dialog.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_filedlg.o: mot/iupmot_filedlg.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \
+ iup_object.h iup_class.h iup_table.h iup_classbase.h iup_attrib.h \
+ iup_str.h iup_drvinfo.h iup_dialog.h iup_strmessage.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_frame.o: mot/iupmot_frame.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_childtree.h iup_attrib.h iup_str.h iup_dialog.h \
+ iup_image.h iup_drv.h iup_drvfont.h iup_stdcontrols.h mot/iupmot_drv.h \
+ mot/iupmot_color.h
+$(OBJDIR)/iupmot_button.o: mot/iupmot_button.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \
+ iup_str.h iup_button.h iup_drv.h iup_image.h iup_key.h mot/iupmot_drv.h
+$(OBJDIR)/iupmot_toggle.o: mot/iupmot_toggle.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \
+ iup_str.h iup_toggle.h iup_drv.h iup_image.h iup_key.h mot/iupmot_drv.h \
+ mot/iupmot_color.h
+$(OBJDIR)/iupmot_progressbar.o: mot/iupmot_progressbar.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \
+ iup_object.h iup_class.h iup_table.h iup_classbase.h iup_childtree.h \
+ iup_attrib.h iup_dialog.h iup_str.h iup_progressbar.h iup_drv.h \
+ mot/iupmot_drv.h mot/iupmot_color.h
+$(OBJDIR)/iupmot_clipboard.o: mot/iupmot_clipboard.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_image.h \
+ mot/iupmot_drv.h
+$(OBJDIR)/iupmot_text.o: mot/iupmot_text.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \
+ iup_str.h iup_mask.h iup_drv.h iup_array.h iup_text.h mot/iupmot_drv.h \
+ mot/iupmot_color.h
+$(OBJDIR)/iupmot_val.o: mot/iupmot_val.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \
+ iup_str.h iup_val.h iup_image.h iup_drv.h mot/iupmot_drv.h \
+ mot/iupmot_color.h
+$(OBJDIR)/iupmot_tabs.o: mot/iupmot_tabs.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_layout.h iup_childtree.h iup_attrib.h \
+ iup_str.h iup_dialog.h iup_drv.h iup_drvfont.h iup_stdcontrols.h \
+ iup_tabs.h iup_image.h mot/iupmot_drv.h mot/iupmot_color.h
+$(OBJDIR)/iupmot_menu.o: mot/iupmot_menu.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \
+ iup_str.h iup_label.h iup_drv.h iup_drvfont.h iup_image.h iup_menu.h \
+ mot/iupmot_drv.h mot/iupmot_color.h
+$(OBJDIR)/iupmot_list.o: mot/iupmot_list.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \
+ iup_str.h iup_drv.h iup_mask.h iup_key.h iup_list.h mot/iupmot_drv.h \
+ mot/iupmot_color.h
+$(OBJDIR)/iupmot_tree.o: mot/iupmot_tree.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_childtree.h iup_dialog.h iup_layout.h \
+ iup_attrib.h iup_str.h iup_drv.h iup_drvinfo.h iup_drvfont.h \
+ iup_stdcontrols.h iup_key.h iup_image.h iup_array.h iup_tree.h \
+ mot/iupmot_drv.h mot/iupmot_color.h
+$(OBJDIR)/iupunix_help.o: mot/iupunix_help.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h
+$(OBJDIR)/iupunix_info.o: mot/iupunix_info.c iup_str.h iup_drvinfo.h
diff --git a/iup/src/iup_array.c b/iup/src/iup_array.c
new file mode 100755
index 0000000..e7d4e12
--- /dev/null
+++ b/iup/src/iup_array.c
@@ -0,0 +1,108 @@
+/** \file
+ * \brief Simple expandable array
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+
+#include "iup_array.h"
+#include "iup_assert.h"
+
+
+struct _Iarray
+{
+ void* data;
+ int count;
+ int max_count;
+ int elem_size;
+ int start_count;
+};
+
+Iarray* iupArrayCreate(int start_count, int elem_size)
+{
+ Iarray* iarray = (Iarray*)malloc(sizeof(Iarray));
+ iarray->count = 0;
+ iarray->elem_size = elem_size;
+ iarray->max_count = start_count;
+ iarray->start_count = start_count;
+ iarray->data = malloc(elem_size*start_count);
+ iupASSERT(iarray->data!=NULL);
+ if (!iarray->data)
+ {
+ free(iarray);
+ return NULL;
+ }
+ memset(iarray->data, 0, elem_size*start_count);
+ return iarray;
+}
+
+void iupArrayDestroy(Iarray* iarray)
+{
+ iupASSERT(iarray!=NULL);
+ if (!iarray)
+ return;
+ if (iarray->data)
+ {
+ memset(iarray->data, 0, iarray->elem_size*iarray->max_count);
+ free(iarray->data);
+ }
+ free(iarray);
+}
+
+void* iupArrayGetData(Iarray* iarray)
+{
+ iupASSERT(iarray!=NULL);
+ if (!iarray)
+ return NULL;
+ return iarray->data;
+}
+
+void* iupArrayInc(Iarray* iarray)
+{
+ iupASSERT(iarray!=NULL);
+ if (!iarray)
+ return NULL;
+ if (iarray->count >= iarray->max_count)
+ {
+ int old_count = iarray->max_count;
+ iarray->max_count += iarray->start_count;
+ iarray->data = realloc(iarray->data, iarray->elem_size*iarray->max_count);
+ iupASSERT(iarray->data!=NULL);
+ if (!iarray->data)
+ return NULL;
+ memset((unsigned char*)iarray->data + iarray->elem_size*old_count, 0, iarray->elem_size*(iarray->max_count-old_count));
+ }
+ iarray->count++;
+ return iarray->data;
+}
+
+void* iupArrayAdd(Iarray* iarray, int new_count)
+{
+ iupASSERT(iarray!=NULL);
+ if (!iarray)
+ return NULL;
+ if (iarray->count+new_count > iarray->max_count)
+ {
+ int old_count = iarray->max_count;
+ iarray->max_count += new_count;
+ iarray->data = realloc(iarray->data, iarray->elem_size*iarray->max_count);
+ iupASSERT(iarray->data!=NULL);
+ if (!iarray->data)
+ return NULL;
+ memset((unsigned char*)iarray->data + iarray->elem_size*old_count, 0, iarray->elem_size*(iarray->max_count-old_count));
+ }
+ iarray->count += new_count;
+ return iarray->data;
+}
+
+int iupArrayCount(Iarray* iarray)
+{
+ iupASSERT(iarray!=NULL);
+ if (!iarray)
+ return 0;
+ return iarray->count;
+}
diff --git a/iup/src/iup_array.h b/iup/src/iup_array.h
new file mode 100755
index 0000000..b44e862
--- /dev/null
+++ b/iup/src/iup_array.h
@@ -0,0 +1,63 @@
+/** \file
+ * \brief Simple expandable array
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_ARRAY_H
+#define __IUP_ARRAY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** \defgroup iarray Simple Array
+ * \par
+ * Expandable array using a simple pointer.
+ * \par
+ * See \ref iup_array.h
+ * \ingroup util */
+
+typedef struct _Iarray Iarray;
+
+/** Creates an array with an initial room for elements, and the element size.
+ * The array count starts at 0. And the maximum number of elements starts at the given count.
+ * The maximum number of elements is increased by the start count, every time it needs more memory.
+ * Must call \ref iupArrayInc to proper allocates memory.
+ * \ingroup iarray */
+Iarray* iupArrayCreate(int start_count, int elem_size);
+
+/** Destroys the array.
+ * \ingroup iarray */
+void iupArrayDestroy(Iarray* iarray);
+
+/** Returns the pointer that contains the array.
+ * \ingroup iarray */
+void* iupArrayGetData(Iarray* iarray);
+
+/** Increments the number of elements in the array.
+ * The array count starts at 0.
+ * If the maximum number of elements is reached, the memory allocated is increased by the initial start count.
+ * Returns the pointer that contains the array.
+ * \ingroup iarray */
+void* iupArrayInc(Iarray* iarray);
+
+/** Increments the number of elements in the array by a given count.
+ * The array count starts at 0.
+ * If the maximum number of elements is reached, the memory allocated is increased by the given count.
+ * Returns the pointer that contains the array.
+ * \ingroup iarray */
+void* iupArrayAdd(Iarray* iarray, int new_count);
+
+/** Returns the actual number of elements in the array.
+ * \ingroup iarray */
+int iupArrayCount(Iarray* iarray);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_assert.c b/iup/src/iup_assert.c
new file mode 100755
index 0000000..11de909
--- /dev/null
+++ b/iup/src/iup_assert.c
@@ -0,0 +1,54 @@
+/** \file
+ * \brief String Utilities
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_assert.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_strmessage.h"
+
+/* from iup_open, but it is not exported, used only here */
+int iupIsOpened(void);
+
+void iupError(const char* format, ...)
+{
+ static char msg[SHRT_MAX];
+ va_list arglist;
+ va_start(arglist, format);
+ vsprintf(msg, format, arglist);
+ va_end(arglist);
+#if IUP_ASSERT_CONSOLE
+ fprintf(stderr, msg);
+#else
+ if (iupIsOpened())
+ iupStrMessageShowError(NULL, msg);
+ else
+ fprintf(stderr, msg);
+#endif
+}
+
+void iupAssert(const char* expr, const char* file, int line, const char* func)
+{
+ if (func)
+ iupError("File: %s\n"
+ "Line: %d\n"
+ "Function: %s\n"
+ "Assertive: (%s)",
+ file, line, func, expr);
+ else
+ iupError("File: %s\n"
+ "Line: %d\n"
+ "Assertive: (%s)",
+ file, line, expr);
+}
diff --git a/iup/src/iup_assert.h b/iup/src/iup_assert.h
new file mode 100755
index 0000000..03cec99
--- /dev/null
+++ b/iup/src/iup_assert.h
@@ -0,0 +1,68 @@
+/** \file
+ * \brief Assert Utilities
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#ifndef __IUP_ASSERT_H
+#define __IUP_ASSERT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup assert Assert Utilities
+ * \par
+ * All functions of the main API (Iup***) calls iupASSERT to check the parameters.
+ * \par
+ * The IUP main library must be recompiled with the IUP_ASSERT define to enable these checks.
+ * iupASSERT is not called inside driver dependent functions nor in each control implementation,
+ * it is used only in the functions of the main API and in some utilities.
+ * \par
+ * See \ref iup_assert.h
+ * \ingroup util */
+
+/* internal functions */
+void iupAssert(const char* expr, const char* file, int line, const char* func);
+void iupError(const char* format, ...);
+
+/** \def iupASSERT
+ * \brief If the expression if false,
+ * displays a message with information of the source code where the assert happen.
+ *
+ * \param _expr The evaluated expression.
+ * \par
+ * It is a macro that calls a function only if IUP_ASSERT is defined.
+ * \ingroup assert */
+
+/** \def iupERROR
+ * \brief Displays an error message. Also used by the iupASSERT.
+ * \par
+ * It is a macro that calls a function only if IUP_ASSERT is defined.
+ * \ingroup assert */
+
+#ifndef IUP_ASSERT
+#define iupASSERT(_expr) ((void)0)
+#define iupERROR(_msg) ((void)0)
+#define iupERROR1(_msg, _p1) ((void)0)
+#define iupERROR2(_msg, _p1, _p2) ((void)0)
+#else
+#ifdef __FUNCTION__
+#define iupASSERT(_expr) ((_expr)? (void)0: iupAssert(#_expr, __FILE__, __LINE__, __FUNCTION__))
+#else
+#define iupASSERT(_expr) ((_expr)? (void)0: iupAssert(#_expr, __FILE__, __LINE__, NULL))
+#endif /* __FUNCTION__ */
+
+#define iupERROR(_msg) iupError(_msg)
+#define iupERROR1(_msg, _p1) iupError(_msg, _p1)
+#define iupERROR2(_msg, _p1, _p2) iupError(_msg, _p1, _p2)
+
+#endif /* IUP_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_attrib.c b/iup/src/iup_attrib.c
new file mode 100755
index 0000000..2bbb80a
--- /dev/null
+++ b/iup/src/iup_attrib.c
@@ -0,0 +1,673 @@
+/** \file
+ * \brief attributes enviroment management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_str.h"
+#include "iup_ledlex.h"
+#include "iup_attrib.h"
+#include "iup_assert.h"
+
+
+int IupGetAllAttributes(Ihandle* ih, char** names, int n)
+{
+ char *name;
+ int i = 0;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return 0;
+
+ if (!names || !n)
+ return iupTableCount(ih->attrib);
+
+ name = iupTableFirst(ih->attrib);
+ while (name)
+ {
+ names[i] = name;
+ i++;
+ if (i == n)
+ break;
+
+ name = iupTableNext(ih->attrib);
+ }
+
+ return i;
+}
+
+char* IupGetAttributes(Ihandle *ih)
+{
+ char *buffer;
+ char *name, *value;
+ char sb[128];
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ buffer = iupStrGetMemory(10240);
+ buffer[0] = 0;
+
+ name = iupTableFirst(ih->attrib);
+ while (name)
+ {
+ if (!iupAttribIsInternal(name))
+ {
+ if (buffer[0] != 0)
+ strcat(buffer,",");
+
+ value = iupTableGetCurr(ih->attrib);
+ if (iupAttribIsPointer(ih, name))
+ {
+ sprintf(sb, "%p", (void*) value);
+ value = sb;
+ }
+ strcat(buffer, name);
+ strcat(buffer,"=\"");
+ strcat(buffer, value);
+ strcat(buffer,"\"");
+ }
+
+ name = iupTableNext(ih->attrib);
+ }
+
+ return buffer;
+}
+
+void iupAttribUpdateFromParent(Ihandle* ih)
+{
+ Iclass* ic = ih->iclass;
+ char *name = iupTableFirst(ic->attrib_func);
+ while (name)
+ {
+ /* if inheritable and NOT defined at the element */
+ if (iupClassObjectCurAttribIsInherit(ic) && !iupAttribGet(ih, name))
+ {
+ /* check in the parent tree if the attribute is defined */
+ Ihandle* parent = ih->parent;
+ while (parent)
+ {
+ char* value = iupTableGet(parent->attrib, name);
+ if (value)
+ {
+ int inherit;
+ /* set on the class */
+ iupClassObjectSetAttribute(ih, name, value, &inherit);
+ break;
+ }
+ parent = parent->parent;
+ }
+ }
+
+ name = iupTableNext(ic->attrib_func);
+ }
+}
+
+static void iAttribNotifyChildren(Ihandle *ih, const char* name, const char *value)
+{
+ int inherit;
+ Ihandle* child = ih->firstchild;
+ while (child)
+ {
+ if (!iupTableGet(child->attrib, 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 iupAttribUpdate(Ihandle* ih)
+{
+ char** name_array;
+ char *name, *value;
+ int count, i = 0, inherit, store;
+
+ count = iupTableCount(ih->attrib);
+ if (!count)
+ return;
+
+ name_array = (char**)malloc(count * sizeof(char*));
+
+ /* store the names before updating so we can add or remove attributes during the update */
+ name = iupTableFirst(ih->attrib);
+ while (name)
+ {
+ name_array[i] = name;
+ name = iupTableNext(ih->attrib);
+ i++;
+ }
+
+ /* for all defined attributes updates the native system */
+ for (i = 0; i < count; i++)
+ {
+ name = name_array[i];
+ if (!iupAttribIsInternal(name))
+ {
+ /* retrieve from the table */
+ value = iupTableGet(ih->attrib, name);
+
+ /* set on the class */
+ store = iupClassObjectSetAttribute(ih, name, value, &inherit);
+
+ if (inherit)
+ iAttribNotifyChildren(ih, name, value);
+
+ if (store == 0)
+ iupTableRemove(ih->attrib, name); /* remove from the table acording to the class SetAttribute */
+ }
+ }
+
+ free(name_array);
+}
+
+void IupSetAttribute(Ihandle *ih, const char* name, const char *value)
+{
+ int inherit;
+
+ iupASSERT(name!=NULL);
+ if (!name)
+ return;
+
+ if (!ih)
+ {
+ IupSetGlobal(name, value);
+ return;
+ }
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+
+ if (iupAttribIsInternal(name))
+ iupAttribSetStr(ih, name, value);
+ else
+ {
+ if (iupClassObjectSetAttribute(ih, name, value, &inherit)!=0) /* store strings and pointers */
+ iupAttribSetStr(ih, name, value);
+
+ if (inherit)
+ iAttribNotifyChildren(ih, name, value);
+ }
+}
+
+void IupStoreAttribute(Ihandle *ih, const char* name, const char *value)
+{
+ int inherit;
+
+ if (!name)
+ return;
+
+ if (!ih)
+ {
+ IupStoreGlobal(name, value);
+ return;
+ }
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+
+ if (iupAttribIsInternal(name))
+ iupAttribStoreStr(ih, name, value);
+ else
+ {
+ if (iupClassObjectSetAttribute(ih, name, value, &inherit)==1) /* store only strings */
+ iupAttribStoreStr(ih, name, value);
+
+ if (inherit)
+ iAttribNotifyChildren(ih, name, value);
+ }
+}
+
+char* IupGetAttribute(Ihandle *ih, const char* name)
+{
+ int inherit;
+ char *value, *def_value;
+
+ iupASSERT(name!=NULL);
+ if (!name)
+ return NULL;
+
+ if (!ih)
+ return IupGetGlobal(name);
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ value = iupClassObjectGetAttribute(ih, name, &def_value, &inherit);
+ if (!value)
+ value = iupAttribGet(ih, name);
+
+ if (!value && !iupAttribIsInternal(name))
+ {
+ if (inherit)
+ {
+ while (!value)
+ {
+ ih = ih->parent;
+ if (!ih)
+ break;
+
+ value = iupAttribGet(ih, name);
+ }
+ }
+
+ if (!value)
+ value = def_value;
+ }
+
+ return value;
+}
+
+float IupGetFloat(Ihandle *ih, const char* name)
+{
+ float f = 0;
+ char *value = IupGetAttribute(ih, name);
+ if (value)
+ iupStrToFloat(value, &f);
+ return f;
+}
+
+int IupGetInt(Ihandle *ih, const char* name)
+{
+ int i = 0;
+ char *value = IupGetAttribute(ih, name);
+ if (value)
+ {
+ if (!iupStrToInt(value, &i))
+ {
+ if (iupStrBoolean(value))
+ i = 1;
+ }
+ }
+ return i;
+}
+
+int IupGetInt2(Ihandle *ih, const char* name)
+{
+ int i1 = 0, i2 = 0;
+ char *value = IupGetAttribute(ih, name);
+ if (value)
+ {
+ if (!iupStrToIntInt(value, &i1, &i2, 'x'))
+ iupStrToIntInt(value, &i1, &i2, ':');
+ }
+ return i2;
+}
+
+int IupGetIntInt(Ihandle *ih, const char* name, int *i1, int *i2)
+{
+ int _i1 = 0, _i2 = 0;
+ char *value = IupGetAttribute(ih, name);
+ if (value)
+ {
+ int count = iupStrToIntInt(value, &_i1, &_i2, 'x');
+ if (!count) count = iupStrToIntInt(value, &_i1, &_i2, ':');
+ if (i1) *i1 = _i1;
+ if (i2) *i2 = _i2;
+ return count;
+ }
+ return 0;
+}
+
+void IupSetfAttribute(Ihandle *ih, const char* name, const char* f, ...)
+{
+ static char value[SHRT_MAX];
+ va_list arglist;
+ va_start(arglist, f);
+ vsprintf(value, f, arglist);
+ va_end(arglist);
+ IupStoreAttribute(ih, name, value);
+}
+
+void iupAttribSetHandleName(Ihandle *ih)
+{
+ char str_name[100];
+ sprintf(str_name, "_IUP_NAME(%p)", ih);
+ IupSetHandle(str_name, ih);
+}
+
+void IupSetAttributeHandle(Ihandle *ih, const char* name, Ihandle *ih_named)
+{
+ int inherit;
+ char* handle_name;
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+ iupASSERT(name!=NULL);
+ if (!name)
+ return;
+
+ handle_name = IupGetName(ih_named);
+ if (!handle_name)
+ {
+ iupAttribSetHandleName(ih_named);
+ handle_name = IupGetName(ih_named);
+ }
+
+ iupClassObjectSetAttribute(ih, name, handle_name, &inherit);
+ iupAttribStoreStr(ih, name, handle_name);
+}
+
+Ihandle* IupGetAttributeHandle(Ihandle *ih, const char* name)
+{
+ char* handle_name = iupAttribGetInherit(ih, name);
+ if (handle_name)
+ return IupGetHandle(handle_name);
+ return NULL;
+}
+
+Ihandle* IupSetAtt(const char* handle_name, Ihandle* ih, const char* name, ...)
+{
+ const char *attr, *val;
+ va_list arg;
+ va_start (arg, name);
+ attr = name;
+ while (attr)
+ {
+ val = va_arg(arg, const char*);
+ IupSetAttribute(ih, attr, val);
+ attr = va_arg(arg, const char*);
+ }
+ va_end(arg);
+ if (handle_name) IupSetHandle(handle_name, ih);
+ return ih;
+}
+
+void iupAttribSetStr(Ihandle* ih, const char* name, const char* value)
+{
+ if (!value)
+ iupTableRemove(ih->attrib, name);
+ else
+ iupTableSet(ih->attrib, name, (void*)value, IUPTABLE_POINTER);
+}
+
+void iupAttribStoreStr(Ihandle* ih, const char* name, const char* value)
+{
+ if (!value)
+ iupTableRemove(ih->attrib, name);
+ else
+ iupTableSet(ih->attrib, name, (void*)value, IUPTABLE_STRING);
+}
+
+void iupAttribSetStrf(Ihandle *ih, const char* name, const char* f, ...)
+{
+ static char value[SHRT_MAX];
+ va_list arglist;
+ va_start(arglist, f);
+ vsprintf(value, f, arglist);
+ va_end(arglist);
+ iupAttribStoreStr(ih, name, value);
+}
+
+void iupAttribSetInt(Ihandle *ih, const char* name, int num)
+{
+ iupAttribSetStrf(ih, name, "%d", num);
+}
+
+void iupAttribSetFloat(Ihandle *ih, const char* name, float num)
+{
+ iupAttribSetStrf(ih, name, "%f", (double)num);
+}
+
+int iupAttribGetBoolean(Ihandle* ih, const char* name)
+{
+ char *value = iupAttribGetStr(ih, name);
+ if (value)
+ {
+ if (iupStrBoolean(value))
+ return 1;
+ }
+ return 0;
+}
+
+int iupAttribGetInt(Ihandle* ih, const char* name)
+{
+ int i = 0;
+ char *value = iupAttribGetStr(ih, name);
+ if (value)
+ {
+ if (!iupStrToInt(value, &i))
+ {
+ if (iupStrBoolean(value))
+ i = 1;
+ }
+ }
+ return i;
+}
+
+float iupAttribGetFloat(Ihandle* ih, const char* name)
+{
+ float f = 0;
+ char *value = iupAttribGetStr(ih, name);
+ if (value)
+ iupStrToFloat(value, &f);
+ return f;
+}
+
+char* iupAttribGet(Ihandle* ih, const char* name)
+{
+ if (!ih || !name)
+ return NULL;
+ return iupTableGet(ih->attrib, name);
+}
+
+char* iupAttribGetStr(Ihandle* ih, const char* name)
+{
+ char* value;
+ if (!ih || !name)
+ return NULL;
+
+ value = iupTableGet(ih->attrib, name);
+
+ if (!value && !iupAttribIsInternal(name))
+ {
+ int inherit;
+ char *def_value;
+ iupClassObjectGetAttributeInfo(ih, name, &def_value, &inherit);
+
+ if (inherit)
+ {
+ while (!value)
+ {
+ ih = ih->parent;
+ if (!ih)
+ break;
+
+ value = iupAttribGet(ih, name);
+ }
+ }
+
+ if (!value)
+ value = def_value;
+ }
+
+ return value;
+}
+
+char* iupAttribGetInherit(Ihandle* ih, const char* name)
+{
+ char* value;
+ if (!ih || !name)
+ return NULL;
+
+ value = iupAttribGet(ih, name); /* Check on the element first */
+ while (!value)
+ {
+ ih = ih->parent; /* iheritance here independs on the attribute */
+ if (!ih)
+ return NULL;
+
+ value = iupAttribGet(ih, name);
+ }
+ return value;
+}
+
+char* iupAttribGetInheritNativeParent(Ihandle* ih, const char* name)
+{
+ char* value;
+ if (!ih || !name)
+ return NULL;
+
+ value = NULL; /* Do NOT check on the element first */
+ while (!value)
+ {
+ ih = iupChildTreeGetNativeParent(ih);
+ if (!ih)
+ return NULL;
+
+ value = iupAttribGet(ih, name);
+ }
+
+ return value;
+}
+
+static const char* env_str = NULL;
+static void iAttribCapture(char* env_buffer, char* dlm)
+{
+ int i=0;
+ int c;
+ do
+ {
+ c = *env_str; ++env_str;
+ if (i < 256)
+ env_buffer[i++] = (char) c;
+ } while (c && !strchr(dlm,c));
+ env_buffer[i-1]='\0'; /* discard delimiter */
+}
+
+static int iAttribToken(char* env_buffer)
+{
+ for (;;)
+ {
+ int c = *env_str; ++env_str;
+ switch (c)
+ {
+ case 0:
+ return IUPLEX_TK_END;
+
+ case ' ': /* ignore whitespace */
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\f':
+ case '\v':
+ continue;
+
+ case '=': /* attribuicao */
+ return IUPLEX_TK_SET;
+
+ case ',':
+ return IUPLEX_TK_COMMA;
+
+ case '\"': /* string */
+ iAttribCapture(env_buffer, "\"");
+ return IUPLEX_TK_NAME;
+
+ default:
+ if (c > 32) /* identifier */
+ {
+ --env_str; /* unget first character of env_buffer */
+ iAttribCapture(env_buffer, "=, \t\n\r\f\v"); /* get env_buffer until delimiter */
+ --env_str; /* unget delimiter */
+ return IUPLEX_TK_NAME;
+ }
+ }
+ }
+}
+
+static void iAttribParse(Ihandle *ih, const char* str)
+{
+ char env_buffer[256];
+ char* name=NULL;
+ char* value=NULL;
+ char state = 'a'; /* get attribute */
+ int end = 0;
+
+ env_str = str;
+
+ for (;;)
+ {
+ switch (iAttribToken(env_buffer))
+ {
+ case IUPLEX_TK_END: /* procedimento igual ao IUPLEX_TK_COMMA */
+ end = 1;
+ case IUPLEX_TK_COMMA:
+ if (name)
+ {
+ IupStoreAttribute(ih, name, value);
+ free(name);
+ }
+ if (end)
+ return;
+ name = value = NULL;
+ state = 'a';
+ break;
+
+ case IUPLEX_TK_SET:
+ state = 'v'; /* get value */
+ break;
+
+ case IUPLEX_TK_NAME:
+ if (state == 'a')
+ name = iupStrDup(env_buffer);
+ else
+ value = env_buffer;
+ break;
+ }
+ }
+}
+
+Ihandle* IupSetAttributes(Ihandle *ih, const char* str)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return ih;
+ if (str)
+ iAttribParse(ih, str);
+ return ih;
+}
+
+int iupAttribIsPointer(Ihandle* ih, const char* name)
+{
+ return iupClassObjectAttribIsNotString(ih, name);
+}
+
+typedef int (*Iconvertxytopos)(Ihandle* ih, int x, int y);
+
+int IupConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ Iconvertxytopos drvConvertXYToPos;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return -1;
+
+ if (!ih->handle)
+ return -1;
+
+ drvConvertXYToPos = (Iconvertxytopos)IupGetCallback(ih, "_IUP_XY2POS_CB");
+ if (drvConvertXYToPos)
+ return drvConvertXYToPos(ih, x, y);
+
+ return -1;
+}
diff --git a/iup/src/iup_attrib.h b/iup/src/iup_attrib.h
new file mode 100755
index 0000000..993dd3c
--- /dev/null
+++ b/iup/src/iup_attrib.h
@@ -0,0 +1,137 @@
+/** \file
+ * \brief Attributes Environment Management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_ATTRIB_H
+#define __IUP_ATTRIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup attrib Attribute Environment
+ * \par
+ * When attributes are not stored at the control
+ * they are stored in a hash table (see \ref table).
+ * \par
+ * As a general rule use:
+ * - IupGetAttribute, IupSetAttribute, ... : when care about control implementation, hash table, inheritance and default value
+ * - iupAttribGetStr,Int,Float: when care about inheritance, hash table and default value
+ * - iupAttribGet,... : ONLY access the hash table
+ * These different functions have very different performances and results. So use them wiselly.
+ * \par
+ * See \ref iup_attrib.h
+ * \ingroup cpi */
+
+
+/** 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)
+
+/** Returns true if the attribute name is a known pointer.
+ * \ingroup attrib */
+int iupAttribIsPointer(Ihandle* ih, const char *name);
+
+/** Sets the attribute only in the hash table as a pointer.
+ * It ignores children.
+ * \ingroup attrib */
+void iupAttribSetStr(Ihandle* ih, const char* name, const char* value);
+
+/** Sets the attribute only in the hash table as a string.
+ * The string is internally duplicated.
+ * It ignores children.
+ * \ingroup attrib */
+void iupAttribStoreStr(Ihandle* ih, const char* name, const char* value);
+
+/** Sets the attribute only in the hash table as a string.
+ * The string is internally duplicated. Use same format as sprintf.
+ * It ignores children.
+ * \ingroup attrib */
+void iupAttribSetStrf(Ihandle *ih, const char* name, const char* format, ...);
+
+/** Sets an integer attribute only in the hash table.
+ * It will be stored as a string.
+ * It ignores children.
+ * \ingroup attrib */
+void iupAttribSetInt(Ihandle *ih, const char* name, int num);
+
+/** Sets an floating point attribute only in the hash table.
+ * It will be stored as a string.
+ * It ignores children.
+ * \ingroup attrib */
+void iupAttribSetFloat(Ihandle *ih, const char* name, float num);
+
+/** Returns the attribute from the hash table only.
+ * \ingroup attrib */
+char* iupAttribGet(Ihandle* ih, const char* name);
+
+/** Returns the attribute from the hash table only,
+ * but if not defined then checks in its parent tree.
+ * \ingroup attrib */
+char* iupAttribGetInherit(Ihandle* ih, const char* name);
+
+/** Returns the attribute from the hash table of a native parent.
+ * Don't check for default values. Don't check at the element.
+ * Used for BGCOLOR and BACKGROUND attributes.
+ * \ingroup attrib */
+char* iupAttribGetInheritNativeParent(Ihandle* ih, const char* name);
+
+/** Returns the attribute from the hash table as a string,
+ * but if not defined then checks in its parent tree if allowed by the control implementation,
+ * if still not defined then returns the registered default value if any.
+ * \ingroup attrib */
+char* iupAttribGetStr(Ihandle* ih, const char* name);
+
+/** Same as \ref iupAttribGetStr but returns an integer number.
+ * Checks also for boolean values.
+ * \ingroup attrib */
+int iupAttribGetInt(Ihandle* ih, const char* name);
+
+/** Same as \ref iupAttribGetStr but checks for boolean values.
+ * Use \ref iupStrBoolean.
+ * \ingroup attrib */
+int iupAttribGetBoolean(Ihandle* ih, const char* name);
+
+/** Same as \ref iupAttribGetStr but returns an floating point number.
+ * \ingroup attrib */
+float iupAttribGetFloat(Ihandle* ih, const char* name);
+
+/** Set an internal name to a handle.
+ * \ingroup attrib */
+void iupAttribSetHandleName(Ihandle *ih);
+
+
+/* For all attributes in the evironment, call the class SetAttribute only.
+ * Called only after the element is 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. */
+void iupAttribUpdateFromParent(Ihandle* ih);
+
+
+
+/* Other functions declared in <iup.h> and implemented here.
+IupGetAllAttributes
+IupGetAttributes
+IupSetAttributes
+IupSetAttribute
+IupStoreAttribute
+IupGetAttribute
+IupGetFloat
+IupGetInt
+IupGetInt2
+IupSetfAttribute
+IupSetAttributeHandle
+IupGetAttributeHandle
+*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_box.c b/iup/src/iup_box.c
new file mode 100755
index 0000000..54e56d9
--- /dev/null
+++ b/iup/src/iup_box.c
@@ -0,0 +1,238 @@
+/** \file
+ * \brief Base for box Controls.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_box.h"
+
+
+static int iBoxCreateMethod(Ihandle* ih, void** params)
+{
+ ih->data = iupALLOCCTRLDATA();
+
+ if (params)
+ {
+ Ihandle** iparams = (Ihandle**)params;
+ while (*iparams)
+ {
+ IupAppend(ih, *iparams);
+ iparams++;
+ }
+ }
+
+ return IUP_NOERROR;
+}
+
+static char* iBoxGetClientSizeAttrib(Ihandle* ih)
+{
+ char* str;
+ int width, height;
+
+ if (ih->handle)
+ {
+ width = ih->currentwidth;
+ height = ih->currentheight;
+ }
+ else
+ {
+ width = ih->userwidth;
+ height = ih->userheight;
+ }
+
+ if (!width && !height)
+ return NULL;
+
+ str = iupStrGetMemory(50);
+
+ width -= 2*ih->data->margin_x;
+ height -= 2*ih->data->margin_y;
+
+ sprintf(str, "%dx%d", width, height);
+ return str;
+}
+
+static int iBoxSetCGapAttrib(Ihandle* ih, const char* value)
+{
+ int cgap;
+ iupStrToInt(value, &cgap);
+ if (iupStrEqual(ih->iclass->name, "vbox"))
+ {
+ int charheight;
+ iupdrvFontGetCharSize(ih, NULL, &charheight);
+ ih->data->gap = iupHEIGHT2RASTER(cgap, charheight);
+ }
+ else
+ {
+ int charwidth;
+ iupdrvFontGetCharSize(ih, &charwidth, NULL);
+ ih->data->gap = iupWIDTH2RASTER(cgap, charwidth);
+ }
+ return 0;
+}
+
+static char* iBoxGetCGapAttrib(Ihandle* ih)
+{
+ char *str = iupStrGetMemory(50);
+ if (iupStrEqual(ih->iclass->name, "vbox"))
+ {
+ int charheight;
+ iupdrvFontGetCharSize(ih, NULL, &charheight);
+ sprintf(str, "%d", iupRASTER2HEIGHT(ih->data->gap, charheight));
+ }
+ else
+ {
+ int charwidth;
+ iupdrvFontGetCharSize(ih, &charwidth, NULL);
+ sprintf(str, "%d", iupRASTER2WIDTH(ih->data->gap, charwidth));
+ }
+ return str;
+}
+
+static int iBoxSetGapAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToInt(value, &ih->data->gap);
+ return 0;
+}
+
+static char* iBoxGetGapAttrib(Ihandle* ih)
+{
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%d", ih->data->gap);
+ return str;
+}
+
+static int iBoxSetHomogeneousAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ ih->data->is_homogeneous = 1;
+ else
+ ih->data->is_homogeneous = 0;
+ return 0;
+}
+
+static char* iBoxGetHomogeneousAttrib(Ihandle* ih)
+{
+ if (ih->data->is_homogeneous)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iBoxSetExpandChildrenAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ {
+ if (iupStrEqual(ih->iclass->name, "vbox"))
+ ih->data->expand_children = IUP_EXPAND_WIDTH; /* in vert. box, expand horizontally */
+ else
+ ih->data->expand_children = IUP_EXPAND_HEIGHT; /* in horiz. box, expand vertically */
+ }
+ else
+ ih->data->expand_children = 0;
+ return 0;
+}
+
+static char* iBoxGetExpandChildrenAttrib(Ihandle* ih)
+{
+ if (ih->data->expand_children)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iBoxSetNormalizeSizeAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->normalize_size = iupNormalizeGetNormalizeSize(value);
+ return 0;
+}
+
+static char* iBoxGetNormalizeSizeAttrib(Ihandle* ih)
+{
+ return iupNormalizeGetNormalizeSizeStr(ih->data->normalize_size);
+}
+
+static int iBoxSetCMarginAttrib(Ihandle* ih, const char* value)
+{
+ int cmargin_x=-1, cmargin_y=-1;
+ int charwidth, charheight;
+ iupdrvFontGetCharSize(ih, &charwidth, &charheight);
+ iupStrToIntInt(value, &cmargin_x, &cmargin_y, 'x');
+ if (cmargin_x!=-1)
+ ih->data->margin_x = iupHEIGHT2RASTER(cmargin_x, charheight);
+ if (cmargin_y!=-1)
+ ih->data->margin_x = iupWIDTH2RASTER(cmargin_y, charwidth);
+ return 0;
+}
+
+static char* iBoxGetCMarginAttrib(Ihandle* ih)
+{
+ char *str = iupStrGetMemory(50);
+ int charwidth, charheight;
+ iupdrvFontGetCharSize(ih, &charwidth, &charheight);
+ sprintf(str, "%dx%d", iupRASTER2WIDTH(ih->data->margin_x, charwidth), iupRASTER2HEIGHT(ih->data->margin_y, charheight));
+ return str;
+}
+
+static int iBoxSetMarginAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->margin_x, &ih->data->margin_y, 'x');
+ return 0;
+}
+
+static char* iBoxGetMarginAttrib(Ihandle* ih)
+{
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%dx%d", ih->data->margin_x, ih->data->margin_y);
+ return str;
+}
+
+
+/******************************************************************************/
+
+
+Iclass* iupBoxClassBase(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->format = "g"; /* array of Ihandle */
+ ic->nativetype = IUP_TYPEVOID;
+ ic->childtype = IUP_CHILDMANY;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = iBoxCreateMethod;
+ ic->Map = iupBaseTypeVoidMapMethod;
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", iBoxGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ /* 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, "MARGIN", iBoxGetMarginAttrib, iBoxSetMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "CMARGIN", iBoxGetCMarginAttrib, iBoxSetCMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+
+ 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);
+ iupClassRegisterAttribute(ic, "NORMALIZESIZE", iBoxGetNormalizeSizeAttrib, iBoxSetNormalizeSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
diff --git a/iup/src/iup_box.h b/iup/src/iup_box.h
new file mode 100755
index 0000000..5d79263
--- /dev/null
+++ b/iup/src/iup_box.h
@@ -0,0 +1,40 @@
+/** \file
+ * \brief Base for box Controls.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_BOX_H
+#define __IUP_BOX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct _IcontrolData
+{
+ int alignment,
+ expand_children,
+ is_homogeneous,
+ normalize_size,
+ margin_x,
+ margin_y,
+ gap;
+ int children_naturalsize, /* calculated in ComputeNaturalSize, used in SetChildrenCurrentSize */
+ homogeneous_size; /* calculated in SetChildrenCurrentSize, used in SetChildrenPosition */
+};
+
+Iclass* iupBoxClassBase(void);
+
+/* Implemented in iup_normalizer.c */
+void iupNormalizeSizeBoxChild(Ihandle *ih, int normalize, int children_natural_maxwidth, int children_natural_maxheight);
+int iupNormalizeGetNormalizeSize(const char* value);
+char* iupNormalizeGetNormalizeSizeStr(int normalize);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_button.c b/iup/src/iup_button.c
new file mode 100755
index 0000000..7719663
--- /dev/null
+++ b/iup/src/iup_button.c
@@ -0,0 +1,206 @@
+/** \file
+ * \brief Button Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_button.h"
+#include "iup_image.h"
+
+
+char* iupButtonGetPaddingAttrib(Ihandle* ih)
+{
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding);
+ return str;
+}
+
+static int iButtonSetImagePositionAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle) /* set only before map */
+ {
+ if (iupStrEqualNoCase(value, "RIGHT"))
+ ih->data->img_position = IUP_IMGPOS_RIGHT;
+ else if (iupStrEqualNoCase(value, "BOTTOM"))
+ ih->data->img_position = IUP_IMGPOS_BOTTOM;
+ else if (iupStrEqualNoCase(value, "TOP"))
+ ih->data->img_position = IUP_IMGPOS_TOP;
+ else /* "LEFT" */
+ ih->data->img_position = IUP_IMGPOS_LEFT;
+ }
+ return 0;
+}
+
+static char* iButtonGetImagePositionAttrib(Ihandle *ih)
+{
+ char* img_pos2str[4] = {"LEFT", "RIGHT", "TOP", "BOTTOM"};
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%s", img_pos2str[ih->data->img_position]);
+ return str;
+}
+
+static int iButtonSetSpacingAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle) /* set only before map */
+ iupStrToInt(value, &ih->data->spacing);
+ return 0;
+}
+
+static char* iButtonGetSpacingAttrib(Ihandle *ih)
+{
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%d", ih->data->spacing);
+ return str;
+}
+
+
+/*****************************************************************************************/
+
+
+static int iButtonCreateMethod(Ihandle* ih, void** params)
+{
+ if (params)
+ {
+ if (params[0]) iupAttribStoreStr(ih, "TITLE", (char*)(params[0]));
+ if (params[1]) iupAttribStoreStr(ih, "ACTION", (char*)(params[1]));
+ }
+ ih->data = iupALLOCCTRLDATA();
+
+ ih->data->spacing = 2;
+
+ /* used only by the Windows driver */
+ ih->data->horiz_alignment = IUP_ALIGN_ACENTER;
+ ih->data->vert_alignment = IUP_ALIGN_ACENTER;
+ return IUP_NOERROR;
+}
+
+static void iButtonComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ int natural_w = 0,
+ natural_h = 0,
+ type = ih->data->type;
+ (void)expand; /* unset if not a container */
+
+ if (!ih->handle)
+ {
+ /* if not mapped must initialize the internal values */
+ char* value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ {
+ type = IUP_BUTTON_IMAGE;
+ if (iupAttribGet(ih, "TITLE"))
+ type |= IUP_BUTTON_TEXT;
+ }
+ else
+ type = IUP_BUTTON_TEXT;
+ }
+
+ if (type & IUP_BUTTON_IMAGE)
+ {
+ iupImageGetInfo(iupAttribGet(ih, "IMAGE"), &natural_w, &natural_h, NULL);
+
+ if (type & IUP_BUTTON_TEXT)
+ {
+ int text_w, text_h;
+ /* must use IupGetAttribute to check from the native implementation */
+ char* title = IupGetAttribute(ih, "TITLE");
+ iupdrvFontGetMultiLineStringSize(ih, title, &text_w, &text_h);
+
+ if (ih->data->img_position == IUP_IMGPOS_RIGHT ||
+ ih->data->img_position == IUP_IMGPOS_LEFT)
+ {
+ natural_w += text_w + ih->data->spacing;
+ natural_h = iupMAX(natural_h, text_h);
+ }
+ else
+ {
+ natural_w = iupMAX(natural_w, text_w);
+ natural_h += text_h + ih->data->spacing;
+ }
+ }
+ }
+ else /* IUP_BUTTON_TEXT only */
+ {
+ /* must use IupGetAttribute to check from the native implementation */
+ char* title = IupGetAttribute(ih, "TITLE");
+ char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */
+ iupdrvFontGetMultiLineStringSize(ih, str, &natural_w, &natural_h);
+ if (str && str!=title) free(str);
+ }
+
+ /* even when IMPRESS is set, must compute the borders space */
+ iupdrvButtonAddBorders(&natural_w, &natural_h);
+
+ natural_w += 2*ih->data->horiz_padding;
+ natural_h += 2*ih->data->vert_padding;
+
+ *w = natural_w;
+ *h = natural_h;
+}
+
+
+/******************************************************************************/
+
+
+Ihandle* IupButton(const char* title, const char* action)
+{
+ void *params[3];
+ params[0] = (void*)title;
+ params[1] = (void*)action;
+ params[2] = NULL;
+ return IupCreatev("button", params);
+}
+
+Iclass* iupButtonGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "button";
+ ic->format = "SA"; /* one optional string, and one optional callback name */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 1;
+
+ /* Class functions */
+ ic->Create = iButtonCreateMethod;
+ ic->ComputeNaturalSize = iButtonComputeNaturalSizeMethod;
+
+ ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "BUTTON_CB", "iiiis");
+ iupClassRegisterCallback(ic, "ACTION", "");
+
+ /* Common Callbacks */
+ iupBaseRegisterCommonCallbacks(ic);
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Visual */
+ iupBaseRegisterVisualAttrib(ic);
+
+ /* IupButton only */
+ iupClassRegisterAttribute(ic, "SPACING", iButtonGetSpacingAttrib, iButtonSetSpacingAttrib, IUPAF_SAMEASSYSTEM, "2", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEPOSITION", iButtonGetImagePositionAttrib, iButtonSetImagePositionAttrib, IUPAF_SAMEASSYSTEM, "LEFT", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESSBORDER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FLAT", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
+
+ iupdrvButtonInitClass(ic);
+
+ return ic;
+}
diff --git a/iup/src/iup_button.h b/iup/src/iup_button.h
new file mode 100755
index 0000000..f85720a
--- /dev/null
+++ b/iup/src/iup_button.h
@@ -0,0 +1,39 @@
+/** \file
+ * \brief Button Controls Private Declarations
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_BUTTON_H
+#define __IUP_BUTTON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void iupdrvButtonInitClass(Iclass* ic);
+void iupdrvButtonAddBorders(int *x, int *y);
+
+char* iupButtonGetPaddingAttrib(Ihandle* ih);
+
+enum{IUP_BUTTON_IMAGE=0x01, IUP_BUTTON_TEXT=0x02, IUP_BUTTON_BOTH=0x03};
+enum{IUP_IMGPOS_LEFT, IUP_IMGPOS_RIGHT, IUP_IMGPOS_TOP, IUP_IMGPOS_BOTTOM};
+
+struct _IcontrolData
+{
+ int type, /* the 2 buttons possibilities */
+ horiz_padding, vert_padding; /* button margin */
+ int spacing, img_position; /* used when both text and image are displayed */
+
+ /* used only by the Windows driver */
+ int horiz_alignment, vert_alignment;
+ unsigned long fgcolor;
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_callback.c b/iup/src/iup_callback.c
new file mode 100755
index 0000000..e000287
--- /dev/null
+++ b/iup/src/iup_callback.c
@@ -0,0 +1,90 @@
+/** \file
+ * \brief get/set callback
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_assert.h"
+
+
+Icallback IupGetCallback(Ihandle *ih, const char *name)
+{
+ Icallback func = NULL;
+ void* value;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ iupASSERT(name!=NULL);
+ if (!name)
+ return NULL;
+
+ func = (Icallback)iupTableGetFunc(ih->attrib, name, &value);
+
+ if (!func && value)
+ {
+ /* if not a IUPTABLE_FUNCPOINTER then it is an old fashion name */
+ func = IupGetFunction((const char*)value);
+ }
+
+ return func;
+}
+
+Icallback IupSetCallback(Ihandle *ih, const char *name, Icallback func)
+{
+ Icallback old_func = NULL;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ iupASSERT(name!=NULL);
+ if (!name)
+ return NULL;
+
+ if (!func)
+ iupTableRemove(ih->attrib, name);
+ else
+ {
+ void* value;
+ old_func = (Icallback)iupTableGetFunc(ih->attrib, name, &value);
+ if (!old_func && value)
+ old_func = IupGetFunction((const char*)value);
+
+ iupTableSetFunc(ih->attrib, name, (Ifunc)func);
+ }
+
+ return old_func;
+}
+
+Ihandle* IupSetCallbacks(Ihandle* ih, const char *name, Icallback func, ...)
+{
+ va_list arglist;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ IupSetCallback(ih, name, func);
+
+ va_start(arglist, func);
+
+ name=va_arg(arglist, const char*);
+ while (name)
+ {
+ func=va_arg(arglist, Icallback);
+ IupSetCallback(ih, name, func);
+
+ name=va_arg(arglist, const char*);
+ }
+
+ va_end (arglist);
+ return ih;
+}
diff --git a/iup/src/iup_canvas.c b/iup/src/iup_canvas.c
new file mode 100755
index 0000000..5eda988
--- /dev/null
+++ b/iup/src/iup_canvas.c
@@ -0,0 +1,169 @@
+/** \file
+ * \brief Canvas Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_canvas.h"
+
+
+void iupCanvasCalcScrollIntPos(double min, double max, double page, double pos,
+ int imin, int imax, int *ipage, int *ipos)
+{
+ double range = max-min;
+ int irange = imax-imin;
+ double ratio = ((double)irange)/range;
+
+ *ipage = (int)(page*ratio);
+ if (*ipage > irange) *ipage = irange;
+ if (*ipage < 1) *ipage = 1;
+
+ if (ipos)
+ {
+ *ipos = (int)((pos-min)*ratio) + imin;
+ if (*ipos < imin) *ipos = imin;
+ if (*ipos > (imax - *ipage)) *ipos = imax - *ipage;
+ }
+}
+
+void iupCanvasCalcScrollRealPos(double min, double max, double *pos,
+ int imin, int imax, int ipage, int *ipos)
+{
+ double range = max-min;
+ int irange = imax-imin;
+ double ratio = ((double)irange)/range;
+
+ if (*ipos < imin) *ipos = imin;
+ if (*ipos > (imax - ipage)) *ipos = imax - ipage;
+
+ *pos = min + ((double)(*ipos-imin))/ratio;
+}
+
+char* iupCanvasGetPosXAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(20);
+ sprintf(str, "%f", ih->data->posx);
+ return str;
+}
+
+char* iupCanvasGetPosYAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(20);
+ sprintf(str, "%f", ih->data->posy);
+ return str;
+}
+
+static int iCanvasCreateMethod(Ihandle* ih, void** params)
+{
+ if (params && params[0])
+ {
+ char* action = (char*)params[0];
+ iupAttribStoreStr(ih, "ACTION", action);
+ }
+
+ ih->data = iupALLOCCTRLDATA();
+
+ /* default EXPAND is YES */
+ ih->expand = IUP_EXPAND_BOTH;
+
+ return IUP_NOERROR;
+}
+
+static void iCanvasComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ int natural_w = 0, natural_h = 0;
+ (void)expand; /* unset if not a container */
+
+ /* canvas natural size is 1 character */
+ iupdrvFontGetCharSize(ih, &natural_w, &natural_h);
+
+ *w = natural_w;
+ *h = natural_h;
+}
+
+
+/******************************************************************************/
+
+
+Ihandle* IupCanvas(const char* action)
+{
+ void *params[2];
+ params[0] = (void*)action;
+ params[1] = NULL;
+ return IupCreatev("canvas", params);
+}
+
+Iclass* iupCanvasGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "canvas";
+ ic->format = "A"; /* one optional callback name */
+ ic->nativetype = IUP_TYPECANVAS;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 1;
+
+ /* Class functions */
+ ic->Create = iCanvasCreateMethod;
+ ic->ComputeNaturalSize = iCanvasComputeNaturalSizeMethod;
+
+ ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "DROPFILES_CB", "siii");
+ iupClassRegisterCallback(ic, "RESIZE_CB", "ii");
+ iupClassRegisterCallback(ic, "FOCUS_CB", "i");
+ iupClassRegisterCallback(ic, "WOM_CB", "i");
+ iupClassRegisterCallback(ic, "BUTTON_CB", "iiiis");
+ iupClassRegisterCallback(ic, "MOTION_CB", "iis");
+ iupClassRegisterCallback(ic, "KEYPRESS_CB", "ii");
+ iupClassRegisterCallback(ic, "ACTION", "ff");
+ iupClassRegisterCallback(ic, "SCROLL_CB", "iff");
+ iupClassRegisterCallback(ic, "WHEEL_CB", "fiis");
+
+ /* Common Callbacks */
+ iupBaseRegisterCommonCallbacks(ic);
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ {
+ /* Change the default to YES */
+ IattribGetFunc _get;
+ IattribSetFunc _set;
+ iupClassRegisterGetAttribute(ic, "EXPAND", &_get, &_set, NULL, NULL, NULL);
+ iupClassRegisterAttribute(ic, "EXPAND", _get, _set, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ }
+
+ /* Visual */
+ iupBaseRegisterVisualAttrib(ic);
+
+ /* IupCanvas only */
+ iupClassRegisterAttribute(ic, "CURSOR", NULL, iupdrvBaseSetCursorAttrib, IUPAF_SAMEASSYSTEM, "ARROW", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "XMIN", NULL, NULL, IUPAF_SAMEASSYSTEM, "0.0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "XMAX", NULL, NULL, IUPAF_SAMEASSYSTEM, "1.0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "YMIN", NULL, NULL, IUPAF_SAMEASSYSTEM, "0.0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "YMAX", NULL, NULL, IUPAF_SAMEASSYSTEM, "1.0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "LINEX", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "LINEY", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "BORDER", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "SCROLLBAR", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ iupdrvCanvasInitClass(ic);
+
+ return ic;
+}
diff --git a/iup/src/iup_canvas.h b/iup/src/iup_canvas.h
new file mode 100755
index 0000000..29d644c
--- /dev/null
+++ b/iup/src/iup_canvas.h
@@ -0,0 +1,37 @@
+/** \file
+ * \brief Canvas Controls Private Declarations
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_CANVAS_H
+#define __IUP_CANVAS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void iupdrvCanvasInitClass(Iclass* ic);
+void iupCanvasCalcScrollIntPos(double min, double max, double page, double pos,
+ int imin, int imax, int *ipage, int *ipos);
+void iupCanvasCalcScrollRealPos(double min, double max, double *pos,
+ int imin, int imax, int ipage, int *ipos);
+char* iupCanvasGetPosXAttrib(Ihandle* ih);
+char* iupCanvasGetPosYAttrib(Ihandle* ih);
+
+#define IUP_SB_MIN 0
+#define IUP_SB_MAX INT_MAX-1
+
+struct _IcontrolData
+{
+ int sb; /* scrollbar configuration, valid only after map, use iupBaseGetScrollbar before map */
+ float posx, posy;
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_cbox.c b/iup/src/iup_cbox.c
new file mode 100755
index 0000000..5a1d409
--- /dev/null
+++ b/iup/src/iup_cbox.c
@@ -0,0 +1,143 @@
+/** \file
+ * \brief cbox control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+
+
+static int iCboxCreateMethod(Ihandle* ih, void** params)
+{
+ if (params)
+ {
+ Ihandle** iparams = (Ihandle**)params;
+ while (*iparams)
+ {
+ IupAppend(ih, *iparams);
+ iparams++;
+ }
+ }
+
+ return IUP_NOERROR;
+}
+
+static void iCboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ Ihandle* child;
+ int children_expand,
+ children_naturalwidth, children_naturalheight;
+ int cx, cy;
+
+ /* calculate total children natural size (even for hidden children) */
+ children_expand = 0;
+ children_naturalwidth = 0;
+ children_naturalheight = 0;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ /* update child natural size first */
+ iupBaseComputeNaturalSize(child);
+
+ cx = iupAttribGetInt(child, "CX");
+ cy = iupAttribGetInt(child, "CY");
+
+ children_expand |= child->expand;
+ children_naturalwidth = iupMAX(children_naturalwidth, cx+child->naturalwidth);
+ children_naturalheight = iupMAX(children_naturalheight, cy+child->naturalheight);
+ }
+
+ *expand = children_expand;
+ *w = children_naturalwidth;
+ *h = children_naturalheight;
+}
+
+static void iCboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink)
+{
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ /* update children to their own natural size */
+ iupBaseSetCurrentSize(child, child->naturalwidth, child->naturalheight, shrink);
+ }
+}
+
+static void iCboxSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ int cx, cy;
+ Ihandle* child;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ cx = iupAttribGetInt(child, "CX");
+ cy = iupAttribGetInt(child, "CY");
+
+ /* update child */
+ iupBaseSetPosition(child, x+cx, y+cy);
+ }
+}
+
+
+/******************************************************************************/
+
+
+Ihandle *IupCboxv(Ihandle** children)
+{
+ return IupCreatev("cbox", (void**)children);
+}
+
+Ihandle *IupCbox (Ihandle * child,...)
+{
+ Ihandle **children;
+ Ihandle *ih;
+
+ va_list arglist;
+ va_start(arglist, child);
+ children = (Ihandle **)iupObjectGetParamList(child, arglist);
+ va_end(arglist);
+
+ ih = IupCreatev("cbox", (void**)children);
+ free(children);
+
+ return ih;
+}
+
+Iclass* iupCboxGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "cbox";
+ ic->format = "g"; /* array of Ihandle */
+ ic->nativetype = IUP_TYPEVOID;
+ ic->childtype = IUP_CHILDMANY;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = iCboxCreateMethod;
+ ic->Map = iupBaseTypeVoidMapMethod;
+
+ ic->ComputeNaturalSize = iCboxComputeNaturalSizeMethod;
+ ic->SetChildrenCurrentSize = iCboxSetChildrenCurrentSizeMethod;
+ ic->SetChildrenPosition = iCboxSetChildrenPositionMethod;
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", iupBaseGetRasterSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
diff --git a/iup/src/iup_childtree.c b/iup/src/iup_childtree.c
new file mode 100755
index 0000000..1d4066e
--- /dev/null
+++ b/iup/src/iup_childtree.c
@@ -0,0 +1,455 @@
+/** \file
+ * \brief Control tree hierarchy manager.
+ * implements also IupDestroy
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_dlglist.h"
+#include "iup_childtree.h"
+#include "iup_class.h"
+#include "iup_attrib.h"
+#include "iup_assert.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+
+
+Ihandle* IupGetDialog(Ihandle* ih)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ for (ih = ih; ih->parent; ih = ih->parent)
+ ; /* empty*/
+
+ if (ih->iclass->nativetype == IUP_TYPEDIALOG)
+ return ih;
+ else if (ih->iclass->nativetype == IUP_TYPEMENU)
+ {
+ Ihandle *dlg;
+ /* if ih is a menu then */
+ /* searches all the dialogs that may have been associated with the menu. */
+ for (dlg = iupDlgListFirst(); dlg; dlg = iupDlgListNext())
+ {
+ if (IupGetAttributeHandle(dlg, "MENU") == ih)
+ return dlg;
+ }
+ }
+
+ return NULL;
+}
+
+static void iChildDetach(Ihandle* parent, Ihandle* child)
+{
+ Ihandle *c,
+ *c_prev = NULL;
+
+ /* Cleans the child entry inside the parent's child list */
+ for (c = parent->firstchild; c; c = c->brother)
+ {
+ if (c == child) /* Found the right child */
+ {
+ if (c_prev == NULL)
+ parent->firstchild = child->brother;
+ else
+ c_prev->brother = child->brother;
+
+ child->brother = NULL;
+ child->parent = NULL;
+ return;
+ }
+
+ c_prev = c;
+ }
+}
+
+void IupDetach(Ihandle *child)
+{
+ Ihandle *parent, *top_parent;
+
+ iupASSERT(iupObjectCheck(child));
+ if (!iupObjectCheck(child))
+ return;
+
+ IupUnmap(child);
+
+ /* Not valid if does NOT has a parent */
+ if (!child->parent)
+ return;
+
+ parent = child->parent;
+ top_parent = iupChildTreeGetNativeParent(child);
+
+ iChildDetach(parent, child);
+ iupClassObjectChildRemoved(parent, child);
+
+ while (parent && parent != top_parent)
+ {
+ parent = parent->parent;
+ if (parent)
+ iupClassObjectChildRemoved(parent, child);
+ }
+}
+
+static int iChildFindRec(Ihandle* parent, Ihandle* child)
+{
+ Ihandle *c;
+
+ /* Finds the reference child entry inside the parent's child list */
+ for (c = parent->firstchild; c; c = c->brother)
+ {
+ if (c == child) /* Found the right child */
+ return 1;
+
+ if (iChildFindRec(c, child))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int iChildTreeCheckInside(Ihandle* parent, Ihandle* child)
+{
+ /* top parent */
+ while (parent->parent)
+ parent = parent->parent;
+
+ return iChildFindRec(parent, child);
+}
+
+static int iChildFind(Ihandle* parent, Ihandle* child)
+{
+ Ihandle *c;
+
+ /* Finds the reference child entry inside the parent's child list */
+ for (c = parent->firstchild; c; c = c->brother)
+ {
+ if (c == child) /* Found the right child */
+ return 1;
+ }
+
+ return 0;
+}
+
+static void iChildInsert(Ihandle* parent, Ihandle* ref_child, Ihandle* child)
+{
+ Ihandle *c,
+ *c_prev = NULL;
+
+ if (!ref_child)
+ ref_child = parent->firstchild;
+
+ /* Finds the reference child entry inside the parent's child list */
+ for (c = parent->firstchild; c; c = c->brother)
+ {
+ if (c == ref_child) /* Found the right child */
+ {
+ child->parent = parent;
+ child->brother = ref_child;
+
+ if (c_prev == NULL)
+ parent->firstchild = child;
+ else
+ c_prev->brother = child;
+ return;
+ }
+
+ c_prev = c;
+ }
+}
+
+Ihandle* IupInsert(Ihandle* parent, Ihandle* ref_child, Ihandle* child)
+{
+ Ihandle* top_parent = parent;
+
+ /* ref_child can be NULL */
+
+ iupASSERT(iupObjectCheck(parent));
+ if (!iupObjectCheck(parent))
+ return NULL;
+
+ iupASSERT(iupObjectCheck(child));
+ if (!iupObjectCheck(child))
+ return NULL;
+
+#ifdef IUP_ASSERT
+ if (iChildTreeCheckInside(parent, child))
+ {
+ iupError("Duplicate Child Found!\n(type(%s) - name(%s))", child->iclass->name, IupGetName(child));
+ return NULL;
+ }
+#endif
+
+
+ /* this will return the actual parent */
+ parent = iupClassObjectGetInnerContainer(top_parent);
+ if (!parent)
+ return NULL;
+
+ if (parent->iclass->childtype == IUP_CHILDNONE)
+ return NULL;
+ if (parent->iclass->childtype == IUP_CHILD_ONE && parent->firstchild)
+ return NULL;
+
+
+ /* if already at the parent box, allow to move even if mapped */
+ if (parent->iclass->nativetype == IUP_TYPEVOID &&
+ iChildFind(parent, child))
+ {
+ iChildDetach(parent, child);
+ iChildInsert(parent, ref_child, child);
+ }
+ else
+ {
+ /* Not valid if it is mapped */
+ if (child->handle)
+ return NULL;
+
+ iChildInsert(parent, ref_child, child);
+ iupClassObjectChildAdded(parent, child);
+ if (top_parent != parent)
+ iupClassObjectChildAdded(top_parent, child);
+ }
+
+ return parent;
+}
+
+void iupChildTreeAppend(Ihandle* parent, Ihandle* child)
+{
+ child->parent = parent;
+
+ if (parent->firstchild == NULL)
+ parent->firstchild = child;
+ else
+ {
+ Ihandle* c = parent->firstchild;
+ while (c->brother)
+ c = c->brother;
+ c->brother = child;
+ }
+}
+
+Ihandle* IupAppend(Ihandle* parent, Ihandle* child)
+{
+ Ihandle* top_parent = parent;
+
+ iupASSERT(iupObjectCheck(parent));
+ if (!iupObjectCheck(parent))
+ return NULL;
+
+ iupASSERT(iupObjectCheck(child));
+ if (!iupObjectCheck(child))
+ return NULL;
+
+#ifdef IUP_ASSERT
+ if (iChildTreeCheckInside(parent, child))
+ {
+ iupError("Duplicate Child Found!\n(type(%s) - name(%s))", child->iclass->name, IupGetName(child));
+ return NULL;
+ }
+#endif
+
+
+ /* this will return the actual parent */
+ parent = iupClassObjectGetInnerContainer(top_parent);
+ if (!parent)
+ return NULL;
+
+ if (parent->iclass->childtype == IUP_CHILDNONE)
+ return NULL;
+ if (parent->iclass->childtype == IUP_CHILD_ONE && parent->firstchild)
+ return NULL;
+
+
+ /* if already at the parent box, allow to move even if mapped */
+ if (parent->iclass->nativetype == IUP_TYPEVOID &&
+ iChildFind(parent, child))
+ {
+ iChildDetach(parent, child);
+ iupChildTreeAppend(parent, child);
+ }
+ else
+ {
+ /* Not valid if it is mapped */
+ if (child->handle)
+ return NULL;
+
+ iupChildTreeAppend(parent, child);
+ iupClassObjectChildAdded(parent, child);
+ if (top_parent != parent)
+ iupClassObjectChildAdded(top_parent, child);
+ }
+
+ return parent;
+}
+
+static void iChildReparent(Ihandle* child, Ihandle* new_parent)
+{
+ Ihandle *c;
+
+ /* Forward the reparent to all native children */
+
+ for (c = child->firstchild; c; c = c->brother)
+ {
+ if (c->iclass->nativetype != IUP_TYPEVOID)
+ iupdrvReparent(c);
+ else
+ iChildReparent(c, new_parent);
+ }
+}
+
+int IupReparent(Ihandle* child, Ihandle* parent)
+{
+ Ihandle* top_parent = parent;
+ Ihandle* old_parent;
+
+ iupASSERT(iupObjectCheck(parent));
+ if (!iupObjectCheck(parent))
+ return IUP_ERROR;
+
+ iupASSERT(iupObjectCheck(child));
+ if (!iupObjectCheck(child))
+ return IUP_ERROR;
+
+
+ /* this will return the actual parent */
+ parent = iupClassObjectGetInnerContainer(top_parent);
+ if (!parent)
+ return IUP_ERROR;
+
+ if (parent->iclass->childtype == IUP_CHILDNONE)
+ return IUP_ERROR;
+ if (parent->iclass->childtype == IUP_CHILD_ONE && parent->firstchild)
+ return IUP_ERROR;
+
+
+ /* both must be already mapped or both unmapped */
+ if ((!parent->handle && child->handle) ||
+ ( parent->handle && !child->handle))
+ return IUP_ERROR;
+
+
+ /* detach from old parent */
+ old_parent = child->parent;
+ iChildDetach(old_parent, child);
+ iupClassObjectChildRemoved(old_parent, child);
+
+
+ /* attach to new parent */
+ iupChildTreeAppend(parent, child);
+ iupClassObjectChildAdded(parent, child);
+ if (top_parent != parent)
+ iupClassObjectChildAdded(top_parent, child);
+
+
+ /* no need to remap, just notify the native system */
+ if (child->handle && parent->handle)
+ {
+ if (child->iclass->nativetype != IUP_TYPEVOID)
+ iupdrvReparent(child);
+ else
+ iChildReparent(child, parent);
+ }
+
+ return IUP_NOERROR;
+}
+
+Ihandle* IupGetChild(Ihandle* ih, int pos)
+{
+ int p;
+ Ihandle* child;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ for (p = 0, child = ih->firstchild; child; child = child->brother, p++)
+ {
+ if (p == pos)
+ return child;
+ }
+
+ return NULL;
+}
+
+int IupGetChildPos(Ihandle* ih, Ihandle* child)
+{
+ int pos;
+ Ihandle* c;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return -1;
+
+ for (pos = 0, c = ih->firstchild; c; c = c->brother, pos++)
+ {
+ if (c == child)
+ return pos;
+ }
+ return -1;
+}
+
+int IupGetChildCount(Ihandle* ih)
+{
+ int count = 0;
+ Ihandle* child;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return -1;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ count++;
+
+ return count;
+}
+
+Ihandle* IupGetNextChild(Ihandle* ih, Ihandle* child)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ if (!child)
+ return ih->firstchild;
+ else
+ return child->brother;
+}
+
+Ihandle* IupGetBrother(Ihandle* ih)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ return ih->brother;
+}
+
+Ihandle* IupGetParent(Ihandle *ih)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ return ih->parent;
+}
+
+Ihandle* iupChildTreeGetNativeParent(Ihandle* ih)
+{
+ Ihandle* parent = ih->parent;
+ while (parent && parent->iclass->nativetype == IUP_TYPEVOID)
+ parent = parent->parent;
+ return parent;
+}
+
+InativeHandle* iupChildTreeGetNativeParentHandle(Ihandle* ih)
+{
+ Ihandle* native_parent = iupChildTreeGetNativeParent(ih);
+ return (InativeHandle*)iupClassObjectGetInnerNativeContainerHandle(native_parent, ih);
+}
diff --git a/iup/src/iup_childtree.h b/iup/src/iup_childtree.h
new file mode 100755
index 0000000..4376c0b
--- /dev/null
+++ b/iup/src/iup_childtree.h
@@ -0,0 +1,54 @@
+/** \file
+ * \brief Control Hierarchy Tree management.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_CHILDTREE_H
+#define __IUP_CHILDTREE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup childtree Child Tree Utilities
+ * \par
+ * Some native containers have an internal native child that
+ * will be the actual container of the children. This native container is
+ * returned by \ref iupClassObjectGetInnerNativeContainerHandle.
+ * \par
+ * Some native elements need an extra parent, the ih->handle points to the main element itself,
+ * NOT to the extra parent. This extra parent is stored as "_IUP_EXTRAPARENT".
+ * \par
+ * See \ref iup_childtree.h
+ * \ingroup object */
+
+/** Returns the native parent. It simply excludes containers that are from IUP_TYPEVOID classes.
+ * \ingroup childtree */
+Ihandle* iupChildTreeGetNativeParent(Ihandle* ih);
+
+/** Returns the native parent handle. Uses \ref iupChildTreeGetNativeParent and \ref iupClassObjectGetInnerNativeContainerHandle.
+ * \ingroup childtree */
+InativeHandle* iupChildTreeGetNativeParentHandle(Ihandle* ih);
+
+/** Adds the child directly to the parent tree.
+ * \ingroup childtree */
+void iupChildTreeAppend(Ihandle* parent, Ihandle* child);
+
+
+/* Other functions declared in <iup.h> and implemented here.
+IupGetDialog
+IupDetach
+IupAppend
+IupGetChild
+IupGetNextChild
+IupGetBrother
+IupGetParent
+*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_class.c b/iup/src/iup_class.c
new file mode 100755
index 0000000..d2c4b02
--- /dev/null
+++ b/iup/src/iup_class.c
@@ -0,0 +1,314 @@
+/** \file
+ * \brief IUP Ihandle Class C Interface
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_str.h"
+#include "iup_attrib.h"
+#include "iup_assert.h"
+
+
+
+/*****************************************************************
+ Method Stubs
+*****************************************************************/
+
+static int iClassCreate(Iclass* ic, Ihandle* ih, void** params)
+{
+ int ret = IUP_NOERROR;
+ if (ic->parent)
+ ret = iClassCreate(ic->parent, ih, params);
+
+ if (ret == IUP_NOERROR && ic->Create)
+ ret = ic->Create(ih, params);
+
+ return ret;
+}
+
+static int iClassMap(Iclass* ic, Ihandle* ih)
+{
+ int ret = IUP_NOERROR;
+ if (ic->parent)
+ ret = iClassMap(ic->parent, ih);
+
+ if (ret == IUP_NOERROR && ic->Map)
+ ret = ic->Map(ih);
+
+ return ret;
+}
+
+static void iClassUnMap(Iclass* ic, Ihandle* ih)
+{
+ /* must be before the parent class */
+ if (ic->UnMap)
+ ic->UnMap(ih);
+
+ if (ic->parent)
+ iClassUnMap(ic->parent, ih);
+}
+
+static void iClassDestroy(Iclass* ic, Ihandle* ih)
+{
+ /* must destroy child class before the parent class */
+ if (ic->Destroy)
+ ic->Destroy(ih);
+
+ if (ic->parent)
+ iClassDestroy(ic->parent, ih);
+}
+
+static void iClassComputeNaturalSize(Iclass* ic, Ihandle* ih, int *w, int *h, int *expand)
+{
+ if (ic->parent)
+ iClassComputeNaturalSize(ic->parent, ih, w, h, expand);
+
+ if (ic->ComputeNaturalSize)
+ ic->ComputeNaturalSize(ih, w, h, expand);
+}
+
+static void iClassSetChildrenCurrentSize(Iclass* ic, Ihandle* ih, int shrink)
+{
+ if (ic->parent)
+ iClassSetChildrenCurrentSize(ic->parent, ih, shrink);
+
+ if (ic->SetChildrenCurrentSize)
+ ic->SetChildrenCurrentSize(ih, shrink);
+}
+
+static void iClassSetChildrenPosition(Iclass* ic, Ihandle* ih, int x, int y)
+{
+ if (ic->parent)
+ iClassSetChildrenPosition(ic->parent, ih, x, y);
+
+ if (ic->SetChildrenPosition)
+ ic->SetChildrenPosition(ih, x, y);
+}
+
+static Ihandle* iClassGetInnerContainer(Iclass* ic, Ihandle* ih)
+{
+ Ihandle* ih_container = ih;
+
+ if (ic->parent)
+ ih_container = iClassGetInnerContainer(ic->parent, ih);
+
+ /* if the class implements the function it will ignore the result of the parent class */
+
+ if (ic->GetInnerContainer)
+ ih_container = ic->GetInnerContainer(ih);
+
+ return ih_container;
+}
+
+static void* iClassGetInnerNativeContainerHandle(Iclass* ic, Ihandle* ih, Ihandle* child)
+{
+ void* container_handle = ih->handle;
+
+ if (ic->parent)
+ container_handle = iClassGetInnerNativeContainerHandle(ic->parent, ih, child);
+
+ /* if the class implements the function it will ignore the result of the parent class */
+
+ if (ic->GetInnerNativeContainerHandle)
+ container_handle = ic->GetInnerNativeContainerHandle(ih, child);
+
+ return container_handle;
+}
+
+static void iClassObjectChildAdded(Iclass* ic, Ihandle* ih, Ihandle* child)
+{
+ if (ic->parent)
+ iClassObjectChildAdded(ic->parent, ih, child);
+
+ if (ic->ChildAdded)
+ ic->ChildAdded(ih, child);
+}
+
+static void iClassObjectChildRemoved(Iclass* ic, Ihandle* ih, Ihandle* child)
+{
+ if (ic->parent)
+ iClassObjectChildRemoved(ic->parent, ih, child);
+
+ if (ic->ChildRemoved)
+ ic->ChildRemoved(ih, child);
+}
+
+static void iClassLayoutUpdate(Iclass* ic, Ihandle *ih)
+{
+ if (ic->parent)
+ iClassLayoutUpdate(ic->parent, ih);
+
+ if (ic->LayoutUpdate)
+ ic->LayoutUpdate(ih);
+}
+
+static int iClassDlgPopup(Iclass* ic, Ihandle* ih, int x, int y)
+{
+ int ret = IUP_INVALID; /* IUP_INVALID means it is not implemented */
+ if (ic->parent)
+ ret = iClassDlgPopup(ic->parent, ih, x, y);
+
+ if (ret != IUP_ERROR && ic->DlgPopup)
+ ret = ic->DlgPopup(ih, x, y);
+
+ return ret;
+}
+
+int iupClassObjectCreate(Ihandle* ih, void** params)
+{
+ return iClassCreate(ih->iclass, ih, params);
+}
+
+int iupClassObjectMap(Ihandle* ih)
+{
+ return iClassMap(ih->iclass, ih);
+}
+
+void iupClassObjectUnMap(Ihandle* ih)
+{
+ iClassUnMap(ih->iclass, ih);
+}
+
+void iupClassObjectDestroy(Ihandle* ih)
+{
+ iClassDestroy(ih->iclass, ih);
+}
+
+void iupClassObjectComputeNaturalSize(Ihandle* ih, int *w, int *h, int *expand)
+{
+ iClassComputeNaturalSize(ih->iclass, ih, w, h, expand);
+}
+
+void iupClassObjectSetChildrenCurrentSize(Ihandle* ih, int shrink)
+{
+ iClassSetChildrenCurrentSize(ih->iclass, ih, shrink);
+}
+
+void iupClassObjectSetChildrenPosition(Ihandle* ih, int x, int y)
+{
+ iClassSetChildrenPosition(ih->iclass, ih, x, y);
+}
+
+Ihandle* iupClassObjectGetInnerContainer(Ihandle* ih)
+{
+ return iClassGetInnerContainer(ih->iclass, ih);
+}
+
+void* iupClassObjectGetInnerNativeContainerHandle(Ihandle* ih, Ihandle* child)
+{
+ return iClassGetInnerNativeContainerHandle(ih->iclass, ih, child);
+}
+
+void iupClassObjectChildAdded(Ihandle* ih, Ihandle* child)
+{
+ iClassObjectChildAdded(ih->iclass, ih, child);
+}
+
+void iupClassObjectChildRemoved(Ihandle* ih, Ihandle* child)
+{
+ iClassObjectChildRemoved(ih->iclass, ih, child);
+}
+
+void iupClassObjectLayoutUpdate(Ihandle *ih)
+{
+ iClassLayoutUpdate(ih->iclass, ih);
+}
+
+int iupClassObjectDlgPopup(Ihandle* ih, int x, int y)
+{
+ return iClassDlgPopup(ih->iclass, ih, x, y);
+}
+
+
+/*****************************************************************
+ Class Definition
+*****************************************************************/
+
+
+static void iClassReleaseAttribFuncTable(Iclass* ic)
+{
+ char* name = iupTableFirst(ic->attrib_func);
+ while (name)
+ {
+ void* afunc = iupTableGetCurr(ic->attrib_func);
+ free(afunc);
+
+ name = iupTableNext(ic->attrib_func);
+ }
+
+ iupTableDestroy(ic->attrib_func);
+}
+
+Iclass* iupClassNew(Iclass* parent)
+{
+ Iclass* ic = malloc(sizeof(Iclass));
+ memset(ic, 0, sizeof(Iclass));
+
+ if (parent)
+ ic->attrib_func = parent->attrib_func;
+ else
+ ic->attrib_func = iupTableCreate(IUPTABLE_STRINGINDEXED);
+
+ ic->parent = parent;
+
+ return ic;
+}
+
+void iupClassRelease(Iclass* ic)
+{
+ Iclass* parent;
+
+ /* must release only the actual class */
+ if (ic->Release)
+ ic->Release(ic);
+
+ /* must free all classes, since a new instance is created when we inherit */
+ parent = ic->parent;
+ while (parent)
+ {
+ Iclass* tmp = parent;
+ parent = parent->parent;
+ free(tmp);
+ }
+
+ /* attributes functions table is released only once */
+ iClassReleaseAttribFuncTable(ic);
+
+ free(ic);
+}
+
+
+/*****************************************************************
+ Main API
+*****************************************************************/
+
+
+char* IupGetClassName(Ihandle *ih)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ return ih->iclass->name;
+}
+
+char* IupGetClassType(Ihandle *ih)
+{
+ static char* type2str[] = {"void", "control", "canvas", "dialog", "image", "menu"};
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ return type2str[ih->iclass->nativetype];
+}
+
diff --git a/iup/src/iup_class.h b/iup/src/iup_class.h
new file mode 100755
index 0000000..a5318f3
--- /dev/null
+++ b/iup/src/iup_class.h
@@ -0,0 +1,414 @@
+/** \file
+ * \brief Ihandle Class Interface
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_CLASS_H
+#define __IUP_CLASS_H
+
+#include "iup_table.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup iclass Ihandle Class
+ * \par
+ * See \ref iup_class.h
+ * \ingroup cpi */
+
+/** Known native types.
+ * \ingroup iclass */
+typedef enum _InativeType {
+ IUP_TYPEVOID, /**< No native representation - HBOX, VBOX, ZBOX, FILL, RADIO (handle==(void*)-1 always) */
+ IUP_TYPECONTROL, /**< Native controls - BUTTON, LABEL, TOGGLE, LIST, TEXT, MULTILINE, FRAME, others */
+ IUP_TYPECANVAS, /**< Drawing canvas, also used as a base control for custom controls. */
+ IUP_TYPEDIALOG, /**< DIALOG */
+ IUP_TYPEIMAGE, /**< IMAGE */
+ IUP_TYPEMENU /**< MENU, SUBMENU, ITEM, SEPARATOR */
+} InativeType;
+
+/** Possible number of children.
+ * \ingroup iclass */
+typedef enum _IchildType {
+ IUP_CHILDNONE,
+ IUP_CHILD_ONE,
+ IUP_CHILDMANY
+} IchildType;
+
+typedef struct Iclass_ Iclass;
+
+/** Ihandle Class Structure
+ * \ingroup iclass */
+struct Iclass_
+{
+ /* Class configuration parameters. */
+ char* name; /**< class name. No default, must be initialized. */
+ char* format; /**< Creation parameters format of the class when specified. \n
+ * It can have none, one or more of the following.
+ * - "b" = (unsigned char) - byte
+ * - "c" = (unsigned char*) - array of byte
+ * - "i" = (int) - integer
+ * - "j" = (int*) - array of integer
+ * - "f" = (float) - real
+ * - "s" = (char*) - string
+ * - "a" = (char*) - name of an action
+ * - "h" = (Ihandle*) - element handle
+ * - "g" = (Ihandle**) - array of element handle
+ * If upper case then it is optional. Default is no parameters. */
+ InativeType nativetype; /**< native type. Default is IUP_TYPEVOID. */
+ IchildType childtype; /**< children count enum: none, one, or many. Default is IUP_CHILDNONE. Used only by IupAppend and IupInsert to control the number of children. */
+ int is_interactive; /**< keyboard interactive boolean,
+ * true if the class can have the keyboard input focus. Default is false. */
+ int has_attrib_id; /**< boolean to indicate if any attribute is numbered. Default is false. */
+
+ Iclass* parent; /**< class parent to implement inheritance.
+ * Class name must be different.
+ * Creation parameters should be the same or repace the parents creation function.
+ * Native type should be the same.
+ * Child type should be a more restrictive or equal type (many->one->none).
+ * Attribute functions will have only one common table.
+ * All methods can be changed, set to NULL, switched, etc. */
+
+ Itable* attrib_func; /**< table of functions to handle attributes, only one per class tree */
+
+ /* Class methods. */
+
+ /** Method that release the memory allocated by the class.
+ * Called only once at \ref iupClassRelease.
+ */
+ void (*Release)(Iclass* ic);
+
+
+
+ /** Method that creates the element and process the creation parameters. \n
+ * Called only from IupCreate. \n
+ * The parameters can be NULL for all the controls. \n
+ * The control should also depend on attributes set before IupMap. \n
+ * Must return IUP_NOERROR or IUP_ERROR. \n
+ * Can be NULL, like all methods.
+ */
+ int (*Create)(Ihandle* ih, void** params);
+
+ /** Method that map (create) the control to the native system. \n
+ * Called only from IupMap. \n
+ * Must return IUP_NOERROR or IUP_ERROR.
+ */
+ int (*Map)(Ihandle* ih);
+
+ /** Method that unmap (destroy) the control from the native system. \n
+ * Called only from IupUnmap if the control is mapped. \n
+ * Must return IUP_NOERROR or IUP_ERROR.
+ */
+ void (*UnMap)(Ihandle* ih);
+
+ /** Method that destroys the element. \n
+ * Called only from IupDestroy. Always called even if the control is not mapped.
+ */
+ void (*Destroy)(Ihandle* ih);
+
+
+
+ /** Returns the actual parent to add a child. The default implementation returns itself. \n
+ * Called only from IupAppend or IupReparent. \n
+ * This allows IUP elements to be a combination of other IUP elements in a single IUP element.
+ */
+ Ihandle* (*GetInnerContainer)(Ihandle* ih);
+
+ /** Returns the internal native parent. The default implementation returns the handle of itself. \n
+ * Called from \ref iupChildTreeGetNativeParentHandle. \n
+ * This allows native elements to have an internal container
+ * that will be the actual native parent, or in other words allows native elements to be a combination of
+ * other native elements in a single IUP element. The actual native parent may depend on the child tree (IupTabs).
+ */
+ void* (*GetInnerNativeContainerHandle)(Ihandle* ih, Ihandle* child);
+
+ /** Notifies the element that a child was appended using IupAppend. \n
+ * Called only from IupAppend or IupReparent. The child is not mapped, but the parent can be mapped.
+ */
+ void (*ChildAdded)(Ihandle* ih, Ihandle* child);
+
+ /** Notifies the element that a child was removed using IupDetach. \n
+ * Called only from IupDetach or IupReparent. The child is not mapped, but the parent can be mapped.
+ */
+ void (*ChildRemoved)(Ihandle* ih, Ihandle* child);
+
+
+ /** Method that update size and position of the native control. \n
+ * Called only from iupLayoutUpdate and if the element is mapped.
+ */
+ void (*LayoutUpdate)(Ihandle* ih);
+
+
+
+ /** Method that computes the natural size based on the user size and the actual natural size. \n
+ * Should update expand if a container, but does NOT depends on expand to compute the natural size. \n
+ * Must call the \ref iupBaseComputeNaturalSize for each children.
+ * First calculate the native size for the children, then for the element. \n
+ * Also called before the element is mapped, so it must be independent of the native control.
+ * First call done at iupLayoutCompute for the dialog.
+ */
+ void (*ComputeNaturalSize)(Ihandle* ih, int *w, int *h, int *children_expand);
+
+ /** Method that calculates and updates the current size of children based on the available size,
+ * the natural size and the expand configuration. \n
+ * Called only if there is any children.\n
+ * Must call \ref iupBaseSetCurrentSize for each children.
+ * shrink is the dialog attribute passed here for optimization. \n
+ * Also called before the element is mapped, so it must be independent of the native control.
+ * First call done at iupLayoutCompute for the dialog.
+ */
+ void (*SetChildrenCurrentSize)(Ihandle* ih, int shrink);
+
+ /** Method that calculates and updates the position relative to the parent. \n
+ * Called only if there is any children.\n
+ * Must call \ref iupBaseSetPosition for each children.
+ * Also called before the element is mapped, so it must be independent of the native control.
+ * First call done at iupLayoutCompute for the dialog.
+ */
+ void (*SetChildrenPosition)(Ihandle* ih, int x, int y);
+
+
+
+ /** Method that shows a popup dialog. Called only for native pre-defined dialogs. \n
+ * The element is not mapped. \n
+ * Must return IUP_ERROR or IUP_NOERROR. \n
+ * Called only from iupDialogPopup.
+ */
+ int (*DlgPopup)(Ihandle* ih, int x, int y);
+};
+
+
+
+/** Allocates memory for the Iclass structure and
+ * initializes the attribute handling functions table.
+ * \ingroup iclass */
+Iclass* iupClassNew(Iclass* ic_parent);
+
+/** Release the memory allocated by the class.
+ * Calls the \ref Iclass::Release method. \n
+ * Called from iupRegisterFinish.
+ * \ingroup iclass */
+void iupClassRelease(Iclass* ic);
+
+
+
+/** GetAttribute called for a specific attribute.
+ * Used by \ref iupClassRegisterAttribute.
+ * \ingroup iclass */
+typedef char* (*IattribGetFunc)(Ihandle* ih);
+
+/** GetAttribute called for a specific attribute when has_attrib_id is true. \n
+ * Same as IattribGetFunc but handle attribute names with number ids at the end. \n
+ * When calling iupClassRegisterAttribute just use a typecast. \n
+ * Pure numbers are translated into IDVALUEid.
+ * Used by \ref iupClassRegisterAttribute.
+ * \ingroup iclass */
+typedef char* (*IattribGetIdFunc)(Ihandle* ih, const char* name_id);
+
+/** SetAttribute called for a specific attribute. \n
+ * If returns 0, the attribute will not be stored in the hash table
+ * (except inheritble attributes that are always stored in the hash table). \n
+ * When IupSetAttribute is called using value=NULL, the default_value is passed to this function.
+ * Used by \ref iupClassRegisterAttribute.
+ * \ingroup iclass */
+typedef int (*IattribSetFunc)(Ihandle* ih, const char* value);
+
+/** SetAttribute called for a specific attribute when has_attrib_id is true. \n
+ * Same as IattribSetFunc but handle attribute names with number ids at the end. \n
+ * When calling iupClassRegisterAttribute just use a typecast. \n
+ * Pure numbers are translated into IDVALUEid, ex: "1" = "IDVALUE1".
+ * Used by \ref iupClassRegisterAttribute.
+ * \ingroup iclass */
+typedef int (*IattribSetIdFunc)(Ihandle* ih, const char* name_id, const char* value);
+
+/** Attribute flags.
+ * Used by \ref iupClassRegisterAttribute.
+ * \ingroup iclass */
+typedef enum _IattribFlags{
+ IUPAF_DEFAULT=0, /**< inheritable, can has a default value, is a string, can call the set/get functions only if mapped, no ID */
+ IUPAF_NO_INHERIT=1, /**< is not inheritable */
+ IUPAF_NO_DEFAULTVALUE=2, /**< can not has a default value */
+ IUPAF_NO_STRING=4, /**< is not a string */
+ IUPAF_NOT_MAPPED=8, /**< will call the set/get functions also when not mapped */
+ IUPAF_HAS_ID=16, /**< can has an ID at the end of the name, automatically set by \ref iupClassRegisterAttributeId */
+ IUPAF_READONLY=32, /**< is read-only, can not be changed */
+ IUPAF_WRITEONLY=64 /**< is write-only, usually an action */
+} IattribFlags;
+
+#define IUPAF_SAMEASSYSTEM ((char*)-1) /**< means that the default value is the same as the system default value, used only in \ref iupClassRegisterAttribute */
+
+
+/** Register attribute handling functions. get, set and default_value can be NULL.
+ * default_value should point to a constant string, it will not be duplicated internally. \n
+ * Notice that when an attribute is not defined then default_value=NULL,
+ * is inheritable can has a default value and is a string. \n
+ * Since there is only one attribute function table per class tree,
+ * if you register the same attribute in a child class, then it will replace the parent registration. \n
+ * If an attribute is not inheritable or not a string then it MUST be registered.
+ * Internal attributes (starting with "_IUP") can never be registered.
+ * \ingroup iclass */
+void iupClassRegisterAttribute(Iclass* ic, const char* name,
+ IattribGetFunc get,
+ IattribSetFunc set,
+ const char* default_value,
+ const char* system_default,
+ int flags);
+
+/** Same as \ref iupClassRegisterAttribute for attributes with Ids.
+ * \ingroup iclass */
+void iupClassRegisterAttributeId(Iclass* ic, const char* name,
+ IattribGetIdFunc get,
+ IattribSetIdFunc set,
+ int flags);
+
+/** Returns the attribute handling functions.
+ * \ingroup iclass */
+void iupClassRegisterGetAttribute(Iclass* ic, const char* name,
+ IattribGetFunc *get,
+ IattribSetFunc *set,
+ const char* *default_value,
+ const char* *system_default,
+ int *flags);
+
+/** Register the parameters of a callback.
+ * Used by language bindings.
+ * format follows the format specification of the class creation parameters format,
+ * but it adds the "double" option and remove array options.
+ * It can have none, one or more of the following. \n
+ * - "b" = (unsigned char) - byte
+ * - "i" = (int) - integer
+ * - "f" = (float) - real
+ * - "d" = (double) - real
+ * - "s" = (char*) - string
+ * - "v" = (void*) - generic pointer
+ * - "h" = (Ihandle*) - element handle
+ * The default return value for all callbacks is "i" (int).
+ * But the return value can be specified using one of the above parameters,
+ * after all parameters using "=" to separate it from them.
+ * \ingroup iclass */
+void iupClassRegisterCallback(Iclass* ic, const char* name, const char* format);
+
+/** Returns the format of the parameters of a registered callback.
+ * If NULL then the default callback definition is assumed.
+ * \ingroup iclass */
+char* iupClassCallbackGetFormat(Iclass* ic, const char* name);
+
+
+
+/** \defgroup iclassobject Class Object Functions
+ * \par
+ * Stubs for the class methods. They implement inheritance and check if method is NULL.
+ * \par
+ * See \ref iup_class.h
+ * \ingroup iclass
+ */
+
+/** Calls \ref Iclass::Create method.
+ * \ingroup iclassobject
+ */
+int iupClassObjectCreate(Ihandle* ih, void** params);
+
+/** Calls \ref Iclass::Map method.
+ * \ingroup iclassobject
+ */
+int iupClassObjectMap(Ihandle* ih);
+
+/** Calls \ref Iclass::UnMap method.
+ * \ingroup iclassobject
+ */
+void iupClassObjectUnMap(Ihandle* ih);
+
+/** Calls \ref Iclass::Destroy method.
+ * \ingroup iclassobject
+ */
+void iupClassObjectDestroy(Ihandle* ih);
+
+/** Calls \ref Iclass::GetInnerContainer method.
+ * The parent class is ignored. If necessary the child class must handle the parent class internally.
+ * \ingroup iclassobject
+ */
+Ihandle* iupClassObjectGetInnerContainer(Ihandle* ih);
+
+/** Calls \ref Iclass::GetInnerNativeContainerHandle method. Returns ih->handle if there is no inner parent.
+ * The parent class is ignored. If necessary the child class must handle the parent class internally.
+ * \ingroup iclassobject
+ */
+void* iupClassObjectGetInnerNativeContainerHandle(Ihandle* ih, Ihandle* child);
+
+/** Calls \ref Iclass::ChildAdded method.
+ * \ingroup iclassobject
+ */
+void iupClassObjectChildAdded(Ihandle* ih, Ihandle* child);
+
+/** Calls \ref Iclass::ChildRemoved method.
+ * \ingroup iclassobject
+ */
+void iupClassObjectChildRemoved(Ihandle* ih, Ihandle* child);
+
+/** Calls \ref Iclass::LayoutUpdate method.
+ * \ingroup iclassobject
+ */
+void iupClassObjectLayoutUpdate(Ihandle* ih);
+
+/** Calls \ref Iclass::ComputeNaturalSize method.
+ * \ingroup iclassobject
+ */
+void iupClassObjectComputeNaturalSize(Ihandle* ih, int *w, int *h, int *children_expand);
+
+/** Calls \ref Iclass::SetChildrenCurrentSize method.
+ * \ingroup iclassobject
+ */
+void iupClassObjectSetChildrenCurrentSize(Ihandle* ih, int shrink);
+
+/** Calls \ref Iclass::SetChildrenPosition method.
+ * \ingroup iclassobject
+ */
+void iupClassObjectSetChildrenPosition(Ihandle* ih, int x, int y);
+
+/** Calls \ref Iclass::DlgPopup method.
+ * \ingroup iclassobject
+ */
+int iupClassObjectDlgPopup(Ihandle* ih, int x, int y);
+
+
+
+/* Handle attributes, but since the attribute function table is shared by the class hierarchy,
+ * the attribute function is retrieved only from the current class.
+ * Set is called from iupAttribUpdate (IupMap), IupStoreAttribute and IupSetAttribute.
+ * Get is called only from IupGetAttribute.
+ */
+int iupClassObjectSetAttribute(Ihandle* ih, const char* name, const char* value, int *inherit);
+char* iupClassObjectGetAttribute(Ihandle* ih, const char* name, char* *def_value, int *inherit);
+
+/* Used only in iupAttribGetStr */
+void iupClassObjectGetAttributeInfo(Ihandle* ih, const char* name, char* *def_value, int *inherit);
+
+/* Used only in iupAttribIsPointer */
+int iupClassObjectAttribIsNotString(Ihandle* ih, const char* name);
+
+/* Used only in iupAttribUpdateFromParent */
+int iupClassObjectCurAttribIsInherit(Iclass* ic);
+
+/* Used in iupObjectCreate and IupMap */
+void iupClassObjectEnsureDefaultAttributes(Ihandle* ih);
+
+/* Used in documentation tests. */
+char* iupClassGetDefaultAttribute(const char* classname, const char *attrib_name);
+
+
+/* Other functions declared in <iup.h> and implemented here.
+IupGetClassType
+IupGetClassName
+*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "iup_classbase.h"
+
+#endif
diff --git a/iup/src/iup_classattrib.c b/iup/src/iup_classattrib.c
new file mode 100755
index 0000000..df8f873
--- /dev/null
+++ b/iup/src/iup_classattrib.c
@@ -0,0 +1,508 @@
+/** \file
+ * \brief Ihandle Class Attribute Management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_str.h"
+#include "iup_attrib.h"
+#include "iup_assert.h"
+#include "iup_register.h"
+#include "iup_globalattrib.h"
+
+
+typedef struct _IattribFunc
+{
+ IattribGetFunc get;
+ IattribSetFunc set;
+ const char* default_value;
+ const char* system_default;
+ int call_global_default;
+ int flags;
+} IattribFunc;
+
+
+static int iClassIsGlobalDefault(const char* name)
+{
+ if (iupStrEqual(name, "DEFAULTFONT"))
+ return 1;
+ if (iupStrEqual(name, "DLGBGCOLOR"))
+ return 1;
+ if (iupStrEqual(name, "DLGFGCOLOR"))
+ return 1;
+ if (iupStrEqual(name, "TXTBGCOLOR"))
+ return 1;
+ if (iupStrEqual(name, "TXTFGCOLOR"))
+ return 1;
+ if (iupStrEqual(name, "MENUBGCOLOR"))
+ return 1;
+ return 0;
+}
+
+static const char* iClassFindId(const char* name)
+{
+ while(*name)
+ {
+ if (*name >= '0' && *name <= '9')
+ return name;
+ if (*name == '*' || *name == ':')
+ return name;
+
+ name++;
+ }
+ return NULL;
+}
+
+static const char* iClassCutNameId(const char* name, const char* name_id)
+{
+ char* str;
+ int len = name_id - name;
+ if (len == 0)
+ return NULL;
+
+ str = iupStrGetMemory(len+1);
+ memcpy(str, name, len);
+ str[len] = 0;
+ return str;
+}
+
+
+static char* iClassGetDefaultValue(IattribFunc* afunc)
+{
+ if (afunc->call_global_default)
+ return IupGetGlobal(afunc->default_value);
+ else
+ return (char*)afunc->default_value;
+}
+
+int iupClassObjectSetAttribute(Ihandle* ih, const char* name, const char * value, int *inherit)
+{
+ IattribFunc* afunc;
+
+ if (ih->iclass->has_attrib_id)
+ {
+ 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,
+ translate them into IDVALUE. */
+ afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, partial_name);
+ if (afunc)
+ {
+ *inherit = 0; /* id numbered attributes are NON inheritable always */
+
+ if (afunc->flags & IUPAF_READONLY)
+ {
+ if (afunc->flags & IUPAF_NO_STRING)
+ return -1; /* value is NOT a string, can NOT call iupAttribStoreStr */
+ return 0;
+ }
+
+ if (afunc->set && (ih->handle || afunc->flags & IUPAF_NOT_MAPPED))
+ {
+ /* id numbered attributes have default value NULL always */
+ IattribSetIdFunc id_set = (IattribSetIdFunc)afunc->set;
+ return id_set(ih, name_id, value);
+ }
+
+ if (afunc->flags & IUPAF_NO_STRING)
+ return -1; /* value is NOT a string, can NOT call iupAttribStoreStr */
+
+ return 1; /* if the function exists, then must return here */
+ }
+ }
+ }
+
+ /* if not has_attrib_id, or not found an ID, or not found the partial name, check using the full name */
+
+ afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, name);
+ *inherit = 1; /* default is inheritable */
+ if (afunc)
+ {
+ *inherit = !(afunc->flags & IUPAF_NO_INHERIT) && !(afunc->flags & IUPAF_NO_STRING);
+
+ if (afunc->flags & IUPAF_READONLY)
+ {
+ if (afunc->flags & IUPAF_NO_STRING)
+ return -1; /* value is NOT a string, can NOT call iupAttribStoreStr */
+ return 0;
+ }
+
+ if (afunc->set && (ih->handle || afunc->flags & IUPAF_NOT_MAPPED))
+ {
+ int ret;
+ if (!value)
+ {
+ /* inheritable attributes when reset must check the parent value */
+ if (*inherit && ih->parent)
+ value = iupAttribGetInherit(ih->parent, name);
+
+ if (!value)
+ value = iClassGetDefaultValue(afunc);
+ }
+
+ if (afunc->flags & IUPAF_HAS_ID)
+ {
+ IattribSetIdFunc id_set = (IattribSetIdFunc)afunc->set;
+ return id_set(ih, "", value); /* empty Id */
+ }
+ else
+ ret = afunc->set(ih, value);
+
+ if (ret == 1 && afunc->flags & IUPAF_NO_STRING)
+ return -1; /* value is NOT a string, can NOT call iupAttribStoreStr */
+
+ if (*inherit)
+ return 1; /* inheritable attributes are always stored in the hash table, */
+ else /* to indicate that they are set at the control. */
+ return ret;
+ }
+ }
+
+ return 1;
+}
+
+char* iupClassObjectGetAttribute(Ihandle* ih, const char* name, char* *def_value, int *inherit)
+{
+ IattribFunc* afunc;
+
+ if (ih->iclass->has_attrib_id)
+ {
+ 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,
+ translate them into IDVALUE. */
+ afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, partial_name);
+ if (afunc)
+ {
+ *def_value = NULL; /* id numbered attributes have default value NULL always */
+ *inherit = 0; /* id numbered attributes are NON inheritable always */
+
+ if (afunc->flags & IUPAF_WRITEONLY)
+ return NULL;
+
+ if (afunc->get && (ih->handle || afunc->flags & IUPAF_NOT_MAPPED))
+ {
+ IattribGetIdFunc id_get = (IattribGetIdFunc)afunc->get;
+ return id_get(ih, name_id);
+ }
+ else
+ return NULL; /* if the function exists, then must return here */
+ }
+ }
+ }
+
+ /* if not has_attrib_id, or not found an ID, or not found the partial name, check using the full name */
+
+ afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, name);
+ *def_value = NULL;
+ *inherit = 1; /* default is inheritable */
+ if (afunc)
+ {
+ *def_value = iClassGetDefaultValue(afunc);
+ *inherit = !(afunc->flags & IUPAF_NO_INHERIT) && !(afunc->flags & IUPAF_NO_STRING);
+
+ if (afunc->flags & IUPAF_WRITEONLY)
+ return NULL;
+
+ if (afunc->get && (ih->handle || afunc->flags & IUPAF_NOT_MAPPED))
+ {
+ if (afunc->flags & IUPAF_HAS_ID)
+ {
+ IattribGetIdFunc id_get = (IattribGetIdFunc)afunc->get;
+ return id_get(ih, ""); /* empty Id */
+ }
+ else
+ return afunc->get(ih);
+ }
+ }
+ return NULL;
+}
+
+void iupClassObjectGetAttributeInfo(Ihandle* ih, const char* name, char* *def_value, int *inherit)
+{
+ IattribFunc* afunc;
+
+ if (ih->iclass->has_attrib_id)
+ {
+ 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,
+ translate them into IDVALUE. */
+ afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, partial_name);
+ if (afunc)
+ {
+ *def_value = NULL; /* id numbered attributes have default value NULL always */
+ *inherit = 0; /* id numbered attributes are NON inheritable always */
+ return; /* if the function exists, then must return here */
+ }
+ }
+ }
+
+ /* if not has_attrib_id, or not found an ID, or not found the partial name, check using the full name */
+
+ afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, name);
+ *def_value = NULL;
+ *inherit = 1; /* default is inheritable */
+ if (afunc)
+ {
+ *def_value = iClassGetDefaultValue(afunc);
+ *inherit = !(afunc->flags & IUPAF_NO_INHERIT) && !(afunc->flags & IUPAF_NO_STRING);
+ }
+}
+
+int iupClassObjectCurAttribIsInherit(Iclass* ic)
+{
+ IattribFunc* afunc = (IattribFunc*)iupTableGetCurr(ic->attrib_func);
+ if (afunc && !(afunc->flags & IUPAF_NO_INHERIT))
+ return 1;
+ return 0;
+}
+
+int iupClassObjectAttribIsNotString(Ihandle* ih, const char* name)
+{
+ IattribFunc* afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, name);
+ if (afunc && afunc->flags & IUPAF_NO_STRING)
+ return 1;
+ return 0;
+}
+
+void iupClassRegisterAttribute(Iclass* ic, const char* name,
+ IattribGetFunc _get, IattribSetFunc _set,
+ const char* _default_value, const char* _system_default, int _flags)
+{
+ IattribFunc* afunc = (IattribFunc*)iupTableGet(ic->attrib_func, name);
+ if (afunc)
+ free(afunc); /* overwrite a previous registration */
+
+ afunc = (IattribFunc*)malloc(sizeof(IattribFunc));
+ afunc->get = _get;
+ afunc->set = _set;
+ if (_default_value == IUPAF_SAMEASSYSTEM)
+ afunc->default_value = _system_default;
+ else
+ afunc->default_value = _default_value;
+ afunc->system_default = _system_default;
+ afunc->flags = _flags;
+
+ if (iClassIsGlobalDefault(afunc->default_value))
+ afunc->call_global_default = 1;
+ else
+ afunc->call_global_default = 0;
+
+ iupTableSet(ic->attrib_func, name, (void*)afunc, IUPTABLE_POINTER);
+}
+
+void iupClassRegisterAttributeId(Iclass* ic, const char* name,
+ IattribGetIdFunc _get, IattribSetIdFunc _set,
+ int _flags)
+{
+ IattribFunc* afunc = (IattribFunc*)iupTableGet(ic->attrib_func, name);
+ if (afunc)
+ free(afunc); /* overwrite a previous registration */
+
+ afunc = (IattribFunc*)malloc(sizeof(IattribFunc));
+ afunc->get = (IattribGetFunc)_get;
+ afunc->set = (IattribSetFunc)_set;
+ afunc->default_value = NULL;
+ afunc->system_default = NULL;
+ afunc->flags = _flags|IUPAF_HAS_ID|IUPAF_NO_INHERIT|IUPAF_NO_DEFAULTVALUE;
+ afunc->call_global_default = 0;
+
+ iupTableSet(ic->attrib_func, name, (void*)afunc, IUPTABLE_POINTER);
+}
+
+void iupClassRegisterGetAttribute(Iclass* ic, const char* name,
+ IattribGetFunc *_get, IattribSetFunc *_set,
+ const char* *_default_value, const char* *_system_default, int *_flags)
+{
+ IattribFunc* afunc = (IattribFunc*)iupTableGet(ic->attrib_func, name);
+ if (afunc)
+ {
+ if (_get) *_get = afunc->get;
+ if (_set) *_set = afunc->set;
+ if (_default_value) *_default_value = afunc->default_value;
+ if (_system_default) *_system_default = afunc->system_default;
+ if (_flags) *_flags = afunc->flags;
+ }
+}
+
+void iupClassRegisterCallback(Iclass* ic, const char* name, const char* format)
+{
+ /* Since attributes and callbacks do not conflict
+ we can use the same structure to store the callback format using the default_value. */
+ iupClassRegisterAttribute(ic, name, NULL, NULL, format, NULL, IUPAF_NO_INHERIT);
+}
+
+char* iupClassCallbackGetFormat(Iclass* ic, const char* name)
+{
+ IattribFunc* afunc = (IattribFunc*)iupTableGet(ic->attrib_func, name);
+ if (afunc)
+ return (char*)afunc->default_value;
+ return NULL;
+}
+
+int IupGetClassAttributes(const char* classname, char** names, int n)
+{
+ Iclass* ic;
+ int i = 0;
+ char* name;
+
+ iupASSERT(classname!=NULL);
+ if (!classname)
+ return 0;
+
+ ic = iupRegisterFindClass(classname);
+ if (!ic)
+ return -1;
+
+ if (!names || !n)
+ return iupTableCount(ic->attrib_func);
+
+ name = iupTableFirst(ic->attrib_func);
+ while (name)
+ {
+ names[i] = name;
+ i++;
+ if (i == n)
+ break;
+
+ name = iupTableNext(ic->attrib_func);
+ }
+
+ return i;
+}
+
+void IupSetClassDefaultAttribute(const char* classname, const char *name, const char* default_value)
+{
+ Iclass* ic;
+ IattribFunc* afunc;
+
+ iupASSERT(classname!=NULL);
+ if (!classname)
+ return;
+
+ iupASSERT(name!=NULL);
+ if (!name)
+ return;
+
+ ic = iupRegisterFindClass(name);
+ if (!ic)
+ return;
+
+ afunc = (IattribFunc*)iupTableGet(ic->attrib_func, name);
+ if (afunc && (!(afunc->flags & IUPAF_NO_DEFAULTVALUE) || !(afunc->flags & IUPAF_NO_STRING) || !(afunc->flags & IUPAF_HAS_ID)))
+ {
+ if (default_value == IUPAF_SAMEASSYSTEM)
+ afunc->default_value = afunc->system_default;
+ else
+ afunc->default_value = default_value;
+
+ if (iClassIsGlobalDefault(afunc->default_value))
+ afunc->call_global_default = 1;
+ else
+ afunc->call_global_default = 0;
+ }
+ else if (default_value)
+ iupClassRegisterAttribute(ic, name, NULL, NULL, default_value, NULL, IUPAF_DEFAULT);
+}
+
+void IupSaveClassAttributes(Ihandle* ih)
+{
+ Iclass* ic;
+ char *name;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+
+ ic = ih->iclass;
+
+ name = iupTableFirst(ic->attrib_func);
+ while (name)
+ {
+ IattribFunc* afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, name);
+ if (afunc && !(afunc->flags & IUPAF_NO_STRING))
+ {
+ int inherit;
+ char *def_value;
+ char *value = iupClassObjectGetAttribute(ih, name, &def_value, &inherit);
+ if (value && value != iupAttribGet(ih, name))
+ iupAttribStoreStr(ih, name, value);
+ }
+
+ name = iupTableNext(ic->attrib_func);
+ }
+}
+
+void iupClassObjectEnsureDefaultAttributes(Ihandle* ih)
+{
+ Iclass* ic;
+ char *name;
+
+ ic = ih->iclass;
+
+ name = iupTableFirst(ic->attrib_func);
+ while (name)
+ {
+ IattribFunc* afunc = (IattribFunc*)iupTableGetCurr(ic->attrib_func);
+ if (afunc && afunc->set && (afunc->default_value || afunc->system_default) &&
+ (!(afunc->flags & IUPAF_NO_DEFAULTVALUE) || !(afunc->flags & IUPAF_NO_STRING) || !(afunc->flags & IUPAF_HAS_ID)))
+ {
+ if ((!iupStrEqualNoCase(afunc->default_value, afunc->system_default)) ||
+ (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));
+ }
+ }
+
+ name = iupTableNext(ic->attrib_func);
+ }
+}
+
+char* iupClassGetDefaultAttribute(const char* classname, const char *attrib_name)
+{
+ Iclass* ic;
+ IattribFunc* afunc;
+
+ iupASSERT(classname!=NULL);
+ if (!classname)
+ return NULL;
+
+ iupASSERT(attrib_name!=NULL);
+ if (!attrib_name)
+ return NULL;
+
+ ic = iupRegisterFindClass(classname);
+ if (!ic)
+ return NULL;
+
+ afunc = (IattribFunc*)iupTableGet(ic->attrib_func, attrib_name);
+ if (afunc)
+ return (char*)afunc->default_value;
+ else
+ return NULL;
+}
diff --git a/iup/src/iup_classbase.c b/iup/src/iup_classbase.c
new file mode 100755
index 0000000..9cb9e63
--- /dev/null
+++ b/iup/src/iup_classbase.c
@@ -0,0 +1,466 @@
+/** \file
+ * \brief Ihandle Class Base Functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_str.h"
+#include "iup_attrib.h"
+#include "iup_assert.h"
+
+
+void iupBaseCallValueChangedCb(Ihandle* ih)
+{
+ IFn vc_cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB");
+ if (vc_cb)
+ vc_cb(ih);
+}
+
+int iupBaseTypeVoidMapMethod(Ihandle* ih)
+{
+ ih->handle = (InativeHandle*)-1; /* fake value just to indicate that it is already mapped */
+ return IUP_NOERROR;
+}
+
+char* iupBaseGetWidAttrib(Ihandle *ih)
+{
+ return (char*)ih->handle;
+}
+
+void iupBaseUpdateSizeFromFont(Ihandle* ih)
+{
+ char* value = iupAttribGet(ih, "SIZE");
+ if (!value)
+ return;
+
+ iupBaseSetSizeAttrib(ih, value);
+}
+
+int iupBaseSetSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ ih->userwidth = 0;
+ ih->userheight = 0;
+ }
+ else
+ {
+ /* if not specified, the value is 0 */
+ int w = 0, h = 0;
+ int charwidth, charheight;
+ iupdrvFontGetCharSize(ih, &charwidth, &charheight);
+ iupStrToIntInt(value, &w, &h, 'x');
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+
+ ih->userwidth = iupWIDTH2RASTER(w, charwidth);
+ ih->userheight = iupHEIGHT2RASTER(h, charheight);
+ }
+ return 1; /* always save in the hash table, so when FONT is changed SIZE can be updated */
+}
+
+char* iupBaseGetSizeAttrib(Ihandle* ih)
+{
+ char* str;
+ int charwidth, charheight, width, height;
+
+ if (ih->handle)
+ {
+ width = ih->currentwidth;
+ height = ih->currentheight;
+ }
+ else
+ {
+ width = ih->userwidth;
+ height = ih->userheight;
+ }
+
+ iupdrvFontGetCharSize(ih, &charwidth, &charheight);
+ if (charwidth == 0 || charheight == 0)
+ return NULL; /* if font failed get from the hash table */
+
+ str = iupStrGetMemory(50);
+ sprintf(str, "%dx%d", iupRASTER2WIDTH(width, charwidth),
+ iupRASTER2HEIGHT(height, charheight));
+ return str;
+}
+
+int iupBaseSetRasterSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ ih->userwidth = 0;
+ ih->userheight = 0;
+ }
+ else
+ {
+ /* if not specified, the value is 0 */
+ int w = 0, h = 0;
+ iupStrToIntInt(value, &w, &h, 'x');
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ ih->userwidth = w;
+ ih->userheight = h;
+ }
+ iupAttribSetStr(ih, "SIZE", NULL); /* clear SIZE in hash table */
+ return 0;
+}
+
+char* iupBaseGetRasterSizeAttrib(Ihandle* ih)
+{
+ char* str;
+ int width, height;
+
+ if (ih->handle)
+ {
+ width = ih->currentwidth;
+ height = ih->currentheight;
+ }
+ else
+ {
+ width = ih->userwidth;
+ height = ih->userheight;
+ }
+
+ if (!width && !height)
+ return NULL;
+
+ str = iupStrGetMemory(50);
+ sprintf(str, "%dx%d", width, height);
+ return str;
+}
+
+char* iupBaseGetCharSizeAttrib(Ihandle* ih)
+{
+ char* str;
+ int charwidth, charheight;
+
+ iupdrvFontGetCharSize(ih, &charwidth, &charheight);
+ if (charwidth == 0 || charheight == 0)
+ return NULL;
+
+ str = iupStrGetMemory(50);
+ sprintf(str, "%dx%d", charwidth, charheight);
+ return str;
+}
+
+static char* iBaseGetPositionAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(50);
+ sprintf(str, "%d,%d", ih->x, ih->y);
+ return str;
+}
+
+static int iBaseSetPositionAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->is_floating)
+ iupStrToIntInt(value, &ih->x, &ih->y, ',');
+ return 0;
+}
+
+char* iupBaseGetActiveAttrib(Ihandle *ih)
+{
+ if (iupdrvIsActive(ih))
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iBaseNativeParentIsActive(Ihandle* ih)
+{
+ if (!ih->parent)
+ return 1;
+
+ if (ih->parent->iclass->nativetype == IUP_TYPEVOID)
+ return iBaseNativeParentIsActive(ih->parent);
+ else
+ return iupdrvIsActive(ih->parent);
+}
+
+int iupBaseSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ {
+ if (iBaseNativeParentIsActive(ih))
+ iupdrvSetActive(ih, 1);
+ }
+ else
+ iupdrvSetActive(ih, 0);
+ return 0;
+}
+
+char* iupBaseGetVisibleAttrib(Ihandle* ih)
+{
+ if (iupdrvIsVisible(ih))
+ return "YES";
+ else
+ return "NO";
+}
+
+int iupBaseSetVisibleAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetVisible(ih, iupStrBoolean(value));
+ return 0;
+}
+
+char* iupBaseNativeParentGetBgColorAttrib(Ihandle* ih)
+{
+ /* Used only by those who need a transparent background */
+ char* color = iupAttribGetInheritNativeParent(ih, "BGCOLOR");
+ if (!color) color = iupAttribGetInheritNativeParent(ih, "BACKGROUND");
+ if (!color) color = IupGetGlobal("DLGBGCOLOR");
+ return color;
+}
+
+char* iupBaseNativeParentGetBgColor(Ihandle* ih)
+{
+ /* Used in SetBgColorAttrib */
+ char* color = iupAttribGetInheritNativeParent(ih, "BGCOLOR");
+ if (!color) color = IupGetGlobal("DLGBGCOLOR");
+ return color;
+}
+
+int iupBaseGetScrollbar(Ihandle* ih)
+{
+ int sb = IUP_SB_NONE; /* NO scrollbar by default */
+ char* value = IupGetAttribute(ih, "SCROLLBAR");
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "YES"))
+ sb = IUP_SB_HORIZ | IUP_SB_VERT;
+ else if (iupStrEqualNoCase(value, "HORIZONTAL"))
+ sb = IUP_SB_HORIZ;
+ else if (iupStrEqualNoCase(value, "VERTICAL"))
+ sb = IUP_SB_VERT;
+ }
+ return sb;
+}
+
+static int iBaseSetNormalizerGroupAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle* ih_normalizer = IupGetHandle(value);
+ if (!ih_normalizer)
+ {
+ ih_normalizer = IupNormalizer(NULL);
+ IupSetHandle(value, ih_normalizer);
+ }
+
+ IupSetAttribute(ih_normalizer, "ADDCONTROL_HANDLE", (char*)ih);
+ return 1;
+}
+
+static Ihandle* iBaseFindChild(Ihandle* ih, const char* name)
+{
+ Ihandle* child = ih->firstchild;
+ while (child)
+ {
+ char* child_name = iupAttribGet(child, "NAME");
+ if (child_name && iupStrEqualNoCase(name, child_name))
+ return child;
+
+ if (child->firstchild)
+ {
+ Ihandle* c = iBaseFindChild(child, name);
+ if (c) return c;
+ }
+
+ child = child->brother;
+ }
+ return NULL;
+}
+
+Ihandle* IupGetDialogChild(Ihandle* ih, const char* name)
+{
+ Ihandle *child, *dialog;
+ char attrib[1024] = "_IUP_DIALOG_CHILD_";
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ if (!name)
+ return NULL;
+
+ dialog = IupGetDialog(ih);
+ if (dialog) ih = dialog;
+
+ strcat(attrib, name);
+ child = (Ihandle*)iupAttribGet(ih, attrib);
+ if (child) return child;
+
+ if (ih->firstchild)
+ {
+ child = iBaseFindChild(ih, name);
+ if (child) return child;
+ }
+ return NULL;
+}
+
+int iupBaseSetNameAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle* dialog = IupGetDialog(ih);
+ if (dialog)
+ {
+ char attrib[1024] = "_IUP_DIALOG_CHILD_";
+ strcat(attrib, value);
+ iupAttribSetStr(dialog, attrib, (char*)ih);
+ }
+ return 1;
+}
+
+static int iBaseSetFloatingAttrib(Ihandle* ih, const char* value)
+{
+ ih->is_floating = iupStrBoolean(value);
+ return 0;
+}
+
+static char* iBaseGetFloatingAttrib(Ihandle* ih)
+{
+ if (ih->is_floating)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iBaseSetMaxSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (value)
+ ih->has_maxsize = 1;
+ else
+ ih->has_maxsize = 0;
+ return 1;
+}
+
+static int iBaseSetMinSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (value)
+ ih->has_minsize = 1;
+ else
+ ih->has_minsize = 0;
+ return 1;
+}
+
+static int iBaseSetExpandAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrEqualNoCase(value, "YES"))
+ ih->expand = IUP_EXPAND_BOTH;
+ else if (iupStrEqualNoCase(value, "HORIZONTAL"))
+ ih->expand = IUP_EXPAND_WIDTH;
+ else if (iupStrEqualNoCase(value, "VERTICAL"))
+ ih->expand = IUP_EXPAND_HEIGHT;
+ else
+ ih->expand = IUP_EXPAND_NONE;
+ return 0;
+}
+
+static char* iBaseGetExpandAttrib(Ihandle* ih)
+{
+ if (ih->expand & IUP_EXPAND_BOTH)
+ return "YES";
+ else if (ih->expand & IUP_EXPAND_WIDTH)
+ return "HORIZONTAL";
+ else if (ih->expand & IUP_EXPAND_HEIGHT)
+ return "VERTICAL";
+ else
+ return "NO";
+}
+
+void iupBaseContainerUpdateExpand(Ihandle* ih)
+{
+ char *expand = iupAttribGetInherit(ih, "EXPAND");
+ if (!expand)
+ ih->expand = IUP_EXPAND_BOTH; /* default for containers is YES */
+ else
+ {
+ if (iupStrEqualNoCase(expand, "NO"))
+ ih->expand = IUP_EXPAND_NONE;
+ else if (iupStrEqualNoCase(expand, "HORIZONTAL"))
+ ih->expand = IUP_EXPAND_WIDTH;
+ else if (iupStrEqualNoCase(expand, "VERTICAL"))
+ ih->expand = IUP_EXPAND_HEIGHT;
+ else
+ ih->expand = IUP_EXPAND_BOTH; /* default for containers is YES */
+ }
+}
+
+/* EXPAND is registered with IUP_NO_INHERIT because it is not inheritable,
+ but it is inheritable for containers.
+ So if you set at a container it will not affect its children,
+ but children that are containers will get the same value. */
+char* iupBaseContainerGetExpandAttrib(Ihandle* ih)
+{
+ return iupAttribGetInherit(ih, "EXPAND");
+}
+
+void iupBaseRegisterCommonAttrib(Iclass* ic)
+{
+ iupClassRegisterAttribute(ic, "WID", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "NAME", NULL, iupBaseSetNameAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ 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);
+
+ /* 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);
+
+ 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);
+
+ iupClassRegisterAttribute(ic, "POSITION", iBaseGetPositionAttrib, iBaseSetPositionAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MAXSIZE", NULL, iBaseSetMaxSizeAttrib, IUPAF_SAMEASSYSTEM, "65535x65535", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MINSIZE", NULL, iBaseSetMinSizeAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */
+ iupClassRegisterAttribute(ic, "FONT", iupGetFontAttrib, iupSetFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "FONTSTYLE", iupGetFontStyleAttrib, iupSetFontStyleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FONTSIZE", iupGetFontSizeAttrib, iupSetFontSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FONTFACE", iupGetFontFaceAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupdrvBaseRegisterCommonAttrib(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, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+
+ iupClassRegisterAttribute(ic, "ZORDER", NULL, iupdrvBaseSetZorderAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "X", iupdrvBaseGetXAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "Y", iupdrvBaseGetYAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "TIP", NULL, iupdrvBaseSetTipAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TIPVISIBLE", NULL, iupdrvBaseSetTipVisibleAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TIPDELAY", NULL, NULL, IUPAF_SAMEASSYSTEM, "5000", IUPAF_NOT_MAPPED); /* 5 seconds */
+ iupClassRegisterAttribute(ic, "TIPBGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "255 255 225", IUPAF_NOT_MAPPED); /* Light Yellow */
+ iupClassRegisterAttribute(ic, "TIPFGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "0 0 0", IUPAF_NOT_MAPPED); /* black */
+}
+
+void iupBaseRegisterCommonCallbacks(Iclass* ic)
+{
+ iupClassRegisterAttribute(ic, "MAP_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "UNMAP_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "GETFOCUS_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "KILLFOCUS_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ENTERWINDOW_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "LEAVEWINDOW_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "HELP_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "K_ANY", NULL, NULL, "i", NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/iup_classbase.h b/iup/src/iup_classbase.h
new file mode 100755
index 0000000..1ced9c6
--- /dev/null
+++ b/iup/src/iup_classbase.h
@@ -0,0 +1,175 @@
+/** \file
+ * \brief Base Class
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_CLASSBASE_H
+#define __IUP_CLASSBASE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup iclassbase Base Class
+ * \par
+ * See \ref iup_classbase.h
+ * \ingroup iclass
+ */
+
+
+/** Register all common base attributes: \n
+ * WID \n
+ * SIZE, RASTERSIZE, POSITION \n
+ * FONT (and derived) \n\n
+ * All controls that are positioned inside a dialog must register all common base attributes.
+ * \ingroup iclassbase */
+void iupBaseRegisterCommonAttrib(Iclass* ic);
+
+/** Register all visual base attributes: \n
+ * VISIBLE, ACTIVE \n
+ * ZORDER, X, Y \n
+ * TIP (and derived) \n\n
+ * All controls that are positioned inside a dialog must register all visual base attributes.
+ * \ingroup iclassbase */
+void iupBaseRegisterVisualAttrib(Iclass* ic);
+
+/** Register all common callbacks: \n
+* MAP_CB, UNMAP_CB, GETFOCUS_CB, KILLFOCUS_CB, ENTERWINDOW_CB, LEAVEWINDOW_CB, K_ANY, HELP_CB.
+* \ingroup iclassbase */
+void iupBaseRegisterCommonCallbacks(Iclass* ic);
+
+/* Register driver dependent common attributes.
+ Used only from iupBaseRegisterCommonAttrib */
+void iupdrvBaseRegisterCommonAttrib(Iclass* ic);
+
+/** Updates the expand member of the IUP object from the EXPAND attribute.
+ * Should be called in the beginning of the ComputeNaturalSize for a container.
+ * \ingroup iclassbase */
+void iupBaseContainerUpdateExpand(Ihandle* ih);
+
+/** Initializes the natural size using the user size, then
+ * if a container then update the "expand" member from the EXPAND attribute, then
+ * call \ref iupClassObjectComputeNaturalSize for containers if they have children or
+ * call \ref iupClassObjectComputeNaturalSize for non-containers if user size is not defined.
+ * Must be called for each children in the container. \n
+ * First call is in iupLayoutCompute.
+ * \ingroup iclassbase */
+void iupBaseComputeNaturalSize(Ihandle* ih);
+
+/** Update the current size from the available size, the natural size, expand and shrink.
+ * Call \ref iupClassObjectSetChildrenCurrentSize for containers if they have children.
+ * Must be called for each children in the container. \n
+ * First call is in iupLayoutCompute.
+ * \ingroup iclassbase */
+void iupBaseSetCurrentSize(Ihandle* ih, int w, int h, int shrink);
+
+/** Set the current position and update children position for containers.
+ * Call \ref iupClassObjectSetChildrenPosition for containers if they have children.
+ * Must be called for each children in the container. \n
+ * First call is in iupLayoutCompute.
+ * \ingroup iclassbase */
+void iupBaseSetPosition(Ihandle* ih, int x, int y);
+
+/* Updates the SIZE attribute if defined.
+ Called only from iupdrvSetStandardFontAttrib. */
+void iupBaseUpdateSizeFromFont(Ihandle* ih);
+
+
+/** \defgroup iclassbasemethod Base Class Methods
+ * \par
+ * See \ref iup_classbase.h
+ * \ingroup iclassbase
+ */
+
+/** Driver dependent \ref Iclass::LayoutUpdate method.
+ * \ingroup iclassbasemethod */
+void iupdrvBaseLayoutUpdateMethod(Ihandle *ih);
+
+/** Driver dependent \ref Iclass::UnMap method.
+ * \ingroup iclassbasemethod */
+void iupdrvBaseUnMapMethod(Ihandle* ih);
+
+/** Native type void \ref Iclass::Map method.
+ * \ingroup iclassbasemethod */
+int iupBaseTypeVoidMapMethod(Ihandle* ih);
+
+
+/** \defgroup iclassbaseattribfunc Base Class Attribute Functions
+ * \par
+ * Used by the controls for iupClassRegisterAttribute.
+ * \par
+ * See \ref iup_classbase.h
+ * \ingroup iclassbase
+ * @{
+ */
+
+/* common */
+char* iupBaseGetWidAttrib(Ihandle* ih);
+int iupBaseSetNameAttrib(Ihandle* ih, const char* value);
+int iupBaseSetRasterSizeAttrib(Ihandle* ih, const char* value);
+int iupBaseSetSizeAttrib(Ihandle* ih, const char* value);
+char* iupBaseGetSizeAttrib(Ihandle* ih);
+char* iupBaseGetRasterSizeAttrib(Ihandle* ih);
+
+/* visual */
+char* iupBaseGetVisibleAttrib(Ihandle* ih);
+int iupBaseSetVisibleAttrib(Ihandle* ih, const char* value);
+char* iupBaseGetActiveAttrib(Ihandle *ih);
+int iupBaseSetActiveAttrib(Ihandle* ih, const char* value);
+int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value);
+char *iupdrvBaseGetXAttrib(Ihandle *ih);
+char *iupdrvBaseGetYAttrib(Ihandle *ih);
+int iupdrvBaseSetTipAttrib(Ihandle* ih, const char* value);
+int iupdrvBaseSetTipVisibleAttrib(Ihandle* ih, const char* value);
+int iupdrvBaseSetBgColorAttrib(Ihandle* ih, const char* value);
+int iupdrvBaseSetFgColorAttrib(Ihandle* ih, const char* value);
+char* iupBaseNativeParentGetBgColorAttrib(Ihandle* ih);
+
+/* other */
+char* iupBaseContainerGetExpandAttrib(Ihandle* ih);
+int iupdrvBaseSetCursorAttrib(Ihandle* ih, const char* value);
+char* iupdrvBaseGetClientSizeAttrib(Ihandle* ih);
+
+/* Windows Only */
+char* iupdrvBaseGetTitleAttrib(Ihandle* ih);
+int iupdrvBaseSetTitleAttrib(Ihandle* ih, const char* value);
+
+/** @} */
+
+
+
+/** \defgroup iclassbaseutil Base Class Utilities
+ * \par
+ * See \ref iup_classbase.h
+ * \ingroup iclassbase
+ * @{
+ */
+
+#define iupMAX(_a,_b) ((_a)>(_b)?(_a):(_b))
+#define iupROUND(_x) ((int)((_x)>0? (_x)+0.5: (_x)-0.5))
+
+#define iupCOLOR8TO16(_x) ((unsigned short)(_x*257)) /* 65535/255 = 257 */
+#define iupCOLOR16TO8(_x) ((unsigned char)(_x/257))
+
+#define iupBYTECROP(_x) ((unsigned char)((_x)<0?0:((_x)>255)?255:(_x)))
+
+enum{IUP_ALIGN_ALEFT, IUP_ALIGN_ACENTER, IUP_ALIGN_ARIGHT};
+#define IUP_ALIGN_ABOTTOM IUP_ALIGN_ARIGHT
+#define IUP_ALIGN_ATOP IUP_ALIGN_ALEFT
+
+enum{IUP_SB_NONE, IUP_SB_HORIZ, IUP_SB_VERT};
+int iupBaseGetScrollbar(Ihandle* ih);
+
+char* iupBaseNativeParentGetBgColor(Ihandle* ih);
+void iupBaseCallValueChangedCb(Ihandle* ih);
+
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_colordlg.c b/iup/src/iup_colordlg.c
new file mode 100755
index 0000000..d3835cd
--- /dev/null
+++ b/iup/src/iup_colordlg.c
@@ -0,0 +1,44 @@
+/** \file
+ * \brief IupColorDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_stdcontrols.h"
+
+
+Ihandle* IupColorDlg(void)
+{
+ return IupCreate("colordlg");
+}
+
+Iclass* iupColorDlgGetClass(void)
+{
+ Iclass* ic = iupClassNew(iupDialogGetClass());
+
+ ic->name = "colordlg";
+ ic->nativetype = IUP_TYPEDIALOG;
+ ic->is_interactive = 1;
+
+ /* reset not used native dialog methods */
+ ic->parent->LayoutUpdate = NULL;
+ ic->parent->SetChildrenPosition = NULL;
+ ic->parent->Map = NULL;
+ ic->parent->UnMap = NULL;
+
+ iupdrvColorDlgInitClass(ic);
+
+ return ic;
+}
diff --git a/iup/src/iup_dialog.c b/iup/src/iup_dialog.c
new file mode 100755
index 0000000..d70e12c
--- /dev/null
+++ b/iup/src/iup_dialog.c
@@ -0,0 +1,747 @@
+/** \file
+ * \brief IupDialog class
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_class.h"
+#include "iup_object.h"
+#include "iup_dlglist.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_drvfont.h"
+#include "iup_focus.h"
+#include "iup_str.h"
+#define _IUPDLG_PRIVATE
+#include "iup_dialog.h"
+
+
+static int dlg_popup_level = 1;
+
+InativeHandle* iupDialogGetNativeParent(Ihandle* ih)
+{
+ Ihandle* parent = IupGetAttributeHandle(ih, "PARENTDIALOG");
+ if (parent && parent->handle)
+ return parent->handle;
+ else
+ return (InativeHandle*)iupAttribGet(ih, "NATIVEPARENT");
+}
+
+static void iupDialogAdjustPos(Ihandle *ih, int *x, int *y)
+{
+ int cursor_x = 0, cursor_y = 0;
+ int screen_width = 0, screen_height = 0;
+ int current_x = 0, current_y = 0;
+ int parent_x = 0, parent_y = 0;
+
+ /* the dialog is already mapped here */
+
+ if (*x == IUP_CURRENT || *y == IUP_CURRENT)
+ {
+ /* if first time, there is no current position */
+ if (!ih->data->first_show)
+ {
+ int center = IUP_CENTER;
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ if (parent)
+ center = IUP_CENTERPARENT;
+
+ if (*x == IUP_CURRENT) *x = center;
+ if (*y == IUP_CURRENT) *y = center;
+ }
+ else
+ iupdrvDialogGetPosition(ih->handle, &current_x, &current_y);
+ }
+
+ if (*x == IUP_CENTER || *y == IUP_CENTER ||
+ *x == IUP_RIGHT || *y == IUP_RIGHT ||
+ *x == IUP_CENTERPARENT || *y == IUP_CENTERPARENT)
+ iupdrvGetScreenSize(&screen_width, &screen_height);
+
+ if (*x == IUP_CENTERPARENT || *y == IUP_CENTERPARENT)
+ {
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ if (parent)
+ {
+ iupdrvDialogGetPosition(parent, &parent_x, &parent_y);
+
+ if (*x == IUP_CENTERPARENT && *y == IUP_CENTERPARENT)
+ iupdrvDialogGetSize(parent, &screen_width, &screen_height);
+ else if (*x == IUP_CENTERPARENT)
+ iupdrvDialogGetSize(parent, &screen_width, NULL);
+ else if (*y == IUP_CENTERPARENT)
+ iupdrvDialogGetSize(parent, NULL, &screen_height);
+ }
+ }
+
+ if (*x == IUP_MOUSEPOS || *y == IUP_MOUSEPOS)
+ iupdrvGetCursorPos(&cursor_x, &cursor_y);
+
+ if (iupAttribGetBoolean(ih, "MDICHILD"))
+ {
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (client)
+ {
+ /* position is relative to mdi client */
+ parent_x = 0;
+ parent_y = 0;
+
+ /* screen size is now the size of the mdi client */
+ screen_width = client->currentwidth;
+ screen_height = client->currentheight;
+
+ iupdrvScreenToClient(client, &current_x, &current_y);
+ iupdrvScreenToClient(client, &cursor_x, &cursor_y);
+ }
+ }
+
+ switch (*x)
+ {
+ case IUP_CENTERPARENT:
+ *x = (screen_width - ih->currentwidth)/2 + parent_x;
+ break;
+ case IUP_CENTER:
+ *x = (screen_width - ih->currentwidth)/2;
+ break;
+ case IUP_LEFT:
+ *x = 0;
+ break;
+ case IUP_RIGHT:
+ *x = screen_width - ih->currentwidth;
+ break;
+ case IUP_MOUSEPOS:
+ *x = cursor_x;
+ break;
+ case IUP_CURRENT:
+ *x = current_x;
+ break;
+ }
+
+ switch (*y)
+ {
+ case IUP_CENTERPARENT:
+ *y = (screen_height - ih->currentheight)/2 + parent_y;
+ break;
+ case IUP_CENTER:
+ *y = (screen_height - ih->currentheight)/2;
+ break;
+ case IUP_LEFT:
+ *y = 0;
+ break;
+ case IUP_RIGHT:
+ *y = screen_height - ih->currentheight;
+ break;
+ case IUP_MOUSEPOS:
+ *y = cursor_y;
+ break;
+ case IUP_CURRENT:
+ *y = current_y;
+ break;
+ }
+}
+
+static void iDialogSetModal(Ihandle* ih_popup)
+{
+ Ihandle *ih;
+ iupAttribSetStr(ih_popup, "MODAL", "YES");
+
+ /* disable all visible dialogs, and mark popup level */
+ for (ih = iupDlgListFirst(); ih; ih = iupDlgListNext())
+ {
+ if (ih != ih_popup &&
+ ih->handle &&
+ iupdrvDialogIsVisible(ih) &&
+ ih->data->popup_level == 0)
+ {
+ iupdrvSetActive(ih, 0);
+ ih->data->popup_level = dlg_popup_level;
+ }
+ }
+
+ dlg_popup_level++;
+}
+
+static void iDialogUnSetModal(Ihandle* ih_popup)
+{
+ Ihandle *ih;
+ if (!iupAttribGetBoolean(ih_popup, "MODAL"))
+ return;
+
+ iupAttribSetStr(ih_popup, "MODAL", NULL);
+
+ /* must enable all visible dialogs at the marked popup level */
+ for (ih = iupDlgListFirst(); ih; ih = iupDlgListNext())
+ {
+ if (ih->handle)
+ {
+ if (ih->data->popup_level == dlg_popup_level-1)
+ {
+ iupdrvSetActive(ih, 1);
+ ih->data->popup_level = 0;
+ }
+ }
+ }
+
+ dlg_popup_level--;
+}
+
+static int iDialogCreateMethod(Ihandle* ih, void** params)
+{
+ ih->data = iupALLOCCTRLDATA();
+
+ ih->data->child_id = 100; /* initial number */
+ ih->data->show_state = IUP_HIDE;
+
+ if (params)
+ {
+ Ihandle** iparams = (Ihandle**)params;
+ if (*iparams)
+ IupAppend(ih, *iparams);
+ }
+
+ iupDlgListAdd(ih);
+
+ return IUP_NOERROR;
+}
+
+static void iDialogDestroyMethod(Ihandle* ih)
+{
+ iupDlgListRemove(ih);
+}
+
+static void iDialogComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ int decorwidth, decorheight;
+ Ihandle* child = ih->firstchild;
+
+ iupDialogGetDecorSize(ih, &decorwidth, &decorheight);
+ *w = decorwidth;
+ *h = decorheight;
+
+ if (child)
+ {
+ /* update child natural size first */
+ iupBaseComputeNaturalSize(child);
+
+ *expand = child->expand;
+ *w += child->naturalwidth;
+ *h += child->naturalheight;
+ }
+}
+
+static void iDialogSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink)
+{
+ int decorwidth, decorheight, client_width, client_height;
+
+ if (shrink)
+ {
+ client_width = ih->currentwidth;
+ client_height = ih->currentheight;
+ }
+ else
+ {
+ client_width = iupMAX(ih->naturalwidth, ih->currentwidth);
+ client_height = iupMAX(ih->naturalheight, ih->currentheight);
+ }
+
+ iupDialogGetDecorSize(ih, &decorwidth, &decorheight);
+
+ client_width -= decorwidth;
+ client_height -= decorheight;
+ if (client_width < 0) client_width = 0;
+ if (client_height < 0) client_height = 0;
+
+ iupBaseSetCurrentSize(ih->firstchild, client_width, client_height, shrink);
+}
+
+static void iDialogSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ (void)x;
+ (void)y;
+
+ /* Child coordinates are relative to client left-top corner. */
+ iupBaseSetPosition(ih->firstchild, 0, 0);
+}
+
+static void iDialogAfterShow(Ihandle* ih)
+{
+ Ihandle* old_focus;
+ IFni show_cb;
+
+ /* process all pending messages */
+ IupFlush();
+
+ old_focus = IupGetFocus();
+
+ show_cb = (IFni)IupGetCallback(ih, "SHOW_CB");
+ if (show_cb && show_cb(ih, ih->data->show_state) == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return;
+ }
+
+ if (ih->data->show_state == IUP_SHOW)
+ {
+ if (show_cb)
+ IupFlush(); /* again to update focus */
+
+ /* do it only if show_cb did NOT changed the current focus */
+ if (old_focus == IupGetFocus())
+ {
+ Ihandle *startfocus = IupGetAttributeHandle(ih, "STARTFOCUS");
+ if (startfocus)
+ IupSetFocus(startfocus);
+ else
+ IupNextField(ih);
+ }
+ }
+}
+
+int iupDialogGetChildId(Ihandle* ih)
+{
+ int id;
+ ih = IupGetDialog(ih);
+ if (!ih) return -1;
+ id = ih->data->child_id;
+ ih->data->child_id = id+1;
+ return id;
+}
+
+char* iupDialogGetChildIdStr(Ihandle* ih)
+{
+ char *str = iupStrGetMemory(50);
+ Ihandle* dialog = IupGetDialog(ih);
+ sprintf(str, "iup-%s-%d", ih->iclass->name, dialog->data->child_id);
+ return str;
+}
+
+int iupDialogPopup(Ihandle* ih, int x, int y)
+{
+ int was_visible;
+
+ int ret = iupClassObjectDlgPopup(ih, x, y);
+ if (ret != IUP_INVALID) /* IUP_INVALID means it is not implemented */
+ return ret;
+
+ ih->data->show_state = IUP_SHOW;
+
+ /* save visible state before iupdrvDialogSetPlacement */
+ /* because it can also show the window when changing placement. */
+ was_visible = iupdrvDialogIsVisible(ih);
+
+ /* Update the position and placement */
+ if (!iupdrvDialogSetPlacement(ih))
+ {
+ iupDialogAdjustPos(ih, &x, &y);
+ iupdrvDialogSetPosition(ih, x, y);
+ }
+
+ if (was_visible) /* already visible */
+ {
+ /* only re-show to raise the window */
+ iupdrvDialogSetVisible(ih, 1);
+
+ /* flush, then process show_cb and startfocus */
+ iDialogAfterShow(ih);
+ return IUP_NOERROR;
+ }
+
+ if (iupAttribGetBoolean(ih, "MODAL")) /* already a popup */
+ return IUP_NOERROR;
+
+ iDialogSetModal(ih);
+
+ ih->data->first_show = 1;
+
+ /* actually show the window */
+ /* test if placement turn the dialog visible */
+ if (!iupdrvDialogIsVisible(ih))
+ iupdrvDialogSetVisible(ih, 1);
+
+ /* increment visible count */
+ iupDlgListVisibleInc();
+
+ /* flush, then process show_cb and startfocus */
+ iDialogAfterShow(ih);
+
+ /* interrupt processing here */
+ IupMainLoop();
+
+ /* if window is still valid (IupDestroy not called),
+ hide the dialog if still visible. */
+ if (iupObjectCheck(ih))
+ {
+ iDialogUnSetModal(ih);
+ IupHide(ih);
+ }
+
+ return IUP_NOERROR;
+}
+
+int iupDialogShowXY(Ihandle* ih, int x, int y)
+{
+ int was_visible;
+
+ /* Calling IupShow for a visible dialog shown with IupPopup does nothing. */
+ if (iupAttribGetBoolean(ih, "MODAL")) /* already a popup */
+ return IUP_NOERROR;
+
+ if (ih->data->popup_level != 0)
+ {
+ /* was disabled by a Popup, re-enable it */
+ iupdrvSetActive(ih, 1);
+ ih->data->popup_level = 0; /* Now it is at the current popup level */
+ }
+
+ /* save visible state before iupdrvDialogSetPlacement */
+ /* because it can also show the window when changing placement. */
+ was_visible = iupdrvDialogIsVisible(ih);
+
+ /* Update the position and placement */
+ if (!iupdrvDialogSetPlacement(ih))
+ {
+ iupDialogAdjustPos(ih, &x, &y);
+ iupdrvDialogSetPosition(ih, x, y);
+ }
+
+ if (was_visible) /* already visible */
+ {
+ /* only re-show to raise the window */
+ iupdrvDialogSetVisible(ih, 1);
+
+ /* flush, then process show_cb and startfocus */
+ iDialogAfterShow(ih);
+ return IUP_NOERROR;
+ }
+
+ ih->data->first_show = 1;
+
+ /* actually show the window */
+ /* test if placement turn the dialog visible */
+ if (!iupdrvDialogIsVisible(ih))
+ iupdrvDialogSetVisible(ih, 1);
+
+ /* increment visible count */
+ iupDlgListVisibleInc();
+
+ /* flush, then process show_cb and startfocus */
+ iDialogAfterShow(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupDialogHide(Ihandle* ih)
+{
+ /* hidden at the system and marked hidden in IUP */
+ if (!iupdrvDialogIsVisible(ih) && ih->data->show_state == IUP_HIDE)
+ return;
+
+ /* marked hidden in IUP */
+ ih->data->show_state = IUP_HIDE;
+
+ /* if called IupHide for a Popup window */
+ if (iupAttribGetBoolean(ih, "MODAL"))
+ {
+ iDialogUnSetModal(ih);
+ IupExitLoop();
+ }
+
+ ih->data->ignore_resize = 1;
+
+ /* actually hide the window */
+ iupdrvDialogSetVisible(ih, 0);
+
+ ih->data->ignore_resize = 0;
+
+ /* decrement visible count */
+ iupDlgListVisibleDec();
+
+ if (iupDlgListVisibleCount() <= 0)
+ {
+ /* if this is the last window visible,
+ exit message loop except when LOCKLOOP==YES */
+ if (!iupStrBoolean(IupGetGlobal("LOCKLOOP")))
+ IupExitLoop();
+ }
+
+ /* flush, then process show_cb and startfocus */
+ iDialogAfterShow(ih);
+}
+
+
+/****************************************************************/
+
+
+static int iDialogSizeGetScale(const char* sz)
+{
+ if (!sz || sz[0] == 0) return 0;
+ if (iupStrEqualNoCase(sz, "FULL")) return 1;
+ if (iupStrEqualNoCase(sz, "HALF")) return 2;
+ if (iupStrEqualNoCase(sz, "THIRD")) return 3;
+ if (iupStrEqualNoCase(sz, "QUARTER")) return 4;
+ if (iupStrEqualNoCase(sz, "EIGHTH")) return 8;
+ return 0;
+}
+
+static int iDialogSetSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ ih->userwidth = 0;
+ ih->userheight = 0;
+ }
+ else
+ {
+ char *sh, sw[40];
+ strcpy(sw, value);
+ sh = strchr(sw, 'x');
+ if (!sh)
+ sh = "";
+ else
+ {
+ *sh = '\0'; /* to mark the end of sw */
+ ++sh;
+ }
+
+ {
+ int charwidth, charheight;
+ int screen_width, screen_height;
+ int wscale = iDialogSizeGetScale(sw);
+ int hscale = iDialogSizeGetScale(sh);
+
+ int width = 0, height = 0;
+ iupStrToIntInt(value, &width, &height, 'x');
+ if (width < 0) width = 0;
+ if (height < 0) height = 0;
+
+ iupdrvFontGetCharSize(ih, &charwidth, &charheight);
+
+ /* desktop size, excluding task bars and menu bars */
+ iupdrvGetScreenSize(&screen_width, &screen_height);
+
+ if (wscale)
+ width = screen_width/wscale;
+ else
+ width = iupWIDTH2RASTER(width, charwidth);
+
+ if (hscale)
+ height = screen_height/hscale;
+ else
+ height = iupHEIGHT2RASTER(height, charheight);
+
+ ih->userwidth = width;
+ ih->userheight = height;
+ }
+ }
+
+ /* must reset the current size, */
+ /* so the user or the natural size will be used to resize the dialog */
+ ih->currentwidth = 0;
+ ih->currentheight = 0;
+
+ return 0;
+}
+
+static int iDialogSetRasterSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ ih->userwidth = 0;
+ ih->userheight = 0;
+ }
+ else
+ {
+ int w = 0, h = 0;
+ iupStrToIntInt(value, &w, &h, 'x');
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ ih->userwidth = w;
+ ih->userheight = h;
+ }
+
+ /* must reset the current size also, */
+ /* so the user or the natural size will be used to resize the dialog */
+ ih->currentwidth = 0;
+ ih->currentheight = 0;
+
+ return 0;
+}
+
+static int iDialogSetVisibleAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ IupShow(ih);
+ else
+ IupHide(ih);
+ return 0;
+}
+
+void iupDialogUpdatePosition(Ihandle* ih)
+{
+ /* Used by pre-defined popup native dialogs */
+ int x = iupAttribGetInt(ih, "_IUPDLG_X");
+ int y = iupAttribGetInt(ih, "_IUPDLG_Y");
+ iupdrvDialogUpdateSize(ih);
+ /* handle always as visible for the first time */
+ ih->data->first_show = 0;
+ iupDialogAdjustPos(ih, &x, &y);
+ iupdrvDialogSetPosition(ih, x, y);
+}
+
+void iupDialogGetDecorSize(Ihandle* ih, int *decorwidth, int *decorheight)
+{
+ int border, caption, menu;
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ *decorwidth = 2*border;
+ *decorheight = 2*border + caption + menu;
+}
+
+static int iDialogSetHideTaskbarAttrib(Ihandle *ih, const char *value)
+{
+ iupdrvDialogSetVisible(ih, !iupStrBoolean(value));
+ return 0;
+}
+
+static int iDialogSetMenuAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle)
+ {
+ Ihandle* menu = IupGetHandle(value);
+ ih->data->menu = menu;
+ return 1;
+ }
+
+ if (!value)
+ {
+ if (ih->data->menu && ih->data->menu->handle)
+ {
+ ih->data->ignore_resize = 1;
+ IupUnmap(ih->data->menu); /* this will remove the menu from the dialog */
+ ih->data->ignore_resize = 0;
+
+ ih->data->menu = NULL;
+ }
+ }
+ else
+ {
+ Ihandle* menu = IupGetHandle(value);
+ if (!menu || menu->iclass->nativetype != IUP_TYPEMENU || menu->parent)
+ return 0;
+
+ /* already the current menu and it is mapped */
+ if (ih->data->menu && ih->data->menu==menu && menu->handle)
+ return 1;
+
+ /* the current menu is mapped, so unmap it */
+ if (ih->data->menu && ih->data->menu->handle && ih->data->menu!=menu)
+ {
+ ih->data->ignore_resize = 1;
+ IupUnmap(ih->data->menu); /* this will remove the menu from the dialog */
+ ih->data->ignore_resize = 0;
+ }
+
+ ih->data->menu = menu;
+
+ menu->parent = ih; /* use this to create a menu bar instead of a popup menu */
+
+ ih->data->ignore_resize = 1;
+ IupMap(menu); /* this will automatically add the menu to the dialog */
+ ih->data->ignore_resize = 0;
+ }
+ return 1;
+}
+
+
+/****************************************************************/
+
+
+Ihandle* IupDialog(Ihandle* child)
+{
+ void *params[2];
+ params[0] = child;
+ params[1] = NULL;
+ return IupCreatev("dialog", params);
+}
+
+Iclass* iupDialogGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "dialog";
+ ic->format = "H"; /* one optional ihandle */
+ ic->nativetype = IUP_TYPEDIALOG;
+ ic->childtype = IUP_CHILD_ONE;
+ ic->is_interactive = 1;
+
+ /* Class functions */
+ ic->Create = iDialogCreateMethod;
+ ic->Destroy = iDialogDestroyMethod;
+ ic->ComputeNaturalSize = iDialogComputeNaturalSizeMethod;
+ ic->SetChildrenCurrentSize = iDialogSetChildrenCurrentSizeMethod;
+ ic->SetChildrenPosition = iDialogSetChildrenPositionMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "SHOW_CB", "i");
+ iupClassRegisterCallback(ic, "DROPFILES_CB", "siii");
+ iupClassRegisterCallback(ic, "RESIZE_CB", "ii");
+ iupClassRegisterCallback(ic, "CLOSE_CB", "");
+
+ /* Common Callbacks */
+ iupBaseRegisterCommonCallbacks(ic);
+
+ /* Attribute functions */
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "SIZE", iupBaseGetSizeAttrib, iDialogSetSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, iDialogSetRasterSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "POSITION", NULL, NULL, NULL, NULL, IUPAF_WRITEONLY|IUPAF_READONLY|IUPAF_NO_INHERIT); /* forbidden in dialog */
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ /* Visual */
+ iupBaseRegisterVisualAttrib(ic);
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, iDialogSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NO_INHERIT); /* the only case where VISIBLE default is NO */
+
+ /* IupDialog only */
+ iupClassRegisterAttribute(ic, "MENU", NULL, iDialogSetMenuAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CURSOR", NULL, iupdrvBaseSetCursorAttrib, IUPAF_SAMEASSYSTEM, "ARROW", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "HIDETASKBAR", NULL, iDialogSetHideTaskbarAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MAXBOX", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MENUBOX", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MINBOX", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "RESIZE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "BORDER", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "DEFAULTENTER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DEFAULTESC", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DIALOGFRAME", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PARENTDIALOG", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHRINK", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "STARTFOCUS", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MODAL", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PLACEMENT", NULL, NULL, "NORMAL", NULL, IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "NATIVEPARENT", NULL, NULL, NULL, NULL, IUPAF_NO_STRING);
+
+ iupdrvDialogInitClass(ic);
+
+ return ic;
+}
diff --git a/iup/src/iup_dialog.h b/iup/src/iup_dialog.h
new file mode 100755
index 0000000..a127111
--- /dev/null
+++ b/iup/src/iup_dialog.h
@@ -0,0 +1,89 @@
+/** \file
+ * \brief Dialog Public and Private Declarations
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_DIALOG_H
+#define __IUP_DIALOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* PUBLIC */
+
+/* Shows the dialog in the given position and disable interaction with other dialogs.
+ * The element must be already mapped.
+ * Must return IUP_ERROR or IUP_NOERROR.
+ * Called only from IupPopup. */
+int iupDialogPopup(Ihandle* ih, int x, int y);
+
+/* Shows the dialog in the given position.
+ * The dialog must be already mapped.
+ * Must return IUP_ERROR or IUP_NOERROR.
+ * Called only from IupShow and IupShowXY. */
+int iupDialogShowXY(Ihandle* ih, int x, int y);
+
+/* Hides the dialog.
+ * Called only from IupHide. */
+void iupDialogHide(Ihandle* ih);
+
+/* Returns a unique number to be as child id. */
+int iupDialogGetChildId(Ihandle* ih);
+char* iupDialogGetChildIdStr(Ihandle* ih);
+
+/* Returns the size of the decoration */
+void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu);
+
+/* Returns the native parent. Can be PARENTDIALOG or NATIVEPARENT attributes. Parent must be mapped. */
+InativeHandle* iupDialogGetNativeParent(Ihandle* ih);
+
+/* Updates the dialog initial position from internal attributes.
+ Used mostly by the native pre-defined dialogs. */
+void iupDialogUpdatePosition(Ihandle* ih);
+
+
+/*********************************************************************/
+ /* PRIVATE */
+/*********************************************************************/
+
+#ifdef _IUPDLG_PRIVATE
+
+/* retrieve the decorations size that offsets the window size of the client size. */
+void iupDialogGetDecorSize(Ihandle* ih, int *decorwidth, int *decorheight);
+
+struct _IcontrolData
+{
+ int show_state, /* save the state to be used used in SHOW_CB */
+ first_show, /* boolean flag to indicate that the dialog was shown for the first time */
+ ignore_resize, /* flag to ignore the next resize */
+ popup_level, /* popup level of the dialog if IupPopup used */
+ child_id, /* serial number used by child controls */
+ cmd_show; /* parameters for ShowWindow in Windows driver */
+ Ihandle* menu;
+};
+
+
+/******************************/
+/* Driver dependent functions */
+/******************************/
+
+void iupdrvDialogInitClass(Iclass* iclass);
+
+void iupdrvDialogGetPosition(InativeHandle* handle, int *x, int *y);
+void iupdrvDialogSetVisible(Ihandle* ih, int visible);
+int iupdrvDialogSetPlacement(Ihandle* ih);
+void iupdrvDialogSetPosition(Ihandle *ih, int x, int y);
+void iupdrvDialogUpdateSize(Ihandle* ih);
+void iupdrvDialogGetSize(InativeHandle* handle, int *w, int *h);
+int iupdrvDialogIsVisible(Ihandle* ih);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_dlglist.c b/iup/src/iup_dlglist.c
new file mode 100755
index 0000000..c385b50
--- /dev/null
+++ b/iup/src/iup_dlglist.c
@@ -0,0 +1,130 @@
+/** \file
+ * \brief list of all created dialogs
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+
+#include "iup.h"
+
+#include "iup_dlglist.h"
+#include "iup_object.h"
+#include "iup_assert.h"
+
+
+typedef struct Idiallst_
+{
+ Ihandle *ih;
+ struct Idiallst_ *next;
+} Idiallst;
+
+static Idiallst *idlglist = NULL; /* list of all created dialogs */
+static int idlg_count = 0;
+
+void iupDlgListAdd(Ihandle *ih)
+{
+ if (ih)
+ {
+ Idiallst *p=(Idiallst *)malloc(sizeof(Idiallst));
+ if (!p)
+ return;
+ p->ih = ih;
+ p->next = idlglist;
+ idlglist = p;
+ idlg_count++;
+ }
+}
+
+void iupDlgListRemove(Ihandle *ih)
+{
+ if (!idlglist || !ih)
+ return;
+
+ if (idlglist->ih == ih) /* ih is header */
+ {
+ Idiallst *p = idlglist->next;
+ free(idlglist);
+ idlglist = p;
+ idlg_count--;
+ }
+ else
+ {
+ Idiallst *p; /* current pointer */
+ Idiallst *b; /* before pointer */
+ for (b = idlglist, p = idlglist->next; p; b = p, p = p->next)
+ {
+ if (p->ih == ih)
+ {
+ b->next = p->next;
+ free (p);
+ idlg_count--;
+ return;
+ }
+ }
+ }
+}
+
+static Idiallst *idlg_first = NULL;
+
+Ihandle *iupDlgListFirst (void)
+{
+ idlg_first = idlglist;
+ return iupDlgListNext();
+}
+
+Ihandle *iupDlgListNext (void)
+{
+ Ihandle *ih = NULL;
+ if (idlg_first)
+ {
+ ih = idlg_first->ih;
+ idlg_first = idlg_first->next;
+ }
+ return ih;
+}
+
+static int idlg_nvisiblewin = 0;
+
+void iupDlgListVisibleInc(void)
+{
+ iupASSERT(idlg_nvisiblewin < idlg_count);
+ if (idlg_nvisiblewin == idlg_count)
+ return;
+ idlg_nvisiblewin++;
+}
+
+void iupDlgListVisibleDec(void)
+{
+ iupASSERT(idlg_nvisiblewin > 0);
+ idlg_nvisiblewin--;
+}
+
+int iupDlgListVisibleCount(void)
+{
+ return idlg_nvisiblewin;
+}
+
+void iupDlgListDestroyAll(void)
+{
+ int i = 0, count;
+ Ihandle** ih_array = (Ihandle**)malloc(idlg_count * sizeof(Ihandle*));
+ Idiallst *list;
+ for (list = idlglist; list; list = list->next)
+ {
+ if (iupObjectCheck(list->ih))
+ {
+ ih_array[i] = list->ih;
+ i++;
+ }
+ }
+
+ count = i;
+ for (i = 0; i < count; i++)
+ {
+ if (iupObjectCheck(ih_array[i]))
+ IupDestroy(ih_array[i]); /* this will also destroy the list */
+ }
+
+ free(ih_array);
+}
diff --git a/iup/src/iup_dlglist.h b/iup/src/iup_dlglist.h
new file mode 100755
index 0000000..99d3184
--- /dev/null
+++ b/iup/src/iup_dlglist.h
@@ -0,0 +1,58 @@
+/** \file
+ * \brief list of all created dialogs
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_DLGLIST_H
+#define __IUP_DLGLIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup dlglist List of Dialogs
+ * \par
+ * See \ref iup_dlglist.h
+ * \ingroup cpi */
+
+
+/** Adds a dialog to the list. Used only in IupDialog.
+ * \ingroup dlglist */
+void iupDlgListAdd(Ihandle *ih);
+
+/** Removes a dialog from the list. Used only in IupDestroy.
+ * \ingroup dlglist */
+void iupDlgListRemove(Ihandle *ih);
+
+/** Starts a loop for all the created dialogs.
+ * \ingroup dlglist */
+Ihandle* iupDlgListFirst(void);
+
+/** Retrieve the next dialog on the list. Must call iupDlgListFirst first.
+ * \ingroup dlglist */
+Ihandle* iupDlgListNext(void);
+
+/** Increments the number of visible dialogs.
+ * \ingroup dlglist */
+void iupDlgListVisibleInc(void);
+
+/** Decrements the number of visible dialogs.
+ * \ingroup dlglist */
+void iupDlgListVisibleDec(void);
+
+/** Returns the number of visible dialogs.
+ * \ingroup dlglist */
+int iupDlgListVisibleCount(void);
+
+/* Destroy all dialogs and the list.
+ Called only from IupClose. */
+void iupDlgListDestroyAll(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_dll.rc b/iup/src/iup_dll.rc
new file mode 100755
index 0000000..a1c78d8
--- /dev/null
+++ b/iup/src/iup_dll.rc
@@ -0,0 +1,41 @@
+TECGRAF_ICON ICON "..\\etc\\tecgraf.ico"
+
+1 VERSIONINFO
+ FILEVERSION 3,0,0,0
+ PRODUCTVERSION 3,0,0,0
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "Comments", "www.tecgraf.puc-rio.br/iup\0"
+ 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 "OriginalFilename", "iup.dll\0"
+ VALUE "ProductName", "IUP for Windows\0"
+ VALUE "ProductVersion", "3.0.0\0"
+ END
+ END
+END
+
+CURSOR_PEN CURSOR "..\\etc\\pen.cur"
+
+/* To avoid the inclusion of <winuser.h> */
+#define WS_CHILD 0x40000000L
+#define WS_VISIBLE 0x10000000L
+#define WS_CLIPSIBLINGS 0x04000000L
+#define DS_3DLOOK 0x0004L
+#define DS_CONTROL 0x0400L
+#define SS_OWNERDRAW 0x0000000DL
+#define WS_EX_STATICEDGE 0x00020000L
+
+#define IUP_PREVIEWCANVAS 3000
+
+iupPreviewDlg DIALOG DISCARDABLE 0, 0, 250, 95
+STYLE WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | DS_3DLOOK | DS_CONTROL
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "", IUP_PREVIEWCANVAS, "STATIC", SS_OWNERDRAW, 70, 0, 120, 90, WS_EX_STATICEDGE
+END
diff --git a/iup/src/iup_drv.h b/iup/src/iup_drv.h
new file mode 100755
index 0000000..5cdb8e7
--- /dev/null
+++ b/iup/src/iup_drv.h
@@ -0,0 +1,99 @@
+/** \file
+ * \brief Driver Interface. Each driver must export the symbols defined here.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_DRV_H
+#define __IUP_DRV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup drv Driver Interface
+ * \par
+ * Each driver must export the symbols defined here.
+ * \par
+ * See \ref iup_drv.h
+ */
+
+
+/** Sets a global environment attribute. Called from IupSetGlobal and IupStoreGlobal.
+ * Must return 1 is process the atribute, or 0 is not.
+ * \ingroup drv */
+int iupdrvSetGlobal(const char* name, const char* value);
+
+/** Returns a global environment attribute. Called from IupGetGlobal.
+ * \ingroup drv */
+char* iupdrvGetGlobal(const char* name);
+
+/** Changes the idle callback. Called from IupSetFunction.
+ * \ingroup drv */
+void iupdrvSetIdleFunction(Icallback func);
+
+/** Convert the coordinates from screen relative to client area releative.
+ * \ingroup drv */
+void iupdrvScreenToClient(Ihandle* ih, int *x, int *y);
+
+/** Returns true if the element is visible.
+ * \ingroup drv */
+int iupdrvIsVisible(Ihandle* ih);
+
+/** Returns true if the element is active.
+ * \ingroup drv */
+int iupdrvIsActive(Ihandle* ih);
+
+/** Actually changes the focus to the given element.
+ * \ingroup drv */
+void iupdrvSetFocus(Ihandle* ih);
+
+/** Changes the visible state of an element.
+ * Not used for dialogs.
+ * \ingroup drv */
+void iupdrvSetVisible(Ihandle* ih, int enable);
+
+/** Changes the active state of an element.
+ * \ingroup drv */
+void iupdrvSetActive(Ihandle* ih, int enable);
+
+/** Post a redraw of a control.
+ * \ingroup drv */
+void iupdrvDisplayUpdate(Ihandle *ih);
+
+/** Force a redraw of a control.
+ * \ingroup drv */
+void iupdrvDisplayRedraw(Ihandle *ih);
+
+/** Reparent the native control.
+ * \ingroup drv */
+void iupdrvReparent(Ihandle* ih);
+
+/** Draws a focus rectangle
+ * \ingroup drv */
+void iupdrvDrawFocusRect(Ihandle* ih, void* gc, int x, int y, int w, int h);
+
+/** Size of the scroolbar.
+ * \ingroup drv */
+int iupdrvGetScrollbarSize(void);
+
+/** Activates a control.
+ * \ingroup drv */
+void iupdrvActivate(Ihandle* ih);
+
+/** Returns the height of a menu bar.
+ * \ingroup drv */
+int iupdrvMenuGetMenuBarSize(Ihandle* ih);
+
+
+/* Called only from IupOpen/IupClose. */
+int iupdrvOpen(int *argc, char ***argv);
+void iupdrvClose(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_drvfont.h b/iup/src/iup_drvfont.h
new file mode 100755
index 0000000..d6fb137
--- /dev/null
+++ b/iup/src/iup_drvfont.h
@@ -0,0 +1,116 @@
+/** \file
+ * \brief Driver Font Management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_DRVFONT_H
+#define __IUP_DRVFONT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup drvfont Driver Font Interface
+ * \par
+ * Each driver must export the symbols defined here.
+ * \par
+ * See \ref iup_drvfont.h
+ * \ingroup drv */
+
+/* Called only from IupOpen/IupClose. */
+void iupdrvFontInit(void);
+void iupdrvFontFinish(void);
+
+/** Retrieve the character size for the selected font.
+ * Should be used only to calculate the SIZE attribute.
+ * \ingroup drvfont */
+void iupdrvFontGetCharSize(Ihandle* ih, int *charwidth, int *charheight);
+
+/** Retrieve the string width for the selected font.
+ * \ingroup drvfont */
+int iupdrvFontGetStringWidth(Ihandle* ih, const char* str);
+
+/** Retrieve the multi-lined string size for the selected font. \n
+ * Width is the maximum line width. \n
+ * Height is charheight*number_of_lines (this will avoid line size variations).
+ * \ingroup drvfont */
+void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h);
+
+/** Returns the System default font.
+ * \ingroup drvfont */
+char* iupdrvGetSystemFont(void);
+
+/** STANDARDFONT attribute set function.
+ * \ingroup drvfont */
+int iupdrvSetStandardFontAttrib(Ihandle* ih, const char* value);
+
+
+
+/** FONT attribute get function.
+ * \ingroup drvfont */
+char* iupGetFontAttrib(Ihandle* ih);
+
+/** FONT attribute set function.
+ * \ingroup drvfont */
+int iupSetFontAttrib(Ihandle* ih, const char* value);
+
+/** Parse the common font format description.
+ * Returns a non zero value if successful.
+ * \ingroup drvfont */
+int iupFontParsePango(const char *value, char *typeface, int *size, int *bold, int *italic, int *underline, int *strikeout);
+
+/** Parse the old IUP Windows font format description.
+ * Returns a non zero value if successful.
+ * \ingroup drvfont */
+int iupFontParseWin(const char *value, char *fontname, int *height, int *bold, int *italic, int *underline, int *strikeout);
+
+/** Parse the X-Windows font format description.
+ * Returns a non zero value if successful.
+ * \ingroup drvfont */
+int iupFontParseX(const char *value, char *fontname, int *height, int *bold, int *italic, int *underline, int *strikeout);
+
+
+/** Changes the FONT style only.
+ * \ingroup attribfunc */
+int iupSetFontStyleAttrib(Ihandle* ih, const char* value);
+
+/** Changes the FONT size only.
+ * \ingroup attribfunc */
+int iupSetFontSizeAttrib(Ihandle* ih, const char* value);
+
+/** Returns the FONT style.
+ * \ingroup attribfunc */
+char* iupGetFontStyleAttrib(Ihandle* ih);
+
+/** Returns the FONT size.
+ * \ingroup attribfunc */
+char* iupGetFontSizeAttrib(Ihandle* ih);
+
+/** Returns the FONT face.
+ * \ingroup attribfunc */
+char* iupGetFontFaceAttrib(Ihandle* ih);
+
+/* Used in GLobal Attributes */
+void iupSetDefaultFontSizeGlobalAttrib(const char* value);
+char* iupGetDefaultFontSizeGlobalAttrib(void);
+
+
+/* Updates the STANDARDFONT attrib.
+ * Called only from IupMap.
+ */
+void iupUpdateStandardFontAttrib(Ihandle* ih);
+
+/* Used to map foreign names into native names */
+const char* iupFontGetWinName(const char* name);
+const char* iupFontGetXName(const char* name);
+const char* iupFontGetPangoName(const char* name);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_drvinfo.h b/iup/src/iup_drvinfo.h
new file mode 100755
index 0000000..7ff303f
--- /dev/null
+++ b/iup/src/iup_drvinfo.h
@@ -0,0 +1,103 @@
+/** \file
+ * \brief Driver Information Functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_DRVINFO_H
+#define __IUP_DRVINFO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup drvinfo Driver Information Interface
+ * \par
+ * Each driver must export the symbols defined here.
+ * But in this case the functions are shared by different drivers in the same system.
+ * \par
+ * For example, the GTK driver and the Windows driver share the same implementation
+ * of these functions when the GTK driver is compiled in Windows.
+ * The GTK driver and the Motif driver share the same implementation
+ * of these functions when the GTK driver is compiled in UNIX.
+ * \par
+ * See \ref iup_drvinfo.h
+ * \ingroup drv */
+
+
+/** Retrieve the main desktop full size.
+ * \ingroup drvinfo */
+void iupdrvGetFullSize(int *width, int *height);
+
+/** Retrieve the main desktop available size.
+ * \ingroup drvinfo */
+void iupdrvGetScreenSize(int *width, int *height);
+
+/** Retrieve the default desktop bits per pixel.
+ * \ingroup drvinfo */
+int iupdrvGetScreenDepth(void);
+
+/** Returns a string with the system version number.
+ * \ingroup drvinfo */
+char *iupdrvGetSystemVersion(void);
+
+/** Returns a string with the system name.
+ * \ingroup drvinfo */
+char* iupdrvGetSystemName(void);
+
+/** Returns a string with the computer name.
+ * \ingroup drvinfo */
+char* iupdrvGetComputerName(void);
+
+/** Returns a string with the user name.
+ * \ingroup drvinfo */
+char* iupdrvGetUserName(void);
+
+/** Returns the key state for Shift, Ctrl, Alt and sYs, in this order.
+ * Left and right keys are considered.
+ * Should declare "char key[5]".
+ * Values could be space (" ") or "SCAY".
+ * \ingroup drvinfo */
+void iupdrvGetKeyState(char* key);
+
+/** Returns the current position of the mouse cursor.
+ * \ingroup drvinfo */
+void iupdrvGetCursorPos(int *x, int *y);
+
+/** Returns the driver "Display" in UNIX and NULL in Windows.
+ * Must be implemented somewhere else.
+ * \ingroup drvinfo */
+void* iupdrvGetDisplay(void);
+
+/** Returns the decoration size of the native window.
+ * In Windows will also includes the menu if any.
+ * Used in DialogGetDecoration.
+ * \ingroup drvinfo */
+int iupdrvGetWindowDecor(void* wnd, int *border, int *caption);
+
+/** Returns the current directory.
+ * \ingroup drvinfo */
+char* iupdrvGetCurrentDirectory(void);
+
+/** Changes the current directory.
+ * \ingroup drvinfo */
+int iupdrvSetCurrentDirectory(const char* dir);
+
+/** Returns true if the given name is an existant file.
+ * \ingroup drvinfo */
+int iupdrvIsFile(const char* name);
+
+/** Returns true if the given name is an existant directory.
+ * \ingroup drvinfo */
+int iupdrvIsDirectory(const char* name);
+
+/** Creates a new direcotry.
+ * \ingroup drvinfo */
+int iupdrvMakeDirectory(const char* name);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_filedlg.c b/iup/src/iup_filedlg.c
new file mode 100755
index 0000000..e764143
--- /dev/null
+++ b/iup/src/iup_filedlg.c
@@ -0,0 +1,67 @@
+/** \file
+ * \brief IupFileDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_stdcontrols.h"
+
+
+Ihandle* IupFileDlg(void)
+{
+ return IupCreate("filedlg");
+}
+
+Iclass* iupFileDlgGetClass(void)
+{
+ Iclass* ic = iupClassNew(iupDialogGetClass());
+
+ ic->name = "filedlg";
+ ic->nativetype = IUP_TYPEDIALOG;
+ ic->is_interactive = 1;
+
+ iupClassRegisterCallback(ic, "FILE_CB", "ss");
+
+ /* reset not used native dialog methods */
+ ic->parent->LayoutUpdate = NULL;
+ ic->parent->SetChildrenPosition = NULL;
+ ic->parent->Map = NULL;
+ ic->parent->UnMap = NULL;
+
+ iupdrvFileDlgInitClass(ic);
+
+ /* only the default value */
+ iupClassRegisterAttribute(ic, "NOCHANGEDIR", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DIALOGTYPE", NULL, NULL, IUPAF_SAMEASSYSTEM, "OPEN", IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "PREVIEWDC", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY|IUPAF_NO_STRING);
+
+ iupClassRegisterAttribute(ic, "PREVIEWWIDTH", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "PREVIEWHEIGHT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY|IUPAF_NO_STRING);
+
+ iupClassRegisterAttribute(ic, "ALLOWNEW", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DIRECTORY", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILE", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "NOOVERWRITEPROMPT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWHIDDEN", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWPREVIEW", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "FILEEXIST", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY);
+ iupClassRegisterAttribute(ic, "STATUS", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY);
+ iupClassRegisterAttribute(ic, "VALUE", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY);
+
+ return ic;
+}
diff --git a/iup/src/iup_fill.c b/iup/src/iup_fill.c
new file mode 100755
index 0000000..4cad3c0
--- /dev/null
+++ b/iup/src/iup_fill.c
@@ -0,0 +1,242 @@
+/** \file
+ * \brief Fill Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+
+
+enum {IUP_FILL_NONE, IUP_FILL_HORIZ, IUP_FILL_VERT};
+
+struct _IcontrolData
+{
+ int dir;
+};
+
+static int iFillGetDir(Ihandle* ih)
+{
+ if (!ih->parent)
+ return IUP_FILL_NONE;
+
+ if (ih->data->dir != IUP_FILL_NONE)
+ return ih->data->dir;
+
+ /* Its parent must be an IupHbox or an IupVbox. */
+ if (ih->parent->iclass->nativetype == IUP_TYPEVOID)
+ {
+ if (iupStrEqual(ih->parent->iclass->name, "hbox"))
+ ih->data->dir = IUP_FILL_HORIZ;
+ else if (iupStrEqual(ih->parent->iclass->name, "vbox"))
+ ih->data->dir = IUP_FILL_VERT;
+ }
+
+ return ih->data->dir;
+}
+
+static int iFillMapMethod(Ihandle* ih)
+{
+ iFillGetDir(ih);
+ return iupBaseTypeVoidMapMethod(ih);
+}
+
+static void iFillUnMapMethod(Ihandle* ih)
+{
+ ih->data->dir = IUP_FILL_NONE;
+}
+
+static int iFillSetRasterSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ ih->userwidth = 0;
+ ih->userheight = 0;
+ }
+ else
+ {
+ int s = 0;
+ if (iFillGetDir(ih) == IUP_FILL_NONE) /* if Fill is not yet a child of a Vbox or Hbox */
+ {
+ iupAttribSetStr(ih, "SIZE", NULL);
+ return 1;
+ }
+
+ iupStrToInt(value, &s);
+ if (s > 0)
+ {
+ if (iFillGetDir(ih) == IUP_FILL_HORIZ)
+ {
+ ih->userwidth = s; /* inside HBOX */
+ ih->userheight = 0;
+ }
+ else
+ {
+ ih->userheight = s; /* inside VBOX */
+ ih->userwidth = 0;
+ }
+ }
+ }
+ iupAttribSetStr(ih, "SIZE", NULL);
+ return 0;
+}
+
+static int iFillSetSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ ih->userwidth = 0;
+ ih->userheight = 0;
+ }
+ else
+ {
+ int s = 0;
+ if (iFillGetDir(ih) == IUP_FILL_NONE) /* if Fill is not yet a child of a Vbox or Hbox */
+ {
+ iupAttribSetStr(ih, "RASTERSIZE", NULL);
+ return 1;
+ }
+
+ iupStrToInt(value, &s);
+ if (s > 0)
+ {
+ int charwidth, charheight;
+ iupdrvFontGetCharSize(ih, &charwidth, &charheight);
+ if (iFillGetDir(ih) == IUP_FILL_HORIZ)
+ {
+ ih->userwidth = iupWIDTH2RASTER(s, charwidth); /* inside HBOX */
+ ih->userheight = 0;
+ }
+ else
+ {
+ ih->userheight = iupHEIGHT2RASTER(s, charheight); /* inside VBOX */
+ ih->userwidth = 0;
+ }
+ }
+ }
+ iupAttribSetStr(ih, "RASTERSIZE", NULL);
+ return 1;
+}
+
+static char* iFillGetExpandAttrib(Ihandle* ih)
+{
+ if (iFillGetDir(ih) == IUP_FILL_NONE) /* if Fill is not yet a child of a Vbox or Hbox */
+ return "NO";
+
+ /* if size is not defined, then expansion on that direction is permited */
+ if (iFillGetDir(ih) == IUP_FILL_HORIZ)
+ {
+ if (ih->userwidth <= 0)
+ return "HORIZONTAL";
+ }
+ else
+ {
+ if (ih->userheight <= 0)
+ return "VERTICAL";
+ }
+
+ return "NO";
+}
+
+static void iFillUpdateSize(Ihandle* ih)
+{
+ char* value = iupAttribGet(ih, "SIZE");
+ if (value)
+ {
+ iFillSetSizeAttrib(ih, value);
+ iupAttribSetStr(ih, "SIZE", NULL);
+ }
+ value = iupAttribGet(ih, "RASTERSIZE");
+ if (value)
+ {
+ iFillSetRasterSizeAttrib(ih, value);
+ iupAttribSetStr(ih, "RASTERSIZE", NULL);
+ }
+}
+
+static void iFillComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ (void)expand; /* unset if not a container */
+
+ /* EXPAND is initialized as none for FILL */
+ ih->expand = IUP_EXPAND_NONE;
+
+ iFillUpdateSize(ih);
+
+ /* always initialize the natural size using the user size,
+ must do this again because of iFillUpdateSize */
+ ih->naturalwidth = ih->userwidth;
+ ih->naturalheight = ih->userheight;
+
+ if (iFillGetDir(ih) == IUP_FILL_NONE) /* if Fill is not a child of a Vbox or Hbox */
+ return;
+
+ /* if size is NOT defined, then expansion on that direction is permited */
+ if (iFillGetDir(ih) == IUP_FILL_HORIZ)
+ {
+ if (ih->naturalwidth <= 0)
+ ih->expand = IUP_EXPAND_W0;
+ }
+ else
+ {
+ if (ih->naturalheight <= 0)
+ ih->expand = IUP_EXPAND_H0;
+ }
+
+ *w = ih->naturalwidth;
+ *h = ih->naturalheight;
+}
+
+static int iFillCreateMethod(Ihandle* ih, void** params)
+{
+ (void)params;
+ ih->data = iupALLOCCTRLDATA();
+ return IUP_NOERROR;
+}
+
+/******************************************************************************/
+
+Ihandle* IupFill(void)
+{
+ return IupCreate("fill");
+}
+
+Iclass* iupFillGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "fill";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPEVOID;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = iFillCreateMethod;
+ ic->Map = iFillMapMethod;
+ ic->UnMap = iFillUnMapMethod;
+ ic->ComputeNaturalSize = iFillComputeNaturalSizeMethod;
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "SIZE", iupBaseGetSizeAttrib, iFillSetSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, iFillSetRasterSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ /* Base */
+ iupClassRegisterAttribute(ic, "EXPAND", iFillGetExpandAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
diff --git a/iup/src/iup_focus.c b/iup/src/iup_focus.c
new file mode 100755
index 0000000..be54b75
--- /dev/null
+++ b/iup/src/iup_focus.c
@@ -0,0 +1,281 @@
+/** \file
+ * \brief Keyboard Focus navigation
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_focus.h"
+#include "iup_class.h"
+#include "iup_assert.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+
+
+Ihandle* iupFocusNextInteractive(Ihandle *ih)
+{
+ Ihandle *c;
+
+ if (!ih)
+ return NULL;
+
+ for (c = ih->brother; c; c = c->brother)
+ {
+ if (c->iclass->is_interactive)
+ return c;
+ }
+
+ return NULL;
+}
+
+int iupFocusCanAccept(Ihandle *ih)
+{
+ if (ih->iclass->is_interactive && /* interactive */
+ iupAttribGetBoolean(ih, "CANFOCUS") && /* can receive focus */
+ ih->handle && /* mapped */
+ IupGetInt(ih, "ACTIVE") && /* active */
+ IupGetInt(ih, "VISIBLE")) /* visible */
+ return 1;
+ else
+ return 0;
+}
+
+static int iFocusCheckActiveRadio(Ihandle *ih)
+{
+ if (iupStrEqual(ih->iclass->name, "toggle") &&
+ IupGetInt(ih, "RADIO") &&
+ !IupGetInt(ih, "VALUE"))
+ return 0;
+ else
+ return 1;
+}
+
+static Ihandle* iFocusFindAtBrothers(Ihandle *start, int checkradio)
+{
+ Ihandle *c;
+ Ihandle *nf;
+
+ for (c = start; c; c = c->brother)
+ {
+ /* check itself */
+ if (iupFocusCanAccept(c) && (!checkradio || iFocusCheckActiveRadio(c)))
+ return c;
+
+ /* then check its children */
+ nf = iFocusFindAtBrothers(c->firstchild, checkradio);
+ if (nf)
+ return nf;
+ }
+
+ return NULL;
+}
+
+static Ihandle* iFocusFindNext(Ihandle *ih, int checkradio)
+{
+ Ihandle *nf, *p;
+
+ if (!ih)
+ return NULL;
+
+ /* look down in the child tree */
+ if (ih->firstchild)
+ {
+ nf = iFocusFindAtBrothers(ih->firstchild, checkradio);
+ if (nf) return nf;
+ }
+
+ /* look in the same level */
+ if (ih->brother)
+ {
+ nf = iFocusFindAtBrothers(ih->brother, checkradio);
+ if (nf) return nf;
+ }
+
+ /* look up in the brothers of the parent level */
+ if (ih->parent)
+ {
+ for (p = ih->parent; p; p = p->parent)
+ {
+ if (p->brother)
+ {
+ nf = iFocusFindAtBrothers(p->brother, checkradio);
+ if (nf) return nf;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+Ihandle* IupNextField(Ihandle *ih)
+{
+ Ihandle *ih_next;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ ih_next = iFocusFindNext(ih, 1);
+ if (!ih_next)
+ {
+ /* not found after the element, then start over from the begining,
+ at the dialog. */
+ ih_next = iFocusFindNext(IupGetDialog(ih), 1);
+ if (ih_next == ih)
+ return NULL;
+ }
+
+ if (ih_next)
+ {
+ iupdrvSetFocus(ih_next);
+ return ih_next;
+ }
+
+ return NULL;
+}
+
+void iupFocusNext(Ihandle *ih)
+{
+ Ihandle *ih_next = iFocusFindNext(ih, 0);
+ if (!ih_next)
+ {
+ /* not found after the element, then start over from the begining,
+ at the dialog. */
+ ih_next = iFocusFindNext(IupGetDialog(ih), 0);
+ if (ih_next == ih)
+ return;
+ }
+ if (ih_next)
+ iupdrvSetFocus(ih_next);
+}
+
+static int iFocusFindPrevious(Ihandle *parent, Ihandle **previous, Ihandle *ih, int checkradio)
+{
+ Ihandle *c;
+
+ if (!parent)
+ return 0;
+
+ for (c = parent->firstchild; c; c = c->brother)
+ {
+ if (c == ih)
+ {
+ /* if found child, returns the current previous.
+ but if previous is NULL, then keep searching until the last element. */
+ if (*previous)
+ return 1;
+ }
+ else
+ {
+ /* save the possible previous */
+ if (iupFocusCanAccept(c) && (!checkradio || iFocusCheckActiveRadio(c)))
+ *previous = c;
+ }
+
+ /* then check its children */
+ if (iFocusFindPrevious(c, previous, ih, checkradio))
+ return 1;
+ }
+
+ return 0;
+}
+
+Ihandle* IupPreviousField(Ihandle *ih)
+{
+ Ihandle *previous = NULL;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+
+ /* search from the dialog down to the element */
+ iFocusFindPrevious(IupGetDialog(ih), &previous, ih, 1);
+
+ if (previous)
+ {
+ iupdrvSetFocus(previous);
+ return previous;
+ }
+
+ return NULL;
+}
+
+void iupFocusPrevious(Ihandle *ih)
+{
+ Ihandle *previous = NULL;
+
+ /* search from the dialog down to the element */
+ iFocusFindPrevious(IupGetDialog(ih), &previous, ih, 0);
+
+ if (previous)
+ iupdrvSetFocus(previous);
+}
+
+/* local variables */
+static Ihandle* iup_current_focus = NULL;
+
+Ihandle *IupSetFocus(Ihandle *ih)
+{
+ Ihandle* old_focus = iup_current_focus;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return old_focus;
+
+ /* iup_current_focus is NOT set here,
+ only in the iupCallGetFocusCb */
+
+ if (iupFocusCanAccept(ih))
+ iupdrvSetFocus(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 */
+ return;
+
+ cb = (Icallback)IupGetCallback(ih, "GETFOCUS_CB");
+ if (cb) cb(ih);
+
+ if (ih->iclass->nativetype == IUP_TYPECANVAS)
+ {
+ IFni cb2 = (IFni)IupGetCallback(ih, "FOCUS_CB");
+ if (cb2) cb2(ih, 1);
+ }
+
+ iup_current_focus = ih;
+}
+
+void iupCallKillFocusCb(Ihandle *ih)
+{
+ Icallback cb;
+
+ if (ih != iup_current_focus) /* avoid duplicate messages */
+ return;
+
+ cb = IupGetCallback(ih, "KILLFOCUS_CB");
+ if (cb) cb(ih);
+
+ if (ih->iclass->nativetype == IUP_TYPECANVAS)
+ {
+ IFni cb2 = (IFni)IupGetCallback(ih, "FOCUS_CB");
+ if (cb2) cb2(ih, 0);
+ }
+
+ iup_current_focus = NULL;
+}
diff --git a/iup/src/iup_focus.h b/iup/src/iup_focus.h
new file mode 100755
index 0000000..239e233
--- /dev/null
+++ b/iup/src/iup_focus.h
@@ -0,0 +1,53 @@
+/** \file
+ * \brief Keyboard Focus navigation
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_FOCUS_H
+#define __IUP_FOCUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup focus Keyboard Focus
+ * \par
+ * See \ref iup_focus.h
+ * \ingroup cpi */
+
+
+/** Utility to check if a control can have the keyboard input focus.
+ * To receive the focus must be interactive, has CANFOCUS=YES, is mapped, is visible and is active.
+ * \ingroup focus */
+int iupFocusCanAccept(Ihandle *ih);
+
+/** Call GETFOCUS_CB and FOCUS_CB.
+ * \ingroup focus */
+void iupCallGetFocusCb(Ihandle *ih);
+
+/** Call KILLFOCUS_CB and FOCUS_CB.
+ * \ingroup focus */
+void iupCallKillFocusCb(Ihandle *ih);
+
+/** Returns the next interactive brother. Independs if it can receive the focus.
+ * \ingroup focus */
+Ihandle* iupFocusNextInteractive(Ihandle *ih);
+
+/* Used only in iupKeyProcessNavigation */
+void iupFocusNext(Ihandle *ih);
+void iupFocusPrevious(Ihandle *ih);
+
+
+/* Other functions declared in <iup.h> and implemented here.
+IupPreviousField
+IupNextField
+*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_font.c b/iup/src/iup_font.c
new file mode 100755
index 0000000..869bd2a
--- /dev/null
+++ b/iup/src/iup_font.c
@@ -0,0 +1,714 @@
+/** \file
+ * \brief Font mapping
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_drvfont.h"
+#include "iup_assert.h"
+#include "iup_attrib.h"
+#include "iup_class.h"
+
+typedef struct _IfontNameMap {
+ const char* pango;
+ const char* x;
+ const char* win;
+} IfontNameMap;
+
+#define IFONT_NAME_MAP_SIZE 7
+
+static IfontNameMap ifont_name_map[IFONT_NAME_MAP_SIZE] = {
+ {"sans", "helvetica", "arial"},
+ {NULL, "new century schoolbook", "century schoolbook"},
+ {"monospace", "courier", "courier new"},
+ {NULL, "lucida", "lucida sans unicode"},
+ {NULL, "lucidabright", "lucida bright"},
+ {NULL, "lucidatypewriter", "lucida console"},
+ {"serif", "times", "times new roman"}
+};
+
+const char* iupFontGetPangoName(const char* name)
+{
+ int i;
+ if (!name)
+ return NULL;
+ for (i=0; i<IFONT_NAME_MAP_SIZE; i++)
+ {
+ if (iupStrEqualNoCase(ifont_name_map[i].win, name))
+ return ifont_name_map[i].pango;
+ if (iupStrEqualNoCase(ifont_name_map[i].x, name))
+ return ifont_name_map[i].pango;
+ }
+
+ return NULL;
+}
+
+const char* iupFontGetWinName(const char* name)
+{
+ int i;
+ if (!name)
+ return NULL;
+ for (i=0; i<IFONT_NAME_MAP_SIZE; i++)
+ {
+ if (iupStrEqualNoCase(ifont_name_map[i].pango, name))
+ return ifont_name_map[i].win;
+ if (iupStrEqualNoCase(ifont_name_map[i].x, name))
+ return ifont_name_map[i].win;
+ }
+
+ return NULL;
+}
+
+const char* iupFontGetXName(const char* name)
+{
+ int i;
+ if (!name)
+ return NULL;
+ for (i=0; i<IFONT_NAME_MAP_SIZE; i++)
+ {
+ if (iupStrEqualNoCase(ifont_name_map[i].win, name))
+ return ifont_name_map[i].x;
+ if (iupStrEqualNoCase(ifont_name_map[i].pango, name))
+ return ifont_name_map[i].x;
+ }
+
+ return NULL;
+}
+
+char *IupUnMapFont(const char *standardfont)
+{
+ int size = 0;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ char typeface[1024];
+ char *str, *iup_typeface, *iup_style;
+
+ iupASSERT(standardfont!=NULL);
+ if (!standardfont)
+ return NULL;
+
+ if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return NULL;
+
+ if (strstr(typeface, "Helvetica"))
+ iup_typeface = "HELVETICA_";
+ else if (strstr(typeface, "Courier"))
+ iup_typeface = "COURIER_";
+ else if (strstr(typeface, "Times"))
+ iup_typeface = "TIMES_";
+ else
+ return NULL;
+
+ if (!is_bold && !is_italic)
+ iup_style = "NORMAL_";
+ else if (!is_bold && is_italic)
+ iup_style = "ITALIC_";
+ else if (is_bold && !is_italic)
+ iup_style = "BOLD_";
+ else
+ return NULL;
+
+ str = iupStrGetMemory(1024);
+ sprintf(str, "%s%s%d", iup_typeface, iup_style, size);
+ return str;
+}
+
+static char* iFontGetStyle(const char* iupfont, int *size)
+{
+ char* style = NULL;
+
+ if (strstr(iupfont, "NORMAL_"))
+ {
+ style = "";
+ iupfont += strlen("NORMAL_");
+ }
+ else if (strstr(iupfont, "ITALIC_"))
+ {
+ style = "Italic";
+ iupfont += strlen("ITALIC_");
+ }
+ else if (strstr(iupfont, "BOLD_"))
+ {
+ style = "Bold";
+ iupfont += strlen("BOLD_");
+ }
+ else
+ return NULL;
+
+ *size = atoi(iupfont);
+ return style;
+}
+
+char *IupMapFont(const char *iupfont)
+{
+ int size = 0;
+ char *str, *typeface, *style;
+
+ iupASSERT(iupfont!=NULL);
+ if (!iupfont)
+ return NULL;
+
+ if (strstr(iupfont, "HELVETICA_"))
+ {
+ typeface = "Helvetica";
+ style = iFontGetStyle(iupfont+strlen("HELVETICA_"), &size);
+ if (!style || size==0)
+ return NULL;
+ }
+ else if (strstr(iupfont, "COURIER_"))
+ {
+ typeface = "Courier";
+ style = iFontGetStyle(iupfont+strlen("COURIER_"), &size);
+ if (!style || size==0)
+ return NULL;
+ }
+ else if (strstr(iupfont, "TIMES_"))
+ {
+ typeface = "Times";
+ style = iFontGetStyle(iupfont+strlen("TIMES_"), &size);
+ if (!style || size==0)
+ return NULL;
+ }
+ else
+ return NULL;
+
+ str = iupStrGetMemory(1024);
+ sprintf(str, "%s, %s %d", typeface, style, size);
+ return str;
+}
+
+int iupSetFontAttrib(Ihandle* ih, const char* value)
+{
+ /* when set FONT can be an OLD IUP Font or a Native font */
+ const char* standardfont = IupMapFont(value);
+ if (!standardfont)
+ standardfont = value;
+
+ IupStoreAttribute(ih, "STANDARDFONT", standardfont);
+ return 0;
+}
+
+char* iupGetFontAttrib(Ihandle* ih)
+{
+ return iupAttribGetStr(ih, "STANDARDFONT");
+}
+
+void iupUpdateStandardFontAttrib(Ihandle* ih)
+{
+ int inherit;
+ iupClassObjectSetAttribute(ih, "STANDARDFONT", iupGetFontAttrib(ih), &inherit);
+}
+
+char* iupGetFontFaceAttrib(Ihandle* ih)
+{
+ int size = 0;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ char typeface[1024];
+ char *str;
+ char* standardfont;
+
+ standardfont = iupGetFontAttrib(ih);
+
+ /* parse the old Windows format first */
+ if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return NULL;
+ }
+ }
+
+ str = iupStrGetMemory(50);
+ sprintf(str, "%s", typeface);
+ return str;
+}
+
+char* iupGetFontSizeAttrib(Ihandle* ih)
+{
+ int size = 0;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ char typeface[1024];
+ char *str;
+ char* standardfont;
+
+ standardfont = iupGetFontAttrib(ih);
+
+ /* parse the old Windows format first */
+ if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return NULL;
+ }
+ }
+
+ str = iupStrGetMemory(50);
+ sprintf(str, "%d", size);
+ return str;
+}
+
+int iupSetFontSizeAttrib(Ihandle* ih, const char* value)
+{
+ int size = 0;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ char typeface[1024];
+ char new_standardfont[1024];
+ char* standardfont;
+
+ if (!value)
+ return 0;
+
+ standardfont = iupGetFontAttrib(ih);
+
+ /* parse the old Windows format first */
+ if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return 0;
+ }
+ }
+
+ sprintf(new_standardfont, "%s, %s%s%s%s%s", typeface, is_bold?"Bold ":"", is_italic?"Italic ":"", is_underline?"Underline ":"", is_strikeout?"Strikeout ":"", value);
+ IupStoreAttribute(ih, "STANDARDFONT", new_standardfont);
+
+ return 0;
+}
+
+void iupSetDefaultFontSizeGlobalAttrib(const char* value)
+{
+ int size = 0;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ char typeface[1024];
+ char new_standardfont[1024];
+ char* standardfont;
+
+ if (!value)
+ return;
+
+ standardfont = IupGetGlobal("DEFAULTFONT");
+
+ /* parse the old Windows format first */
+ if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return;
+ }
+ }
+
+ sprintf(new_standardfont, "%s, %s%s%s%s%s", typeface, is_bold?"Bold ":"", is_italic?"Italic ":"", is_underline?"Underline ":"", is_strikeout?"Strikeout ":"", value);
+ IupStoreGlobal("DEFAULTFONT", new_standardfont);
+
+ return;
+}
+
+char* iupGetDefaultFontSizeGlobalAttrib(void)
+{
+ int size = 0;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ char typeface[1024];
+ char *str;
+ char* standardfont;
+
+ standardfont = IupGetGlobal("DEFAULTFONT");
+
+ /* parse the old Windows format first */
+ if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return NULL;
+ }
+ }
+
+ str = iupStrGetMemory(50);
+ sprintf(str, "%d", size);
+ return str;
+}
+
+char* iupGetFontStyleAttrib(Ihandle* ih)
+{
+ int size = 0;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ char typeface[1024];
+ char *str;
+ char* standardfont;
+
+ standardfont = iupGetFontAttrib(ih);
+
+ /* parse the old Windows format first */
+ if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return NULL;
+ }
+ }
+
+ str = iupStrGetMemory(200);
+ sprintf(str, "%s%s%s%s", is_bold?"Bold ":"", is_italic?"Italic ":"", is_underline?"Underline ":"", is_strikeout?"Strikeout ":"");
+ return str;
+}
+
+int iupSetFontStyleAttrib(Ihandle* ih, const char* value)
+{
+ int size = 0;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ char typeface[1024];
+ char new_standardfont[1024];
+ char* standardfont;
+
+ if (!value)
+ return 0;
+
+ standardfont = iupGetFontAttrib(ih);
+
+ /* parse the old Windows format first */
+ if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return 0;
+ }
+ }
+
+ sprintf(new_standardfont, "%s, %s %d", typeface, value, size);
+ IupStoreAttribute(ih, "STANDARDFONT", new_standardfont);
+
+ return 0;
+}
+
+/**************************************************************/
+/* Native Font Format, compatible with Pango Font Description */
+/**************************************************************/
+
+/*
+The string contains the font name, the style and the size.
+Style can be a free combination of some names separated by spaces.
+Font name can be a list of font family names separated by comma.
+*/
+
+#define isspace(_x) (_x == ' ')
+
+enum { /* style */
+ FONT_PLAIN = 0,
+ FONT_BOLD = 1,
+ FONT_ITALIC = 2,
+ FONT_UNDERLINE = 4,
+ FONT_STRIKEOUT = 8
+};
+
+static int iFontFindStyleName(const char *name, int len, int *style)
+{
+#define STYLE_NUM_NAMES 21
+ static struct { const char* name; int style; } cd_style_names[STYLE_NUM_NAMES] = {
+ {"Normal", 0},
+ {"Oblique", FONT_ITALIC},
+ {"Italic", FONT_ITALIC},
+ {"Small-Caps", 0},
+ {"Ultra-Light", 0},
+ {"Light", 0},
+ {"Medium", 0},
+ {"Semi-Bold", FONT_BOLD},
+ {"Bold", FONT_BOLD},
+ {"Ultra-Bold", FONT_BOLD},
+ {"Heavy", 0},
+ {"Ultra-Condensed",0},
+ {"Extra-Condensed",0},
+ {"Condensed", 0},
+ {"Semi-Condensed", 0},
+ {"Semi-Expanded", 0},
+ {"Expanded", 0},
+ {"Extra-Expanded", 0},
+ {"Ultra-Expanded", 0},
+ {"Underline", FONT_UNDERLINE},
+ {"Strikeout", FONT_STRIKEOUT}
+ };
+
+ int i;
+ for (i = 0; i < STYLE_NUM_NAMES; i++)
+ {
+ if (strncmp(cd_style_names[i].name, name, len)==0)
+ {
+ *style = cd_style_names[i].style;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static const char * iFontGetWord(const char *str, const char *last, int *wordlen)
+{
+ const char *result;
+
+ while (last > str && isspace(*(last - 1)))
+ last--;
+
+ result = last;
+ while (result > str && !isspace(*(result - 1)))
+ result--;
+
+ *wordlen = last - result;
+
+ return result;
+}
+
+int iupFontParsePango(const char *standardfont, char *typeface, int *size, int *bold, int *italic, int *underline, int *strikeout)
+{
+ const char *p, *last;
+ int len, wordlen, style = 0;
+
+ if (standardfont[0] == '-') /* X font, abort */
+ return 0;
+
+ len = (int)strlen(standardfont);
+ last = standardfont + len;
+ p = iFontGetWord(standardfont, last, &wordlen);
+
+ /* Look for a size at the end of the string */
+ if (wordlen != 0)
+ {
+ int new_size = atoi(p);
+ if (new_size != 0)
+ {
+ *size = new_size;
+ last = p;
+ }
+ }
+
+ /* Now parse style words */
+ p = iFontGetWord(standardfont, last, &wordlen);
+ while (wordlen != 0)
+ {
+ int new_style = 0;
+
+ if (!iFontFindStyleName(p, wordlen, &new_style))
+ break;
+ else
+ {
+ style |= new_style;
+
+ last = p;
+ p = iFontGetWord(standardfont, last, &wordlen);
+ }
+ }
+
+ *bold = 0;
+ *italic = 0;
+ *underline = 0;
+ *strikeout = 0;
+
+ if (style&FONT_BOLD)
+ *bold = 1;
+ if (style&FONT_ITALIC)
+ *italic = 1;
+ if (style&FONT_UNDERLINE)
+ *underline = 1;
+ if (style&FONT_STRIKEOUT)
+ *strikeout = 1;
+
+ /* Remainder is font family list. */
+
+ /* Trim off trailing white space */
+ while (last > standardfont && isspace(*(last - 1)))
+ last--;
+
+ /* Trim off trailing commas */
+ if (last > standardfont && *(last - 1) == ',')
+ last--;
+
+ /* Again, trim off trailing white space */
+ while (last > standardfont && isspace(*(last - 1)))
+ last--;
+
+ /* Trim off leading white space */
+ while (last > standardfont && isspace(*standardfont))
+ standardfont++;
+
+ if (standardfont != last)
+ {
+ len = (last - standardfont);
+ strncpy(typeface, standardfont, len);
+ typeface[len] = 0;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int iupFontParseWin(const char *value, char *fontname, int *height, int *bold, int *italic, int *underline, int *strikeout)
+{
+ int c;
+
+ if (value[0] == '-') /* X font, abort */
+ return 0;
+
+ if (strstr(value, ":") == NULL)
+ return 0;
+
+ if (value[0] == ':') /* check if it has the typeface */
+ value++; /* jump separator */
+ else
+ {
+ c = (int)strcspn(value, ":"); /* extract typeface */
+ if (c == 0) return 0;
+ strncpy(fontname, value, c);
+ fontname[c]='\0';
+ value += c+1; /* jump typeface and separator */
+ }
+
+ *bold = 0;
+ *italic = 0;
+ *underline = 0;
+ *strikeout = 0;
+
+ if (value[0] == ':') /* check if it has attributes */
+ value++; /* jump separator */
+ else
+ {
+ do /* extract style (bold/italic etc) */
+ {
+ char style[30];
+
+ c = (int)strcspn(value, ":,");
+ if (c == 0)
+ break;
+
+ strncpy(style, value, c);
+ style[c] = '\0';
+
+ if(iupStrEqual(style, "BOLD"))
+ *bold = 1;
+ else if(iupStrEqual(style,"ITALIC"))
+ *italic = 1;
+ else if(iupStrEqual(style,"UNDERLINE"))
+ *underline = 1;
+ else if(iupStrEqual(style,"STRIKEOUT"))
+ *strikeout = 1;
+
+ value += c; /* jump only the attribute */
+
+ if(value[0] == ':') /* end of attribute list */
+ {
+ value++;
+ break;
+ }
+
+ value++; /* jump separator */
+ } while (value[0]);
+ }
+
+ /* extract size in points */
+ if (!iupStrToInt(value, height))
+ return 0;
+
+ if (height == 0)
+ return 0;
+
+ return 1;
+}
+
+int iupFontParseX(const char *standardfont, char *typeface, int *size, int *bold, int *italic, int *underline, int *strikeout)
+{
+ char style1[30], style2[30];
+ char* token;
+ char font[1024];
+
+ if (standardfont[0] != '-')
+ return 0;
+
+ strcpy(font, standardfont+1); /* skip first '-' */
+
+ *bold = 0;
+ *italic = 0;
+ *underline = 0;
+ *strikeout = 0;
+
+ /* fndry */
+ token = strtok(font, "-");
+ if (!token) return 0;
+
+ /* fmly */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ strcpy(typeface, token);
+
+ /* wght */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ strcpy(style1, token);
+ if (strstr("bold", style1))
+ *bold = 1;
+
+ /* slant */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ strcpy(style2, token);
+ if (*style2 == 'i' || *style2 == 'o')
+ *italic = 1;
+
+ /* sWdth */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ /* adstyl */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+
+ /* pxlsz */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ *size = -atoi(token); /* size in pixels */
+
+ if (*size < 0)
+ return 1;
+
+ /* ptSz */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ *size = atoi(token)/10; /* size in deci-points */
+
+ if (*size > 0)
+ return 1;
+
+ return 0;
+}
+
diff --git a/iup/src/iup_fontdlg.c b/iup/src/iup_fontdlg.c
new file mode 100755
index 0000000..9e0f05c
--- /dev/null
+++ b/iup/src/iup_fontdlg.c
@@ -0,0 +1,48 @@
+/** \file
+ * \brief IupFontDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_stdcontrols.h"
+
+
+Ihandle* IupFontDlg(void)
+{
+ return IupCreate("fontdlg");
+}
+
+Iclass* iupFontDlgGetClass(void)
+{
+ Iclass* ic = iupClassNew(iupDialogGetClass());
+
+ ic->name = "fontdlg";
+ ic->nativetype = IUP_TYPEDIALOG;
+ ic->is_interactive = 1;
+
+ /* reset not used native dialog methods */
+ ic->parent->LayoutUpdate = NULL;
+ ic->parent->SetChildrenPosition = NULL;
+ ic->parent->Map = NULL;
+ ic->parent->UnMap = NULL;
+
+ /* IupFontDialog only */
+ iupClassRegisterAttribute(ic, "STATUS", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY);
+ iupClassRegisterAttribute(ic, "VALUE", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ iupdrvFontDlgInitClass(ic);
+
+ return ic;
+}
diff --git a/iup/src/iup_frame.c b/iup/src/iup_frame.c
new file mode 100755
index 0000000..e1d0a13
--- /dev/null
+++ b/iup/src/iup_frame.c
@@ -0,0 +1,165 @@
+/** \file
+ * \brief Frame Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_frame.h"
+
+
+int iupFrameGetTitleHeight(Ihandle* ih)
+{
+ int charheight;
+ iupdrvFontGetCharSize(ih, NULL, &charheight);
+ return charheight;
+}
+
+static void iFrameGetDecorSize(Ihandle* ih, int *width, int *height)
+{
+ *width = 5;
+ *height = 5;
+
+ if (iupAttribGet(ih, "_IUPFRAME_HAS_TITLE") || iupAttribGet(ih, "TITLE"))
+ {
+ (*height) += iupFrameGetTitleHeight(ih);
+ }
+}
+
+static char* iFrameGetClientSizeAttrib(Ihandle* ih)
+{
+ int width, height, decorwidth, decorheight;
+ char* str = iupStrGetMemory(20);
+ width = ih->currentwidth;
+ height = ih->currentheight;
+ iFrameGetDecorSize(ih, &decorwidth, &decorheight);
+ width -= decorwidth;
+ height -= decorheight;
+ if (width < 0) width = 0;
+ if (height < 0) height = 0;
+ sprintf(str, "%dx%d", width, height);
+ return str;
+}
+
+static int iFrameCreateMethod(Ihandle* ih, void** params)
+{
+ if (params)
+ {
+ Ihandle** iparams = (Ihandle**)params;
+ if (*iparams)
+ IupAppend(ih, *iparams);
+ }
+
+ return IUP_NOERROR;
+}
+
+static void iFrameComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ int decorwidth, decorheight;
+ Ihandle* child = ih->firstchild;
+
+ iFrameGetDecorSize(ih, &decorwidth, &decorheight);
+ *w = decorwidth;
+ *h = decorheight;
+
+ if (child)
+ {
+ /* update child natural size first */
+ iupBaseComputeNaturalSize(child);
+
+ *expand = child->expand;
+ *w += child->naturalwidth;
+ *h += child->naturalheight;
+ }
+}
+
+static void iFrameSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink)
+{
+ int width, height, decorwidth, decorheight;
+
+ iFrameGetDecorSize(ih, &decorwidth, &decorheight);
+
+ width = ih->currentwidth-decorwidth;
+ height = ih->currentheight-decorheight;
+ if (width < 0) width = 0;
+ if (height < 0) height = 0;
+
+ iupBaseSetCurrentSize(ih->firstchild, width, height, shrink);
+}
+
+static void iFrameSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ /* IupFrame is the native parent of its children,
+ so the position is restarted at (0,0) */
+
+ iupdrvFrameGetDecorOffset(ih, &x, &y);
+
+ /* Child coordinates are relative to client left-top corner. */
+ iupBaseSetPosition(ih->firstchild, x, y);
+}
+
+
+/******************************************************************************/
+
+
+Ihandle* IupFrame(Ihandle* child)
+{
+ void *params[2];
+ params[0] = (void*)child;
+ params[1] = NULL;
+ return IupCreatev("frame", params);
+}
+
+Iclass* iupFrameGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "frame";
+ ic->format = "H"; /* one optional ihandle */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILD_ONE;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = iFrameCreateMethod;
+
+ ic->ComputeNaturalSize = iFrameComputeNaturalSizeMethod;
+ ic->SetChildrenCurrentSize = iFrameSetChildrenCurrentSizeMethod;
+ ic->SetChildrenPosition = iFrameSetChildrenPositionMethod;
+
+ ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Common Callbacks */
+ iupClassRegisterCallback(ic, "MAP_CB", "");
+ iupClassRegisterCallback(ic, "UNMAP_CB", "");
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Visual */
+ iupBaseRegisterVisualAttrib(ic);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", iFrameGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ /* IupFrame only */
+ iupClassRegisterAttribute(ic, "SUNKEN", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ iupdrvFrameInitClass(ic);
+
+ return ic;
+}
diff --git a/iup/src/iup_frame.h b/iup/src/iup_frame.h
new file mode 100755
index 0000000..a7fd520
--- /dev/null
+++ b/iup/src/iup_frame.h
@@ -0,0 +1,22 @@
+/** \file
+ * \brief Frame Control Private Declarations
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_FRAME_H
+#define __IUP_FRAME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void iupdrvFrameInitClass(Iclass* ic);
+void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y);
+int iupFrameGetTitleHeight(Ihandle* ih);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_func.c b/iup/src/iup_func.c
new file mode 100755
index 0000000..76683c7
--- /dev/null
+++ b/iup/src/iup_func.c
@@ -0,0 +1,78 @@
+/** \file
+ * \brief function table manager
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_table.h"
+#include "iup_func.h"
+#include "iup_drv.h"
+#include "iup_assert.h"
+
+
+static Itable *ifunc_table = NULL; /* the function hast table indexed by the name string */
+static const char *ifunc_action_name = NULL; /* name of the action being retrieved in IupGetFunction */
+
+void iupFuncInit(void)
+{
+ ifunc_table = iupTableCreate(IUPTABLE_STRINGINDEXED);
+}
+
+void iupFuncFinish(void)
+{
+ iupTableDestroy(ifunc_table);
+ ifunc_table = NULL;
+}
+
+const char *IupGetActionName(void)
+{
+ return ifunc_action_name;
+}
+
+Icallback IupGetFunction(const char *name)
+{
+ void* value;
+ Icallback func;
+
+ iupASSERT(name!=NULL);
+ if (!name)
+ return NULL;
+
+ ifunc_action_name = name; /* store the retrieved name */
+
+ func = (Icallback)iupTableGetFunc(ifunc_table, name, &value);
+
+ /* if not defined and not the idle, then check for the DEFAULT_ACTION */
+ if (!func && !iupStrEqual(name, "IDLE_ACTION"))
+ func = (Icallback)iupTableGetFunc(ifunc_table, "DEFAULT_ACTION", &value);
+
+ return func;
+}
+
+Icallback IupSetFunction(const char *name, Icallback func)
+{
+ void* value;
+ Icallback old_func;
+
+ iupASSERT(name!=NULL);
+ if (!name)
+ return NULL;
+
+ old_func = (Icallback)iupTableGetFunc(ifunc_table, name, &value);
+
+ if (!func)
+ iupTableRemove(ifunc_table, name);
+ else
+ iupTableSetFunc(ifunc_table, name, (Ifunc)func);
+
+ /* notifies the driver if changing the Idle */
+ if (iupStrEqual(name, "IDLE_ACTION"))
+ iupdrvSetIdleFunction(func);
+
+ return old_func;
+}
diff --git a/iup/src/iup_func.h b/iup/src/iup_func.h
new file mode 100755
index 0000000..8372163
--- /dev/null
+++ b/iup/src/iup_func.h
@@ -0,0 +1,28 @@
+/** \file
+ * \brief Global Function table.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_FUNC_H
+#define __IUP_FUNC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* called only in IupOpen and IupClose */
+void iupFuncInit(void);
+void iupFuncFinish(void);
+
+/* Other functions declared in <iup.h> and implemented here.
+IupGetActionName
+IupGetFunction
+IupSetFunction
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_getparam.c b/iup/src/iup_getparam.c
new file mode 100755
index 0000000..1418aa5
--- /dev/null
+++ b/iup/src/iup_getparam.c
@@ -0,0 +1,1254 @@
+/** \file
+ * \brief IupGetParam
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include "iup.h"
+
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_strmessage.h"
+#include "iup_drvfont.h"
+
+
+#define RAD2DEG 57.296f /* radians to degrees */
+
+
+/*******************************************************************************************
+ Internal Callbacks
+*******************************************************************************************/
+
+static int iParamButtonOK_CB(Ihandle* self)
+{
+ Ihandle* dlg = IupGetDialog(self);
+ Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB");
+ iupAttribSetStr(dlg, "STATUS", "1");
+ if (cb && !cb(dlg, -1, (void*)iupAttribGet(dlg, "USER_DATA")))
+ return IUP_DEFAULT;
+ else
+ return IUP_CLOSE;
+}
+
+static int iParamButtonCancel_CB(Ihandle* self)
+{
+ Ihandle* dlg = IupGetDialog(self);
+ Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB");
+ iupAttribSetStr(dlg, "STATUS", "0");
+ if (cb) cb(dlg, -3, (void*)iupAttribGet(dlg, "USER_DATA"));
+ return IUP_CLOSE;
+}
+
+static int iParamToggleAction_CB(Ihandle *self, int v)
+{
+ Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM");
+ Ihandle* dlg = IupGetDialog(self);
+ Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB");
+ int old_v = iupAttribGetInt(param, "VALUE");
+
+ if (v == 1)
+ iupAttribSetStr(param, "VALUE", "1");
+ else
+ iupAttribSetStr(param, "VALUE", "0");
+
+ if (cb && !cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA")))
+ {
+ /* Undo */
+ if (old_v == 1)
+ {
+ iupAttribSetStr(param, "VALUE", "1");
+ IupSetAttribute(self, "VALUE", "1");
+ }
+ else
+ {
+ iupAttribSetStr(param, "VALUE", "0");
+ IupSetAttribute(self, "VALUE", "0");
+ }
+
+ /* there is no IUP_IGNORE for IupToggle */
+ return IUP_DEFAULT;
+ }
+
+ /* update the interface */
+ if (v == 1)
+ IupStoreAttribute(self, "TITLE", iupAttribGet(param, "_IUPGP_TRUE"));
+ else
+ IupStoreAttribute(self, "TITLE", iupAttribGet(param, "_IUPGP_FALSE"));
+
+ return IUP_DEFAULT;
+}
+
+static int iParamTextAction_CB(Ihandle *self, int c, char *after)
+{
+ Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM");
+ Ihandle* dlg = IupGetDialog(self);
+ Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB");
+ Ihandle* aux = (Ihandle*)iupAttribGet(param, "AUXCONTROL");
+ (void)c;
+
+ iupAttribStoreStr(param, "VALUE", after);
+
+ if (cb && !cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA")))
+ {
+ /* Undo */
+ iupAttribStoreStr(param, "VALUE", IupGetAttribute(self, "VALUE"));
+ return IUP_IGNORE;
+ }
+
+ if (aux)
+ {
+ if (iupStrEqual(iupAttribGet(param, "TYPE"), "COLOR"))
+ IupStoreAttribute(aux, "BGCOLOR", after);
+ else
+ IupStoreAttribute(aux, "VALUE", after);
+ }
+
+ if (IupGetInt(self, "SPIN"))
+ {
+ if (iupAttribGet(self, "_IUPGP_SPINREAL"))
+ {
+ float min = iupAttribGetFloat(param, "MIN");
+ float step = iupAttribGetFloat(self, "_IUPGP_INCSTEP");
+ float val;
+ if (iupStrToFloat(after, &val))
+ IupSetfAttribute(self, "SPINVALUE", "%d", (int)((val-min)/step + 0.5));
+ }
+ else
+ {
+ int val;
+ if (iupStrToInt(after, &val))
+ IupSetfAttribute(self, "SPINVALUE", "%d", val);
+ }
+ }
+
+ return IUP_DEFAULT;
+}
+
+static int iParamValAction_CB(Ihandle *self)
+{
+ Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM");
+ Ihandle* text = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_TEXT");
+ Ihandle* dlg = IupGetDialog(self);
+ Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB");
+ float old_value = iupAttribGetFloat(param, "VALUE");
+ float val = IupGetFloat(self, "VALUE");
+
+ char* type = iupAttribGet(param, "TYPE");
+ if (iupStrEqual(type, "INTEGER"))
+ {
+ iupAttribSetStrf(param, "VALUE", "%d", (int)val);
+ }
+ else
+ {
+ if (iupAttribGetInt(param, "ANGLE"))
+ {
+ float old_angle;
+
+ if (val == 0)
+ {
+ old_angle = iupAttribGetFloat(param, "VALUE");
+ iupAttribSetStrf(param, "_IUPGP_OLD_ANGLE", "%g", old_angle);
+ }
+ else
+ old_angle = iupAttribGetFloat(param, "_IUPGP_OLD_ANGLE");
+
+ val = old_angle + val*RAD2DEG;
+
+ if (iupAttribGetInt(param, "INTERVAL"))
+ {
+ float min = iupAttribGetFloat(param, "MIN");
+ float max = iupAttribGetFloat(param, "MAX");
+ if (val < min)
+ val = min;
+ if (val > max)
+ val = max;
+ }
+ else if (iupAttribGetInt(param, "PARTIAL"))
+ {
+ float min = iupAttribGetFloat(param, "MIN");
+ if (val < min)
+ val = min;
+ }
+ }
+
+ iupAttribSetStrf(param, "VALUE", "%g", val);
+ }
+
+ if (cb && !cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA")))
+ {
+ /* Undo */
+ iupAttribSetStrf(param, "VALUE", "%g", old_value);
+
+ if (!iupAttribGetInt(param, "ANGLE"))
+ IupSetfAttribute(self, "VALUE", "%g", old_value);
+
+ /* there is no IUP_IGNORE for IupVal */
+ return IUP_DEFAULT;
+ }
+
+ type = iupAttribGet(param, "TYPE");
+ if (iupStrEqual(type, "INTEGER"))
+ IupSetfAttribute(text, "VALUE", "%d", (int)val);
+ else
+ IupSetfAttribute(text, "VALUE", "%g", val);
+
+ if (IupGetInt(text, "SPIN"))
+ {
+ if (iupAttribGet(text, "_IUPGP_SPINREAL"))
+ {
+ float min = iupAttribGetFloat(param, "MIN");
+ float step = iupAttribGetFloat(text, "_IUPGP_INCSTEP");
+ float val = IupGetFloat(text, "VALUE");
+ IupSetfAttribute(text, "SPINVALUE", "%d", (int)((val-min)/step + 0.5));
+ }
+ else
+ {
+ int val = IupGetInt(text, "VALUE");
+ IupSetfAttribute(text, "SPINVALUE", "%d", val);
+ }
+ }
+
+ return IUP_DEFAULT;
+}
+
+static int iParamListAction_CB(Ihandle *self, char *t, int i, int v)
+{
+ (void)t;
+ if (v == 1)
+ {
+ Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM");
+ Ihandle* dlg = IupGetDialog(self);
+ Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB");
+ int old_i = iupAttribGetInt(param, "VALUE");
+
+ iupAttribSetStrf(param, "VALUE", "%d", i-1);
+
+ if (cb && !cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA")))
+ {
+ /* Undo */
+ iupAttribSetStrf(param, "VALUE", "%d", old_i);
+ IupSetfAttribute(self, "VALUE", "%d", old_i+1);
+
+ /* there is no IUP_IGNORE for IupList */
+ return IUP_DEFAULT;
+ }
+ }
+
+ return IUP_DEFAULT;
+}
+
+static int iParamFileButton_CB(Ihandle *self)
+{
+ Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM");
+ Ihandle* textbox = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_TEXT");
+
+ Ihandle* dlg = IupFileDlg();
+
+ IupSetAttributeHandle(dlg, "PARENTDIALOG", IupGetDialog(self));
+ IupSetAttribute(dlg, "TITLE", iupAttribGet(param, "TITLE"));
+ IupSetAttribute(dlg, "VALUE", iupAttribGet(param, "VALUE"));
+
+ IupSetAttribute(dlg, "DIALOGTYPE", iupAttribGet(param, "_IUPGP_DIALOGTYPE"));
+ IupSetAttribute(dlg, "FILTER", iupAttribGet(param, "_IUPGP_FILTER"));
+ IupSetAttribute(dlg, "DIRECTORY", iupAttribGet(param, "_IUPGP_DIRECTORY"));
+ IupSetAttribute(dlg, "NOCHANGEDIR", iupAttribGet(param, "_IUPGP_NOCHANGEDIR"));
+ IupSetAttribute(dlg, "NOOVERWRITEPROMPT", iupAttribGet(param, "_IUPGP_NOOVERWRITEPROMPT"));
+
+ IupPopup(dlg, IUP_CENTER, IUP_CENTER);
+
+ if (IupGetInt(dlg, "STATUS") != -1)
+ {
+ IupSetAttribute(textbox, "VALUE", iupAttribGet(dlg, "VALUE"));
+ iupAttribStoreStr(param, "VALUE", iupAttribGet(dlg, "VALUE"));
+ }
+
+ IupDestroy(dlg);
+
+ return IUP_DEFAULT;
+}
+
+static int iParamColorButton_CB(Ihandle *self, int button, int pressed)
+{
+ if (button==IUP_BUTTON1 && pressed)
+ {
+ Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM");
+ Ihandle* textbox = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_TEXT");
+
+ Ihandle* dlg = IupColorDlg();
+
+ IupSetAttributeHandle(dlg, "PARENTDIALOG", IupGetDialog(self));
+ IupSetAttribute(dlg, "TITLE", iupAttribGet(param, "TITLE"));
+ IupSetAttribute(dlg, "VALUE", iupAttribGet(param, "VALUE"));
+
+ IupPopup(dlg, IUP_CENTER, IUP_CENTER);
+
+ if (IupGetInt(dlg, "STATUS") != -1)
+ {
+ char* value = IupGetAttribute(dlg, "VALUE");
+ IupSetAttribute(textbox, "VALUE", value);
+ iupAttribStoreStr(param, "VALUE", value);
+ IupStoreAttribute(self, "BGCOLOR", value);
+ }
+
+ IupDestroy(dlg);
+ }
+
+ return IUP_DEFAULT;
+}
+
+static int iParamSpinReal_CB(Ihandle *self, int pos)
+{
+ Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM");
+ Ihandle* dlg = IupGetDialog(self);
+ Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB");
+ Ihandle* text = (Ihandle*)iupAttribGet(param, "CONTROL");
+ float min = iupAttribGetFloat(param, "MIN");
+ float max = iupAttribGetFloat(param, "MAX");
+ float val, step = iupAttribGetFloat(text, "_IUPGP_INCSTEP");
+
+ /* here spin is always [0-spinmax] converted to [min-max] */
+ val = (float)pos*step + min;
+ if (val < min)
+ val = min;
+ if (val > max)
+ val = max;
+
+ iupAttribSetStrf(param, "VALUE", "%g", (double)val);
+
+ if (cb)
+ {
+ int ret;
+ iupAttribSetStr(dlg, "SPINNING", "1");
+ ret = cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA"));
+ iupAttribSetStr(dlg, "SPINNING", NULL);
+ if (!ret)
+ return IUP_IGNORE;
+ }
+
+ IupSetfAttribute(text, "VALUE", "%g", (double)val);
+
+ {
+ Ihandle* aux = (Ihandle*)iupAttribGet(param, "AUXCONTROL");
+ if (aux)
+ IupSetfAttribute(aux, "VALUE", "%g", (double)val);
+ }
+
+ return IUP_DEFAULT;
+}
+
+static int iParamSpinInt_CB(Ihandle *self, int pos)
+{
+ Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM");
+ Ihandle* dlg = IupGetDialog(self);
+ Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB");
+ Ihandle* text = (Ihandle*)iupAttribGet(param, "CONTROL");
+
+ /* here spin is always [min-max] */
+
+ iupAttribSetInt(param, "VALUE", pos);
+
+ if (cb)
+ {
+ int ret;
+ iupAttribSetStr(dlg, "SPINNING", "1");
+ ret = cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA"));
+ iupAttribSetStr(dlg, "SPINNING", NULL);
+ if (!ret)
+ return IUP_IGNORE;
+ }
+
+ IupSetfAttribute(text, "VALUE", "%g", (double)pos);
+
+ {
+ Ihandle* aux = (Ihandle*)iupAttribGet(param, "AUXCONTROL");
+ if (aux)
+ IupSetfAttribute(aux, "VALUE", "%g", (double)pos);
+ }
+
+ return IUP_DEFAULT;
+}
+
+/*******************************************************************************************
+ Creates One Parameter Box
+*******************************************************************************************/
+
+static Ihandle* iParamCreateBox(Ihandle* param)
+{
+ Ihandle *box, *ctrl = NULL, *label;
+ char *type;
+
+ label = IupLabel(iupAttribGet(param, "TITLE"));
+
+ type = iupAttribGet(param, "TYPE");
+ if (iupStrEqual(type, "SEPARATOR"))
+ {
+ box = IupHbox(label, NULL);
+ IupSetAttribute(box,"ALIGNMENT","ACENTER");
+ }
+ else
+ {
+ if (iupStrEqual(type, "STRING") && iupAttribGetInt(param, "MULTILINE"))
+ {
+ Ihandle* hbox1 = IupHbox(IupSetAttributes(IupFill(), "SIZE=5"), label, NULL);
+ IupSetAttribute(hbox1,"ALIGNMENT","ACENTER");
+
+ box = IupVbox(hbox1, NULL);
+ IupSetAttribute(box,"ALIGNMENT","ALEFT");
+ }
+ else
+ {
+ box = IupHbox(IupSetAttributes(IupFill(), "SIZE=5"), label, NULL);
+ IupSetAttribute(box,"ALIGNMENT","ACENTER");
+ }
+ }
+
+ IupSetAttribute(box,"MARGIN","0x0");
+
+ type = iupAttribGet(param, "TYPE");
+ if (iupStrEqual(type, "BOOLEAN"))
+ {
+ int value = iupAttribGetInt(param, "VALUE");
+ if (value)
+ {
+ ctrl = IupToggle(iupAttribGet(param, "_IUPGP_TRUE"), NULL);
+ IupSetAttribute(ctrl, "VALUE", "ON");
+ }
+ else
+ {
+ ctrl = IupToggle(iupAttribGet(param, "_IUPGP_FALSE"), NULL);
+ IupSetAttribute(ctrl, "VALUE", "OFF");
+ }
+ IupSetCallback(ctrl, "ACTION", (Icallback)iParamToggleAction_CB);
+
+ IupAppend(box, ctrl);
+ iupAttribSetStr(param, "DATA_TYPE", "1");
+ }
+ else if (iupStrEqual(type, "SEPARATOR"))
+ {
+ ctrl = IupLabel("");
+ IupSetAttribute(ctrl, "SEPARATOR", "HORIZONTAL");
+
+ IupAppend(box, ctrl);
+ iupAttribSetStr(param, "DATA_TYPE", "-1");
+ }
+ else if (iupStrEqual(type, "LIST"))
+ {
+ char str[20] = "1";
+ int i = 1;
+ ctrl = IupList(NULL);
+ IupSetCallback(ctrl, "ACTION", (Icallback)iParamListAction_CB);
+ IupSetAttribute(ctrl, "DROPDOWN", "YES");
+ IupSetfAttribute(ctrl, "VALUE", "%d", iupAttribGetInt(param, "VALUE")+1);
+
+ while (*iupAttribGet(param, str) != 0)
+ {
+ IupStoreAttribute(ctrl, str, iupAttribGet(param, str));
+ i++;
+ sprintf(str, "%d", i);
+ }
+ IupStoreAttribute(ctrl, str, NULL);
+
+ IupAppend(box, ctrl);
+ iupAttribSetStr(param, "DATA_TYPE", "1");
+ }
+ else if (iupStrEqual(type, "STRING"))
+ {
+ if (iupAttribGetInt(param, "MULTILINE"))
+ {
+ Ihandle* hbox;
+
+ ctrl = IupMultiLine(NULL);
+ IupSetAttribute(ctrl, "SIZE", "100x50");
+ IupSetAttribute(ctrl, "EXPAND", "YES");
+
+ hbox = IupHbox(IupSetAttributes(IupFill(), "SIZE=5"), ctrl, NULL);
+ IupSetAttribute(hbox,"ALIGNMENT","ACENTER");
+
+ IupAppend(box, hbox);
+ }
+ else
+ {
+ ctrl = IupText(NULL);
+ IupSetAttribute(ctrl, "SIZE", "100x");
+ IupSetAttribute(ctrl, "EXPAND", "HORIZONTAL");
+ IupAppend(box, ctrl);
+ }
+ IupSetCallback(ctrl, "ACTION", (Icallback)iParamTextAction_CB);
+ IupStoreAttribute(ctrl, "VALUE", iupAttribGet(param, "VALUE"));
+
+ {
+ char* mask = iupAttribGet(param, "MASK");
+ if (mask)
+ IupStoreAttribute(ctrl, "MASK", mask);
+ }
+
+ iupAttribSetStr(param, "DATA_TYPE", "0");
+ iupAttribSetStr(param, "EXPAND", "1");
+ }
+ else if (iupStrEqual(type, "FILE"))
+ {
+ Ihandle* aux;
+
+ ctrl = IupText(NULL);
+ IupSetAttribute(ctrl, "SIZE", "100x");
+ IupSetAttribute(ctrl, "EXPAND", "HORIZONTAL");
+ IupAppend(box, ctrl);
+
+ IupSetCallback(ctrl, "ACTION", (Icallback)iParamTextAction_CB);
+ IupStoreAttribute(ctrl, "VALUE", iupAttribGet(param, "VALUE"));
+
+ iupAttribSetStr(param, "DATA_TYPE", "0");
+ iupAttribSetStr(param, "EXPAND", "1");
+
+
+ aux = IupButton("...", "");
+ IupSetAttribute(aux, "EXPAND", "NO");
+
+ IupSetCallback(aux, "ACTION", (Icallback)iParamFileButton_CB);
+ iupAttribSetStr(aux, "_IUPGP_PARAM", (char*)param);
+ iupAttribSetStr(aux, "_IUPGP_TEXT", (char*)ctrl);
+ IupSetAttribute(aux, "EXPAND", "NO");
+
+ IupAppend(box, aux);
+ }
+ else if (iupStrEqual(type, "COLOR"))
+ {
+ Ihandle* aux;
+
+ ctrl = IupText(NULL);
+ IupSetAttribute(ctrl, "SIZE", "100x");
+ IupSetAttribute(ctrl, "EXPAND", "HORIZONTAL");
+ IupAppend(box, ctrl);
+
+ IupSetCallback(ctrl, "ACTION", (Icallback)iParamTextAction_CB);
+ IupSetAttribute(ctrl, "MASK", "(/d|/d/d|1/d/d|2(0|1|2|3|4)/d|25(0|1|2|3|4|5)) (/d|/d/d|1/d/d|2(0|1|2|3|4)/d|25(0|1|2|3|4|5)) (/d|/d/d|1/d/d|2(0|1|2|3|4)/d|25(0|1|2|3|4|5)) (/d|/d/d|1/d/d|2(0|1|2|3|4)/d|25(0|1|2|3|4|5))");
+ IupStoreAttribute(ctrl, "VALUE", iupAttribGet(param, "VALUE"));
+
+ iupAttribSetStr(param, "DATA_TYPE", "0");
+ iupAttribSetStr(param, "EXPAND", "1");
+
+
+ aux = IupCanvas(NULL);
+ IupSetAttribute(aux, "SIZE", "20x10");
+ IupSetAttribute(aux, "EXPAND", "NO");
+ IupStoreAttribute(aux, "BGCOLOR", iupAttribGet(param, "VALUE"));
+
+ IupSetCallback(aux, "BUTTON_CB", (Icallback)iParamColorButton_CB);
+ iupAttribSetStr(param, "AUXCONTROL", (char*)aux);
+ iupAttribSetStr(aux, "_IUPGP_PARAM", (char*)param);
+ iupAttribSetStr(aux, "_IUPGP_TEXT", (char*)ctrl);
+ IupSetAttribute(aux, "EXPAND", "NO");
+
+ IupAppend(box, aux);
+ }
+ else /* INTEGER, REAL */
+ {
+ ctrl = IupText(NULL);
+ IupSetCallback(ctrl, "ACTION", (Icallback)iParamTextAction_CB);
+ IupStoreAttribute(ctrl, "VALUE", iupAttribGet(param, "VALUE"));
+
+ type = iupAttribGet(param, "TYPE");
+ if (iupStrEqual(type, "REAL"))
+ {
+ if (iupAttribGetInt(param, "INTERVAL"))
+ {
+ float min = iupAttribGetFloat(param, "MIN");
+ float max = iupAttribGetFloat(param, "MAX");
+ 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);
+
+ /* here spin is always [0-spinmax] converted to [min-max] */
+
+ IupSetAttribute(ctrl, "SPIN", "YES"); /* spin only for intervals */
+ IupSetAttribute(ctrl, "SPINAUTO", "NO");
+ IupAppend(box, ctrl);
+ IupSetCallback(ctrl, "SPIN_CB", (Icallback)iParamSpinReal_CB);
+ /* SPINMIN=0 and SPININC=1 */
+ IupSetfAttribute(ctrl, "SPINMAX", "%d", (int)((max-min)/step + 0.5));
+ IupSetfAttribute(ctrl, "SPINVALUE", "%d", (int)((val-min)/step + 0.5));
+
+ iupAttribSetStrf(ctrl, "_IUPGP_INCSTEP", "%g", step);
+ iupAttribSetStr(ctrl, "_IUPGP_SPINREAL", "1");
+ }
+ else if (iupAttribGetInt(param, "PARTIAL"))
+ {
+ float min = iupAttribGetFloat(param, "MIN");
+ if (min == 0)
+ IupSetAttribute(ctrl, "MASK", IUP_MASK_UFLOAT);
+ else
+ IupSetfAttribute(ctrl, "MASKFLOAT", "%f:%f", (double)min, (double)1.0e10);
+ IupAppend(box, ctrl);
+ }
+ else
+ {
+ IupSetAttribute(ctrl, "MASK", IUP_MASK_FLOAT);
+ IupAppend(box, ctrl);
+ }
+
+ iupAttribSetStr(param, "DATA_TYPE", "2");
+ IupSetAttribute(ctrl, "SIZE", "50x");
+ }
+ else /* INTEGER*/
+ {
+ int val = iupAttribGetInt(param, "VALUE");
+ IupSetAttribute(ctrl, "SPIN", "YES"); /* spin always */
+ IupSetAttribute(ctrl, "SPINAUTO", "NO"); /* manually update spin so the callback can also updated it */
+ IupAppend(box, ctrl);
+ IupSetCallback(ctrl, "SPIN_CB", (Icallback)iParamSpinInt_CB);
+ iupAttribSetStr(ctrl, "_IUPGP_INCSTEP", "1");
+ IupSetfAttribute(ctrl, "SPINVALUE", "%d", val);
+
+ /* here spin is always [min-max] */
+
+ if (iupAttribGetInt(param, "INTERVAL"))
+ {
+ int min = iupAttribGetInt(param, "MIN");
+ int max = iupAttribGetInt(param, "MAX");
+ int step = iupAttribGetInt(param, "STEP");
+ if (step)
+ {
+ iupAttribSetStrf(ctrl, "_IUPGP_INCSTEP", "%d", step);
+ IupSetfAttribute(ctrl, "SPININC", "%d", step);
+ }
+ IupSetfAttribute(ctrl, "SPINMAX", "%d", max);
+ IupSetfAttribute(ctrl, "SPINMIN", "%d", min);
+ }
+ else if (iupAttribGetInt(param, "PARTIAL"))
+ {
+ int min = iupAttribGetInt(param, "MIN");
+ if (min == 0)
+ IupSetAttribute(ctrl, "MASK", IUP_MASK_UINT);
+ else
+ IupSetfAttribute(ctrl, "MASKINT", "%d:2147483647", min);
+ IupSetfAttribute(ctrl, "SPINMIN", "%d", min);
+ IupSetAttribute(ctrl, "SPINMAX", "2147483647");
+ }
+ else
+ {
+ IupSetAttribute(ctrl, "SPINMIN", "-2147483647");
+ IupSetAttribute(ctrl, "SPINMAX", "2147483647");
+ IupSetAttribute(ctrl, "MASK", IUP_MASK_INT);
+ }
+
+ iupAttribSetStr(param, "DATA_TYPE", "1");
+ IupSetAttribute(ctrl, "SIZE", "50x");
+ }
+
+ if (iupAttribGetInt(param, "INTERVAL") || iupAttribGetInt(param, "ANGLE"))
+ {
+ Ihandle* aux;
+
+ if (iupAttribGetInt(param, "ANGLE"))
+ {
+ aux = IupCreatep("dial", "HORIZONTAL", NULL);
+ if (aux)
+ {
+ IupSetfAttribute(aux, "VALUE", "%g", (double)(iupAttribGetFloat(param, "VALUE")/RAD2DEG));
+ IupSetAttribute(aux, "SIZE", "50x10");
+ }
+ }
+ else
+ {
+ char* step;
+ aux = IupVal("HORIZONTAL");
+ IupStoreAttribute(aux, "MIN", iupAttribGet(param, "MIN"));
+ IupStoreAttribute(aux, "MAX", iupAttribGet(param, "MAX"));
+ IupStoreAttribute(aux, "VALUE", iupAttribGet(param, "VALUE"));
+ IupSetAttribute(aux, "EXPAND", "HORIZONTAL");
+ iupAttribSetStr(param, "AUXCONTROL", (char*)aux);
+ iupAttribSetStr(param, "EXPAND", "1");
+ step = iupAttribGet(param, "STEP");
+ if (step)
+ IupSetfAttribute(aux, "STEP", "%g", iupAttribGetFloat(param, "STEP")/(iupAttribGetFloat(param, "MAX")-iupAttribGetFloat(param, "MIN")));
+ else if (iupStrEqual(type, "INTEGER"))
+ IupSetfAttribute(aux, "STEP", "%g", 1.0/(iupAttribGetFloat(param, "MAX")-iupAttribGetFloat(param, "MIN")));
+ }
+
+ if (aux)
+ {
+ IupSetCallback(aux, "VALUECHANGED_CB", (Icallback)iParamValAction_CB);
+ iupAttribSetStr(aux, "_IUPGP_PARAM", (char*)param);
+ iupAttribSetStr(aux, "_IUPGP_TEXT", (char*)ctrl);
+
+ IupAppend(box, aux);
+ }
+ }
+ }
+
+ if (ctrl) IupStoreAttribute(ctrl, "TIP", iupAttribGet(param, "TIP"));
+ iupAttribSetStr(box, "_IUPGP_PARAM", (char*)param);
+ iupAttribSetStr(param, "CONTROL", (char*)ctrl);
+ iupAttribSetStr(param, "LABEL", (char*)label);
+ return box;
+}
+
+/*******************************************************************************************
+ Creates the Dialog and Normalize Sizes
+*******************************************************************************************/
+
+static Ihandle* IupParamDlgP(Ihandle** params)
+{
+ Ihandle *dlg, *button_ok, *button_cancel,
+ *dlg_box, *button_box, *param_box;
+ int i, lbl_width, p, expand;
+
+ button_ok = IupButton("OK", NULL);
+ IupSetAttribute(button_ok, "PADDING", "20x0");
+ IupSetCallback(button_ok, "ACTION", (Icallback)iParamButtonOK_CB);
+
+ button_cancel = IupButton(iupStrMessageGet("IUP_CANCEL"), NULL);
+ IupSetAttribute(button_cancel, "PADDING", "20x0");
+ IupSetCallback(button_cancel, "ACTION", (Icallback)iParamButtonCancel_CB);
+
+ param_box = IupVbox(NULL);
+
+ i = 0; expand = 0;
+ while (params[i] != NULL)
+ {
+ IupAppend(param_box, iParamCreateBox(params[i]));
+
+ if (IupGetInt(params[i], "EXPAND"))
+ expand = 1;
+
+ i++;
+ }
+
+ button_box = IupHbox(
+ IupFill(),
+ button_ok,
+ button_cancel,
+ NULL);
+ IupSetAttribute(button_box,"MARGIN","0x0");
+ IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL");
+
+ dlg_box = IupVbox(
+ IupFrame(param_box),
+ button_box,
+ NULL);
+ IupSetAttribute(dlg_box, "MARGIN", "10x10");
+ IupSetAttribute(dlg_box, "GAP", "5");
+
+ dlg = IupDialog(dlg_box);
+
+ IupSetAttribute(dlg, "MINBOX", "NO");
+ IupSetAttribute(dlg, "MAXBOX", "NO");
+ if (!expand)
+ {
+ IupSetAttribute(dlg, "RESIZE", "NO");
+ IupSetAttribute(dlg, "DIALOGFRAME", "YES");
+ IupSetAttribute(dlg,"DIALOGHINT","YES");
+ }
+ IupSetAttributeHandle(dlg, "DEFAULTENTER", button_ok);
+ IupSetAttributeHandle(dlg, "DEFAULTESC", button_cancel);
+ IupSetAttribute(dlg, "TITLE", "ParamDlg");
+ IupSetAttribute(dlg, "PARENTDIALOG", IupGetGlobal("PARENTDIALOG"));
+ IupSetAttribute(dlg, "ICON", IupGetGlobal("ICON"));
+ iupAttribSetStr(dlg, "OK", (char*)button_ok);
+ iupAttribSetStr(dlg, "CANCEL", (char*)button_cancel);
+
+ IupMap(dlg);
+
+ /* get the largest label size and set INDEX */
+ i = 0; lbl_width = 0, p = 0;
+ while (params[i] != NULL)
+ {
+ int w;
+
+ char* type = iupAttribGet(params[i], "TYPE");
+ if (!iupStrEqual(type, "SEPARATOR"))
+ {
+ char str[20];
+ sprintf(str, "PARAM%d", p);
+ IupSetAttribute(dlg, str, (char*)params[i]);
+ iupAttribSetStrf(params[i], "INDEX", "%d", p);
+ p++;
+ }
+
+ w = IupGetInt((Ihandle*)iupAttribGet(params[i], "LABEL"), "SIZE");
+ if (w > lbl_width)
+ lbl_width = w;
+
+ i++;
+ }
+
+ i = 0;
+ while (params[i] != NULL)
+ {
+ char* type = iupAttribGet(params[i], "TYPE");
+ if (!iupStrEqual(type, "SEPARATOR"))
+ {
+ if (iupStrEqual(type, "LIST"))
+ {
+ /* set a minimum size for lists */
+ Ihandle* ctrl = (Ihandle*)iupAttribGet(params[i], "CONTROL");
+ if (IupGetInt(ctrl, "SIZE") < 50)
+ IupSetAttribute(ctrl, "SIZE", "50x");
+ }
+ else if (iupStrEqual(type, "BOOLEAN"))
+ {
+ /* reserve enough space for boolean strings */
+ Ihandle* ctrl = (Ihandle*)iupAttribGet(params[i], "CONTROL");
+ int wf = iupdrvFontGetStringWidth(ctrl, iupAttribGet(params[i], "_IUPGP_FALSE"));
+ int wt = iupdrvFontGetStringWidth(ctrl, iupAttribGet(params[i], "_IUPGP_TRUE"));
+ int w = IupGetInt(ctrl, "SIZE");
+ int v = IupGetInt(ctrl, "VALUE");
+ if (v) /* True */
+ {
+ int box = w - wt;
+ wf += box;
+ if (wf > w)
+ IupSetfAttribute(ctrl, "SIZE", "%dx", wf+8);
+ }
+ else
+ {
+ int box = w - wf;
+ wt += box;
+ if (wt > w)
+ IupSetfAttribute(ctrl, "SIZE", "%dx", wt+8);
+ }
+ }
+
+ IupSetfAttribute((Ihandle*)iupAttribGet(params[i], "LABEL"), "SIZE", "%dx", lbl_width);
+ }
+
+ i++;
+ }
+
+ IupSetAttribute(dlg, "SIZE", NULL);
+
+ return dlg;
+}
+
+/*******************************************************************************************
+ Parameter String Parsing
+*******************************************************************************************/
+
+static char* iParamGetNextStrItem(char* line, char sep, int *count)
+{
+ int i = 0;
+
+ while (line[i] != '\n' && line[i] != 0)
+ {
+ if (line[i] == sep)
+ {
+ line[i] = 0;
+ *count = i+1;
+ return line;
+ }
+
+ i++;
+ }
+
+ /* last item may not have the separator */
+ line[i] = 0;
+ *count = i;
+ return line;
+}
+
+static void iParamSetBoolNames(char* extra, Ihandle* param)
+{
+ char *falsestr = NULL, *truestr = NULL;
+ int count;
+
+ if (extra)
+ {
+ falsestr = iParamGetNextStrItem(extra, ',', &count); extra += count;
+ truestr = iParamGetNextStrItem(extra, ',', &count);
+ }
+
+ if (falsestr && truestr)
+ {
+ iupAttribStoreStr(param, "_IUPGP_TRUE", truestr);
+ iupAttribStoreStr(param, "_IUPGP_FALSE", falsestr);
+ }
+ else
+ {
+/* iupAttribStoreStr(param, "_IUPGP_TRUE", iupStrMessageGet("IUP_TRUE")); */
+/* iupAttribStoreStr(param, "_IUPGP_FALSE", iupStrMessageGet("IUP_FALSE")); */
+ iupAttribStoreStr(param, "_IUPGP_TRUE", "");
+ iupAttribStoreStr(param, "_IUPGP_FALSE", "");
+ }
+}
+
+static void iParamSetInterval(char* extra, Ihandle* param)
+{
+ char *min, *max, *step;
+ int count;
+
+ if (!extra)
+ return;
+
+ min = iParamGetNextStrItem(extra, ',', &count); extra += count;
+ max = iParamGetNextStrItem(extra, ',', &count); extra += count;
+ step = iParamGetNextStrItem(extra, ',', &count);
+
+ if (max[0])
+ {
+ iupAttribSetStr(param, "INTERVAL", "1");
+ iupAttribStoreStr(param, "MIN", min);
+ iupAttribStoreStr(param, "MAX", max);
+ if (step[0])
+ iupAttribStoreStr(param, "STEP", step);
+ }
+ else
+ {
+ iupAttribSetStr(param, "PARTIAL", "1");
+ iupAttribStoreStr(param, "MIN", min);
+ }
+}
+
+static void iParamSetFileOptions(char* extra, Ihandle* param)
+{
+ char *type, *filter, *directory, *nochangedir, *nooverwriteprompt;
+ int count;
+
+ if (!extra)
+ return;
+
+ type = iParamGetNextStrItem(extra, '|', &count); extra += count;
+ filter = iParamGetNextStrItem(extra, '|', &count); extra += count;
+ directory = iParamGetNextStrItem(extra, '|', &count); extra += count;
+ nochangedir = iParamGetNextStrItem(extra, '|', &count); extra += count;
+ nooverwriteprompt = iParamGetNextStrItem(extra, '|', &count); extra += count;
+
+ iupAttribStoreStr(param, "_IUPGP_DIALOGTYPE", type);
+ iupAttribStoreStr(param, "_IUPGP_FILTER", filter);
+ iupAttribStoreStr(param, "_IUPGP_DIRECTORY", directory);
+ iupAttribStoreStr(param, "_IUPGP_NOCHANGEDIR", nochangedir);
+ iupAttribStoreStr(param, "_IUPGP_NOOVERWRITEPROMPT", nooverwriteprompt);
+}
+
+static void iParamSetListItems(char* extra, Ihandle* param)
+{
+ int d = 1, count;
+ char str[20], *item;
+
+ if (!extra)
+ return;
+
+ item = iParamGetNextStrItem(extra, '|', &count); extra += count;
+ while (*item)
+ {
+ sprintf(str, "%d", d);
+ iupAttribStoreStr(param, str, item);
+
+ item = iParamGetNextStrItem(extra, '|', &count); extra += count;
+ d++;
+ }
+
+ sprintf(str, "%d", d);
+ iupAttribSetStr(param, str, "");
+}
+
+static char* iParamGetStrExtra(char* line, char start, char end, int *count)
+{
+ int i = 0, end_pos = -1;
+
+ if (*line != start)
+ {
+ *count = 0;
+ return NULL;
+ }
+ line++; /* skip start */
+
+ while (line[i] != '\n' && line[i] != 0)
+ {
+ if (line[i] == end)
+ end_pos = i;
+
+ i++;
+ }
+
+ if (end_pos != -1)
+ {
+ line[end_pos] = 0;
+ *count = 1+end_pos+1;
+ return line;
+ }
+ else
+ {
+ *count = 0;
+ return NULL;
+ }
+}
+
+static int iParamCopyStrLine(char* line, const char* format)
+{
+ int i = 0;
+ while (format[i] != '\n' && format[i] != 0)
+ {
+ line[i] = format[i];
+ i++;
+ if (i > 4094) /* to avoid being bigger than the local array */
+ break;
+ }
+ line[i] = '\n';
+ line[i+1] = 0;
+ return i+1;
+}
+
+char iupGetParamType(const char* format, int *line_size)
+{
+ char* type = strchr(format, '%');
+ char* line_end = strchr(format, '\n');
+ if (line_end)
+ *line_size = line_end-format+1;
+ if (type)
+ return *(type+1);
+ else
+ return 0;
+}
+
+static Ihandle *IupParamf(const char* format, int *line_size)
+{
+ Ihandle* param;
+ char line[4096];
+ char* line_ptr = &line[0], *title, type, *tip, *extra, *mask;
+ int count;
+
+ *line_size = iParamCopyStrLine(line, format);
+
+ title = iParamGetNextStrItem(line_ptr, '%', &count); line_ptr += count;
+ param = IupUser();
+ iupAttribStoreStr(param, "TITLE", title);
+
+ type = *line_ptr;
+ line_ptr++;
+
+ switch(type)
+ {
+ case 'b':
+ iupAttribSetStr(param, "TYPE", "BOOLEAN");
+ iupAttribSetStr(param, "DATA_TYPE", "1"); /* integer */
+ extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count;
+ iParamSetBoolNames(extra, param);
+ break;
+ case 'l':
+ iupAttribSetStr(param, "TYPE", "LIST");
+ iupAttribSetStr(param, "DATA_TYPE", "1"); /* integer */
+ extra = iParamGetStrExtra(line_ptr, '|', '|', &count); line_ptr += count;
+ iParamSetListItems(extra, param);
+ break;
+ case 'a':
+ iupAttribSetStr(param, "TYPE", "REAL");
+ iupAttribSetStr(param, "DATA_TYPE", "2"); /* real */
+ iupAttribSetStr(param, "ANGLE", "1");
+ extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count;
+ iParamSetInterval(extra, param);
+ break;
+ case 'm':
+ iupAttribSetStr(param, "MULTILINE", "1");
+ /* continue */
+ case 's':
+ iupAttribSetStr(param, "TYPE", "STRING");
+ iupAttribSetStr(param, "DATA_TYPE", "0"); /* string */
+ mask = iParamGetNextStrItem(line_ptr, '{', &count);
+ if (*mask)
+ iupAttribStoreStr(param, "MASK", mask);
+ line_ptr += count-1; /* ignore the fake separator */
+ line_ptr[0] = '{'; /* restore possible separator */
+ break;
+ case 'i':
+ iupAttribSetStr(param, "TYPE", "INTEGER");
+ iupAttribSetStr(param, "DATA_TYPE", "1"); /* integer */
+ extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count;
+ iParamSetInterval(extra, param);
+ break;
+ case 'r':
+ iupAttribSetStr(param, "TYPE", "REAL");
+ iupAttribSetStr(param, "DATA_TYPE", "2"); /* real */
+ extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count;
+ iParamSetInterval(extra, param);
+ break;
+ case 'f':
+ iupAttribSetStr(param, "TYPE", "FILE");
+ iupAttribSetStr(param, "DATA_TYPE", "0"); /* string */
+ extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count;
+ iParamSetFileOptions(extra, param);
+ break;
+ case 'c':
+ iupAttribSetStr(param, "TYPE", "COLOR");
+ iupAttribSetStr(param, "DATA_TYPE", "0"); /* string */
+ break;
+ case 't':
+ iupAttribSetStr(param, "TYPE", "SEPARATOR");
+ iupAttribSetStr(param, "DATA_TYPE", "-1"); /* NONE */
+ break;
+ default:
+ return NULL;
+ }
+
+ tip = iParamGetStrExtra(line_ptr, '{', '}', &count);
+ if (tip)
+ iupAttribStoreStr(param, "TIP", tip);
+
+ return param;
+}
+
+/*******************************************************************************************
+ Exported Functions
+*******************************************************************************************/
+
+int iupGetParamCount(const char *format, int *param_extra)
+{
+ int param_count = 0, sep = 0;
+ const char* s = format;
+
+ *param_extra = 0;
+ while(*s)
+ {
+ if (*s == '%' && *(s+1) == 't') /* do not count separator lines */
+ {
+ sep = 1;
+ (*param_extra)++;
+ }
+
+ if (*s == '\n')
+ {
+ if (sep)
+ sep = 0;
+ else
+ param_count++;
+ }
+
+ s++;
+ }
+
+ return param_count;
+}
+
+static void iParamDestroyAll(Ihandle **params)
+{
+ int i = 0;
+ while (params[i] != NULL)
+ {
+ IupDestroy(params[i]);
+ i++;
+ }
+}
+
+int IupGetParamv(const char* title, Iparamcb action, void* user_data, const char* format, int param_count, int param_extra, void** param_data)
+{
+ Ihandle *dlg, *params[50];
+ int i, line_size, p;
+
+ assert(title && format);
+ if (!title || !format)
+ return 0;
+
+ for (i = 0, p = 0; i < param_count+param_extra; i++)
+ {
+ int data_type;
+
+ params[i] = IupParamf(format, &line_size);
+ assert(params[i]);
+ if (!params[i])
+ 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)
+ {
+ 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)
+ {
+ char *data_str = (char*)(param_data[p]);
+ if (!data_str) return 0;
+ iupAttribStoreStr(params[i], "VALUE", data_str);
+ p++;
+ }
+
+ format += line_size;
+ }
+ params[i] = NULL;
+
+ dlg = IupParamDlgP(params);
+ IupSetAttribute(dlg, "TITLE", (char*)title);
+ IupSetCallback(dlg, "PARAM_CB", (Icallback)action);
+ iupAttribSetStr(dlg, "USER_DATA", (char*)user_data);
+
+ if (action)
+ action(dlg, -2, user_data);
+
+ IupPopup(dlg, IUP_CENTERPARENT, IUP_CENTERPARENT);
+
+ if (!IupGetInt(dlg, "STATUS"))
+ {
+ iParamDestroyAll(params);
+ IupDestroy(dlg);
+ return 0;
+ }
+ else
+ {
+ for (i = 0, p = 0; i < param_count; i++)
+ {
+ Ihandle* param;
+ int data_type;
+ char str[20];
+
+ sprintf(str, "PARAM%d", i);
+ param = (Ihandle*)iupAttribGet(dlg, str);
+
+ data_type = iupAttribGetInt(param, "DATA_TYPE");
+ if (data_type == 1)
+ {
+ int *data_int = (int*)(param_data[i]);
+ *data_int = iupAttribGetInt(param, "VALUE");
+ p++;
+ }
+ else if (data_type == 2)
+ {
+ float *data_float = (float*)(param_data[i]);
+ *data_float = iupAttribGetFloat(param, "VALUE");
+ p++;
+ }
+ else
+ {
+ char *data_str = (char*)(param_data[i]);
+ strcpy(data_str, iupAttribGet(param, "VALUE"));
+ p++;
+ }
+ }
+
+ iParamDestroyAll(params);
+ IupDestroy(dlg);
+ return 1;
+ }
+}
+
+int IupGetParam(const char* title, Iparamcb action, void* user_data, const char* format,...)
+{
+ int param_count, param_extra, i;
+ void* param_data[50];
+ va_list arg;
+
+ param_count = iupGetParamCount(format, &param_extra);
+
+ va_start(arg, format);
+ for (i = 0; i < param_count; i++)
+ {
+ param_data[i] = (void*)(va_arg(arg, void*));
+ }
+ va_end(arg);
+
+ return IupGetParamv(title, action, user_data, format, param_count, param_extra, param_data);
+}
+
diff --git a/iup/src/iup_globalattrib.c b/iup/src/iup_globalattrib.c
new file mode 100755
index 0000000..00586fb
--- /dev/null
+++ b/iup/src/iup_globalattrib.c
@@ -0,0 +1,153 @@
+/** \file
+ * \brief global attributes enviroment
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "iup.h"
+
+#include "iup_table.h"
+#include "iup_globalattrib.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_assert.h"
+#include "iup_str.h"
+
+
+static Itable *iglobal_table = NULL;
+
+void iupGlobalAttribInit(void)
+{
+ iglobal_table = iupTableCreate(IUPTABLE_STRINGINDEXED);
+}
+
+void iupGlobalAttribFinish(void)
+{
+ iupTableDestroy(iglobal_table);
+ iglobal_table = NULL;
+}
+
+static int iGlobalChangingDefaultColor(const char *name)
+{
+ if (iupStrEqual(name, "DLGBGCOLOR") ||
+ iupStrEqual(name, "DLGFGCOLOR") ||
+ iupStrEqual(name, "MENUBGCOLOR") ||
+ iupStrEqual(name, "MENUFGCOLOR") ||
+ iupStrEqual(name, "TXTBGCOLOR") ||
+ iupStrEqual(name, "TXTFGCOLOR"))
+ {
+ char str[50] = "_IUP_USER_DEFAULT_";
+ strcat(str, name);
+ iupTableSet(iglobal_table, str, (void*)"1", IUPTABLE_POINTER); /* mark as changed by the User */
+ return 1;
+ }
+ return 0;
+}
+
+int iupGlobalDefaultColorChanged(const char *name)
+{
+ char str[50] = "_IUP_USER_DEFAULT_";
+ strcat(str, name);
+ return iupTableGet(iglobal_table, str) != NULL;
+}
+
+void iupGlobalSetDefaultColorAttrib(const char* name, int r, int g, int b)
+{
+ if (!iupGlobalDefaultColorChanged(name))
+ {
+ char value[50];
+ sprintf(value, "%3d %3d %3d", r, g, b);
+ iupTableSet(iglobal_table, name, (void*)value, IUPTABLE_STRING);
+ }
+}
+
+void IupSetGlobal(const char *name, const char *value)
+{
+ iupASSERT(name!=NULL);
+ if (!name) return;
+
+ if (iupStrEqual(name, "DEFAULTFONTSIZE"))
+ {
+ iupSetDefaultFontSizeGlobalAttrib(value);
+ return;
+ }
+
+ if (iGlobalChangingDefaultColor(name) || iupdrvSetGlobal(name, value))
+ {
+ if (!value)
+ iupTableRemove(iglobal_table, name);
+ else
+ iupTableSet(iglobal_table, name, (void*)value, IUPTABLE_POINTER);
+ }
+}
+
+void IupStoreGlobal(const char *name, const char *value)
+{
+ iupASSERT(name!=NULL);
+ if (!name) return;
+
+ if (iupStrEqual(name, "DEFAULTFONTSIZE"))
+ {
+ iupSetDefaultFontSizeGlobalAttrib(value);
+ return;
+ }
+
+ if (iGlobalChangingDefaultColor(name) || iupdrvSetGlobal(name, value))
+ {
+ if (!value)
+ iupTableRemove(iglobal_table, name);
+ else
+ iupTableSet(iglobal_table, name, (void*)value, IUPTABLE_STRING);
+ }
+}
+
+char *IupGetGlobal(const char *name)
+{
+ char* value;
+
+ iupASSERT(name!=NULL);
+ if (!name)
+ return NULL;
+
+ if (iupStrEqual(name, "DEFAULTFONTSIZE"))
+ return iupGetDefaultFontSizeGlobalAttrib();
+
+ value = iupdrvGetGlobal(name);
+
+ if (!value)
+ value = (char*)iupTableGet(iglobal_table, name);
+
+ return value;
+}
+
+int iupGlobalIsPointer(const char* name)
+{
+ static struct {
+ const char *name;
+ } ptr_table[] = {
+#ifdef WIN32
+ {"HINSTANCE"},
+#else
+ {"XDISPLAY"},
+ {"XSCREEN"},
+ {"APPSHELL"},
+#endif
+ };
+#define PTR_TABLE_SIZE ((sizeof ptr_table)/(sizeof ptr_table[0]))
+
+ if (name)
+ {
+ int i;
+ for (i = 0; i < PTR_TABLE_SIZE; i++)
+ {
+ if (iupStrEqualNoCase(name, ptr_table[i].name))
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/iup/src/iup_globalattrib.h b/iup/src/iup_globalattrib.h
new file mode 100755
index 0000000..706a6ac
--- /dev/null
+++ b/iup/src/iup_globalattrib.h
@@ -0,0 +1,33 @@
+/** \file
+ * \brief global attributes enviroment
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_GLOBALATTRIB_H
+#define __IUP_GLOBALATTRIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* called only in IupOpen and IupClose */
+void iupGlobalAttribInit(void);
+void iupGlobalAttribFinish(void);
+
+int iupGlobalIsPointer(const char* name);
+
+int iupGlobalDefaultColorChanged(const char *name); /* check if user changed */
+void iupGlobalSetDefaultColorAttrib(const char* name, int r, int g, int b); /* internal change method */
+
+/* Other functions declared in <iup.h> and implemented here.
+IupSetGlobal
+IupStoreGlobal
+IupGetGlobal
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_hbox.c b/iup/src/iup_hbox.c
new file mode 100755
index 0000000..e790636
--- /dev/null
+++ b/iup/src/iup_hbox.c
@@ -0,0 +1,309 @@
+/** \file
+ * \brief Hbox Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_box.h"
+
+
+static int iHboxSetRasterSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ ih->userwidth = 0;
+ ih->userheight = 0;
+ }
+ else
+ {
+ int s = 0;
+ iupStrToInt(value, &s);
+ if (s > 0)
+ {
+ ih->userheight = 0;
+ ih->userwidth = s;
+ }
+ }
+ iupAttribSetStr(ih, "SIZE", NULL); /* clear SIZE in hash table */
+ return 0;
+}
+
+static int iHboxSetSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ ih->userwidth = 0;
+ ih->userheight = 0;
+ }
+ else
+ {
+ int s = 0;
+ iupStrToInt(value, &s);
+ if (s > 0)
+ {
+ int charwidth, charheight;
+ iupdrvFontGetCharSize(ih, &charwidth, &charheight);
+ ih->userheight = 0;
+ ih->userwidth = iupWIDTH2RASTER(s, charwidth);
+ }
+ }
+ return 1;
+}
+
+static int iHboxSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrEqualNoCase(value, "ABOTTOM"))
+ ih->data->alignment = IUP_ALIGN_ABOTTOM;
+ else if (iupStrEqualNoCase(value, "ACENTER"))
+ ih->data->alignment = IUP_ALIGN_ACENTER;
+ else if (iupStrEqualNoCase(value, "ATOP"))
+ ih->data->alignment = IUP_ALIGN_ATOP;
+ return 0;
+}
+
+static char* iHboxGetAlignmentAttrib(Ihandle* ih)
+{
+ static char* align2str[3] = {"ATOP", "ACENTER", "ABOTTOM"};
+ return align2str[ih->data->alignment];
+}
+
+static void iHboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ Ihandle* child;
+ int children_naturalwidth, children_naturalheight;
+
+ /* calculate total children natural size */
+ int children_expand = 0;
+ int children_count = 0;
+ int children_natural_totalwidth = 0;
+ int children_natural_maxwidth = 0;
+ int children_natural_maxheight = 0;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ /* update child natural size first */
+ iupBaseComputeNaturalSize(child);
+
+ if (!child->is_floating)
+ {
+ children_expand |= child->expand;
+ children_natural_maxwidth = iupMAX(children_natural_maxwidth, child->naturalwidth);
+ children_natural_maxheight = iupMAX(children_natural_maxheight, child->naturalheight);
+ children_count++;
+ }
+ }
+
+ /* reset to max natural width and/or height if NORMALIZESIZE is defined */
+ if (ih->data->normalize_size)
+ iupNormalizeSizeBoxChild(ih, ih->data->normalize_size, children_natural_maxwidth, children_natural_maxheight);
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating)
+ children_natural_totalwidth += child->naturalwidth;
+ }
+
+ /* leave room at the element for the maximum natural size of the children when is_homogeneous */
+ if (ih->data->is_homogeneous)
+ children_natural_totalwidth = children_natural_maxwidth*children_count;
+
+ /* compute the Hbox contents natural size */
+ children_naturalwidth = children_natural_totalwidth + (children_count-1)*ih->data->gap + 2*ih->data->margin_x;
+ children_naturalheight = children_natural_maxheight + 2*ih->data->margin_y;
+
+ /* Store to be used in iHboxCalcEmptyWidth */
+ ih->data->children_naturalsize = children_naturalwidth;
+
+ *expand = children_expand;
+ *w = children_naturalwidth;
+ *h = children_naturalheight;
+}
+
+static int iHboxCalcHomogeneousWidth(Ihandle *ih)
+{
+ Ihandle* child;
+ int homogeneous_width;
+
+ int children_count=0;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating)
+ children_count++;
+ }
+ if (children_count == 0)
+ return 0;
+
+ /* equal spaces for all elements */
+ homogeneous_width = (ih->currentwidth - (children_count-1)*ih->data->gap - 2*ih->data->margin_x)/children_count;
+ if (homogeneous_width<0) homogeneous_width = 0;
+ return homogeneous_width;
+}
+
+static int iHboxCalcEmptyWidth(Ihandle *ih, int expand)
+{
+ /* This is the space that the child can be expanded. */
+ Ihandle* child;
+ int empty_width;
+
+ int expand_count=0;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating && child->expand & expand)
+ expand_count++;
+ }
+ if (expand_count == 0)
+ return 0;
+
+ /* equal spaces for all expandable elements */
+ empty_width = (ih->currentwidth - ih->data->children_naturalsize)/expand_count;
+ if (empty_width < 0) empty_width = 0;
+ return empty_width;
+}
+
+static void iHboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink)
+{
+ /* update children */
+ Ihandle* child;
+ int empty_w0 = 0, empty_w1 = 0, client_height;
+
+ if (ih->data->expand_children)
+ ih->expand |= ih->data->expand_children;
+
+ if (ih->data->is_homogeneous)
+ ih->data->homogeneous_size = iHboxCalcHomogeneousWidth(ih);
+ else
+ {
+ ih->data->homogeneous_size = 0;
+
+ /* must calculate the space left for each control to grow inside the container */
+ /* W1 means there is an EXPAND enabled inside */
+ if (ih->expand & IUP_EXPAND_W1)
+ empty_w1 = iHboxCalcEmptyWidth(ih, IUP_EXPAND_W1);
+ /* Not W1 and W0 means that EXPAND is not enabled but there are some IupFill inside */
+ else if (ih->expand & IUP_EXPAND_W0)
+ empty_w0 = iHboxCalcEmptyWidth(ih, IUP_EXPAND_W0);
+ }
+
+ client_height = ih->currentheight - 2*ih->data->margin_y;
+ if (client_height<0) client_height=0;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating)
+ {
+ int old_expand = child->expand;
+ if (ih->data->expand_children)
+ child->expand |= ih->data->expand_children;
+
+ if (ih->data->homogeneous_size)
+ iupBaseSetCurrentSize(child, ih->data->homogeneous_size, client_height, shrink);
+ else
+ {
+ int empty = (child->expand & IUP_EXPAND_W1)? empty_w1: ((child->expand & IUP_EXPAND_W0)? empty_w0: 0);
+ iupBaseSetCurrentSize(child, child->naturalwidth+empty, client_height, shrink);
+ }
+
+ if (ih->data->expand_children)
+ child->expand = old_expand;
+ }
+ else
+ {
+ /* update children to their own natural size */
+ iupBaseSetCurrentSize(child, child->naturalwidth, child->naturalheight, shrink);
+ }
+ }
+}
+
+static void iHboxSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ int dy, client_height;
+ Ihandle* child;
+
+ x += ih->data->margin_x;
+ y += ih->data->margin_y;
+
+ client_height = ih->currentheight - 2*ih->data->margin_y;
+ if (client_height<0) client_height=0;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating)
+ {
+ if (ih->data->alignment == IUP_ALIGN_ACENTER)
+ dy = (client_height - child->currentheight)/2;
+ else if (ih->data->alignment == IUP_ALIGN_ABOTTOM)
+ dy = client_height - child->currentheight;
+ else /* IUP_ALIGN_ATOP */
+ dy = 0;
+ if (dy<0) dy = 0;
+
+ /* update child */
+ iupBaseSetPosition(child, x, y+dy);
+
+ /* calculate next */
+ if (ih->data->homogeneous_size)
+ x += ih->data->homogeneous_size + ih->data->gap;
+ else
+ x += child->currentwidth + ih->data->gap;
+ }
+ }
+}
+
+
+/******************************************************************************/
+
+
+Ihandle *IupHboxv(Ihandle **children)
+{
+ return IupCreatev("hbox", (void**)children);
+}
+
+Ihandle *IupHbox(Ihandle* child, ...)
+{
+ Ihandle **children;
+ Ihandle *ih;
+
+ va_list arglist;
+ va_start(arglist, child);
+ children = (Ihandle **)iupObjectGetParamList(child, arglist);
+ va_end(arglist);
+
+ ih = IupCreatev("hbox", (void**)children);
+ free(children);
+
+ return ih;
+}
+
+Iclass* iupHboxGetClass(void)
+{
+ Iclass* ic = iupBoxClassBase();
+
+ ic->name = "hbox";
+
+ /* Class functions */
+ ic->ComputeNaturalSize = iHboxComputeNaturalSizeMethod;
+ ic->SetChildrenCurrentSize = iHboxSetChildrenCurrentSizeMethod;
+ ic->SetChildrenPosition = iHboxSetChildrenPositionMethod;
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "SIZE", iupBaseGetSizeAttrib, iHboxSetSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, iHboxSetRasterSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ /* Hbox only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", iHboxGetAlignmentAttrib, iHboxSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ATOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
diff --git a/iup/src/iup_image.c b/iup/src/iup_image.c
new file mode 100755
index 0000000..12b1169
--- /dev/null
+++ b/iup/src/iup_image.c
@@ -0,0 +1,1017 @@
+/** \file
+ * \brief Image Resource.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_assert.h"
+#include "iup_stdcontrols.h"
+
+
+typedef struct _IimageStock
+{
+ iupImageStockCreateFunc func;
+ Ihandle* image; /* cache image */
+ const char* native_name; /* used to map to GTK stock images */
+} IimageStock;
+
+static Itable *istock_table = NULL; /* the function hast table indexed by the name string */
+
+void iupImageStockInit(void)
+{
+ istock_table = iupTableCreate(IUPTABLE_STRINGINDEXED);
+}
+
+void iupImageStockFinish(void)
+{
+ char* name = iupTableFirst(istock_table);
+ while (name)
+ {
+ IimageStock* istock = (IimageStock*)iupTableGetCurr(istock_table);
+ if (iupObjectCheck(istock->image))
+ IupDestroy(istock->image);
+ free(istock);
+ name = iupTableNext(istock_table);
+ }
+
+ iupTableDestroy(istock_table);
+ istock_table = NULL;
+}
+
+void iupImageStockSet(const char *name, iupImageStockCreateFunc func, const char* native_name)
+{
+ IimageStock* istock = (IimageStock*)iupTableGet(istock_table, name);
+ if (istock)
+ free(istock); /* overwrite a previous registration */
+
+ istock = (IimageStock*)malloc(sizeof(IimageStock));
+ istock->func = func;
+ istock->image = NULL;
+ istock->native_name = native_name;
+
+ iupTableSet(istock_table, name, (void*)istock, IUPTABLE_POINTER);
+}
+
+static void iImageStockGet(const char* name, Ihandle* *ih, const char* *native_name)
+{
+ IimageStock* istock = (IimageStock*)iupTableGet(istock_table, name);
+ if (istock)
+ {
+ if (istock->image)
+ *ih = istock->image;
+ else if (istock->native_name)
+ *native_name = istock->native_name;
+ else if (istock->func)
+ {
+ istock->image = istock->func();
+ *ih = istock->image;
+ }
+ }
+}
+
+void iupImageStockLoad(const char *name)
+{
+ /* Used only in iupImageLibLoadAll */
+ const char* native_name = NULL;
+ Ihandle* ih = NULL;
+ iImageStockGet(name, &ih, &native_name);
+ if (ih)
+ IupSetHandle(name, ih);
+ else if (native_name)
+ {
+ /* dummy image to save the GTK stock name */
+ void* handle = iupdrvImageLoad(native_name, IUPIMAGE_IMAGE);
+ if (handle)
+ {
+ int w, h, bpp;
+ iupdrvImageGetInfo(handle, &w, &h, &bpp);
+ if (bpp == 32)
+ ih = IupImageRGBA(w,h,NULL);
+ else
+ ih = IupImageRGB(w,h,NULL);
+ IupSetHandle(native_name, ih);
+ }
+ }
+}
+
+
+/**************************************************************************************************/
+/**************************************************************************************************/
+
+
+int iupImageNormBpp(int bpp)
+{
+ if (bpp <= 8) return 8;
+ if (bpp <= 24) return 24;
+ return 32;
+}
+
+static void iupColorSet(iupColor *c, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+ c->r = r;
+ c->g = g;
+ c->b = b;
+ c->a = a;
+}
+
+int iupImageInitColorTable(Ihandle *ih, iupColor* colors, int *colors_count)
+{
+ char attr[6], *value;
+ unsigned char red, green, blue;
+ int i, has_alpha = 0;
+ static iupColor default_colors[] = {
+ { 0,0,0,255 }, { 128,0,0,255 }, { 0,128,0,255 }, { 128,128,0,255 },
+ { 0,0,128,255 }, { 128,0,128,255 }, { 0,128,128,255 }, { 192,192,192,255 },
+ { 128,128,128,255 }, { 255,0,0,255 }, { 0,255,0,255 }, { 255,255,0,255 },
+ { 0,0,255,255 }, { 255,0,255,255 }, { 0,255,255,255 }, { 255,255,255,255 } };
+
+ memset(colors, 0, sizeof(iupColor)*256);
+
+ for (i=0;i<16;i++)
+ {
+ sprintf(attr, "%d", i);
+ value = iupAttribGet(ih, attr);
+
+ if (value)
+ {
+ if (iupStrEqual(value, "BGCOLOR"))
+ {
+ iupColorSet(&colors[i], 0, 0, 0, 0);
+ has_alpha = 1;
+ }
+ else
+ {
+ if (!iupStrToRGB(value, &red, &green, &blue))
+ iupColorSet(&colors[i], default_colors[i].r, default_colors[i].g, default_colors[i].b, 255);
+ else
+ iupColorSet(&colors[i], red, green, blue, 255);
+ }
+ }
+ else
+ {
+ iupColorSet(&colors[i], default_colors[i].r, default_colors[i].g, default_colors[i].b, 255);
+ }
+ }
+
+ for (;i<256;i++)
+ {
+ sprintf(attr, "%d", i);
+ value = iupAttribGet(ih, attr);
+ if (!value)
+ break;
+
+ if (iupStrEqual(value, "BGCOLOR"))
+ {
+ iupColorSet(&colors[i], 0, 0, 0, 0);
+ has_alpha = 1;
+ }
+ else
+ {
+ if (!iupStrToRGB(value, &red, &green, &blue))
+ break;
+
+ iupColorSet(&colors[i], red, green, blue, 255);
+ }
+ }
+
+ if (colors_count) *colors_count = i;
+
+ return has_alpha;
+}
+
+void iupImageInitNonBgColors(Ihandle* ih, unsigned char *colors)
+{
+ char attr[6], *value;
+ int i;
+
+ memset(colors, 0, 256);
+
+ for (i=0;i<16;i++)
+ {
+ sprintf(attr, "%d", i);
+ value = iupAttribGet(ih, attr);
+ if (!iupStrEqual(value, "BGCOLOR"))
+ colors[i] = 1;
+ }
+
+ for (;i<256;i++)
+ {
+ sprintf(attr, "%d", i);
+ value = iupAttribGet(ih, attr);
+ if (!value)
+ break;
+
+ if (!iupStrEqual(value, "BGCOLOR"))
+ colors[i] = 1;
+ }
+}
+
+void iupImageColorMakeInactive(unsigned char *r, unsigned char *g, unsigned char *b, unsigned char bg_r, unsigned char bg_g, unsigned char bg_b)
+{
+ if (*r==bg_r && *g==bg_g && *b==bg_b) /* preserve colors identical to the background color */
+ {
+ *r = bg_r;
+ *g = bg_g;
+ *b = bg_b;
+ }
+ else
+ {
+ int ir = 0, ig = 0, ib = 0,
+ i = (*r+*g+*b)/3,
+ bg_i = (bg_r+bg_g+bg_b)/3;
+
+ if (bg_i)
+ {
+ ir = (bg_r*i)/bg_i;
+ ig = (bg_g*i)/bg_i;
+ ib = (bg_b*i)/bg_i;
+ }
+
+#define LIGHTER(_c) ((255 + _c)/2)
+ ir = LIGHTER(ir);
+ ig = LIGHTER(ig);
+ ib = LIGHTER(ib);
+
+ *r = iupBYTECROP(ir);
+ *g = iupBYTECROP(ig);
+ *b = iupBYTECROP(ib);
+ }
+}
+
+
+/**************************************************************************************************/
+/**************************************************************************************************/
+
+
+void* iupImageGetMask(const char* name)
+{
+ void* mask;
+ Ihandle *ih;
+
+ if (!name)
+ return NULL;
+
+ /* get handle from name */
+ ih = IupGetHandle(name);
+ if (!ih)
+ return NULL;
+
+ /* Check for an already created icon */
+ mask = iupAttribGet(ih, "_IUPIMAGE_MASK");
+ if (mask)
+ return mask;
+
+ /* Not created, tries to create the mask */
+ mask = iupdrvImageCreateMask(ih);
+
+ /* save the pixbuf */
+ iupAttribSetStr(ih, "_IUPIMAGE_MASK", (char*)mask);
+
+ return mask;
+}
+
+void* iupImageGetIcon(const char* name)
+{
+ void* icon;
+ Ihandle *ih;
+
+ if (!name)
+ return NULL;
+
+ /* Check first in the system resources. */
+ icon = iupdrvImageLoad(name, IUPIMAGE_ICON);
+ if (icon)
+ return icon;
+
+ /* get handle from name */
+ ih = IupGetHandle(name);
+ if (!ih)
+ return NULL;
+
+ /* Check for an already created icon */
+ icon = iupAttribGet(ih, "_IUPIMAGE_ICON");
+ if (icon)
+ return icon;
+
+ /* Not created, tries to create the icon */
+ icon = iupdrvImageCreateIcon(ih);
+
+ /* save the pixbuf */
+ iupAttribSetStr(ih, "_IUPIMAGE_ICON", (char*)icon);
+
+ return icon;
+}
+
+void* iupImageGetCursor(const char* name)
+{
+ void* cursor;
+ Ihandle *ih;
+
+ if (!name)
+ return NULL;
+
+ /* Check first in the system resources. */
+ cursor = iupdrvImageLoad(name, IUPIMAGE_CURSOR);
+ if (cursor)
+ return cursor;
+
+ /* get handle from name */
+ ih = IupGetHandle(name);
+ if (!ih)
+ return NULL;
+
+ /* Check for an already created cursor */
+ cursor = iupAttribGet(ih, "_IUPIMAGE_CURSOR");
+ if (cursor)
+ return cursor;
+
+ /* Not created, tries to create the cursor */
+ cursor = iupdrvImageCreateCursor(ih);
+
+ /* save the pixbuf */
+ iupAttribSetStr(ih, "_IUPIMAGE_CURSOR", (char*)cursor);
+
+ return cursor;
+}
+
+void iupImageGetInfo(const char* name, int *w, int *h, int *bpp)
+{
+ void* handle;
+ Ihandle *ih;
+
+ if (!name)
+ return;
+
+ /* Check first in the system resources. */
+ handle = iupdrvImageLoad(name, IUPIMAGE_IMAGE);
+ if (handle)
+ {
+ iupdrvImageGetInfo(handle, w, h, bpp);
+ return;
+ }
+
+ /* get handle from name */
+ ih = IupGetHandle(name);
+ if (!ih)
+ {
+ /* Check in the stock images. */
+ const char* native_name = NULL;
+ iImageStockGet(name, &ih, &native_name);
+
+ if (native_name)
+ {
+ handle = iupdrvImageLoad(native_name, IUPIMAGE_IMAGE);
+ if (handle)
+ {
+ iupdrvImageGetInfo(handle, w, h, bpp);
+ return;
+ }
+ }
+
+ if (!ih)
+ return;
+ }
+
+ if (w) *w = ih->currentwidth;
+ if (h) *h = ih->currentheight;
+ if (bpp) *bpp = IupGetInt(ih, "BPP");
+}
+
+void* iupImageGetImage(const char* name, Ihandle* ih_parent, int make_inactive)
+{
+ char cache_name[100] = "_IUPIMAGE_IMAGE";
+ char* bgcolor;
+ void* handle;
+ Ihandle *ih;
+ int bg_concat = 0;
+
+ if (!name)
+ return NULL;
+
+ /* Check first in the system resources. */
+ handle = iupdrvImageLoad(name, IUPIMAGE_IMAGE);
+ if (handle)
+ return handle;
+
+ /* get handle from name */
+ ih = IupGetHandle(name);
+ if (!ih)
+ {
+ /* Check in the stock images. */
+ const char* native_name = NULL;
+ iImageStockGet(name, &ih, &native_name);
+
+ if (native_name)
+ {
+ handle = iupdrvImageLoad(native_name, IUPIMAGE_IMAGE);
+ if (handle)
+ return handle;
+ }
+
+ if (!ih)
+ return NULL;
+ }
+
+ bgcolor = iupAttribGet(ih, "BGCOLOR");
+ if (ih_parent && !bgcolor)
+ bgcolor = IupGetAttribute(ih_parent, "BGCOLOR"); /* Use IupGetAttribute to use inheritance and native implementation */
+
+ if (make_inactive)
+ strcat(cache_name, "_INACTIVE");
+
+ if (iupAttribGet(ih, "_IUP_BGCOLOR_DEPEND") && bgcolor)
+ {
+ strcat(cache_name, "(");
+ strcat(cache_name, bgcolor);
+ strcat(cache_name, ")");
+ bg_concat = 1;
+ }
+
+ /* Check for an already created native image */
+ handle = (void*)iupAttribGet(ih, cache_name);
+ if (handle)
+ return handle;
+
+ if (ih_parent && iupAttribGetStr(ih_parent, "FLAT_ALPHA"))
+ iupAttribSetStr(ih, "FLAT_ALPHA", "1");
+
+ /* Creates the native image */
+ handle = iupdrvImageCreateImage(ih, bgcolor, make_inactive);
+
+ if (ih_parent && iupAttribGetStr(ih_parent, "FLAT_ALPHA"))
+ iupAttribSetStr(ih, "FLAT_ALPHA", NULL);
+
+ if (iupAttribGet(ih, "_IUP_BGCOLOR_DEPEND") && bgcolor && !bg_concat) /* _IUP_BGCOLOR_DEPEND could be set during creation */
+ {
+ strcat(cache_name, "(");
+ strcat(cache_name, bgcolor);
+ strcat(cache_name, ")");
+ }
+
+ /* save the native image in the cache */
+ iupAttribSetStr(ih, cache_name, (char*)handle);
+
+ return handle;
+}
+
+void iupImageUpdateParent(Ihandle *ih) /* ih here is the element that contains images */
+{
+ int inherit;
+
+ /* Called when BGCOLOR is changed */
+ /* it will re-create the image, if the case */
+
+ char* value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ iupClassObjectSetAttribute(ih, "IMAGE", value, &inherit);
+
+ value = iupAttribGet(ih, "IMINACTIVE");
+ if (value)
+ iupClassObjectSetAttribute(ih, "IMINACTIVE", value, &inherit);
+
+ value = iupAttribGet(ih, "IMPRESS");
+ if (value)
+ iupClassObjectSetAttribute(ih, "IMPRESS", value, &inherit);
+}
+
+static char* iImageGetWidthAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(50);
+ sprintf(str, "%d", ih->currentwidth);
+ return str;
+}
+
+static char* iImageGetHeightAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(50);
+ sprintf(str, "%d", ih->currentheight);
+ return str;
+}
+
+void iupImageClearCache(Ihandle* ih, void* handle)
+{
+ char *name;
+ void* cur_handle;
+
+ name = iupTableFirst(ih->attrib);
+ while (name)
+ {
+ if (iupStrEqualPartial(name, "_IUPIMAGE_"))
+ {
+ cur_handle = iupTableGetCurr(ih->attrib);
+ if (cur_handle == handle)
+ {
+ iupTableRemoveCurr(ih->attrib);
+ return;
+ }
+ }
+
+ name = iupTableNext(ih->attrib);
+ }
+}
+
+static void iImageUnMapMethod(Ihandle* ih)
+{
+ char *name;
+ void* handle;
+
+ handle = iupAttribGet(ih, "_IUPIMAGE_ICON");
+ if (handle)
+ {
+ iupdrvImageDestroy(handle, IUPIMAGE_ICON);
+ iupAttribSetStr(ih, "_IUPIMAGE_ICON", NULL);
+ }
+
+ handle = iupAttribGet(ih, "_IUPIMAGE_CURSOR");
+ if (handle)
+ {
+ iupdrvImageDestroy(handle, IUPIMAGE_CURSOR);
+ iupAttribSetStr(ih, "_IUPIMAGE_CURSOR", NULL);
+ }
+
+ /* the remaining images are all IUPIMAGE_IMAGE */
+ name = iupTableFirst(ih->attrib);
+ while (name)
+ {
+ if (iupStrEqualPartial(name, "_IUPIMAGE_"))
+ {
+ handle = iupTableGetCurr(ih->attrib);
+ if (handle) iupdrvImageDestroy(handle, IUPIMAGE_IMAGE);
+ }
+
+ name = iupTableNext(ih->attrib);
+ }
+}
+
+static int iImageCreate(Ihandle* ih, void** params, int bpp)
+{
+ int width, height, channels, count;
+ unsigned char *imgdata;
+
+ iupASSERT(params!=NULL);
+ if (!params)
+ return IUP_ERROR;
+
+ width = (int)(params[0]);
+ height = (int)(params[1]);
+
+ iupASSERT(width>0);
+ iupASSERT(height>0);
+
+ if (width <= 0 || height <= 0)
+ return IUP_ERROR;
+
+ ih->currentwidth = width;
+ ih->currentheight = height;
+
+ channels = 1;
+ if (bpp == 24)
+ channels = 3;
+ else if (bpp == 32)
+ channels = 4;
+
+ count = width*height*channels;
+ imgdata = (unsigned char *)malloc(count);
+
+ if (((int)(params[2])==-1) || ((int)(params[3])==-1)) /* compacted in one pointer */
+ {
+ if ((int)(params[2])!=-1)
+ memcpy(imgdata, params[2], count);
+ }
+ else /* one param for each element */
+ {
+ int i;
+ for(i=0; i<count; i++)
+ {
+ imgdata[i] = (unsigned char)((int)(params[i+2]));
+ }
+ }
+
+ iupAttribSetStr(ih, "WID", (char*)imgdata);
+ iupAttribSetInt(ih, "BPP", bpp);
+ iupAttribSetInt(ih, "CHANNELS", channels);
+
+ return IUP_NOERROR;
+}
+
+static int iImageCreateMethod(Ihandle* ih, void** params)
+{
+ return iImageCreate(ih, params, 8);
+}
+
+static int iImageRGBCreateMethod(Ihandle* ih, void** params)
+{
+ return iImageCreate(ih, params, 24);
+}
+
+static int iImageRGBACreateMethod(Ihandle* ih, void** params)
+{
+ return iImageCreate(ih, params, 32);
+}
+
+static void iImageDestroyMethod(Ihandle* ih)
+{
+ unsigned char* imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+ if (imgdata)
+ {
+ iupAttribSetStr(ih, "WID", NULL);
+ free(imgdata);
+ }
+}
+
+/******************************************************************************/
+
+Ihandle* IupImage(int width, int height, const unsigned char *imgdata)
+{
+ void *params[4];
+ params[0] = (void*)width;
+ params[1] = (void*)height;
+ params[2] = imgdata? (void*)imgdata: (void*)-1;
+ params[3] = (void*)-1;
+ return IupCreatev("image", params);
+}
+
+Ihandle* IupImageRGB(int width, int height, const unsigned char *imgdata)
+{
+ void *params[4];
+ params[0] = (void*)width;
+ params[1] = (void*)height;
+ params[2] = imgdata? (void*)imgdata: (void*)-1;
+ params[3] = (void*)-1;
+ return IupCreatev("imagergb", params);
+}
+
+Ihandle* IupImageRGBA(int width, int height, const unsigned char *imgdata)
+{
+ void *params[4];
+ params[0] = (void*)width;
+ params[1] = (void*)height;
+ params[2] = imgdata? (void*)imgdata: (void*)-1;
+ params[3] = (void*)-1;
+ return IupCreatev("imagergba", params);
+}
+
+static Iclass* iImageGetClassBase(char* name, int (*create_func)(Ihandle* ih, void** params))
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = name;
+ ic->format = "iiC"; /* (int,int,unsigned char*) */
+ ic->nativetype = IUP_TYPEIMAGE;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = create_func;
+ ic->Destroy = iImageDestroyMethod;
+ ic->Map = iupBaseTypeVoidMapMethod;
+ ic->UnMap = iImageUnMapMethod;
+
+ /* Attribute functions */
+ iupClassRegisterAttribute(ic, "WID", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "WIDTH", iImageGetWidthAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "HEIGHT", iImageGetHeightAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "BPP", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CHANNELS", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "HOTSPOT", NULL, NULL, "0:0", NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
+
+Iclass* iupImageGetClass(void)
+{
+ return iImageGetClassBase("image", iImageCreateMethod);
+}
+
+Iclass* iupImageRGBGetClass(void)
+{
+ return iImageGetClassBase("imagergb", iImageRGBCreateMethod);
+}
+
+Iclass* iupImageRGBAGetClass(void)
+{
+ return iImageGetClassBase("imagergba", iImageRGBACreateMethod);
+}
+
+static int SaveImageC(const char* file_name, Ihandle* ih, const char* name, FILE* packfile)
+{
+ int y, x, width, height, channels, linesize;
+ unsigned char* data;
+ FILE* file;
+
+ if (packfile)
+ file = packfile;
+ else
+ file = fopen(file_name, "wb");
+
+ if (!file)
+ return 0;
+
+ width = IupGetInt(ih, "WIDTH");
+ height = IupGetInt(ih, "HEIGHT");
+ channels = IupGetInt(ih, "CHANNELS");
+ linesize = width*channels;
+
+ data = (unsigned char*)IupGetAttribute(ih, "WID");
+
+ if (fprintf(file, "static Ihandle* load_image_%s(void)\n", name)<0)
+ {
+ if (!packfile)
+ fclose(file);
+ return 0;
+ }
+
+ fprintf(file, "{\n");
+ fprintf(file, " unsigned char imgdata[] = {\n");
+
+ for (y = 0; y < height; y++)
+ {
+ fprintf(file, " ");
+
+ for (x = 0; x < linesize; x++)
+ {
+ if (x != 0)
+ fprintf(file, ", ");
+
+ fprintf(file, "%d", (int)data[y*linesize+x]);
+ }
+
+ if (y == height-1)
+ fprintf(file, "};\n\n");
+ else
+ fprintf(file, ",\n");
+ }
+
+ if (channels == 1)
+ {
+ int c;
+ char str[20];
+ char* color;
+
+ fprintf(file, " Ihandle* image = IupImage(%d, %d, imgdata);\n\n", width, height);
+
+ for (c = 0; c < 256; c++)
+ {
+ sprintf(str, "%d", c);
+ color = IupGetAttribute(ih, str);
+ if (!color)
+ break;
+
+ fprintf(file, " IupSetAttribute(image, \"%d\", \"%s\");\n", c, color);
+ }
+
+ fprintf(file, "\n");
+ }
+ else if (channels == 3)
+ fprintf(file, " Ihandle* image = IupImageRGB(%d, %d, imgdata);\n", width, height);
+ else /* channels == 4 */
+ fprintf(file, " Ihandle* image = IupImageRGBA(%d, %d, imgdata);\n", width, height);
+
+ fprintf(file, " return image;\n");
+ fprintf(file, "}\n\n");
+
+ if (!packfile)
+ fclose(file);
+
+ return 1;
+}
+
+static int SaveImageLua(const char* file_name, Ihandle* ih, const char* name, FILE* packfile)
+{
+ int y, x, width, height, channels, linesize;
+ unsigned char* data;
+ FILE* file;
+
+ if (packfile)
+ file = packfile;
+ else
+ file = fopen(file_name, "wb");
+
+ if (!file)
+ return 0;
+
+ width = IupGetInt(ih, "WIDTH");
+ height = IupGetInt(ih, "HEIGHT");
+ channels = IupGetInt(ih, "CHANNELS");
+ linesize = width*channels;
+
+ data = (unsigned char*)IupGetAttribute(ih, "WID");
+
+ if (fprintf(file, "function load_image_%s()\n", name)<0)
+ {
+ if (!packfile)
+ fclose(file);
+ return 0;
+ }
+
+ if (channels == 1)
+ fprintf(file, " local %s = iup.image\n", name);
+ else if (channels == 3)
+ fprintf(file, " local %s = iup.imagergb\n", name);
+ else /* channels == 4 */
+ fprintf(file, " local %s = iup.imagergba\n", name);
+
+ fprintf(file, " {\n");
+
+ fprintf(file, " width = %d,\n", width);
+ fprintf(file, " height = %d,\n", height);
+ fprintf(file, " pixels = {\n");
+
+ for (y = 0; y < height; y++)
+ {
+ fprintf(file, " ");
+ for (x = 0; x < linesize; x++)
+ {
+ fprintf(file, "%d, ", (int)data[y*linesize+x]);
+ }
+ fprintf(file, "\n");
+ }
+
+ fprintf(file, " },\n");
+
+ if (channels == 1)
+ {
+ int c;
+ char* color;
+ unsigned int r, g, b;
+ char str[20];
+
+ fprintf(file, " colors = {\n");
+
+ for(c = 0; c < 256; c++)
+ {
+ sprintf(str, "%d", c);
+ color = IupGetAttribute(ih, str);
+ if (!color)
+ break;
+
+ if (iupStrEqualNoCase(color, "BGCOLOR"))
+ fprintf(file, " \"BGCOLOR\",\n");
+ else
+ {
+ sscanf(color, "%d %d %d", &r, &g, &b);
+ fprintf(file, " \"%d %d %d\",\n", r, g, b);
+ }
+ }
+
+ fprintf(file, " }\n");
+ }
+
+ fprintf(file, " }\n");
+
+ fprintf(file, " return %s\n", name);
+ fprintf(file, "end\n\n");
+
+ if (!packfile)
+ fclose(file);
+
+ return 1;
+}
+
+static int SaveImageLED(const char* file_name, Ihandle* ih, const char* name, FILE* packfile)
+{
+ int y, x, width, height, channels, linesize;
+ unsigned char* data;
+ FILE* file;
+
+ if (packfile)
+ file = packfile;
+ else
+ file = fopen(file_name, "wb");
+
+ if (!file)
+ return 0;
+
+ width = IupGetInt(ih, "WIDTH");
+ height = IupGetInt(ih, "HEIGHT");
+ channels = IupGetInt(ih, "CHANNELS");
+ linesize = width*channels;
+
+ data = (unsigned char*)IupGetAttribute(ih, "WID");
+
+ if (channels == 1)
+ {
+ int c;
+ unsigned int r, g, b;
+ char str[20];
+ char* color;
+
+ if (fprintf(file, "%s = IMAGE\n", name)<0)
+ {
+ if (!packfile)
+ fclose(file);
+ return 0;
+ }
+
+ fprintf(file, "[\n");
+ for(c = 0; c < 256; c++)
+ {
+ sprintf(str, "%d", c);
+ color = IupGetAttribute(ih, str);
+ if (!color)
+ {
+ if (c < 16)
+ continue;
+ else
+ break;
+ }
+
+ if (c != 0)
+ fprintf(file, ",\n");
+
+ if (iupStrEqualNoCase(color, "BGCOLOR"))
+ fprintf(file, " %d = \"BGCOLOR\"", c);
+ else
+ {
+ sscanf(color, "%d %d %d", &r, &g, &b);
+ fprintf(file, " %d = \"%d %d %d\"", c, r, g, b);
+ }
+ }
+ fprintf(file, "\n]\n");
+ }
+ else if (channels == 3)
+ {
+ if (fprintf(file, "%s = IMAGERGB\n", name)<0)
+ {
+ if (!packfile)
+ fclose(file);
+ return 0;
+ }
+ }
+ else /* channels == 4 */
+ {
+ if (fprintf(file, "%s = IMAGERGBA\n", name)<0)
+ {
+ if (!packfile)
+ fclose(file);
+ return 0;
+ }
+ }
+
+ fprintf(file, "(%d, %d,\n", width, height);
+
+ for (y = 0; y < height; y++)
+ {
+ fprintf(file, " ");
+ for (x = 0; x < linesize; x++)
+ {
+ if (y == height-1 && x==linesize-1)
+ fprintf(file, "%d", (int)data[y*linesize+x]);
+ else
+ fprintf(file, "%d, ", (int)data[y*linesize+x]);
+ }
+ fprintf(file, "\n");
+ }
+
+ fprintf(file, ")\n\n");
+
+ if (!packfile)
+ fclose(file);
+
+ return 1;
+}
+
+int iupSaveImageAsText(Ihandle* ih, FILE* packfile, const char* format, const char* name)
+{
+ int ret = 0;
+ if (iupStrEqualNoCase(format, "LED"))
+ ret = SaveImageLED(NULL, ih, name, packfile);
+ else if (iupStrEqualNoCase(format, "LUA"))
+ ret = SaveImageLua(NULL, ih, name, packfile);
+ else if (iupStrEqualNoCase(format, "C") || iupStrEqualNoCase(format, "H"))
+ ret = SaveImageC(NULL, ih, name, packfile);
+ return ret;
+}
+
+int IupSaveImageAsText(Ihandle* ih, const char* file_name, const char* format, const char* name)
+{
+ int ret = 0;
+ if (!name)
+ {
+ name = IupGetName(ih);
+ if (!name)
+ name = "image";
+ }
+ if (iupStrEqualNoCase(format, "LED"))
+ ret = SaveImageLED(file_name, ih, name, NULL);
+ else if (iupStrEqualNoCase(format, "LUA"))
+ ret = SaveImageLua(file_name, ih, name, NULL);
+ else if (iupStrEqualNoCase(format, "C") || iupStrEqualNoCase(format, "H"))
+ ret = SaveImageC(file_name, ih, name, NULL);
+ return ret;
+}
diff --git a/iup/src/iup_image.h b/iup/src/iup_image.h
new file mode 100755
index 0000000..89e6795
--- /dev/null
+++ b/iup/src/iup_image.h
@@ -0,0 +1,61 @@
+/** \file
+ * \brief Image Resource Private Declarations
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_IMAGE_H
+#define __IUP_IMAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void* iupdrvImageCreateMask(Ihandle *ih);
+void* iupdrvImageCreateIcon(Ihandle *ih);
+void* iupdrvImageCreateCursor(Ihandle *ih);
+void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive);
+
+enum {IUPIMAGE_IMAGE, IUPIMAGE_ICON, IUPIMAGE_CURSOR};
+void* iupdrvImageLoad(const char* name, int type);
+void iupdrvImageDestroy(void* handle, int type);
+int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp); /* only for IUPIMAGE_IMAGE */
+
+void* iupImageGetMask(const char* name);
+void* iupImageGetIcon(const char* name);
+void* iupImageGetCursor(const char* name);
+void* iupImageGetImage(const char* name, Ihandle* parent, int make_inactive);
+void iupImageGetInfo(const char* name, int *w, int *h, int *bpp);
+void iupImageUpdateParent(Ihandle *parent);
+void iupImageClearCache(Ihandle* ih, void* handle);
+
+typedef struct _iupColor {
+ unsigned char r, g, b, a;
+} iupColor;
+
+int iupImageInitColorTable(Ihandle *ih, iupColor* colors, int *colors_count);
+void iupImageInitNonBgColors(Ihandle* ih, unsigned char *colors);
+void iupImageColorMakeInactive(unsigned char *r, unsigned char *g, unsigned char *b,
+ unsigned char bg_r, unsigned char bg_g, unsigned char bg_b);
+int iupImageNormBpp(int bpp);
+
+#define iupALPHABLEND(_src,_dst,_alpha) (unsigned char)(((_src) * (_alpha) + (_dst) * (255 - (_alpha))) / 255)
+
+/* In Windows, RAW data is a DIB handle.
+ imgdata here is bottom-up arranged and has separated planes */
+void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata);
+int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count);
+void iupdrvImageGetRawData(void* handle, unsigned char* imgdata);
+
+void iupImageStockInit(void);
+void iupImageStockFinish(void);
+typedef Ihandle* (*iupImageStockCreateFunc)(void);
+void iupImageStockSet(const char *name, iupImageStockCreateFunc func, const char* native_name);
+void iupImageStockLoad(const char *name); /* Used only in iupImageLibLoadAll */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_key.c b/iup/src/iup_key.c
new file mode 100755
index 0000000..6c57c60
--- /dev/null
+++ b/iup/src/iup_key.c
@@ -0,0 +1,269 @@
+/** \file
+ * \brief Manage keys encoding and decoding.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <memory.h>
+#include <stdio.h>
+
+#include "iup.h"
+#include "iupkey.h"
+#include "iupcbs.h"
+
+#include "iup_key.h"
+#include "iup_str.h"
+#include "iup_object.h"
+#include "iup_drv.h"
+#include "iup_focus.h"
+
+
+static struct
+{
+ char *name;
+ int code;
+} ikey_map_list[]=
+ {
+ {"K_exclam", K_exclam},
+ {"K_grave", K_grave},
+ {"K_quotedbl", K_quotedbl},
+ {"K_numbersign", K_numbersign},
+ {"K_dollar", K_dollar},
+ {"K_percent", K_percent},
+ {"K_ampersand", K_ampersand},
+ {"K_apostrophe", K_apostrophe},
+ {"K_parentleft", K_parentleft},
+ {"K_parentright", K_parentright},
+ {"K_asterisk", K_asterisk}, {"K_sAsterisk",K_sAsterisk},{"K_cAsterisk",K_cAsterisk},{"K_mAsterisk",K_mAsterisk},{"K_yAsterisk",K_yAsterisk},
+ {"K_plus", K_plus}, {"K_sPlus", K_sPlus}, {"K_cPlus", K_cPlus}, {"K_mPlus", K_mPlus}, {"K_yPlus", K_yPlus},
+ {"K_comma", K_comma}, {"K_sComma", K_sComma}, {"K_cComma", K_cComma}, {"K_mComma", K_mComma}, {"K_yComma", K_yComma},
+ {"K_minus", K_minus}, {"K_sMinus", K_sMinus}, {"K_cMinus", K_cMinus}, {"K_mMinus", K_mMinus}, {"K_yMinus", K_yMinus},
+ {"K_period", K_period}, {"K_sPeriod", K_sPeriod}, {"K_cPeriod", K_cPeriod}, {"K_mPeriod", K_mPeriod}, {"K_yPeriod", K_yPeriod},
+ {"K_slash", K_slash}, {"K_sSlash", K_sSlash}, {"K_cSlash", K_cSlash}, {"K_mSlash", K_mSlash}, {"K_ySlash", K_ySlash},
+ {"K_colon", K_colon},
+ {"K_semicolon ", K_semicolon}, {"K_cSemicolon ", K_cSemicolon}, {"K_mSemicolon ", K_mSemicolon}, {"K_ySemicolon ", K_ySemicolon},
+ {"K_less", K_less},
+ {"K_equal", K_equal}, {"K_cEqual", K_cEqual}, {"K_mEqual", K_mEqual}, {"K_yEqual", K_yEqual},
+ {"K_greater", K_greater},
+ {"K_question", K_question},
+ {"K_bracketleft", K_bracketleft}, {"K_cBracketleft", K_cBracketleft}, {"K_mBracketleft", K_mBracketleft}, {"K_yBracketleft", K_yBracketleft},
+ {"K_backslash", K_backslash}, {"K_cBackslash", K_cBackslash}, {"K_mBackslash", K_mBackslash}, {"K_yBackslash", K_yBackslash},
+ {"K_bracketright", K_bracketright}, {"K_cBracketright", K_cBracketright}, {"K_mBracketright", K_mBracketright}, {"K_yBracketright", K_yBracketright},
+ {"K_circum", K_circum},
+ {"K_underscore", K_underscore},
+ {"K_at", K_at},
+ {"K_braceleft", K_braceleft},
+ {"K_bar", K_bar},
+ {"K_braceright", K_braceright},
+ {"K_tilde", K_tilde},
+ {"K_acute", K_acute},
+ {"K_ccedilla" ,K_ccedilla}, {"K_Ccedilla" ,K_Ccedilla}, {"K_cCcedilla" ,K_cCcedilla}, {"K_mCcedilla" ,K_mCcedilla}, {"K_yCcedilla" ,K_yCcedilla},
+ {"K_ESC" ,K_ESC}, {"K_sESC" ,K_sESC}, {"K_cESC" ,K_cESC}, {"K_mESC" ,K_mESC}, {"K_yESC" ,K_yESC},
+ {"K_PAUSE" ,K_PAUSE}, {"K_sPAUSE" ,K_sPAUSE}, {"K_cPAUSE" ,K_cPAUSE}, {"K_mPAUSE" ,K_mPAUSE}, {"K_yPAUSE" ,K_yPAUSE},
+ {"K_HOME" ,K_HOME}, {"K_sHOME" ,K_sHOME}, {"K_cHOME" ,K_cHOME}, {"K_mHOME" ,K_mHOME}, {"K_yHOME" ,K_yHOME},
+ {"K_UP" ,K_UP}, {"K_sUP" ,K_sUP}, {"K_cUP" ,K_cUP}, {"K_mUP" ,K_mUP}, {"K_yUP" ,K_yUP},
+ {"K_PGUP" ,K_PGUP}, {"K_sPGUP" ,K_sPGUP}, {"K_cPGUP" ,K_cPGUP}, {"K_mPGUP" ,K_mPGUP}, {"K_yPGUP" ,K_yPGUP},
+ {"K_LEFT" ,K_LEFT}, {"K_sLEFT" ,K_sLEFT}, {"K_cLEFT" ,K_cLEFT}, {"K_mLEFT" ,K_mLEFT}, {"K_yLEFT" ,K_yLEFT},
+ {"K_MIDDLE",K_MIDDLE}, {"K_sMIDDLE",K_sMIDDLE},{"K_cMIDDLE",K_cMIDDLE},{"K_mMIDDLE",K_mMIDDLE}, {"K_yMIDDLE",K_yMIDDLE},
+ {"K_RIGHT" ,K_RIGHT}, {"K_sRIGHT" ,K_sRIGHT}, {"K_cRIGHT" ,K_cRIGHT}, {"K_mRIGHT" ,K_mRIGHT}, {"K_yRIGHT" ,K_yRIGHT},
+ {"K_END" ,K_END}, {"K_sEND" ,K_sEND}, {"K_cEND" ,K_cEND}, {"K_mEND" ,K_mEND}, {"K_yEND" ,K_yEND},
+ {"K_DOWN" ,K_DOWN}, {"K_sDOWN" ,K_sDOWN}, {"K_cDOWN" ,K_cDOWN}, {"K_mDOWN" ,K_mDOWN}, {"K_yDOWN" ,K_yDOWN},
+ {"K_PGDN" ,K_PGDN}, {"K_sPGDN" ,K_sPGDN}, {"K_cPGDN" ,K_cPGDN}, {"K_mPGDN" ,K_mPGDN}, {"K_yPGDN" ,K_yPGDN},
+ {"K_INS" ,K_INS}, {"K_sINS" ,K_sINS}, {"K_cINS" ,K_cINS}, {"K_mINS" ,K_mINS}, {"K_yINS" ,K_yINS},
+ {"K_DEL" ,K_DEL}, {"K_sDEL" ,K_sDEL}, {"K_cDEL" ,K_cDEL}, {"K_mDEL" ,K_mDEL}, {"K_yDEL" ,K_yDEL},
+ {"K_SP" ,K_SP}, {"K_sSP" ,K_sSP}, {"K_cSP" ,K_cSP}, {"K_mSP" ,K_mSP}, {"K_ySP" ,K_ySP},
+ {"K_TAB" ,K_TAB}, {"K_sTAB" ,K_sTAB}, {"K_cTAB" ,K_cTAB}, {"K_mTAB" ,K_mTAB}, {"K_yTAB" ,K_yTAB},
+ {"K_CR" ,K_CR}, {"K_sCR" ,K_sCR}, {"K_cCR" ,K_cCR}, {"K_mCR" ,K_mCR}, {"K_yCR" ,K_yCR},
+ {"K_BS" ,K_BS}, {"K_sBS" ,K_sBS}, {"K_cBS" ,K_cBS}, {"K_mBS" ,K_mBS}, {"K_yBS" ,K_yBS},
+ {"K_Print" ,K_Print}, {"K_sPrint" ,K_sPrint}, {"K_cPrint" ,K_cPrint}, {"K_mPrint" ,K_mPrint}, {"K_yPrint" ,K_yPrint},
+ {"K_Menu" ,K_Menu}, {"K_sMenu" ,K_sMenu}, {"K_cMenu" ,K_cMenu}, {"K_mMenu" ,K_mMenu}, {"K_yMenu" ,K_yMenu},
+ {"K_0", K_0}, {"K_c0", K_c0}, {"K_m0", K_m0}, {"K_y0", K_y0},
+ {"K_1", K_1}, {"K_c1", K_c1}, {"K_m1", K_m1}, {"K_y1", K_y1},
+ {"K_2", K_2}, {"K_c2", K_c2}, {"K_m2", K_m2}, {"K_y2", K_y2},
+ {"K_3", K_3}, {"K_c3", K_c3}, {"K_m3", K_m3}, {"K_y3", K_y3},
+ {"K_4", K_4}, {"K_c4", K_c4}, {"K_m4", K_m4}, {"K_y4", K_y4},
+ {"K_5", K_5}, {"K_c5", K_c5}, {"K_m5", K_m5}, {"K_y5", K_y5},
+ {"K_6", K_6}, {"K_c6", K_c6}, {"K_m6", K_m6}, {"K_y6", K_y6},
+ {"K_7", K_7}, {"K_c7", K_c7}, {"K_m7", K_m7}, {"K_y7", K_y7},
+ {"K_8", K_8}, {"K_c8", K_c8}, {"K_m8", K_m8}, {"K_y8", K_y8},
+ {"K_9", K_9}, {"K_c9", K_c9}, {"K_m9", K_m9}, {"K_y9", K_y9},
+ {"K_a", K_a}, {"K_A", K_A}, {"K_cA" ,K_cA}, {"K_mA" ,K_mA}, {"K_yA" ,K_yA},
+ {"K_b", K_b}, {"K_B", K_B}, {"K_cB" ,K_cB}, {"K_mB" ,K_mB}, {"K_yB" ,K_yB},
+ {"K_c", K_c}, {"K_C", K_C}, {"K_cC" ,K_cC}, {"K_mC" ,K_mC}, {"K_yC" ,K_yC},
+ {"K_d", K_d}, {"K_D", K_D}, {"K_cD" ,K_cD}, {"K_mD" ,K_mD}, {"K_yD" ,K_yD},
+ {"K_e", K_e}, {"K_E", K_E}, {"K_cE" ,K_cE}, {"K_mE" ,K_mE}, {"K_yE" ,K_yE},
+ {"K_f", K_f}, {"K_F", K_F}, {"K_cF" ,K_cF}, {"K_mF" ,K_mF}, {"K_yF" ,K_yF},
+ {"K_g", K_g}, {"K_G", K_G}, {"K_cG" ,K_cG}, {"K_mG" ,K_mG}, {"K_yG" ,K_yG},
+ {"K_h", K_h}, {"K_H", K_H}, {"K_cH" ,K_cH}, {"K_mH" ,K_mH}, {"K_yH" ,K_yH},
+ {"K_i", K_i}, {"K_I", K_I}, {"K_cI" ,K_cI}, {"K_mI" ,K_mI}, {"K_yI" ,K_yI},
+ {"K_j", K_j}, {"K_J", K_J}, {"K_cJ" ,K_cJ}, {"K_mJ" ,K_mJ}, {"K_yJ" ,K_yJ},
+ {"K_k", K_k}, {"K_K", K_K}, {"K_cK" ,K_cK}, {"K_mK" ,K_mK}, {"K_yK" ,K_yK},
+ {"K_l", K_l}, {"K_L", K_L}, {"K_cL" ,K_cL}, {"K_mL" ,K_mL}, {"K_yL" ,K_yL},
+ {"K_m", K_m}, {"K_M", K_M}, {"K_cM" ,K_cM}, {"K_mM" ,K_mM}, {"K_yM" ,K_yM},
+ {"K_n", K_n}, {"K_N", K_N}, {"K_cN" ,K_cN}, {"K_mN" ,K_mN}, {"K_yN" ,K_yN},
+ {"K_o", K_o}, {"K_O", K_O}, {"K_cO" ,K_cO}, {"K_mO" ,K_mO}, {"K_yO" ,K_yO},
+ {"K_p", K_p}, {"K_P", K_P}, {"K_cP" ,K_cP}, {"K_mP" ,K_mP}, {"K_yP" ,K_yP},
+ {"K_q", K_q}, {"K_Q", K_Q}, {"K_cQ" ,K_cQ}, {"K_mQ" ,K_mQ}, {"K_yQ" ,K_yQ},
+ {"K_r", K_r}, {"K_R", K_R}, {"K_cR" ,K_cR}, {"K_mR" ,K_mR}, {"K_yR" ,K_yR},
+ {"K_s", K_s}, {"K_S", K_S}, {"K_cS" ,K_cS}, {"K_mS" ,K_mS}, {"K_yS" ,K_yS},
+ {"K_t", K_t}, {"K_T", K_T}, {"K_cT" ,K_cT}, {"K_mT" ,K_mT}, {"K_yT" ,K_yT},
+ {"K_u", K_u}, {"K_U", K_U}, {"K_cU" ,K_cU}, {"K_mU" ,K_mU}, {"K_yU" ,K_yU},
+ {"K_v", K_v}, {"K_V", K_V}, {"K_cV" ,K_cV}, {"K_mV" ,K_mV}, {"K_yV" ,K_yV},
+ {"K_w", K_w}, {"K_W", K_W}, {"K_cW" ,K_cW}, {"K_mW" ,K_mW}, {"K_yW" ,K_yW},
+ {"K_x", K_x}, {"K_X", K_X}, {"K_cX" ,K_cX}, {"K_mX" ,K_mX}, {"K_yX" ,K_yX},
+ {"K_y", K_y}, {"K_Y", K_Y}, {"K_cY" ,K_cY}, {"K_mY" ,K_mY}, {"K_yY" ,K_yY},
+ {"K_z", K_z}, {"K_Z", K_Z}, {"K_cZ" ,K_cZ}, {"K_mZ" ,K_mZ}, {"K_yZ" ,K_yZ},
+ {"K_F1" ,K_F1}, {"K_sF1" ,K_sF1}, {"K_cF1" ,K_cF1}, {"K_mF1" ,K_mF1}, {"K_yF1" ,K_yF1},
+ {"K_F2" ,K_F2}, {"K_sF2" ,K_sF2}, {"K_cF2" ,K_cF2}, {"K_mF2" ,K_mF2}, {"K_yF2" ,K_yF2},
+ {"K_F3" ,K_F3}, {"K_sF3" ,K_sF3}, {"K_cF3" ,K_cF3}, {"K_mF3" ,K_mF3}, {"K_yF3" ,K_yF3},
+ {"K_F4" ,K_F4}, {"K_sF4" ,K_sF4}, {"K_cF4" ,K_cF4}, {"K_mF4" ,K_mF4}, {"K_yF4" ,K_yF4},
+ {"K_F5" ,K_F5}, {"K_sF5" ,K_sF5}, {"K_cF5" ,K_cF5}, {"K_mF5" ,K_mF5}, {"K_yF5" ,K_yF5},
+ {"K_F6" ,K_F6}, {"K_sF6" ,K_sF6}, {"K_cF6" ,K_cF6}, {"K_mF6" ,K_mF6}, {"K_yF6" ,K_yF6},
+ {"K_F7" ,K_F7}, {"K_sF7" ,K_sF7}, {"K_cF7" ,K_cF7}, {"K_mF7" ,K_mF7}, {"K_yF7" ,K_yF7},
+ {"K_F8" ,K_F8}, {"K_sF8" ,K_sF8}, {"K_cF8" ,K_cF8}, {"K_mF8" ,K_mF8}, {"K_yF8" ,K_yF8},
+ {"K_F9" ,K_F9}, {"K_sF9" ,K_sF9}, {"K_cF9" ,K_cF9}, {"K_mF9" ,K_mF9}, {"K_yF9" ,K_yF9},
+ {"K_F10" ,K_F10}, {"K_sF10" ,K_sF10}, {"K_cF10" ,K_cF10}, {"K_mF10" ,K_mF10}, {"K_yF10" ,K_yF10},
+ {"K_F11" ,K_F11}, {"K_sF11" ,K_sF11}, {"K_cF11" ,K_cF11}, {"K_mF11" ,K_mF11}, {"K_yF11" ,K_yF11},
+ {"K_F12" ,K_F12}, {"K_sF12" ,K_sF12}, {"K_cF12" ,K_cF12}, {"K_mF12" ,K_mF12}, {"K_yF12" ,K_yF12},
+ {NULL ,0}
+ };
+
+static char* ikey_map[IUP_NUMMAXCODES];
+
+void iupKeyInit(void)
+{
+ int i;
+ memset(ikey_map, 0, IUP_NUMMAXCODES*sizeof(char*));
+ for (i = 0; ikey_map_list[i].name; i++)
+ ikey_map[ikey_map_list[i].code] = ikey_map_list[i].name;
+}
+
+int iupKeyCanCaps(int code)
+{
+ if (code >= K_a && code <= K_z)
+ return 1;
+ if (code == K_ccedilla)
+ return 1;
+ return 0;
+}
+
+char* iupKeyCodeToName(int code)
+{
+ if (code < 0 || code > IUP_NUMMAXCODES)
+ return NULL;
+ return ikey_map[code];
+}
+
+int iupKeyNameToCode(const char *name)
+{
+ int i;
+ for (i = 0; ikey_map_list[i].name; i++)
+ if (iupStrEqual(name, ikey_map_list[i].name))
+ return ikey_map_list[i].code;
+
+ return 0;
+}
+
+void iupKeyForEach(void (*func)(const char *name, int code, void* user_data), void* user_data)
+{
+ int i;
+ for (i = 0; ikey_map_list[i].name; ++i)
+ func(ikey_map_list[i].name, ikey_map_list[i].code, user_data);
+}
+
+int iupKeyCallKeyCb(Ihandle *ih, int code)
+{
+ char* name = iupKeyCodeToName(code);
+ for (; ih; ih = ih->parent)
+ {
+ IFni cb = NULL;
+ if (name)
+ cb = (IFni)IupGetCallback(ih, name);
+ if (!cb)
+ cb = (IFni)IupGetCallback(ih, "K_ANY");
+
+ if (cb)
+ {
+ int ret = cb(ih, code);
+ if (ret != IUP_CONTINUE)
+ return ret;
+ }
+ }
+ return IUP_DEFAULT;
+}
+
+int iupKeyCallKeyPressCb(Ihandle *ih, int code, int press)
+{
+ IFnii cb = (IFnii)IupGetCallback(ih, "KEYPRESS_CB");
+ if (cb) return cb(ih, code, press);
+ return IUP_DEFAULT;
+}
+
+int iupKeyProcessNavigation(Ihandle* ih, int key, int shift)
+{
+ /* this is called after K_ANY is processed,
+ so the user may change its behavior */
+
+ if (key == K_cTAB)
+ {
+ int is_multiline = (iupStrEqual(ih->iclass->name, "multiline") ||
+ (iupStrEqual(ih->iclass->name, "text") && IupGetInt(ih, "MULTILINE")));
+ if (is_multiline)
+ {
+ if (shift)
+ IupPreviousField(ih);
+ else
+ IupNextField(ih);
+ return 0; /* abort default processing */
+ }
+ }
+ else if (key == K_TAB || key == K_sTAB)
+ {
+ int is_multiline = (iupStrEqual(ih->iclass->name, "multiline") ||
+ (iupStrEqual(ih->iclass->name, "text") && IupGetInt(ih, "MULTILINE")));
+ if (!is_multiline)
+ {
+ if (key == K_sTAB)
+ IupPreviousField(ih);
+ else
+ IupNextField(ih);
+ return 0; /* abort default processing */
+ }
+ }
+ else if (key == K_UP || key == K_DOWN)
+ {
+ int is_button = (iupStrEqual(ih->iclass->name, "button") ||
+ iupStrEqual(ih->iclass->name, "toggle"));
+ if (is_button)
+ {
+ if (key == K_UP)
+ iupFocusPrevious(ih);
+ else
+ iupFocusNext(ih);
+ return 0; /* abort default processing */
+ }
+ }
+ else if (key==K_ESC)
+ {
+ Ihandle* bt = IupGetAttributeHandle(IupGetDialog(ih), "DEFAULTESC");
+ if (iupObjectCheck(bt) && iupStrEqual(bt->iclass->name, "button"))
+ iupdrvActivate(bt);
+ return 0; /* abort default processing */
+ }
+ else if (key==K_CR || key==K_cCR)
+ {
+ int is_multiline = (iupStrEqual(ih->iclass->name, "multiline") ||
+ (iupStrEqual(ih->iclass->name, "text") && IupGetInt(ih, "MULTILINE")));
+
+ if ((key==K_CR && !is_multiline) || (key==K_cCR && is_multiline))
+ {
+ Ihandle* bt = IupGetAttributeHandle(IupGetDialog(ih), "DEFAULTENTER");
+ if (iupObjectCheck(bt) && iupStrEqual(bt->iclass->name, "button"))
+ iupdrvActivate(bt);
+ return 0; /* abort default processing */
+ }
+ }
+
+ return 1;
+}
+
diff --git a/iup/src/iup_key.h b/iup/src/iup_key.h
new file mode 100755
index 0000000..37d6c9d
--- /dev/null
+++ b/iup/src/iup_key.h
@@ -0,0 +1,70 @@
+/** \file
+ * \brief Manage keys encoding and decoding.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_KEY_H
+#define __IUP_KEY_H
+
+
+/** \defgroup key Key Coding and Key Callbacks
+ * \par
+ * See \ref iup_key.h
+ * \ingroup cpi */
+
+
+/** Returns the key name from its code.
+ * Returns NULL if code not found.
+ * \ingroup key */
+char *iupKeyCodeToName(int code);
+
+/** Returns the key code from its name.
+ * Returns 0 if name not found.
+ * \ingroup key */
+int iupKeyNameToCode(const char *name);
+
+/** Returns true if the key code can be changed by CAPSLOCK.
+ * \ingroup key */
+int iupKeyCanCaps(int code);
+
+/** Calls a function for each defined key.
+ * \ingroup key */
+void iupKeyForEach(void (*func)(const char *name, int code, void* user_data), void* user_data);
+
+/** Calls the K_ANY or K_* callbacks. Should be called when a keyboard event occoured.
+ * \ingroup key */
+int iupKeyCallKeyCb(Ihandle *ih, int c);
+
+/** Calls the KEYPRESS_CB callback. Should be called when a keyboard event occoured.
+ * \ingroup key */
+int iupKeyCallKeyPressCb(Ihandle *ih, int code, int press);
+
+/** Process Tab, DEFAULTENTER and DEFAULTESC in key press events.
+ * \ingroup key */
+int iupKeyProcessNavigation(Ihandle* ih, int key, int shift);
+
+
+/* Called only from IupOpen. */
+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')
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_label.c b/iup/src/iup_label.c
new file mode 100755
index 0000000..33d96af
--- /dev/null
+++ b/iup/src/iup_label.c
@@ -0,0 +1,183 @@
+/** \file
+ * \brief Label Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_label.h"
+#include "iup_image.h"
+
+
+static int iLabelSetSeparatorAttrib(Ihandle* ih, const char* value)
+{
+ /* valid only before map */
+ if (ih->handle)
+ return 0;
+
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "HORIZONTAL"))
+ ih->expand = IUP_EXPAND_WIDTH;
+ else if (iupStrEqualNoCase(value, "VERTICAL"))
+ ih->expand = IUP_EXPAND_HEIGHT;
+ else
+ return 0;
+ }
+
+ return 1;
+}
+
+static char* iLabelGetSeparatorAttrib(Ihandle* ih)
+{
+ if (ih->handle)
+ {
+ if (ih->data->type == IUP_LABEL_SEP_HORIZ)
+ return "HORIZONTAL";
+ else if (ih->data->type == IUP_LABEL_SEP_VERT)
+ return "VERTICAL";
+ }
+ return NULL;
+}
+
+char* iupLabelGetPaddingAttrib(Ihandle* ih)
+{
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+
+/**************************************************************************************/
+
+
+static int iLabelCreateMethod(Ihandle* ih, void** params)
+{
+ if (params && params[0])
+ iupAttribStoreStr(ih, "TITLE", (char*)(params[0]));
+
+ ih->data = iupALLOCCTRLDATA();
+
+ /* used only by the Windows driver */
+ ih->data->vert_alignment = IUP_ALIGN_ACENTER;
+ return IUP_NOERROR;
+}
+
+static void iLabelComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ int natural_w = 0,
+ natural_h = 0,
+ type = ih->data->type;
+ (void)expand; /* unset if not a container */
+
+ if (!ih->handle)
+ {
+ /* if not mapped must initialize the internal values */
+ char* value = iupAttribGet(ih, "SEPARATOR");
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "HORIZONTAL"))
+ type = IUP_LABEL_SEP_HORIZ;
+ else /* "VERTICAL" */
+ type = IUP_LABEL_SEP_VERT;
+ }
+ else
+ {
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ type = IUP_LABEL_IMAGE;
+ else
+ type = IUP_LABEL_TEXT;
+ }
+ }
+
+ if (type == IUP_LABEL_SEP_HORIZ)
+ natural_h = 2;
+ else if (type == IUP_LABEL_SEP_VERT)
+ natural_w = 2;
+ else if (type == IUP_LABEL_IMAGE)
+ {
+ iupImageGetInfo(iupAttribGet(ih, "IMAGE"), &natural_w, &natural_h, NULL);
+
+ natural_w += 2*ih->data->horiz_padding;
+ natural_h += 2*ih->data->vert_padding;
+ }
+ else /* IUP_LABEL_TEXT */
+ {
+ /* must use IupGetAttribute to check from the native implementation */
+ char* title = IupGetAttribute(ih, "TITLE");
+ char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */
+ iupdrvFontGetMultiLineStringSize(ih, str, &natural_w, &natural_h);
+ if (str && str!=title) free(str);
+
+ natural_w += 2*ih->data->horiz_padding;
+ natural_h += 2*ih->data->vert_padding;
+ }
+
+ *w = natural_w;
+ *h = natural_h;
+}
+
+
+/******************************************************************************/
+
+
+Ihandle* IupLabel(const char* title)
+{
+ void *params[2];
+ params[0] = (void*)title;
+ params[1] = NULL;
+ return IupCreatev("label", params);
+}
+
+Iclass* iupLabelGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "label";
+ ic->format = "S"; /* one optional string */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = iLabelCreateMethod;
+ ic->ComputeNaturalSize = iLabelComputeNaturalSizeMethod;
+
+ ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Common Callbacks */
+ iupClassRegisterCallback(ic, "MAP_CB", "");
+ iupClassRegisterCallback(ic, "UNMAP_CB", "");
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Visual */
+ iupBaseRegisterVisualAttrib(ic);
+
+ /* IupLabel only */
+ iupClassRegisterAttribute(ic, "SEPARATOR", iLabelGetSeparatorAttrib, iLabelSetSeparatorAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupdrvLabelInitClass(ic);
+
+ return ic;
+}
diff --git a/iup/src/iup_label.h b/iup/src/iup_label.h
new file mode 100755
index 0000000..f50d26f
--- /dev/null
+++ b/iup/src/iup_label.h
@@ -0,0 +1,37 @@
+/** \file
+ * \brief Label Controls Private Declarations
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_LABEL_H
+#define __IUP_LABEL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void iupdrvLabelInitClass(Iclass* ic);
+
+char* iupLabelGetPaddingAttrib(Ihandle* ih);
+
+enum{IUP_LABEL_SEP_HORIZ, IUP_LABEL_SEP_VERT, IUP_LABEL_IMAGE, IUP_LABEL_TEXT};
+
+struct _IcontrolData
+{
+ int type, /* the 4 labels possibilities */
+ horiz_padding, vert_padding; /* label margin */
+
+ /* used only by the Windows driver */
+ int horiz_alignment, vert_alignment,
+ text_style;
+ unsigned long fgcolor;
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_layout.c b/iup/src/iup_layout.c
new file mode 100755
index 0000000..b96293c
--- /dev/null
+++ b/iup/src/iup_layout.c
@@ -0,0 +1,273 @@
+/** \file
+ * \brief Abstract Layout Management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_drv.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_layout.h"
+#include "iup_assert.h"
+
+
+void IupRefresh(Ihandle* ih)
+{
+ Ihandle* dialog;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+
+ dialog = IupGetDialog(ih);
+ if (dialog)
+ {
+ iupLayoutCompute(dialog);
+ if (dialog->handle)
+ iupLayoutUpdate(dialog);
+ }
+}
+
+static void iLayoutDisplayUpdateChildren(Ihandle *ih)
+{
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ iLayoutDisplayUpdateChildren(child);
+
+ if (child->handle && child->iclass->nativetype != IUP_TYPEVOID)
+ iupdrvDisplayUpdate(child);
+ }
+}
+
+void IupUpdate(Ihandle* ih)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+
+ if (ih->handle && ih->iclass->nativetype != IUP_TYPEVOID)
+ iupdrvDisplayUpdate(ih);
+}
+
+void IupUpdateChildren(Ihandle* ih)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+
+ iLayoutDisplayUpdateChildren(ih);
+}
+
+static void iLayoutDisplayRedrawChildren(Ihandle *ih)
+{
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ iLayoutDisplayRedrawChildren(child);
+
+ if (child->handle && child->iclass->nativetype != IUP_TYPEVOID)
+ iupdrvDisplayRedraw(child);
+ }
+}
+
+void IupRedraw(Ihandle* ih, int children)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+
+ if (ih->handle && ih->iclass->nativetype != IUP_TYPEVOID)
+ iupdrvDisplayRedraw(ih);
+
+ if (children)
+ iLayoutDisplayRedrawChildren(ih);
+}
+
+void iupLayoutUpdate(Ihandle* ih)
+{
+ Ihandle* child;
+
+ /* update size and position of the native control */
+ iupClassObjectLayoutUpdate(ih);
+
+ /* update its children */
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (child->handle)
+ iupLayoutUpdate(child);
+ }
+}
+
+void iupLayoutCompute(Ihandle* ih)
+{
+ int shrink = iupAttribGetBoolean(ih, "SHRINK");
+
+ /* Compute the natural size for all elements in the dialog,
+ using the minimum visible size and the defined user size.
+ The minimum visible size is the size where all the controls can display
+ all their contents.
+ The defined user size is used to increase the value of the minimum visible size for containers,
+ for standard controls will replace the minimum visible size.
+ So the native size will be the maximum value between
+ minimum visible size and defined user size.
+ Also calculates the expand configuration for each element, but expand is used only in SetChildrenCurrentSize.
+ SEQUENCE: will first calculate the native size for the children, then for the element. */
+ iupBaseComputeNaturalSize(ih);
+
+ /* Set the current size (not reflected in the native element yet) based on
+ the natural size and the expand configuration.
+ If shrink is 0 (default) the current size of containers can be only larger than the natural size,
+ the result will depend on the EXPAND attribute.
+ If shrink is 1 the containers can be resized to sizes smaller than the natural size.
+ SEQUENCE: will first calculate the current size of the element, then for the children. */
+ iupBaseSetCurrentSize(ih, 0, 0, shrink);
+
+ /* Now that the current size is known, set the position of the elements
+ relative to the parent.
+ SEQUENCE: will first set the position of the element, then for the children. */
+ iupBaseSetPosition(ih, 0, 0);
+}
+
+static void iLayoutSetMinMaxSize(Ihandle* ih, int *w, int *h)
+{
+ if (ih->has_minsize)
+ {
+ char* value = iupAttribGet(ih, "MINSIZE");
+ int min_w = 0, min_h = 0; /* MINSIZE default value */
+ iupStrToIntInt(value, &min_w, &min_h, 'x');
+ if (*w < min_w) *w = min_w;
+ if (*h < min_h) *h = min_h;
+ }
+
+ if (ih->has_maxsize)
+ {
+ char* value = iupAttribGet(ih, "MAXSIZE");
+ int max_w = 65535, max_h = 65535; /* MAXSIZE default value */
+ iupStrToIntInt(value, &max_w, &max_h, 'x');
+ if (*w > max_w) *w = max_w;
+ if (*h > max_h) *h = max_h;
+ }
+}
+
+void iupBaseComputeNaturalSize(Ihandle* ih)
+{
+ /* always initialize the natural size using the user size */
+ ih->naturalwidth = ih->userwidth;
+ ih->naturalheight = ih->userheight;
+
+ if (ih->iclass->childtype!=IUP_CHILDNONE || ih->iclass->nativetype == IUP_TYPEDIALOG)
+ {
+ int w=0, h=0, children_expand;
+
+ /* if a container then update the "expand" member from the EXPAND attribute */
+ iupBaseContainerUpdateExpand(ih);
+ children_expand = ih->expand; /* use it as default value */
+
+ iupClassObjectComputeNaturalSize(ih, &w, &h, &children_expand);
+
+ if (ih->iclass->nativetype == IUP_TYPEDIALOG)
+ {
+ /* only update the natural size if user size is not defined. */
+ /* IupDialog is the only container where this must be done */
+ /* if the natural size is bigger than the actual dialog size then
+ the dialog will be resized, if smaller then the dialog remains with the same size. */
+ ih->expand |= children_expand;
+ if (ih->naturalwidth <= 0) ih->naturalwidth = iupMAX(ih->currentwidth, w);
+ if (ih->naturalheight <= 0) ih->naturalheight = iupMAX(ih->currentheight, h);
+ }
+ else
+ {
+ ih->expand &= children_expand; /* combine but only expand where the element can expand */
+ ih->naturalwidth = iupMAX(ih->naturalwidth, w);
+ ih->naturalheight = iupMAX(ih->naturalheight, h);
+
+ /* crop the natural size */
+ iLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight));
+ }
+ }
+ else
+ {
+ /* 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);
+
+ if (ih->naturalwidth <= 0) ih->naturalwidth = w;
+ if (ih->naturalheight <= 0) ih->naturalheight = h;
+ }
+
+ /* crop the natural size */
+ iLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight));
+ }
+}
+
+void iupBaseSetCurrentSize(Ihandle* ih, int w, int h, int shrink)
+{
+ if (ih->iclass->nativetype == IUP_TYPEDIALOG)
+ {
+ /* w and h parameters here are ignored, because they are always 0 for the dialog. */
+
+ /* current size is zero before map and when reset by the application */
+ /* after that the current size must follow the actual size of the dialog */
+ if (!ih->currentwidth) ih->currentwidth = ih->naturalwidth;
+ if (!ih->currentheight) ih->currentheight = ih->naturalheight;
+
+ if (ih->firstchild)
+ iupClassObjectSetChildrenCurrentSize(ih, shrink);
+ }
+ else
+ {
+ if (ih->iclass->childtype!=IUP_CHILDNONE)
+ {
+ if (shrink)
+ {
+ /* if expand then use the given size, else use the natural size */
+ /* this expand is a combination of the expand defined for the element and its children */
+ ih->currentwidth = (ih->expand & IUP_EXPAND_WIDTH)? w: ih->naturalwidth;
+ ih->currentheight = (ih->expand & IUP_EXPAND_HEIGHT)? h: ih->naturalheight;
+ }
+ else
+ {
+ /* if expand then use the given size (if greater than natural size), else use the natural size */
+ /* this expand is a combination of the expand defined for the element and its children */
+ ih->currentwidth = (ih->expand & IUP_EXPAND_WIDTH)? iupMAX(ih->naturalwidth, w): ih->naturalwidth;
+ ih->currentheight = (ih->expand & IUP_EXPAND_HEIGHT)? iupMAX(ih->naturalheight, h): ih->naturalheight;
+ }
+
+ if (ih->firstchild)
+ iupClassObjectSetChildrenCurrentSize(ih, shrink);
+ }
+ else
+ {
+ /* shrink is only used by containers, usually is 0 */
+ /* for non containers is always 1, so they always can be smaller than the natural size */
+
+ /* if expand use the given size, else use the natural size */
+ /* this expand is the defined for the element */
+ ih->currentwidth = (ih->expand & IUP_EXPAND_WIDTH)? w: ih->naturalwidth;
+ ih->currentheight = (ih->expand & IUP_EXPAND_HEIGHT)? h: ih->naturalheight;
+ }
+
+ /* crop the current size if expanded */
+ if (ih->expand & IUP_EXPAND_WIDTH || ih->expand & IUP_EXPAND_HEIGHT)
+ iLayoutSetMinMaxSize(ih, &(ih->currentwidth), &(ih->currentheight));
+ }
+}
+
+void iupBaseSetPosition(Ihandle* ih, int x, int y)
+{
+ ih->x = x;
+ ih->y = y;
+
+ if (ih->firstchild)
+ iupClassObjectSetChildrenPosition(ih, x, y);
+}
diff --git a/iup/src/iup_layout.h b/iup/src/iup_layout.h
new file mode 100755
index 0000000..a2a0c29
--- /dev/null
+++ b/iup/src/iup_layout.h
@@ -0,0 +1,28 @@
+/** \file
+ * \brief Abstract Layout Management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_LAYOUT_H
+#define __IUP_LAYOUT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* called from IupMap and IupRefresh */
+void iupLayoutCompute(Ihandle* ih); /* can be called before map */
+void iupLayoutUpdate(Ihandle* ih); /* called only after map */
+
+/* Other functions declared in <iup.h> and implemented here.
+IupRefresh
+*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_ledlex.c b/iup/src/iup_ledlex.c
new file mode 100755
index 0000000..3283a43
--- /dev/null
+++ b/iup/src/iup_ledlex.c
@@ -0,0 +1,366 @@
+/** \file
+ * \brief lexical analysis manager for LED
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include "iup.h"
+
+#include "iup_class.h"
+#include "iup_ledlex.h"
+#include "iup_str.h"
+#include "iup_table.h"
+#include "iup_register.h"
+
+
+static struct /* lexical variables */
+{
+ const char* filename; /* file name */
+ const char* f;
+ FILE* file; /* file handle */
+ int token; /* lookahead iLexToken */
+ char name[40960]; /* lexical identifier value */
+ float number; /* lexical number value */
+ int line; /* line number */
+ Iclass *ic; /* control class when func is CONTROL_ */
+} ilex = {NULL, NULL, NULL, 0, "", (float) 0.0, 0, NULL};
+
+static int iLexGetChar (void);
+static int iLexToken(int *erro);
+static int iLexCapture (char* dlm);
+static int iLexSkip (char* dlm);
+static int iLexCaptureAttr (void);
+
+int iupLexStart(const char* filename, int is_file) /* initialize lexical analysis */
+{
+ ilex.filename = filename;
+ if (is_file)
+ {
+ ilex.file = fopen (ilex.filename,"r");
+ if (!ilex.file)
+ return iupLexError (IUPLEX_FILENOTOPENED, filename);
+ }
+ else
+ {
+ ilex.f = ilex.filename;
+ ilex.file = NULL;
+ }
+ ilex.line = 0;
+ ilex.line = 1;
+ return iupLexAdvance();
+}
+
+void iupLexClose(void)
+{
+ if (!ilex.file)
+ return;
+ fclose (ilex.file);
+ ilex.file = NULL;
+}
+
+static void iLexUngetc(int c)
+{
+ if (ilex.file)
+ ungetc(c, ilex.file);
+ else
+ {
+ if (*ilex.f != 0)
+ *(char*)ilex.f = (char)c; /* write back to the string ???? */
+ }
+}
+
+static int iLexGetc(void)
+{
+ if (ilex.file)
+ return getc(ilex.file);
+ else
+ {
+ if (*ilex.f != 0)
+ ilex.f++;
+ if (*ilex.f == 0)
+ return EOF;
+ return *ilex.f;
+ }
+}
+
+int iupLexLookAhead(void)
+{
+ return ilex.token;
+}
+
+int iupLexAdvance(void)
+{
+ int erro = 0;
+ ilex.token = iLexToken(&erro);
+ return erro;
+}
+
+int iupLexFollowedBy(int t)
+{
+ return (ilex.token==t);
+}
+
+int iupLexMatch(int t)
+{
+ if (ilex.token==t)
+ return iupLexAdvance();
+ else
+ return iupLexError (IUPLEX_NOTMATCH, ilex.token, t);
+}
+
+
+int iupLexSeenMatch(int t, int *erro)
+{
+ if (ilex.token==t)
+ {
+ *erro = iupLexAdvance();
+ return 1;
+ }
+ else
+ return 0;
+}
+
+unsigned char iupLexByte(void)
+{
+ unsigned int b;
+ sscanf(ilex.name,"%u", &b); /* read as integer to avoid reading number as characters */
+ if (b>255) b = 255;
+ return (unsigned char)b;
+}
+
+int iupLexInt(void)
+{
+ int i;
+ sscanf(ilex.name,"%d", &i);
+ return i;
+}
+
+float iupLexFloat(void)
+{
+ float f;
+ sscanf(ilex.name,"%g", &f);
+ return f;
+}
+
+char* iupLexGetName(void)
+{
+ if (ilex.name)
+ return iupStrDup(ilex.name);
+ else
+ return NULL;
+}
+
+char* iupLexName(void)
+{
+ return ilex.name;
+}
+
+float iupLexGetNumber(void)
+{
+ return ilex.number;
+}
+
+Iclass *iupLexGetClass(void)
+{
+ return ilex.ic;
+}
+
+static int iLexToken(int *erro)
+{
+ for (;;)
+ {
+ int c = iLexGetChar();
+ switch (c)
+ {
+ case 26:
+ case EOF:
+ return IUPLEX_TK_END;
+
+ case ']':
+ return IUPLEX_TK_ENDATTR;
+
+ case '#': /* iLexSkip comment */
+ case '%': /* iLexSkip comment */
+ iLexSkip ("\n\r");
+ continue;
+
+ case ' ': /* ignore whitespace */
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\f':
+ case '\v':
+ continue;
+
+ case '=': /* attribuicao */
+ return IUPLEX_TK_SET;
+
+ case ',':
+ return IUPLEX_TK_COMMA;
+
+ case '(': /* begin parameters */
+ return IUPLEX_TK_BEGP;
+
+ case ')': /* end parameters */
+ return IUPLEX_TK_ENDP;
+
+ case '[': /* attributes */
+ if (iLexCaptureAttr() == IUPLEX_TK_END)
+ {
+ *erro=iupLexError (IUPLEX_NOTENDATTR);
+ return 0;
+ }
+ return IUPLEX_TK_ATTR;
+
+ case '\"': /* string */
+ iLexCapture ("\"");
+ return IUPLEX_TK_STR;
+
+ case '\'': /* string */
+ iLexCapture ("\'");
+ return IUPLEX_TK_STR;
+
+ default:
+ if (c > 32) /* identifier */
+ {
+ char class_name[50];
+ iLexUngetc(c);
+ iLexUngetc(iLexCapture ("=[](), \t\n\r\f\v"));
+ iupStrLower(class_name, iupLexName());
+ ilex.ic = iupRegisterFindClass(class_name);
+ if (ilex.ic)
+ return IUPLEX_TK_FUNC;
+ else
+ return IUPLEX_TK_NAME;
+ }
+ }
+ return c;
+ }
+}
+
+static int iLexCapture (char* dlm)
+{
+ int i=0;
+ int c;
+ do
+ {
+ c = iLexGetChar ();
+ if (i < sizeof(ilex.name))
+ ilex.name[i++] = (char) c;
+ } while ((c > 0) && !strchr (dlm,c));
+ ilex.name[i-1]='\0'; /* discard delimiter */
+ return c; /* return delimiter */
+}
+
+static int iLexCaptureAttr (void)
+{
+ int i=0;
+ int c;
+ int aspas=0;
+ do
+ {
+ c = iLexGetChar ();
+ if (i < sizeof(ilex.name))
+ ilex.name[i++] = (char) c;
+ if (c == '"')
+ ++aspas;
+ } while ((c > 0) && ((aspas & 1) || c != ']'));
+ ilex.name[i-1]='\0'; /* discard delimiter */
+ return c; /* return delimiter */
+}
+
+static int iLexSkip (char* dlm)
+{
+ int c;
+ do
+ {
+ c = iLexGetChar ();
+ } while ((c > 0) && !strchr (dlm,c));
+ return c; /* return delimiter */
+}
+
+static int iLexGetChar (void)
+{
+ int c = iLexGetc(); if (c == '\n') ++ilex.line;
+ if (c == '\\')
+ {
+ c = iLexGetc();
+ if (c == 'n')
+ return '\n';
+ else if (c == '\\')
+ return '\\';
+ }
+ return c;
+}
+
+static char* iupTokenStr(int t)
+{
+ switch (t)
+ {
+ case IUPLEX_TK_END : return "end of file";
+ case IUPLEX_TK_BEGP : return "(";
+ case IUPLEX_TK_ENDP : return ")";
+ case IUPLEX_TK_ATTR : return "[";
+ case IUPLEX_TK_STR : return "string";
+ case IUPLEX_TK_NAME : return "identifier";
+ case IUPLEX_TK_NUMB : return "number";
+ case IUPLEX_TK_SET : return "=";
+ case IUPLEX_TK_COMMA: return ",";
+ case IUPLEX_TK_FUNC : return "function";
+ case IUPLEX_TK_ENDATTR : return "]";
+ }
+ return "";
+}
+
+static char ilex_erromsg[10240];
+
+char *iupLexGetError(void)
+{
+ return ilex_erromsg;
+}
+
+int iupLexError (int n, ...)
+{
+ char msg[10240];
+ va_list va;
+ va_start(va,n);
+ switch (n)
+ {
+ case IUPLEX_FILENOTOPENED:
+ {
+ char *fn=va_arg(va,char *);
+ sprintf (msg, "cannot open file %s", fn);
+ }
+ break;
+ case IUPLEX_NOTMATCH:
+ {
+ int tr=va_arg(va,int); /* iLexToken read */
+ int te=va_arg(va,int); /* iLexToken expected */
+ char *str=iupTokenStr(tr);
+ char *ste=iupTokenStr(te);
+ sprintf (msg, "expected %s but found %s", ste, str);
+ }
+ break;
+ case IUPLEX_NOTENDATTR:
+ {
+ sprintf (msg, "missing ']'");
+ }
+ break;
+ case IUPLEX_PARSEERROR:
+ {
+ char* s=va_arg(va,char*); /* iLexToken expected */
+ sprintf(msg,"%.*s",(int)(sizeof(msg)-1),s);
+ }
+ break;
+ }
+ va_end(va);
+ sprintf(ilex_erromsg, "led(%s): bad input at line %d - %s\n", ilex.filename, ilex.line, msg);
+ return n;
+}
diff --git a/iup/src/iup_ledlex.h b/iup/src/iup_ledlex.h
new file mode 100755
index 0000000..ad79ee1
--- /dev/null
+++ b/iup/src/iup_ledlex.h
@@ -0,0 +1,54 @@
+/** \file
+ * \brief lexical analysis manager for LED.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_LEX_H
+#define __IUP_LEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* TOKENS */
+#define IUPLEX_TK_END -1
+#define IUPLEX_TK_BEGP 1
+#define IUPLEX_TK_ENDP 2
+#define IUPLEX_TK_ATTR 3
+#define IUPLEX_TK_STR 4
+#define IUPLEX_TK_NAME 5
+#define IUPLEX_TK_NUMB 6
+#define IUPLEX_TK_SET 7
+#define IUPLEX_TK_COMMA 8
+#define IUPLEX_TK_FUNC 9
+#define IUPLEX_TK_ENDATTR 10
+
+/* ERRORS */
+#define IUPLEX_FILENOTOPENED 1
+#define IUPLEX_NOTMATCH 2
+#define IUPLEX_NOTENDATTR 3
+#define IUPLEX_PARSEERROR 4
+
+char* iupLexGetError (void);
+int iupLexStart (const char *filename, int is_file);
+void iupLexClose (void);
+int iupLexLookAhead (void);
+int iupLexAdvance (void);
+int iupLexFollowedBy (int t);
+int iupLexMatch (int t);
+int iupLexSeenMatch (int t, int *erro);
+unsigned char iupLexByte (void);
+int iupLexInt (void);
+float iupLexFloat (void);
+char* iupLexGetName (void);
+char* iupLexName (void);
+float iupLexGetNumber (void);
+int iupLexError (int n, ...);
+Iclass* iupLexGetClass (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_ledparse.c b/iup/src/iup_ledparse.c
new file mode 100755
index 0000000..2878e0b
--- /dev/null
+++ b/iup/src/iup_ledparse.c
@@ -0,0 +1,288 @@
+/** \file
+ * \brief parser for LED.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <memory.h>
+#include <string.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_ledlex.h"
+#include "iup_str.h"
+#include "iup_assert.h"
+
+
+#define IPARSE_SYMBEXIST 1
+#define IPARSE_SYMBNOTDEF 2
+
+static Ihandle* iParseExp (void);
+static Ihandle* iParseFunction (Iclass *ic);
+static int iParseError (int err, char *s);
+
+static int iparse_error = 0;
+#define IPARSE_RETURN_IF_ERRO(_e) {iparse_error=(_e); if (iparse_error) return NULL;}
+#define IPARSE_RETURN_IF_ERRO2(_e, _x) {iparse_error=(_e); if (iparse_error) { if (_x) free(_x); return NULL;} }
+
+
+char* IupLoad(const char *filename)
+{
+ iupASSERT(filename!=NULL);
+ if (!filename)
+ return "invalid file name";
+
+ iparse_error = iupLexStart(filename, 1);
+ if (iparse_error)
+ {
+ iupLexClose();
+ return iupLexGetError();
+ }
+
+ while (iupLexLookAhead() != IUPLEX_TK_END)
+ {
+ iParseExp();
+ if (iparse_error)
+ {
+ iupLexClose();
+ return iupLexGetError();
+ }
+ }
+
+ iupLexClose();
+ return NULL;
+}
+
+char* IupLoadBuffer(const char *buffer)
+{
+ iupASSERT(buffer!=NULL);
+ if (!buffer)
+ return "invalid buffer";
+
+ iparse_error = iupLexStart(buffer, 0);
+ if (iparse_error)
+ {
+ iupLexClose();
+ return iupLexGetError();
+ }
+
+ while (iupLexLookAhead() != IUPLEX_TK_END)
+ {
+ iParseExp();
+ if (iparse_error)
+ {
+ iupLexClose();
+ return iupLexGetError();
+ }
+ }
+
+ iupLexClose();
+ return NULL;
+}
+
+static Ihandle* iParseExp(void)
+{
+ char* nm = NULL;
+ Ihandle* ih = NULL;
+
+ int match = iupLexSeenMatch(IUPLEX_TK_FUNC,&iparse_error);
+ IPARSE_RETURN_IF_ERRO(iparse_error);
+
+ if (match)
+ return iParseFunction(iupLexGetClass());
+
+ if (iupLexLookAhead() == IUPLEX_TK_NAME)
+ {
+ nm = iupLexGetName();
+ IPARSE_RETURN_IF_ERRO(iupLexAdvance());
+ }
+ else
+ {
+ iparse_error = iupLexMatch(IUPLEX_TK_NAME);
+ return NULL; /* force iparse_error */
+ }
+
+ match = iupLexSeenMatch(IUPLEX_TK_SET,&iparse_error);
+ IPARSE_RETURN_IF_ERRO(iparse_error);
+
+ if (match)
+ {
+ ih = iParseExp();
+ IPARSE_RETURN_IF_ERRO(iparse_error);
+ IupSetHandle(nm, ih);
+ }
+ else
+ {
+ ih = IupGetHandle(nm);
+ if (!ih)
+ IPARSE_RETURN_IF_ERRO(iParseError(IPARSE_SYMBNOTDEF,nm));
+ }
+
+ if (nm) free(nm);
+ return ih;
+}
+
+static void* iParseControlParam(char type)
+{
+ switch(type)
+ {
+ case 'a':
+ IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_NAME));
+ return iupLexGetName();
+
+ case 's':
+ IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_STR));
+ return iupLexGetName();
+
+ case 'b':
+ case 'c':
+ IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_NAME));
+ return (void*)(unsigned long)iupLexByte();
+
+ case 'i':
+ case 'j':
+ IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_NAME));
+ return (void*)(unsigned long)iupLexInt();
+
+ case 'f':
+ IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_NAME));
+ {
+ float f = iupLexFloat();
+ unsigned long* l = (unsigned long*)&f;
+ return (void*)*l;
+ }
+
+ case 'g':
+ case 'h':
+ {
+ char *new_control = (char*)iParseExp();
+ IPARSE_RETURN_IF_ERRO(iparse_error);
+ return new_control;
+ }
+
+ default:
+ return 0;
+ }
+}
+
+static Ihandle* iParseControl(Iclass *ic)
+{
+ const char *format = ic->format;
+ if (!format || format[0] == 0)
+ return iupObjectCreate(ic, NULL);
+ else
+ {
+ Ihandle *new_control;
+ void** params;
+ int i, alloc_arg, num_arg,
+ num_format = strlen(format);
+
+ num_arg = num_format;
+ alloc_arg = num_arg+20;
+ params = (void**)malloc(sizeof(void*)*alloc_arg);
+
+ for (i = 0; i < num_arg; )
+ {
+ char p_format = (char)tolower(format[i]); /* there is no optional parameters in LED */
+
+ if (i > 0)
+ IPARSE_RETURN_IF_ERRO2(iupLexMatch (IUPLEX_TK_COMMA), params);
+
+ if (p_format != 'j' && /* not array */
+ p_format != 'g' &&
+ p_format != 'c')
+ {
+ params[i] = iParseControlParam(p_format);
+ i++;
+ IPARSE_RETURN_IF_ERRO2(iparse_error, params);
+ }
+ else /* array */
+ {
+ int match;
+ do
+ {
+ if (num_arg == i)
+ {
+ num_arg++;
+ if (num_arg >= alloc_arg)
+ {
+ alloc_arg = num_arg+20;
+ params = realloc(params, sizeof(void*)*alloc_arg);
+ }
+ }
+ params[i] = iParseControlParam(p_format);
+ i++;
+ IPARSE_RETURN_IF_ERRO2(iparse_error, params);
+ match = iupLexSeenMatch(IUPLEX_TK_COMMA,&iparse_error);
+ IPARSE_RETURN_IF_ERRO2(iparse_error, params);
+ } while (match);
+
+ /* after an array of parameters there are no more parameters */
+ break;
+ }
+ }
+
+ params[i] = NULL;
+ new_control = iupObjectCreate(ic, params);
+
+ for (i = 0; params[i] && i<num_format ; i++)
+ {
+ if (format[i] == 'j' ||
+ format[i] == 'g' ||
+ format[i] == 'c')
+ break;
+
+ if (format[i] == 'a' || format[i] == 's' ||
+ format[i] == 'A' || format[i] == 'S')
+ free(params[i]); /* iupLexGetName returned a duplicated string */
+ }
+
+ free(params);
+ return new_control;
+ }
+}
+
+static Ihandle* iParseFunction(Iclass *ic)
+{
+ Ihandle* ih = NULL;
+ char *attr = NULL;
+
+ int match = iupLexSeenMatch(IUPLEX_TK_ATTR,&iparse_error);
+ IPARSE_RETURN_IF_ERRO(iparse_error);
+
+ if (match)
+ attr = (char*)iupStrDup(iupLexName());
+
+ IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_BEGP));
+
+ ih = iParseControl(ic);
+ IPARSE_RETURN_IF_ERRO(iparse_error);
+
+ if (attr)
+ {
+ IupSetAttributes(ih, attr);
+ free(attr);
+ }
+
+ IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_ENDP));
+ return ih;
+}
+
+static int iParseError(int err, char *s)
+{
+ static char msg[256];
+ switch (err)
+ {
+ case IPARSE_SYMBEXIST:
+ sprintf(msg, "symbol '%s' %s",s,"already exists");
+ break;
+ case IUPLEX_NOTMATCH:
+ sprintf(msg, "symbol '%s' %s",s,"not defined");
+ break;
+ }
+ return iupLexError(IUPLEX_PARSEERROR,msg);
+}
diff --git a/iup/src/iup_list.c b/iup/src/iup_list.c
new file mode 100755
index 0000000..5965665
--- /dev/null
+++ b/iup/src/iup_list.c
@@ -0,0 +1,711 @@
+/** \file
+ * \brief List Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_assert.h"
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_mask.h"
+#include "iup_list.h"
+
+
+void iupListSingleCallDblClickCallback(Ihandle* ih, IFnis cb, int pos)
+{
+ char *text;
+ char str[30];
+
+ if (pos<=0)
+ return;
+
+ sprintf(str, "%d", pos);
+ text = IupGetAttribute(ih, str);
+
+ if (cb(ih, pos, text) == IUP_CLOSE)
+ IupExitLoop();
+}
+
+static void iListCallActionCallback(Ihandle* ih, IFnsii cb, int pos, int state)
+{
+ char *text;
+ char str[30];
+
+ if (pos<=0)
+ return;
+
+ sprintf(str, "%d", pos);
+ text = IupGetAttribute(ih, str);
+
+ if (cb(ih, text, pos, state) == IUP_CLOSE)
+ IupExitLoop();
+}
+
+void iupListSingleCallActionCallback(Ihandle* ih, IFnsii cb, int pos)
+{
+ char* old_str = iupAttribGet(ih, "_IUPLIST_OLDVALUE");
+ if (old_str)
+ {
+ int oldpos = atoi(old_str);
+ if (oldpos != pos)
+ {
+ iListCallActionCallback(ih, cb, oldpos, 0);
+ iListCallActionCallback(ih, cb, pos, 1);
+ }
+ }
+ else
+ iListCallActionCallback(ih, cb, pos, 1);
+ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos);
+}
+
+void iupListMultipleCallActionCallback(Ihandle* ih, IFnsii cb, IFns multi_cb, int* pos, int sel_count)
+{
+ int i, count = iupdrvListGetCount(ih);
+
+ char* old_str = iupAttribGet(ih, "_IUPLIST_OLDVALUE");
+ int old_count = old_str? strlen(old_str): 0;
+
+ char* str = iupStrGetMemory(count+1);
+ memset(str, '-', count);
+ str[count]=0;
+ for (i=0; i<sel_count; i++)
+ str[pos[i]] = '+';
+
+ if (old_count != count)
+ {
+ old_count = 0;
+ old_str = NULL;
+ }
+
+ if (multi_cb)
+ {
+ int unchanged = 1;
+ for (i=0; i<count && old_str; i++)
+ {
+ if (str[i] == old_str[i])
+ str[i] = 'x'; /* mark unchanged values */
+ else
+ unchanged = 0;
+ }
+
+ if (old_str && unchanged)
+ return;
+
+ if (multi_cb(ih, str) == IUP_CLOSE)
+ IupExitLoop();
+
+ for (i=0; i<count && old_str; i++)
+ {
+ if (str[i] == 'x')
+ str[i] = old_str[i]; /* restore unchanged values */
+ }
+ }
+ else
+ {
+ /* must simulate the click on each item */
+ for (i=0; i<count; i++)
+ {
+ if (i >= old_count) /* new items, if selected then call the callback */
+ {
+ if (str[i] == '+')
+ iListCallActionCallback(ih, cb, i+1, 1);
+ }
+ else if (str[i] != old_str[i])
+ {
+ if (str[i] == '+')
+ iListCallActionCallback(ih, cb, i+1, 1);
+ else
+ iListCallActionCallback(ih, cb, i+1, 0);
+ }
+ }
+ }
+
+ iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", str);
+}
+
+int iupListGetPos(Ihandle* ih, const char* name_id)
+{
+ int pos;
+ if (iupStrToInt(name_id, &pos))
+ {
+ int count = iupdrvListGetCount(ih);
+
+ pos--; /* IUP items start at 1 */
+
+ if (pos < 0) return -1;
+ if (pos > count-1) return -1;
+
+ return pos;
+ }
+ return -1;
+}
+
+void iupListSetInitialItems(Ihandle* ih)
+{
+ char str[20], *value;
+ int i = 1;
+ sprintf(str, "%d", i);
+ while ((value = iupAttribGet(ih, str))!=NULL)
+ {
+ iupdrvListAppendItem(ih, value);
+ iupAttribSetStr(ih, str, NULL);
+
+ i++;
+ sprintf(str, "%d", i);
+ }
+}
+
+char* iupListGetSpacingAttrib(Ihandle* ih)
+{
+ if (!ih->data->is_dropdown)
+ {
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%d", ih->data->spacing);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+char* iupListGetPaddingAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+char* iupListGetNCAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char* str = iupStrGetMemory(100);
+ sprintf(str, "%d", ih->data->nc);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+int iupListSetIdValueAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int pos;
+ if (iupStrToInt(name_id, &pos))
+ {
+ int count = iupdrvListGetCount(ih);
+
+ pos--; /* IUP starts at 1 */
+
+ if (!value)
+ {
+ if (pos >= 0 && pos <= count-1)
+ {
+ if (pos == 0)
+ iupdrvListRemoveAllItems(ih);
+ else
+ {
+ int i = pos;
+ while (i < count)
+ {
+ iupdrvListRemoveItem(ih, pos);
+ i++;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (pos >= 0 && pos <= count-1)
+ {
+ iupdrvListRemoveItem(ih, pos);
+ iupdrvListInsertItem(ih, pos, value);
+ }
+ else if (pos == count)
+ iupdrvListAppendItem(ih, value);
+ }
+ }
+ return 1;
+}
+
+static int iListSetAppendItemAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (value)
+ iupdrvListAppendItem(ih, value);
+ return 0;
+}
+
+static int iListSetInsertItemAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (value)
+ {
+ int pos = iupListGetPos(ih, name_id);
+ if (pos!=-1)
+ iupdrvListInsertItem(ih, pos, value);
+ }
+ return 0;
+}
+
+static int iListSetRemoveItemAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (!value)
+ iupdrvListRemoveAllItems(ih);
+ else
+ {
+ int pos = iupListGetPos(ih, value);
+ if (pos!=-1)
+ iupdrvListRemoveItem(ih, pos);
+ }
+ return 0;
+}
+
+static int iListGetCount(Ihandle* ih)
+{
+ int count;
+ if (ih->handle)
+ count = iupdrvListGetCount(ih);
+ else
+ {
+ char str[20];
+ count = 0;
+ sprintf(str, "%d", count+1);
+ while (iupAttribGet(ih, str))
+ {
+ count++;
+ sprintf(str, "%d", count+1);
+ }
+ }
+ return count;
+}
+
+static char* iListGetCountAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(50);
+ sprintf(str, "%d", iListGetCount(ih));
+ return str;
+}
+
+static int iListSetDropdownAttrib(Ihandle* ih, const char* value)
+{
+ /* valid only before map */
+ if (ih->handle)
+ return 0;
+
+ if (iupStrBoolean(value))
+ {
+ ih->data->is_dropdown = 1;
+ ih->data->is_multiple = 0;
+ }
+ else
+ ih->data->is_dropdown = 0;
+
+ return 0;
+}
+
+static char* iListGetDropdownAttrib(Ihandle* ih)
+{
+ if (ih->data->is_dropdown)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iListSetMultipleAttrib(Ihandle* ih, const char* value)
+{
+ /* valid only before map */
+ if (ih->handle)
+ return 0;
+
+ if (iupStrBoolean(value))
+ {
+ ih->data->is_multiple = 1;
+ ih->data->is_dropdown = 0;
+ ih->data->has_editbox = 0;
+ }
+ else
+ ih->data->is_multiple = 0;
+
+ return 0;
+}
+
+static char* iListGetMultipleAttrib(Ihandle* ih)
+{
+ if (ih->data->is_multiple)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iListSetEditboxAttrib(Ihandle* ih, const char* value)
+{
+ /* valid only before map */
+ if (ih->handle)
+ return 0;
+
+ if (iupStrBoolean(value))
+ {
+ ih->data->has_editbox = 1;
+ ih->data->is_multiple = 0;
+ }
+ else
+ ih->data->has_editbox = 0;
+
+ return 0;
+}
+
+static char* iListGetEditboxAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iListSetScrollbarAttrib(Ihandle* ih, const char* value)
+{
+ /* valid only before map */
+ if (ih->handle)
+ return 0;
+
+ else if (iupStrBoolean(value))
+ ih->data->sb = 1;
+ else
+ ih->data->sb = 0;
+
+ return 0;
+}
+
+static char* iListGetScrollbarAttrib(Ihandle* ih)
+{
+ if (ih->data->sb)
+ return "YES";
+ else
+ return "NO";
+}
+
+static char* iListGetMaskDataAttrib(Ihandle* ih)
+{
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ /* Used only by the OLD iupmask API */
+ return (char*)ih->data->mask;
+}
+
+static int iListSetMaskAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ {
+ if (ih->data->mask)
+ iupMaskDestroy(ih->data->mask);
+ }
+ else
+ {
+ int casei = iupAttribGetInt(ih, "MASKCASEI");
+ Imask* mask = iupMaskCreate(value,casei);
+ if (mask)
+ {
+ if (ih->data->mask)
+ iupMaskDestroy(ih->data->mask);
+
+ ih->data->mask = mask;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int iListSetMaskIntAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ {
+ if (ih->data->mask)
+ iupMaskDestroy(ih->data->mask);
+
+ iupAttribSetStr(ih, "MASK", NULL);
+ }
+ else
+ {
+ Imask* mask;
+ int min, max;
+
+ if (iupStrToIntInt(value, &min, &max, ':')!=2)
+ return 0;
+
+ mask = iupMaskCreateInt(min,max);
+
+ if (ih->data->mask)
+ iupMaskDestroy(ih->data->mask);
+
+ ih->data->mask = mask;
+
+ if (min < 0)
+ iupAttribSetStr(ih, "MASK", IUP_MASK_INT);
+ else
+ iupAttribSetStr(ih, "MASK", IUP_MASK_UINT);
+ }
+
+ return 0;
+}
+
+static int iListSetMaskFloatAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ {
+ if (ih->data->mask)
+ iupMaskDestroy(ih->data->mask);
+
+ iupAttribSetStr(ih, "MASK", NULL);
+ }
+ else
+ {
+ Imask* mask;
+ float min, max;
+
+ if (iupStrToFloatFloat(value, &min, &max, ':')!=2)
+ return 0;
+
+ mask = iupMaskCreateFloat(min,max);
+
+ if (ih->data->mask)
+ iupMaskDestroy(ih->data->mask);
+
+ ih->data->mask = mask;
+
+ if (min < 0)
+ iupAttribSetStr(ih, "MASK", IUP_MASK_FLOAT);
+ else
+ iupAttribSetStr(ih, "MASK", IUP_MASK_UFLOAT);
+ }
+
+ return 0;
+}
+
+
+/*****************************************************************************************/
+
+
+static int iListCreateMethod(Ihandle* ih, void** params)
+{
+ if (params && params[0])
+ iupAttribStoreStr(ih, "ACTION", (char*)(params[0]));
+
+ ih->data = iupALLOCCTRLDATA();
+ ih->data->sb = 1;
+
+ return IUP_NOERROR;
+}
+
+static void iListGetNaturalItemsSize(Ihandle *ih, int *w, int *h)
+{
+ char *value;
+ int visiblecolumns,
+ count = iListGetCount(ih);
+
+ *w = 0;
+ *h = 0;
+
+ iupdrvFontGetCharSize(ih, w, h); /* one line height, and one character width */
+
+ visiblecolumns = iupAttribGetInt(ih, "VISIBLECOLUMNS");
+ if (visiblecolumns)
+ {
+ *w = iupdrvFontGetStringWidth(ih, "WWWWWWWWWW");
+ *w = (visiblecolumns*(*w))/10;
+ }
+ else
+ {
+ int item_w, i;
+ char str[20];
+
+ for (i=1; i<=count; i++)
+ {
+ sprintf(str, "%d", i);
+ value = IupGetAttribute(ih, str); /* must use IupGetAttribute to check the native system */
+ if (value)
+ {
+ item_w = iupdrvFontGetStringWidth(ih, value);
+ if (item_w > *w)
+ *w = item_w;
+ }
+ }
+
+ if (*w == 0) /* default is 5 characters in 1 item */
+ *w = iupdrvFontGetStringWidth(ih, "WWWWW");
+ }
+
+ /* compute height for multiple lines, drodown is just 1 line */
+ if (!ih->data->is_dropdown)
+ {
+ int visiblelines, num_lines, line_size = *h;
+
+ iupdrvListAddItemSpace(ih, h); /* this independs from spacing */
+
+ *h += 2*ih->data->spacing; /* this will be multiplied by the number of lines */
+ *w += 2*ih->data->spacing; /* include also horizontal spacing */
+
+ num_lines = count;
+ if (num_lines == 0) num_lines = 1;
+
+ visiblelines = iupAttribGetInt(ih, "VISIBLELINES");
+ if (visiblelines)
+ num_lines = visiblelines;
+
+ *h = *h * num_lines;
+
+ if (ih->data->has_editbox)
+ *h += line_size;
+ }
+}
+
+static void iListComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ int natural_w, natural_h;
+ int sb_size = iupdrvGetScrollbarSize();
+ (void)expand; /* unset if not a container */
+
+ iListGetNaturalItemsSize(ih, &natural_w, &natural_h);
+
+ /* compute the borders space */
+ iupdrvListAddBorders(ih, &natural_w, &natural_h);
+
+ if (ih->data->is_dropdown)
+ {
+ /* add room for dropdown box */
+ natural_w += sb_size;
+
+ if (natural_h < sb_size)
+ natural_h = sb_size;
+ }
+ else
+ {
+ /* add room for scrollbar */
+ if (ih->data->sb)
+ {
+ natural_h += sb_size;
+ natural_w += sb_size;
+ }
+ }
+
+ if (ih->data->has_editbox)
+ {
+ natural_w += 2*ih->data->horiz_padding;
+ natural_h += 2*ih->data->vert_padding;
+ }
+
+ *w = natural_w;
+ *h = natural_h;
+}
+
+static void iListDestroyMethod(Ihandle* ih)
+{
+ if (ih->data->mask)
+ iupMaskDestroy(ih->data->mask);
+}
+
+
+/******************************************************************************/
+
+
+Ihandle* IupList(const char* action)
+{
+ void *params[2];
+ params[0] = (void*)action;
+ params[1] = NULL;
+ return IupCreatev("list", params);
+}
+
+Iclass* iupListGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "list";
+ ic->format = "A"; /* one optional callback name */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 1;
+ ic->has_attrib_id = 1;
+
+ /* Class functions */
+ ic->Create = iListCreateMethod;
+ ic->Destroy = iListDestroyMethod;
+ ic->ComputeNaturalSize = iListComputeNaturalSizeMethod;
+
+ ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "ACTION", "sii");
+ iupClassRegisterCallback(ic, "MULTISELECT_CB", "s");
+ iupClassRegisterCallback(ic, "DROPFILES_CB", "siii");
+ iupClassRegisterCallback(ic, "DROPDOWN_CB", "i");
+ iupClassRegisterCallback(ic, "DBLCLICK_CB", "is");
+ iupClassRegisterCallback(ic, "VALUECHANGED_CB", "");
+
+ iupClassRegisterCallback(ic, "EDIT_CB", "is");
+ iupClassRegisterCallback(ic, "CARET_CB", "iii");
+
+ /* Common Callbacks */
+ iupBaseRegisterCommonCallbacks(ic);
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Visual */
+ iupBaseRegisterVisualAttrib(ic);
+
+ /* IupList only */
+ iupClassRegisterAttribute(ic, "SCROLLBAR", iListGetScrollbarAttrib, iListSetScrollbarAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MULTIPLE", iListGetMultipleAttrib, iListSetMultipleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DROPDOWN", iListGetDropdownAttrib, iListSetDropdownAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "EDITBOX", iListGetEditboxAttrib, iListSetEditboxAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "COUNT", iListGetCountAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "INSERTITEM", NULL, iListSetInsertItemAttrib, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPENDITEM", NULL, iListSetAppendItemAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "REMOVEITEM", NULL, iListSetRemoveItemAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "AUTOHIDE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "MASKCASEI", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MASK", NULL, iListSetMaskAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MASKINT", NULL, iListSetMaskIntAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MASKFLOAT", NULL, iListSetMaskFloatAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "OLD_MASK_DATA", iListGetMaskDataAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "VISIBLECOLUMNS", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VISIBLELINES", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupdrvListInitClass(ic);
+
+ return ic;
+}
diff --git a/iup/src/iup_list.h b/iup/src/iup_list.h
new file mode 100755
index 0000000..045116b
--- /dev/null
+++ b/iup/src/iup_list.h
@@ -0,0 +1,53 @@
+/** \file
+ * \brief List Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_LIST_H
+#define __IUP_LIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void iupdrvListInitClass(Iclass* ic);
+void iupdrvListAddBorders(Ihandle* ih, int *w, int *h);
+void iupdrvListAddItemSpace(Ihandle* ih, int *h);
+int iupdrvListGetCount(Ihandle* ih);
+void iupdrvListAppendItem(Ihandle* ih, const char* value);
+void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value);
+void iupdrvListRemoveItem(Ihandle* ih, int pos);
+void iupdrvListRemoveAllItems(Ihandle* ih);
+
+int iupListGetPos(Ihandle* ih, const char* name_id);
+int iupListSetIdValueAttrib(Ihandle* ih, const char* name_id, const char* value);
+void iupListSetInitialItems(Ihandle* ih);
+void iupListSingleCallActionCallback(Ihandle* ih, IFnsii cb, int pos);
+void iupListMultipleCallActionCallback(Ihandle* ih, IFnsii cb, IFns multi_cb, int* pos, int sel_count);
+char* iupListGetNCAttrib(Ihandle* ih);
+char* iupListGetPaddingAttrib(Ihandle* ih);
+char* iupListGetSpacingAttrib(Ihandle* ih);
+void iupListSingleCallDblClickCallback(Ihandle* ih, IFnis cb, int pos);
+
+struct _IcontrolData
+{
+ int sb, /* scrollbar configuration, can be changed only before map */
+ nc,
+ spacing,
+ horiz_padding,
+ vert_padding,
+ last_caret_pos,
+ is_multiple,
+ is_dropdown,
+ has_editbox;
+ Imask* mask;
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_mask.c b/iup/src/iup_mask.c
new file mode 100755
index 0000000..f241a22
--- /dev/null
+++ b/iup/src/iup_mask.c
@@ -0,0 +1,146 @@
+/** \file
+ * \brief mask pattern matching
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "iup_maskparse.h"
+#include "iup_mask.h"
+#include "iup_str.h"
+
+
+#define IUP_MASK_FLOAT "[+/-]?(/d+/.?/d*|/./d+)"
+#define IUP_MASK_UFLOAT "(/d+/.?/d*|/./d+)"
+#define IUP_MASK_INT "[+/-]?/d+"
+#define IUP_MASK_UINT "/d+"
+
+struct _Imask
+{
+ char* mask_str;
+ ImaskParsed* fsm;
+ int casei;
+ char type;
+ float fmin,
+ fmax;
+ int imin,
+ imax;
+};
+
+
+int iupMaskCheck(Imask* mask, const char *val)
+{
+ int ret;
+
+ /* empty text or no mask */
+ if (!val || !(*val) || !mask)
+ return 1;
+
+ ret = iupMaskMatch(val,mask->fsm,0,NULL,NULL,NULL,mask->casei);
+ if (ret == IMASK_PARTIALMATCH)
+ return -1;
+ if (ret != (int)strlen(val))
+ return 0;
+
+ switch(mask->type)
+ {
+ case 'I':
+ {
+ int ival = 0;
+ sscanf(val,"%d",&ival);
+ if(ival < mask->imin || ival > mask->imax)
+ return 0;
+ break;
+ }
+ case 'F':
+ {
+ float fval = 0;
+ sscanf(val,"%f",&fval);
+ if(fval < mask->fmin || fval > mask->fmax)
+ return 0;
+ break;
+ }
+ }
+
+ return 1;
+}
+
+Imask* iupMaskCreate(const char* mask_str, int casei)
+{
+ ImaskParsed* fsm;
+ Imask* mask;
+ char* copy_mask_str;
+
+ if (!mask_str)
+ return NULL;
+
+ /* Parse the mask first */
+ copy_mask_str = iupStrDup(mask_str);
+ if (iupMaskParse(copy_mask_str, &fsm) != IMASK_PARSE_OK)
+ {
+ free(copy_mask_str);
+ return NULL;
+ }
+
+ mask = (Imask*)malloc(sizeof(Imask));
+ memset(mask, 0, sizeof(Imask));
+
+ mask->mask_str = copy_mask_str;
+ mask->casei = casei;
+ mask->fsm = fsm;
+
+ return mask;
+}
+
+Imask* iupMaskCreateInt(int min, int max)
+{
+ Imask* mask;
+
+ if (min < 0)
+ mask = iupMaskCreate(IUP_MASK_INT, 0);
+ else
+ mask = iupMaskCreate(IUP_MASK_UINT, 0);
+
+ if (mask)
+ {
+ mask->imin = min;
+ mask->imax = max;
+ mask->type = 'I';
+ }
+
+ return mask;
+}
+
+Imask* iupMaskCreateFloat(float min, float max)
+{
+ Imask* mask;
+
+ if (min < 0)
+ mask = iupMaskCreate(IUP_MASK_FLOAT, 0);
+ else
+ mask = iupMaskCreate(IUP_MASK_UFLOAT, 0);
+
+ if (mask)
+ {
+ mask->fmin = min;
+ mask->fmax = max;
+ mask->type = 'F';
+ }
+
+ return mask;
+}
+
+void iupMaskDestroy(Imask* mask)
+{
+ free(mask->mask_str);
+ free(mask->fsm);
+ free(mask);
+}
+
+char* iupMaskGetStr(Imask* mask)
+{
+ return mask->mask_str;
+}
diff --git a/iup/src/iup_mask.h b/iup/src/iup_mask.h
new file mode 100755
index 0000000..5e87f24
--- /dev/null
+++ b/iup/src/iup_mask.h
@@ -0,0 +1,55 @@
+/** \file
+ * \brief Mask functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_MASK_H
+#define __IUP_MASK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup mask Text Mask
+ * \par
+ * Used to filter text input in IupText.
+ * \par
+ * See \ref iup_mask.h
+ * \ingroup util */
+
+typedef struct _Imask Imask;
+
+/** Creates a mask given a string. \n
+ * If casei is true, will turn the mask case insensitive.
+ * \ingroup mask */
+Imask* iupMaskCreate(const char* mask_str, int casei);
+
+/** Creates an integer mask with limits.
+ * \ingroup mask */
+Imask* iupMaskCreateInt(int min, int max);
+
+/** Creates a float mask with limits.
+ * \ingroup mask */
+Imask* iupMaskCreateFloat(float min, float max);
+
+/** Destroys the mask.
+ * \ingroup mask */
+void iupMaskDestroy(Imask* mask);
+
+/** Check if the value is valid using the mask to filter it.
+ * Returns 1 if full match, -1 if partial match, and 0 otherwise.
+ * \ingroup mask */
+int iupMaskCheck(Imask* mask, const char *value);
+
+/** Returns the mask string.
+ * \ingroup mask */
+char* iupMaskGetStr(Imask* mask);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_maskmatch.c b/iup/src/iup_maskmatch.c
new file mode 100755
index 0000000..f0aa9fd
--- /dev/null
+++ b/iup/src/iup_maskmatch.c
@@ -0,0 +1,582 @@
+/** \file
+ * \brief iupmask imask_match_functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "iup_maskparse.h"
+#include "iup_maskmatch.h"
+
+
+#define IMASK_MIN_STACK_ELEMENTS 1000
+enum {IMASK_CAPT_OPEN, IMASK_CAPT_CLOSE};
+
+typedef struct _ImaskCapt
+{
+ struct _ImaskCapt* next_one;
+ int type;
+ short which_one;
+ long pos;
+} ImaskCapt;
+
+typedef struct _ImaskMatchVars
+{
+ const char *text;
+ ImaskParsed *fsm;
+ iMaskMatchFunc function;
+ short *tested;
+ void *user;
+} ImaskMatchVars;
+
+
+typedef struct _ImaskStack
+{
+ short *stack;
+ short size;
+} ImaskStack;
+
+
+#define isalphanum(_x) (isalnum((int)(_x)) || ((_x) == '_'))
+
+
+/* match functions corresponding to regular expressions */
+
+static int match_blanks (const char *text, long j)
+{
+ return (((text[j] == '\t') || (text[j] == '\xff') || (text[j] == ' ') ||
+ (text[j] == '\n'))) ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH;
+}
+
+static int match_non_blanks (const char *text, long j)
+{
+ return (!((text[j] == '\t') || (text[j] == '\xff') ||
+ (text[j] == ' ') || (text[j] == '\n')))
+ ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH;
+}
+
+static int match_alpha (const char *text, long j)
+{
+ return (isalpha((int)text[j])) ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH;
+}
+
+static int match_non_alpha (const char *text, long j)
+{
+ return (!isalpha((int)text[j]) && (text[j] != '\0'))
+ ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH;
+}
+
+static int match_digit (const char *text, long j)
+{
+ return (isdigit((int)text[j])) ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH;
+}
+
+static int match_non_digit (const char *text, long j)
+{
+ return (!isdigit((int)text[j]) && (text[j] != '\0'))
+ ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH;
+}
+
+static int match_alphanum (const char *text, long j)
+{
+ return isalphanum (text[j]) ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH;
+}
+
+static int match_non_alphanum (const char *text, long j)
+{
+ return (isalphanum (text[j]) || (text[j] == '\0'))
+ ? IMASK_NO_MATCH : IMASK_NORMAL_MATCH;
+}
+
+static int match_word_boundary (const char *text, long j)
+{
+ if ((j == 0) && isalphanum (text[j]))
+ return IMASK_NO_CHAR_MATCH;
+
+ else if (isalphanum (text[j - 1]) && !isalphanum (text[j]))
+ return IMASK_NO_CHAR_MATCH;
+
+ else if (isalphanum (text[j]) && !isalphanum (text[j - 1]))
+ return IMASK_NO_CHAR_MATCH;
+
+ return IMASK_NO_MATCH;
+
+}
+
+static ImaskMatchFunc imask_match_functions[] =
+{
+ {'w', &match_alphanum},
+ {'W', &match_non_alphanum},
+ {'d', &match_digit},
+ {'D', &match_non_digit},
+ {'S', &match_non_blanks},
+ {'s', &match_blanks},
+ {'b', &match_word_boundary},
+ {'l', &match_alpha},
+ {'L', &match_non_alpha},
+ {'\0', NULL}
+};
+
+ImaskMatchFunc* iupMaskMatchGetFuncs(void)
+{
+ return imask_match_functions;
+}
+
+static void iMaskMatchCaptureResult (ImaskMatchVars * vars, ImaskCapt * capture)
+{
+ ImaskCapt *next = NULL;
+
+ while (capture != NULL)
+ {
+ ImaskCapt *cap = capture->next_one;
+
+ capture->next_one = next;
+ next = capture;
+ capture = cap;
+ }
+
+ capture = next;
+ next = NULL;
+
+ while (capture != NULL)
+ {
+ if (capture->type == IMASK_CAPT_OPEN)
+ {
+ ImaskCapt *cap = capture->next_one;
+
+ capture->next_one = next;
+ next = capture;
+ capture = cap;
+ }
+ else
+ {
+ if (capture->pos >= next->pos)
+ (*vars->function)((char)capture->which_one, next->pos, capture->pos, vars->text, vars->user);
+
+ next = next->next_one;
+ capture = capture->next_one;
+ }
+ }
+}
+
+static long iMaskMatchRecursive (ImaskMatchVars * vars, long j, int state, ImaskCapt * capture, int size)
+{
+ switch (vars->fsm[state].command)
+ {
+ case IMASK_NULL_CMD:
+ if (vars->fsm[state].next1 == 0) /*se chegou ao fim da maquina de estados */
+ {
+ if (vars->function != NULL)
+ iMaskMatchCaptureResult (vars, capture); /* guarda capturas */
+
+ return j;
+ }
+
+ /* verifica o estado atual ja foi avaliado antes */
+ {
+ int count;
+ for (count = 0; count < size; count++)
+ if (vars->tested[count] == state)
+ return IMASK_NOMATCH;
+ }
+
+ vars->tested[size++] = (short)state; /* indicada que o estado foi testado */
+
+ /* se houverem dois ramos, chama a funcao recursivamente,
+ retornando com o primeiro que completar a maquina */
+
+ if (vars->fsm[state].next1 != vars->fsm[state].next2)
+ {
+ long a;
+
+ a = iMaskMatchRecursive (vars, j, vars->fsm[state].next2, capture, size);
+
+ if (a != IMASK_NOMATCH) /* se deu match */
+ return a;
+
+ a = iMaskMatchRecursive (vars, j, vars->fsm[state].next1, capture, size);
+
+ return a;
+ }
+ break;
+
+ case IMASK_CAP_OPEN_CMD:
+ {
+ long a;
+ ImaskCapt new_cap;
+
+ new_cap.next_one = capture;
+ new_cap.type = IMASK_CAPT_OPEN;
+ new_cap.pos = j;
+ new_cap.which_one = vars->fsm[state].ch;
+
+ a = iMaskMatchRecursive (vars, j, vars->fsm[state].next1, &new_cap, size);
+
+ return a;
+ }
+ break;
+
+ case IMASK_CAP_CLOSE_CMD:
+ {
+ long a;
+ ImaskCapt new_cap;
+
+ new_cap.next_one = capture;
+ new_cap.type = IMASK_CAPT_CLOSE;
+ new_cap.pos = j - 1;
+ new_cap.which_one = vars->fsm[state].ch;
+
+ a = iMaskMatchRecursive (vars, j, vars->fsm[state].next1, &new_cap, size);
+
+ return a;
+ }
+
+ case IMASK_CLASS_CMD:
+ {
+ int temp, found = 0, negate;
+
+ temp = vars->fsm[state].next1;
+ negate = vars->fsm[state].next2;
+ state++;
+
+ while (vars->fsm[state].command != IMASK_NULL_CMD)
+ {
+ if (vars->fsm[state].command == IMASK_CLASS_CMD_RANGE)
+ {
+ if ((vars->text[j] >= vars->fsm[state].ch) &&
+ (vars->text[j] <= vars->fsm[state].next1))
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ else if ((vars->fsm[state].command == IMASK_CLASS_CMD_CHAR) &&
+ (vars->text[j] == vars->fsm[state].ch))
+ {
+ found = 1;
+ break;
+ };
+ state++;
+ }
+
+ if (found ^ negate)
+ {
+ if (vars->text[j] == '\0')
+ return IMASK_NOMATCH;
+ j++;
+ vars->tested = &vars->tested[size + 1];
+ size = 0;
+ return iMaskMatchRecursive (vars, j, temp, capture, size);
+ }
+ else
+ return IMASK_NOMATCH;
+ }
+
+ case IMASK_CHAR_CMD:
+ if (vars->text[j] != vars->fsm[state].ch)
+ return IMASK_NOMATCH;
+ j++;
+ vars->tested = &vars->tested[size + 1];
+ size = 0;
+ break;
+
+ case IMASK_ANY_CMD:
+ if ((vars->text[j] == '\0') || (vars->text[j] == '\n'))
+ return IMASK_NOMATCH;
+ j++;
+ vars->tested = &vars->tested[size + 1];
+ size = 0;
+ break;
+
+ case IMASK_SPC_CMD:
+ {
+ long a;
+
+ a = (*imask_match_functions[(int) vars->fsm[state].ch].function) (vars->text, j);
+
+ switch (a)
+ {
+ case IMASK_NO_MATCH:
+ return IMASK_NOMATCH;
+
+ case IMASK_NORMAL_MATCH:
+ j++;
+ vars->tested = &vars->tested[size + 1];
+ size = 0;
+ break;
+
+ case IMASK_NO_CHAR_MATCH:; /* does nothing */
+ }
+ }
+ break;
+
+ case IMASK_BEGIN_CMD:
+ if (!((vars->text[j - 1] == '\n') || (j == 0)))
+ return IMASK_NOMATCH;
+
+ break;
+
+ case IMASK_END_CMD:
+ if (!((vars->text[j] == '\n') || (vars->text[j] == '\0')))
+ return IMASK_NOMATCH;
+
+ break;
+ }
+
+ return iMaskMatchRecursive (vars, j, vars->fsm[state].next1, capture, size);
+}
+
+static int iMaskInStack (ImaskStack * stack, int state)
+{
+ int a;
+ for (a = 0; a < stack->size; a++)
+ if (stack->stack[a] == state)
+ return 1;
+
+ return 0;
+}
+
+static void iMaskNewStack (ImaskStack * new_stack, short *stack)
+{
+ new_stack->size = 0;
+ new_stack->stack = stack;
+}
+
+static void iMaskPushStack (ImaskStack * stack, int value)
+{
+ stack->stack[stack->size++] = (short)value;
+}
+
+static void iMaskMoveStack (ImaskStack * dest, ImaskStack * source)
+{
+ short *temp = dest->stack;
+ dest->stack = source->stack;
+ source->stack = temp;
+
+ dest->size = source->size;
+ source->size = 0;
+}
+
+/* non recursive */
+static long iMaskMatchLocal (const char *text, ImaskParsed * fsm, long start, char *addchar, int casei)
+{
+ int finished = IMASK_NOMATCH;
+ ImaskStack now, next;
+ short a1[IMASK_MIN_STACK_ELEMENTS];
+ short a2[IMASK_MIN_STACK_ELEMENTS];
+ int state;
+ int j = 0;
+ int pos;
+
+ if (addchar) addchar[0] = 0;
+
+ j = start;
+
+ iMaskNewStack(&now, a1);
+ iMaskNewStack(&next, a2);
+
+ iMaskPushStack (&now, fsm[0].next1);
+
+ for (;;)
+ {
+ for (pos = 0; pos < now.size; pos++)
+ {
+ state = now.stack[pos];
+
+ if (state == 0)
+ {
+ finished = j - start;
+ continue;
+ }
+
+ if (fsm[state].command == IMASK_NULL_CMD)
+ {
+ if(!iMaskInStack (&now, fsm[state].next2))
+ iMaskPushStack (&now, fsm[state].next2);
+
+ if(fsm[state].next1 != fsm[state].next2)
+ {
+ if(!iMaskInStack (&now, fsm[state].next1))
+ iMaskPushStack (&now, fsm[state].next1);
+ }
+ }
+ else if (text[j] == '\0'); /* ignore \0 */
+ else if (((fsm[state].command == IMASK_CHAR_CMD) &&
+ ((!casei && fsm[state].ch == text[j]) ||
+ (casei && tolower(fsm[state].ch) == tolower(text[j]))
+ )
+ ) ||
+ ((fsm[state].command == IMASK_ANY_CMD) &&
+ (text[j] != '\n')
+ )
+ )
+ iMaskPushStack (&next, fsm[state].next1);
+ else if (fsm[state].command == IMASK_SPC_CMD)
+ {
+ int ret;
+
+ ret = (*(imask_match_functions[(int) fsm[state].ch].function))(text, j);
+ switch (ret)
+ {
+ case IMASK_NO_MATCH:
+ break;
+
+ case IMASK_NORMAL_MATCH:
+ iMaskPushStack (&next, fsm[state].next1);
+ break;
+
+ case IMASK_NO_CHAR_MATCH:
+ iMaskPushStack (&now, fsm[state].next1);
+ break;
+ }
+ }
+ else if (fsm[state].command == IMASK_CLASS_CMD)
+ {
+ int temp, found = 0, negate;
+
+ temp = fsm[state].next1;
+ negate = fsm[state].next2;
+ state++;
+
+ while (fsm[state].command != IMASK_NULL_CMD)
+ {
+ if (fsm[state].command == IMASK_CLASS_CMD_RANGE)
+ {
+ if((!casei && (text[j]>=fsm[state].ch) &&
+ (text[j]<=fsm[state].next1)
+ ) ||
+ (casei && (tolower(text[j])>=tolower(fsm[state].ch)) &&
+ (tolower(text[j])<=tolower(fsm[state].next1))
+ )
+ )
+ {
+ found = 1;
+ break;
+ }
+ }
+ else if ((fsm[state].command == IMASK_CLASS_CMD_CHAR) &&
+ ((!casei && text[j] == fsm[state].ch) ||
+ (casei && tolower(text[j]) == tolower(fsm[state].ch))
+ )
+ )
+ {
+ found = 1;
+ break;
+ }
+ state++;
+ }
+
+ if(found ^ negate)
+ {
+ iMaskPushStack (&next, temp);
+ state = temp;
+ }
+ }
+ else if (fsm[state].command == IMASK_BEGIN_CMD)
+ {
+ if (text[j - 1] == '\n' || j == 0)
+ iMaskPushStack (&now, fsm[state].next1);
+ }
+ else if (fsm[state].command == IMASK_END_CMD)
+ {
+ if (text[j] == '\n' || text[j] == '\0')
+ iMaskPushStack (&now, fsm[state].next1);
+ }
+ }
+
+ if (text[j] == '\0')
+ {
+ if(next.size == 0 && finished == j)
+ {
+ return finished;
+ }
+ else if(addchar)
+ {
+ int pos;
+
+ for (pos = 0; pos < now.size; pos++)
+ {
+ state = now.stack[pos];
+ if (fsm[state].command == IMASK_CHAR_CMD)
+ {
+ iMaskPushStack (&next, state);
+ }
+ else if (fsm[state].command != IMASK_NULL_CMD)
+ {
+ next.size = 0;
+ break;
+ }
+ else
+ {
+ if (!iMaskInStack (&now, fsm[state].next2))
+ iMaskPushStack (&now, fsm[state].next2);
+
+ if (fsm[state].next1 != fsm[state].next2)
+ {
+ if (!iMaskInStack (&now, fsm[state].next1))
+ iMaskPushStack (&now, fsm[state].next1);
+ }
+ }
+ }
+
+ iMaskMoveStack (&now, &next);
+
+ if (now.size == 1)
+ {
+ int inx=0;
+ state = now.stack[0];
+ while(fsm[state].next1 == fsm[state].next2)
+ {
+ if(fsm[state].command == IMASK_CHAR_CMD)
+ addchar[inx++] = fsm[state].ch;
+ else if(fsm[state].command != IMASK_NULL_CMD)
+ break;
+
+ state = fsm[state].next1;
+ }
+ addchar[inx]=0;
+ }
+ }
+ return IMASK_PARTIALMATCH;
+ }
+
+ j++;
+
+ if (next.size == 0)
+ {
+ if (finished > IMASK_NOMATCH)
+ return finished;
+
+ return IMASK_NOMATCH;
+ }
+
+ iMaskMoveStack (&now, &next);
+ }
+}
+
+int iupMaskMatch (const char *text, ImaskParsed * fsm, long start, iMaskMatchFunc function, void *user, char *addchar, int icase)
+{
+ long ret;
+ short tested[10000]; /* to be eliminated */
+ ImaskMatchVars vars;
+
+ /* use recursive only for standard capture */
+
+ if (fsm[0].ch == IMASK_NOCAPTURE)
+ return iMaskMatchLocal (text, fsm, start, addchar, icase);
+
+ vars.text = text;
+ vars.fsm = fsm;
+ vars.tested = tested;
+ vars.function = function;
+ vars.user = user;
+
+ ret = iMaskMatchRecursive (&vars, start, fsm[0].next1, NULL, 0);
+
+ return (int)((ret >= start) ? ret - start : ret);
+}
diff --git a/iup/src/iup_maskmatch.h b/iup/src/iup_maskmatch.h
new file mode 100755
index 0000000..d0c7918
--- /dev/null
+++ b/iup/src/iup_maskmatch.h
@@ -0,0 +1,62 @@
+/** \file
+ * \brief Mask match private definitions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_MASKMATCH_H
+#define __IUP_MASKMATCH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+enum
+{
+ IMASK_NULL_CMD=1,
+ IMASK_ANY_CMD=2,
+ IMASK_CHAR_CMD=3,
+ IMASK_SPC_CMD=4,
+ IMASK_CLASS_CMD=5,
+ IMASK_BEGIN_CMD=6,
+ IMASK_END_CMD=7,
+ IMASK_CAP_OPEN_CMD=71,
+ IMASK_CAP_CLOSE_CMD=72,
+ IMASK_NEG_OPEN_CMD=81,
+ IMASK_NEG_CLOSE_CMD=82
+};
+
+enum
+{
+ IMASK_CLASS_CMD_RANGE=50,
+ IMASK_CLASS_CMD_CHAR=51
+};
+
+enum
+{
+ IMASK_NORMAL_MATCH,
+ IMASK_NO_CHAR_MATCH,
+ IMASK_NO_MATCH
+};
+
+enum
+{
+ IMASK_CAPTURE=100,
+ IMASK_NOCAPTURE=101
+};
+
+typedef struct _ImaskMatchFunc
+{
+ char ch;
+ int (*function) (const char *, long);
+} ImaskMatchFunc;
+
+ImaskMatchFunc* iupMaskMatchGetFuncs(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_maskparse.c b/iup/src/iup_maskparse.c
new file mode 100755
index 0000000..859d951
--- /dev/null
+++ b/iup/src/iup_maskparse.c
@@ -0,0 +1,547 @@
+/** \file
+ * \brief imask parser
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <setjmp.h>
+
+#include "iup_maskparse.h"
+#include "iup_maskmatch.h"
+
+/*
+ * Table of characters (customizaveis atraves de iupMaskSetChar)
+ */
+
+static char *imask_parse_chars = "|*+()[]-^/.?^${}~";
+/* 01234567890123456 */
+
+#define OR_CH imask_parse_chars[0] /* OR CHaracter */
+#define CL_CH imask_parse_chars[1] /* CLosure CHaracter */
+#define OOM_CH imask_parse_chars[2] /* One Or More CHaracter */
+#define OPGR_CH imask_parse_chars[3] /* OPen GRoup CHaracter */
+#define CLGR_CH imask_parse_chars[4] /* CLose GRoup CHaracter */
+#define OPCL_CH imask_parse_chars[5] /* OPen CLass CHaracter */
+#define CLCL_CH imask_parse_chars[6] /* CLose CLass CHaracter */
+#define SEPCL_CH imask_parse_chars[7] /* SEParate CLass CHaracter */
+#define NEGCL_CH imask_parse_chars[8] /* NEGation CLass CHaracter */
+#define SPC_CH imask_parse_chars[9] /* SPeCial function CHaracter */
+#define ANY_CH imask_parse_chars[10] /* ANY CHaracter */
+#define ONE_CH imask_parse_chars[11] /* ONE or no CHaracter */
+#define BEGIN_CH imask_parse_chars[12] /* BEGINning of a line CHaracter*/
+#define END_CH imask_parse_chars[13] /* END of a line CHaracter */
+#define CAP_OPEN_CH imask_parse_chars[14] /* CAPture OPEN CHaracter */
+#define CAP_CLOSE_CH imask_parse_chars[15] /* CAPture CLOSE CHaracter */
+#define NEG_CH imask_parse_chars[16] /* NEGation CHaracter */
+
+#define SPC2_CH '\\' /* SPeCial 2 CHaracter */
+
+#define isvalid(c) (c != 0 && c != OR_CH && c != OPGR_CH && c != CLGR_CH &&\
+ c != CL_CH && c != OPCL_CH && c != CLCL_CH &&\
+ c != CAP_OPEN_CH && c != CAP_CLOSE_CH && c != OOM_CH)
+
+#define STATE_BLOCK 30
+
+typedef struct _ImaskParseVars
+{
+ const char *string;
+ int state, j, num_states;
+ ImaskParsed *fsm;
+ short capture[30];
+ short size;
+ char nextcap;
+ jmp_buf env;
+} ImaskParseVars;
+
+static int iMaskParseExpression (ImaskParseVars * vars);
+static int iMaskParseTerm (ImaskParseVars * vars);
+static int iMaskParseFactor (ImaskParseVars * vars);
+static void iMaskParseError (ImaskParseVars *vars);
+static void iMaskParseNewState (ImaskParseVars * vars);
+static void iMaskParseSetState (ImaskParseVars * vars, int state, char ch, char command, int next1, int next2);
+
+int iupMaskSetChar (int char_number, char new_char)
+{
+ if ((char_number < 0) || (char_number > (int)strlen(imask_parse_chars)))
+ return 0;
+
+ imask_parse_chars[char_number] = new_char;
+
+ return 1;
+}
+
+ /*
+ * Funcao de interface, recebe padrao e retorna array contendo as finite
+ * state machines (fsm) construidas a partir do padrao
+ */
+
+int iupMaskParse(const char *text, ImaskParsed ** fsm)
+{
+ int t;
+ ImaskParseVars vars;
+
+ /* inicializacao das variaveis */
+
+ vars.state = 1;
+ vars.j = 0;
+ vars.num_states = 0;
+ vars.size = 0;
+ vars.nextcap = 0;
+ vars.string = text;
+
+ if ((vars.fsm = (ImaskParsed *) malloc (STATE_BLOCK * sizeof (ImaskParsed))) == NULL)
+ return IMASK_MEM_ERROR;
+
+ vars.num_states = STATE_BLOCK;
+
+ /* a principio, nao ha captura. Se ocorrer uma, ele e setado
+ para IMASK_CAPTURE */
+
+ vars.fsm[0].ch = IMASK_NOCAPTURE;
+
+ if (setjmp (vars.env) == 0)
+ t = iMaskParseExpression (&vars);
+
+ else
+ {
+ free (vars.fsm);
+ return IMASK_PARSE_ERROR;
+ }
+
+ /* seta os estados inicial e final, guardando no inicial
+ (fsm[0].next1) o tamanho da maquina */
+
+ iMaskParseSetState (&vars, 0, vars.fsm[0].ch, IMASK_NULL_CMD, t, vars.state + 1);
+ iMaskParseSetState (&vars, vars.state, 0, IMASK_NULL_CMD, 0, 0);
+
+ *fsm = vars.fsm;
+
+ return IMASK_PARSE_OK;
+}
+
+static int iMaskParseExpression (ImaskParseVars * vars)
+{
+ int r, t1;
+ int last_state = vars->state - 1;
+
+ t1 = iMaskParseTerm (vars);
+ r = t1;
+
+ if (vars->string[vars->j] == OR_CH)
+ {
+ int t2 = vars->state;
+ int t3;
+
+ r = t2;
+
+ vars->j++;
+ iMaskParseNewState (vars);
+
+ t3 = iMaskParseExpression (vars); /* pega o 2o ramo do OR */
+
+ /* faz o primeiro state antes do OR apontar para o state de entrada
+ * do OR */
+
+ if (vars->fsm[last_state].next1 == t1)
+ vars->fsm[last_state].next1 = t2;
+
+ if (vars->fsm[last_state].next2 == t1)
+ vars->fsm[last_state].next2 = t2;
+
+ /* faz o ultimo state do primeiro ramo do OR apontar para o
+ * state de saida do OR */
+
+ if (vars->fsm[t2 - 1].next1 == t2)
+ vars->fsm[t2 - 1].next1 = vars->state;
+
+ if (vars->fsm[t2 - 1].next2 == t2)
+ vars->fsm[t2 - 1].next2 = vars->state;
+
+ iMaskParseSetState (vars, t2, 0, IMASK_NULL_CMD, t1, t3);
+ iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1,
+ vars->state + 1);
+
+ iMaskParseNewState (vars);
+ }
+ return r;
+}
+
+static int iMaskParseTerm (ImaskParseVars * vars)
+{
+ int r;
+
+ r = iMaskParseFactor (vars);
+
+ if ((vars->string[vars->j] == OPGR_CH) ||
+ (isvalid (vars->string[vars->j])) ||
+ (vars->string[vars->j] == OPCL_CH) ||
+ (vars->string[vars->j] == CAP_OPEN_CH) ||
+ (vars->string[vars->j] == NEG_CH))
+ iMaskParseTerm (vars);
+
+ if (!((vars->string[vars->j] == OR_CH) ||
+ (vars->string[vars->j] == CLGR_CH) ||
+ (vars->string[vars->j] == '\0') ||
+ (vars->string[vars->j] == CAP_CLOSE_CH)))
+ iMaskParseError (vars);
+
+ return r;
+}
+
+static int iMaskParseFactor (ImaskParseVars * vars)
+{
+ int r, t1, t2 = 0;
+
+ t1 = vars->state;
+
+ if (vars->string[vars->j] == OPGR_CH)
+ {
+ vars->j++;
+ t2 = iMaskParseExpression (vars);
+
+ if (vars->string[vars->j] == CLGR_CH)
+ vars->j++;
+ else
+ iMaskParseError (vars);
+ }
+
+ else if (vars->string[vars->j] == CAP_OPEN_CH)
+ {
+ vars->fsm[0].ch = IMASK_CAPTURE;
+ iMaskParseSetState (vars, vars->state, vars->nextcap,
+ IMASK_CAP_OPEN_CMD, vars->state + 1, vars->state + 1);
+ t2 = vars->state;
+ iMaskParseNewState (vars);
+ vars->capture[++vars->size] = vars->nextcap++;
+ vars->j++;
+
+ iMaskParseExpression (vars);
+
+ if (vars->string[vars->j] == CAP_CLOSE_CH)
+ {
+ iMaskParseSetState (vars, vars->state, (char)vars->capture[vars->size--],
+ IMASK_CAP_CLOSE_CMD, vars->state + 1, vars->state + 1);
+
+ iMaskParseNewState (vars);
+ vars->j++;
+ }
+ else
+ iMaskParseError (vars);
+
+ }
+
+ else if (vars->string[vars->j] == ANY_CH)
+ {
+ iMaskParseSetState (vars, vars->state, 1, IMASK_ANY_CMD, vars->state + 1, vars->state + 1);
+ t2 = vars->state;
+ vars->j++;
+ iMaskParseNewState (vars);
+ }
+
+ else if (vars->string[vars->j] == NEG_CH)
+ {
+ int t6;
+ t2 = vars->state;
+ vars->j++;
+ iMaskParseNewState (vars);
+ t6 = iMaskParseFactor (vars);
+ iMaskParseSetState (vars, t2, 1, IMASK_NEG_OPEN_CMD, t6, vars->state);
+ iMaskParseSetState (vars, vars->state, 1, IMASK_NEG_CLOSE_CMD, vars->state + 1, vars->state + 1);
+ iMaskParseNewState (vars);
+ }
+
+ else if (vars->string[vars->j] == BEGIN_CH)
+ {
+ iMaskParseSetState (vars, vars->state, 1, IMASK_BEGIN_CMD, vars->state + 1,
+ vars->state + 1);
+ t2 = vars->state;
+ vars->j++;
+ iMaskParseNewState (vars);
+ }
+ else if (vars->string[vars->j] == END_CH)
+ {
+ iMaskParseSetState (vars, vars->state, 1, IMASK_END_CMD, vars->state + 1,
+ vars->state + 1);
+ t2 = vars->state;
+ vars->j++;
+ iMaskParseNewState (vars);
+ }
+
+ else if (isvalid (vars->string[vars->j]) && (vars->string[vars->j]
+ != SPC_CH) && (vars->string[vars->j] != ANY_CH))
+ {
+ iMaskParseSetState (vars, vars->state, vars->string[vars->j],
+ IMASK_CHAR_CMD, vars->state + 1, vars->state + 1);
+ t2 = vars->state;
+ vars->j++;
+ iMaskParseNewState (vars);
+ }
+
+ else if (vars->string[vars->j] == OPCL_CH)
+ {
+ vars->j++;
+ iMaskParseSetState (vars, vars->state, 0, IMASK_CLASS_CMD, 0, 0);
+
+ if (vars->string[vars->j] == NEGCL_CH)
+ {
+ vars->fsm[vars->state].next2 = 1;
+ vars->j++;
+ }
+
+ t2 = vars->state;
+ iMaskParseNewState (vars);
+
+ if (vars->string[vars->j] == SEPCL_CH)
+ iMaskParseError (vars);
+
+ while ((vars->string[vars->j] != CLCL_CH) && (vars->string[vars->j] != '\n')
+ && (vars->string[vars->j] != '\0'))
+ {
+ if (vars->string[vars->j] == SPC_CH)
+ {
+ char temp;
+
+ vars->j++;
+ switch (vars->string[vars->j])
+ {
+ case 'n':
+ temp = '\n';
+ break;
+
+ case 't':
+ temp = '\t';
+ break;
+
+ case 'e':
+ temp = 27;
+ break;
+
+ default:
+ temp = vars->string[vars->j];
+ }
+ iMaskParseSetState (vars, vars->state, temp, IMASK_CLASS_CMD_CHAR, 0, 0);
+ vars->j++;
+ iMaskParseNewState (vars);
+ }
+ else if (vars->string[vars->j] == SEPCL_CH)
+ {
+ char temp = 0;
+
+ vars->j++;
+
+ if (vars->string[vars->j] == SPC_CH)
+ {
+ vars->j++;
+ switch (vars->string[vars->j])
+ {
+ case 'n':
+ temp = '\n';
+ break;
+
+ case 't':
+ temp = '\t';
+ break;
+
+ case 'e':
+ temp = 27;
+ break;
+
+ default:
+ temp = vars->string[vars->j];
+ }
+ }
+ else if (vars->string[vars->j] != CLCL_CH)
+ temp = vars->string[vars->j];
+
+ else
+ iMaskParseError (vars);
+
+ iMaskParseSetState (vars, vars->state - 1, vars->fsm[vars->state - 1].ch,
+ IMASK_CLASS_CMD_RANGE, temp, 0);
+ vars->j++;
+ }
+ else if (vars->string[vars->j] == BEGIN_CH)
+ {
+ iMaskParseSetState (vars, vars->state, 1, IMASK_BEGIN_CMD, vars->state + 1, vars->state + 1);
+ t2 = vars->state;
+ vars->j++;
+ iMaskParseNewState (vars);
+ }
+ else if (vars->string[vars->j] == END_CH)
+ {
+ iMaskParseSetState (vars, vars->state, 1, IMASK_END_CMD, vars->state + 1, vars->state + 1);
+ t2 = vars->state;
+ vars->j++;
+ iMaskParseNewState (vars);
+ }
+
+ else
+ {
+ iMaskParseSetState (vars, vars->state, vars->string[vars->j], IMASK_CLASS_CMD_CHAR, 0, 0);
+ vars->j++;
+ iMaskParseNewState (vars);
+ }
+
+ }
+ if (vars->string[vars->j] != CLCL_CH)
+ iMaskParseError (vars);
+ iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1, vars->state + 1);
+ vars->fsm[t2].next1 = vars->state;
+ vars->j++;
+ iMaskParseNewState (vars);
+
+ }
+
+ else if (vars->string[vars->j] == SPC_CH)
+ {
+ int loop1 = 0;
+ ImaskMatchFunc* match_functions = iupMaskMatchGetFuncs();
+
+ vars->j++;
+
+ while (match_functions[loop1].ch != '\0' &&
+ match_functions[loop1].ch != vars->string[vars->j])
+ loop1++;
+
+ if (match_functions[loop1].ch == '\0')
+ {
+ int temp;
+
+ switch (vars->string[vars->j])
+ {
+ case 'n':
+ temp = '\n';
+ break;
+
+ case 't':
+ temp = '\t';
+ break;
+
+ case 'e':
+ temp = 27;
+ break;
+
+ case 'x':
+ vars->j++;
+ sscanf (&vars->string[vars->j], "%2x", &temp);
+ vars->j++;
+ break;
+
+ case 'o':
+ vars->j++;
+ sscanf (&vars->string[vars->j], "%3o", &temp);
+ vars->j += 2;
+ break;
+
+ default:
+ if (isdigit((int)vars->string[vars->j]))
+ {
+ sscanf (&vars->string[vars->j], "%3d", &temp);
+ if (temp > 255)
+ {
+ iMaskParseError (vars);
+ }
+ vars->j += 2;
+ }
+ else
+ temp = vars->string[vars->j];
+ }
+ iMaskParseSetState (vars, vars->state, (char)temp, IMASK_CHAR_CMD, vars->state + 1, vars->state + 1);
+ }
+
+ else
+ {
+ iMaskParseSetState (vars, vars->state, (char)loop1, IMASK_SPC_CMD, vars->state + 1, vars->state + 1);
+ }
+
+ t2 = vars->state;
+ vars->j++;
+ iMaskParseNewState (vars);
+ }
+ else
+ iMaskParseError (vars);
+
+ if (vars->string[vars->j] == CL_CH)
+ {
+ iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1, t2);
+ r = vars->state;
+
+ if (vars->fsm[t1 - 1].next1 == t1)
+ vars->fsm[t1 - 1].next1 = vars->state;
+
+ if (vars->fsm[t1 - 1].next2 == t1)
+ vars->fsm[t1 - 1].next2 = vars->state;
+
+ vars->j++;
+ iMaskParseNewState (vars);
+ }
+
+ else if (vars->string[vars->j] == ONE_CH)
+ {
+ iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1, t2);
+ r = vars->state;
+
+ if (vars->fsm[t1 - 1].next1 == t1)
+ vars->fsm[t1 - 1].next1 = vars->state;
+
+ if (vars->fsm[t1 - 1].next2 == t1)
+ vars->fsm[t1 - 1].next2 = vars->state;
+
+ if (vars->fsm[vars->state - 1].next1 == vars->state)
+ vars->fsm[vars->state - 1].next1 = vars->state + 1;
+
+ if (vars->fsm[vars->state - 1].next2 == vars->state)
+ vars->fsm[vars->state - 1].next2 = vars->state + 1;
+
+ vars->j++;
+ iMaskParseNewState (vars);
+
+ iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1, vars->state + 1);
+
+ iMaskParseNewState (vars);
+ }
+ else if (vars->string[vars->j] == OOM_CH)
+ {
+ iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1, t2);
+ r = t2;
+
+ vars->j++;
+
+ iMaskParseNewState (vars);
+
+ }
+ else
+ r = t2;
+
+ return r;
+}
+
+static void iMaskParseError (ImaskParseVars * vars)
+{
+ longjmp (vars->env, 1);
+}
+
+static void iMaskParseNewState (ImaskParseVars * vars)
+{
+
+ if (vars->state >= vars->num_states - 1)
+ {
+ ImaskParsed *new_fsm = (ImaskParsed*) realloc (vars->fsm, (vars->num_states + STATE_BLOCK) * sizeof (ImaskParsed));
+ vars->fsm = new_fsm;
+ vars->num_states += STATE_BLOCK;
+ }
+
+ vars->state++;
+}
+
+static void iMaskParseSetState (ImaskParseVars * vars, int state, char ch, char command, int next1, int next2)
+{
+ vars->fsm[state].ch = ch;
+ vars->fsm[state].command = command;
+ vars->fsm[state].next1 = next1;
+ vars->fsm[state].next2 = next2;
+}
diff --git a/iup/src/iup_maskparse.h b/iup/src/iup_maskparse.h
new file mode 100755
index 0000000..a12a7fa
--- /dev/null
+++ b/iup/src/iup_maskparse.h
@@ -0,0 +1,46 @@
+/** \file
+ * \brief Mask internal functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_MASKPARSE_H
+#define __IUP_MASKPARSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct _ImaskParsed
+{
+ char ch;
+ int command;
+ int next1;
+ int next2;
+} ImaskParsed;
+
+typedef int (*iMaskMatchFunc) (char which_one, long next_pos, long capture_pos, const char *text, void* user_data);
+
+/* Parse the mask and if it is ok create and returns the internal structure. */
+int iupMaskParse(const char* mask, ImaskParsed** imk);
+
+/* Do the pattern matching on the given text. */
+int iupMaskMatch(const char* text, ImaskParsed* imk, long start, iMaskMatchFunc mask_func, void* user_data, char *addchar, int icase);
+
+/* Change a control character. */
+int iupMaskSetChar(int char_number, char new_char);
+
+/* iupMaskMatch return codes */
+#define IMASK_PARSE_OK 0 /* No error */
+#define IMASK_NOMATCH -1 /* no match */
+#define IMASK_MEM_ERROR -2 /* memory error */
+#define IMASK_PARSE_ERROR -3 /* parser error */
+#define IMASK_PARTIALMATCH -4 /* partial match */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_menu.c b/iup/src/iup_menu.c
new file mode 100755
index 0000000..7e62744
--- /dev/null
+++ b/iup/src/iup_menu.c
@@ -0,0 +1,364 @@
+/** \file
+ * \brief Menu Resources.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_assert.h"
+#include "iup_key.h"
+#include "iup_stdcontrols.h"
+#include "iup_drvinfo.h"
+#include "iup_menu.h"
+
+
+struct _IcontrolData
+{
+ int child_id; /* serial number used by child controls */
+};
+
+static Ihandle* iMenuGetTopMenu(Ihandle* ih)
+{
+ for (; ih->parent; ih = ih->parent)
+ ; /* empty*/
+ return ih;
+}
+
+int iupMenuGetChildId(Ihandle* ih)
+{
+ Ihandle* dlg = IupGetDialog(ih);
+ if (dlg)
+ return iupDialogGetChildId(ih);
+ else
+ {
+ int id;
+ ih = iMenuGetTopMenu(ih);
+ if (!ih) return -1;
+ id = ih->data->child_id;
+ if (id == 0) id = 100; /* initial number */
+ ih->data->child_id = id+1;
+ return id;
+ }
+}
+
+char* iupMenuGetChildIdStr(Ihandle* ih)
+{
+ Ihandle* dlg = IupGetDialog(ih);
+ if (dlg)
+ return iupDialogGetChildIdStr(ih);
+ else
+ {
+ char *str = iupStrGetMemory(50);
+ Ihandle* dialog = iMenuGetTopMenu(ih);
+ sprintf(str, "iup-%s-%d", ih->iclass->name, dialog->data->child_id);
+ return str;
+ }
+}
+
+int iupMenuIsMenuBar(Ihandle* ih)
+{
+ if (ih->parent && ih->parent->iclass->nativetype == IUP_TYPEDIALOG)
+ return 1;
+ else
+ return 0;
+}
+
+static void iMenuAdjustPos(int *x, int *y)
+{
+ int cursor_x = 0, cursor_y = 0;
+ int screen_width = 0, screen_height = 0;
+
+ if (*x == IUP_CENTER || *y == IUP_CENTER ||
+ *x == IUP_RIGHT || *y == IUP_RIGHT ||
+ *x == IUP_CENTERPARENT || *y == IUP_CENTERPARENT)
+ iupdrvGetScreenSize(&screen_width, &screen_height);
+
+ if (*x == IUP_MOUSEPOS || *y == IUP_MOUSEPOS)
+ iupdrvGetCursorPos(&cursor_x, &cursor_y);
+
+ switch (*x)
+ {
+ case IUP_CENTER:
+ *x = screen_width/2;
+ break;
+ case IUP_LEFT:
+ *x = 0;
+ break;
+ case IUP_RIGHT:
+ *x = screen_width;
+ break;
+ case IUP_MOUSEPOS:
+ *x = cursor_x;
+ break;
+ }
+
+ switch (*y)
+ {
+ case IUP_CENTER:
+ *y = screen_height/2;
+ break;
+ case IUP_LEFT:
+ *y = 0;
+ break;
+ case IUP_RIGHT:
+ *y = screen_height;
+ break;
+ case IUP_MOUSEPOS:
+ *y = cursor_y;
+ break;
+ }
+}
+
+char* iupMenuProcessTitle(Ihandle* ih, const char* title)
+{
+ int keychar;
+ char* str;
+
+ char* key = iupAttribGet(ih, "KEY");
+ if (!key) return (char*)title;
+
+ keychar = iupKeyNameToCode(key);
+ if (!keychar) return (char*)title;
+
+ str = strchr(title, keychar);
+ if (str)
+ {
+ int len = strlen(title);
+ char *new_title = malloc(len+1+1);
+ int pos = str-title;
+ memcpy(new_title, title, pos);
+ new_title[pos] = '&';
+ memcpy(new_title+pos+1, title+pos, len-pos+1);
+ return new_title;
+ }
+
+ return (char*)title;
+}
+
+int iupMenuPopup(Ihandle* ih, int x, int y)
+{
+ iMenuAdjustPos(&x, &y);
+ return iupdrvMenuPopup(ih, x, y);
+}
+
+
+/******************************************************************/
+
+
+static int iItemCreateMethod(Ihandle* ih, void** params)
+{
+ if (params)
+ {
+ if (params[0]) iupAttribStoreStr(ih, "TITLE", (char*)(params[0]));
+ if (params[1]) iupAttribStoreStr(ih, "ACTION", (char*)(params[1]));
+ }
+ return IUP_NOERROR;
+}
+
+static int iSubmenuCreateMethod(Ihandle* ih, void** params)
+{
+ if (params)
+ {
+ if (params[0]) iupAttribStoreStr(ih, "TITLE", (char*)(params[0]));
+ if (params[1])
+ {
+ Ihandle* child = (Ihandle*)(params[1]);
+ if (child->iclass->nativetype == IUP_TYPEMENU)
+ IupAppend(ih, child);
+ }
+ }
+ return IUP_NOERROR;
+}
+
+static int iMenuCreateMethod(Ihandle* ih, void** params)
+{
+ ih->data = iupALLOCCTRLDATA();
+
+ if (params)
+ {
+ Ihandle** iparams = (Ihandle**)params;
+ while (*iparams)
+ {
+ Ihandle* child = (Ihandle*)(*iparams);
+ if (child->iclass->nativetype == IUP_TYPEMENU)
+ IupAppend(ih, child);
+ iparams++;
+ }
+ }
+
+ return IUP_NOERROR;
+}
+
+
+/******************************************************************************************/
+
+
+Iclass* iupSeparatorGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "separator";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPEMENU;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "WID", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "NAME", NULL, iupBaseSetNameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupdrvSeparatorInitClass(ic);
+
+ return ic;
+}
+
+Iclass* iupItemGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "item";
+ ic->format = "SA"; /* one optional string and one optional callback name */
+ ic->nativetype = IUP_TYPEMENU;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 1;
+
+ /* Class functions */
+ ic->Create = iItemCreateMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "HIGHLIGHT_CB", "");
+ iupClassRegisterCallback(ic, "ACTION", "");
+
+ /* Common Callbacks */
+ iupClassRegisterCallback(ic, "MAP_CB", "");
+ iupClassRegisterCallback(ic, "UNMAP_CB", "");
+ iupClassRegisterCallback(ic, "HELP_CB", "");
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "WID", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "NAME", NULL, iupBaseSetNameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "AUTOTOGGLE", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "KEY", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupdrvItemInitClass(ic);
+
+ return ic;
+}
+
+Iclass* iupSubmenuGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "submenu";
+ ic->format = "SH"; /* one string and one Ihandle (both optional) */
+ ic->nativetype = IUP_TYPEMENU;
+ ic->childtype = IUP_CHILD_ONE;
+ ic->is_interactive = 1;
+
+ /* Class functions */
+ ic->Create = iSubmenuCreateMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "HIGHLIGHT_CB", "");
+
+ /* Common Callbacks */
+ iupClassRegisterCallback(ic, "MAP_CB", "");
+ iupClassRegisterCallback(ic, "UNMAP_CB", "");
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "WID", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "NAME", NULL, iupBaseSetNameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "KEY", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupdrvSubmenuInitClass(ic);
+
+ return ic;
+}
+
+Iclass* iupMenuGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "menu";
+ ic->format = "g"; /* (Ihandle**) */
+ ic->nativetype = IUP_TYPEMENU;
+ ic->childtype = IUP_CHILDMANY;
+ ic->is_interactive = 1;
+
+ /* Class functions */
+ ic->Create = iMenuCreateMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "OPEN_CB", "");
+ iupClassRegisterCallback(ic, "MENUCLOSE_CB", "");
+
+ /* Common Callbacks */
+ iupClassRegisterCallback(ic, "MAP_CB", "");
+ iupClassRegisterCallback(ic, "UNMAP_CB", "");
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "WID", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "NAME", NULL, iupBaseSetNameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "RADIO", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupdrvMenuInitClass(ic);
+
+ return ic;
+}
+
+/************************************************************************/
+
+Ihandle* IupItem(const char* title, const char* action)
+{
+ void *params[2];
+ params[0] = (void*)title;
+ params[1] = (void*)action;
+ return IupCreatev("item", params);
+}
+
+Ihandle* IupSubmenu(const char* title, Ihandle* child)
+{
+ void *params[2];
+ params[0] = (void*)title;
+ params[1] = (void*)child;
+ return IupCreatev("submenu", params);
+}
+
+Ihandle *IupMenuv(Ihandle **children)
+{
+ return IupCreatev("menu", (void**)children);
+}
+
+Ihandle *IupMenu(Ihandle *child, ...)
+{
+ Ihandle **children;
+ Ihandle *ih;
+
+ va_list arglist;
+ va_start(arglist, child);
+ children = (Ihandle **)iupObjectGetParamList(child, arglist);
+ va_end(arglist);
+
+ ih = IupCreatev("menu", (void**)children);
+ free(children);
+
+ return ih;
+}
+
+Ihandle* IupSeparator(void)
+{
+ return IupCreate("separator");
+}
diff --git a/iup/src/iup_menu.h b/iup/src/iup_menu.h
new file mode 100755
index 0000000..f1eb164
--- /dev/null
+++ b/iup/src/iup_menu.h
@@ -0,0 +1,35 @@
+/** \file
+ * \brief IUP Menu Class
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_MENU_H
+#define __IUP_MENU_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Shows a popup menu in the given position.
+* Must return IUP_ERROR or IUP_NOERROR.
+* Called only from IupPopup.
+*/
+int iupMenuPopup(Ihandle* ih, int x, int y);
+
+int iupdrvMenuPopup(Ihandle* ih, int x, int y);
+void iupdrvSeparatorInitClass(Iclass* ic);
+void iupdrvItemInitClass(Iclass* ic);
+void iupdrvMenuInitClass(Iclass* ic);
+void iupdrvSubmenuInitClass(Iclass* ic);
+
+char* iupMenuProcessTitle(Ihandle* ih, const char* title);
+int iupMenuGetChildId(Ihandle* ih);
+char* iupMenuGetChildIdStr(Ihandle* ih);
+int iupMenuIsMenuBar(Ihandle* ih);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_messagedlg.c b/iup/src/iup_messagedlg.c
new file mode 100755
index 0000000..816e740
--- /dev/null
+++ b/iup/src/iup_messagedlg.c
@@ -0,0 +1,70 @@
+/** \file
+ * \brief IupMessageDlg class
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_stdcontrols.h"
+
+
+Ihandle* IupMessageDlg(void)
+{
+ return IupCreate("messagedlg");
+}
+
+Iclass* iupMessageDlgGetClass(void)
+{
+ Iclass* ic = iupClassNew(iupDialogGetClass());
+
+ ic->name = "messagedlg";
+ ic->nativetype = IUP_TYPEDIALOG;
+ ic->is_interactive = 1;
+
+ /* reset not used native dialog methods */
+ ic->parent->LayoutUpdate = NULL;
+ ic->parent->SetChildrenPosition = NULL;
+ ic->parent->Map = NULL;
+ ic->parent->UnMap = NULL;
+
+ iupdrvMessageDlgInitClass(ic);
+
+ /* only the default values */
+ iupClassRegisterAttribute(ic, "DIALOGTYPE", NULL, NULL, IUPAF_SAMEASSYSTEM, "MESSAGE", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "BUTTONS", NULL, NULL, IUPAF_SAMEASSYSTEM, "OK", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "BUTTONDEFAULT", NULL, NULL, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "BUTTONRESPONSE", NULL, NULL, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT);
+
+ return ic;
+}
+
+void IupMessage(const char* title, const char* message)
+{
+ Ihandle* dlg = IupCreate("messagedlg");
+
+ IupSetAttribute(dlg, "TITLE", (char*)title);
+ IupSetAttribute(dlg, "VALUE", (char*)message);
+ IupSetAttribute(dlg, "PARENTDIALOG", IupGetGlobal("PARENTDIALOG"));
+
+ IupPopup(dlg, IUP_CENTER, IUP_CENTER);
+ IupDestroy(dlg);
+}
+
+void IupMessagef(const char *title, const char *format, ...)
+{
+ static char message[SHRT_MAX];
+ va_list arglist;
+ va_start(arglist, format);
+ vsprintf(message, format, arglist);
+ va_end (arglist);
+ IupMessage(title, message);
+}
diff --git a/iup/src/iup_names.c b/iup/src/iup_names.c
new file mode 100755
index 0000000..9ec01a6
--- /dev/null
+++ b/iup/src/iup_names.c
@@ -0,0 +1,193 @@
+/** \file
+ * \brief Ihandle <-> Name table manager.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_table.h"
+#include "iup_names.h"
+#include "iup_object.h"
+#include "iup_class.h"
+#include "iup_assert.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 iupNamesDestroyHandles(void)
+{
+ char *name;
+ Ihandle** ih_array, *ih;
+ int count, i = 0;
+
+ count = iupTableCount(inames_strtable);
+ if (!count)
+ return;
+
+ ih_array = (Ihandle**)malloc(count * sizeof(Ihandle*));
+
+ /* store the names before updating so we can remove elements in the loop */
+ name = iupTableFirst(inames_strtable);
+ while (name)
+ {
+ ih = (Ihandle*)iupTableGetCurr(inames_strtable);
+ if (iupObjectCheck(ih))
+ {
+ ih_array[i] = ih;
+ i++;
+ }
+ name = iupTableNext(inames_strtable);
+ }
+
+ count = i;
+ for (i = 0; i < count; i++)
+ {
+ if (iupObjectCheck(ih_array[i]))
+ 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)
+{
+ 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);
+
+ name = iupTableNext(inames_strtable);
+ }
+
+ iupTableRemove(inames_ihtable, (char*)ih);
+}
+
+Ihandle *IupGetHandle(const char *name)
+{
+ if (!name) /* no iupASSERT needed here */
+ return NULL;
+ return (Ihandle*)iupTableGet (inames_strtable, name);
+}
+
+Ihandle* IupSetHandle(const char *name, Ihandle *ih)
+{
+ Ihandle *old_ih;
+
+ iupASSERT(name!=NULL);
+ if (!name)
+ 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 */
+ }
+ 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);
+ }
+ }
+ return old_ih;
+}
+
+int IupGetAllNames(char** names, int n)
+{
+ int i = 0;
+ char* name;
+
+ if (!names || !n)
+ return iupTableCount(inames_strtable);
+
+ name = iupTableFirst(inames_strtable);
+ while (name)
+ {
+ names[i] = name;
+ i++;
+ if (i == n)
+ break;
+
+ name = iupTableNext(inames_strtable);
+ }
+ return i;
+}
+
+static int iNamesCountDialogs(void)
+{
+ int i = 0;
+ char* name = iupTableFirst(inames_strtable);
+ while (name)
+ {
+ Ihandle* dlg = (Ihandle*)iupTableGetCurr(inames_strtable);
+ if (iupObjectCheck(dlg) && dlg->iclass->nativetype == IUP_TYPEDIALOG)
+ i++;
+
+ name = iupTableNext(inames_strtable);
+ }
+ return i;
+}
+
+int IupGetAllDialogs(char** names, int n)
+{
+ int i = 0;
+ char* name;
+
+ if (!names || !n)
+ return iNamesCountDialogs();
+
+ name = iupTableFirst(inames_strtable);
+ while (name)
+ {
+ Ihandle* dlg = (Ihandle*)iupTableGetCurr(inames_strtable);
+ if (iupObjectCheck(dlg) && dlg->iclass->nativetype == IUP_TYPEDIALOG)
+ {
+ names[i] = name;
+ i++;
+ if (i == n)
+ break;
+ }
+
+ name = iupTableNext(inames_strtable);
+ }
+ return i;
+}
+
+char* IupGetName(Ihandle* ih)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return NULL;
+ return iupTableGet(inames_ihtable, (char*)ih);
+}
diff --git a/iup/src/iup_names.h b/iup/src/iup_names.h
new file mode 100755
index 0000000..9d3adc7
--- /dev/null
+++ b/iup/src/iup_names.h
@@ -0,0 +1,34 @@
+/** \file
+ * \brief Ihandle <-> Name table manager.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_NAMES_H
+#define __IUP_NAMES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* called only in IupOpen and IupClose */
+void iupNamesInit(void);
+void iupNamesFinish(void);
+void iupNamesDestroyHandles(void);
+
+/* called from IupDestroy */
+void iupRemoveAllNames(Ihandle* ih);
+
+/* Other functions declared in <iup.h> and implemented here.
+IupGetName
+IupGetAllDialogs
+IupGetAllNames
+IupSetHandle
+IupGetHandle
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_normalizer.c b/iup/src/iup_normalizer.c
new file mode 100755
index 0000000..7f7a5ff
--- /dev/null
+++ b/iup/src/iup_normalizer.c
@@ -0,0 +1,188 @@
+/** \file
+ * \brief Normalizer Element.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_array.h"
+#include "iup_stdcontrols.h"
+
+
+enum {NORMALIZE_NONE, NORMALIZE_WIDTH, NORMALIZE_HEIGHT};
+
+struct _IcontrolData
+{
+ Iarray* ih_array;
+};
+
+int iupNormalizeGetNormalizeSize(const char* value)
+{
+ if (!value)
+ return NORMALIZE_NONE;
+ if (iupStrEqualNoCase(value, "HORIZONTAL"))
+ return NORMALIZE_WIDTH;
+ if (iupStrEqualNoCase(value, "VERTICAL"))
+ return NORMALIZE_HEIGHT;
+ if (iupStrEqualNoCase(value, "BOTH"))
+ return NORMALIZE_WIDTH|NORMALIZE_HEIGHT;
+ return NORMALIZE_NONE;
+}
+
+char* iupNormalizeGetNormalizeSizeStr(int normalize)
+{
+ char* int2str[] = {"NONE", "HORIZONTAL", "VERTICAL", "BOTH"};
+ return int2str[normalize];
+}
+
+void iupNormalizeSizeBoxChild(Ihandle *ih, int normalize, int children_natural_maxwidth, int children_natural_maxheight)
+{
+ /* It is called from Vbox and Hbox ComputeNaturalSizeMethod after the natural size is calculated */
+ /* reset the natural width and/or height */
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating && (child->iclass->nativetype != IUP_TYPEVOID || !iupStrEqual(child->iclass->name, "fill")))
+ {
+ if (normalize & NORMALIZE_WIDTH)
+ child->naturalwidth = children_natural_maxwidth;
+ if (normalize & NORMALIZE_HEIGHT)
+ child->naturalheight = children_natural_maxheight;
+ }
+ }
+}
+
+static int iNormalizerSetNormalizeAttrib(Ihandle* ih, const char* value)
+{
+ int i, count;
+ Ihandle** ih_list;
+ Ihandle* ih_control;
+ int natural_maxwidth = 0, natural_maxheight = 0;
+ int normalize = iupNormalizeGetNormalizeSize(value);
+ if (!normalize)
+ return 1;
+
+ count = iupArrayCount(ih->data->ih_array);
+ ih_list = (Ihandle**)iupArrayGetData(ih->data->ih_array);
+
+ for (i = 0; i < count; i++)
+ {
+ ih_control = ih_list[i];
+ iupBaseComputeNaturalSize(ih_control);
+ natural_maxwidth = iupMAX(natural_maxwidth, ih_control->naturalwidth);
+ natural_maxheight = iupMAX(natural_maxheight, ih_control->naturalheight);
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ ih_control = ih_list[i];
+ if (!ih_control->is_floating && (ih_control->iclass->nativetype != IUP_TYPEVOID || !iupStrEqual(ih_control->iclass->name, "fill")))
+ {
+ if (normalize & NORMALIZE_WIDTH)
+ ih_control->userwidth = natural_maxwidth;
+ if (normalize & NORMALIZE_HEIGHT)
+ ih_control->userheight = natural_maxheight;
+ }
+ }
+ return 1;
+}
+
+static int iNormalizerSetAddControlHandleAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle* ih_control = (Ihandle*)value;
+ Ihandle** ih_list = (Ihandle**)iupArrayInc(ih->data->ih_array);
+ int count = iupArrayCount(ih->data->ih_array);
+ ih_list[count-1] = ih_control;
+ return 0;
+}
+
+static int iNormalizerSetAddControlAttrib(Ihandle* ih, const char* value)
+{
+ return iNormalizerSetAddControlHandleAttrib(ih, (char*)IupGetHandle(value));
+}
+
+static void iNormalizerComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ (void)w;
+ (void)h;
+ (void)expand;
+ iNormalizerSetNormalizeAttrib(ih, iupAttribGetStr(ih, "NORMALIZE"));
+}
+
+static int iNormalizerCreateMethod(Ihandle* ih, void** params)
+{
+ ih->data = iupALLOCCTRLDATA();
+ ih->data->ih_array = iupArrayCreate(10, sizeof(Ihandle*));
+
+ if (params)
+ {
+ Ihandle** iparams = (Ihandle**)params;
+ Ihandle** ih_list;
+ int i = 0;
+ while (*iparams)
+ {
+ ih_list = (Ihandle**)iupArrayInc(ih->data->ih_array);
+ ih_list[i] = *iparams;
+ i++;
+ iparams++;
+ }
+ }
+
+ return IUP_NOERROR;
+}
+
+static void iNormalizerDestroy(Ihandle* ih)
+{
+ iupArrayDestroy(ih->data->ih_array);
+}
+
+Iclass* iupNormalizerGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "normalizer";
+ ic->format = "g"; /* array of Ihandle */
+ ic->nativetype = IUP_TYPEVOID;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = iNormalizerCreateMethod;
+ ic->Map = iupBaseTypeVoidMapMethod;
+ ic->ComputeNaturalSize = iNormalizerComputeNaturalSizeMethod;
+ ic->Destroy = iNormalizerDestroy;
+
+ iupClassRegisterAttribute(ic, "NORMALIZE", NULL, iNormalizerSetNormalizeAttrib, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ADDCONTROL_HANDLE", NULL, iNormalizerSetAddControlHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ADDCONTROL", NULL, iNormalizerSetAddControlAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
+
+Ihandle *IupNormalizerv(Ihandle **ih_list)
+{
+ return IupCreatev("normalizer", (void**)ih_list);
+}
+
+Ihandle *IupNormalizer(Ihandle* ih_first, ...)
+{
+ Ihandle **ih_list;
+ Ihandle *ih;
+
+ va_list arglist;
+ va_start(arglist, ih_first);
+ ih_list = (Ihandle **)iupObjectGetParamList(ih_first, arglist);
+ va_end(arglist);
+
+ ih = IupCreatev("normalizer", (void**)ih_list);
+ free(ih_list);
+
+ return ih;
+}
diff --git a/iup/src/iup_object.c b/iup/src/iup_object.c
new file mode 100755
index 0000000..7f4ce23
--- /dev/null
+++ b/iup/src/iup_object.c
@@ -0,0 +1,180 @@
+/** \file
+ * \brief Ihandle management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_assert.h"
+#include "iup_register.h"
+#include "iup_names.h"
+
+
+static Ihandle* iHandleCreate(void)
+{
+ Ihandle *ih = (Ihandle*)malloc(sizeof(Ihandle));
+ memset(ih, 0, sizeof(Ihandle));
+
+ ih->sig[0] = 'I';
+ ih->sig[1] = 'U';
+ ih->sig[2] = 'P';
+ ih->sig[3] = 0;
+
+ ih->serial = -1;
+
+ ih->attrib = iupTableCreate(IUPTABLE_STRINGINDEXED);
+
+ return ih;
+}
+
+static void iHandleDestroy(Ihandle* ih)
+{
+ iupTableDestroy(ih->attrib);
+ memset(ih, 0, sizeof(Ihandle));
+ free(ih);
+}
+
+int iupObjectCheck(Ihandle* ih)
+{
+ char* sig = (char*)ih;
+
+ if (!ih) return 0;
+
+ if (sig[0] != 'I' ||
+ sig[1] != 'U' ||
+ sig[2] != 'P' ||
+ sig[3] != 0)
+ return 0;
+
+ return 1;
+}
+
+Ihandle* iupObjectCreate(Iclass* iclass, void** params)
+{
+ /* create the base handle structure */
+ Ihandle* ih = iHandleCreate();
+
+ ih->iclass = iclass;
+
+ /* create the element */
+ if (iupClassObjectCreate(ih, params) == IUP_ERROR)
+ {
+ iupERROR1("IUP object creation failed (%s).", iclass->name);
+ iHandleDestroy(ih);
+ return NULL;
+ }
+
+ /* ensure attributes default values, at this time only the ones that can be set before map */
+ iupClassObjectEnsureDefaultAttributes(ih);
+
+ return ih;
+}
+
+void** iupObjectGetParamList(void* first, va_list arglist)
+{
+ const int INITIAL_NUMBER = 50;
+ void **params;
+ void *param;
+ int max_count = INITIAL_NUMBER, count = 0;
+
+ params = (void **) malloc (sizeof (void *) * INITIAL_NUMBER);
+
+ param = first;
+
+ while (param != NULL)
+ {
+ params[count] = param;
+ count++;
+
+ /* verifica se precisa realocar memoria */
+ if (count >= max_count)
+ {
+ void **new_params = NULL;
+
+ max_count += INITIAL_NUMBER;
+
+ new_params = (void **) realloc (params, sizeof (void *) * max_count);
+
+ params = new_params;
+ }
+
+ param = va_arg (arglist, void*);
+ }
+ params[count] = NULL;
+
+ return params;
+}
+
+Ihandle* IupCreatev(const char *name, void **params)
+{
+ Iclass *ic;
+ iupASSERT(name!=NULL);
+ ic = iupRegisterFindClass(name);
+ if (ic)
+ return iupObjectCreate(ic, params);
+ else
+ return NULL;
+}
+
+Ihandle *IupCreatep(const char *name, void* first, ...)
+{
+ va_list arglist;
+ void **params;
+ Ihandle *ih;
+ iupASSERT(name!=NULL);
+
+ va_start(arglist, first);
+ params = iupObjectGetParamList(first, arglist);
+ va_end(arglist);
+
+ ih = IupCreatev(name, params);
+ free(params);
+
+ return ih;
+}
+
+Ihandle* IupCreate(const char *name)
+{
+ iupASSERT(name!=NULL);
+ return IupCreatev(name, NULL);
+}
+
+void IupDestroy(Ihandle *ih)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+
+ /* Hide before destroy to avoid children redraw */
+ if (ih->iclass->nativetype == IUP_TYPEDIALOG)
+ IupHide(ih);
+
+ /* Destroy all its children.
+ Just need to remove the first child,
+ IupDetach will update firstchild. */
+ while (ih->firstchild)
+ IupDestroy(ih->firstchild);
+
+ /* unmap if mapped and remove from its parent child list */
+ IupDetach(ih);
+
+ /* destroy the element */
+ iupClassObjectDestroy(ih);
+
+ /* destroy the private data */
+ 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
new file mode 100755
index 0000000..6f6b668
--- /dev/null
+++ b/iup/src/iup_object.h
@@ -0,0 +1,132 @@
+/** \file
+ * \brief Ihandle Object Definition
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_OBJECT_H
+#define __IUP_OBJECT_H
+
+#include <stdarg.h>
+#include "iup_class.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup object Ihandle Object
+ * \par
+ * Object handle for all the elements.
+ * \par
+ * See \ref iup_object.h
+ * \ingroup cpi */
+
+
+/* SIZE to RASTERSIZE
+ * \ingroup object */
+#define iupWIDTH2RASTER(_w, _cw) ((int)((_w * _cw)/4.0 + 0.5))
+/* SIZE to RASTERSIZE
+ * \ingroup object */
+#define iupHEIGHT2RASTER(_h, _ch) ((int)((_h * _ch)/8.0 + 0.5))
+
+/* RASTERSIZE to SIZE
+ * \ingroup object */
+#define iupRASTER2WIDTH(_w, _cw) ((int)((_w * 4.0)/_cw + 0.5))
+/* RASTERSIZE to SIZE
+ * \ingroup object */
+#define iupRASTER2HEIGHT(_h, _ch) ((int)((_h * 8.0)/_ch + 0.5))
+
+
+/** Expand configuration
+ * \ingroup object */
+enum Iexpand {
+ IUP_EXPAND_NONE = 0x00,
+ IUP_EXPAND_H0 = 0x01, /* only set by IupFill */
+ IUP_EXPAND_H1 = 0x02,
+ IUP_EXPAND_W0 = 0x04, /* only set by IupFill */
+ IUP_EXPAND_W1 = 0x08
+};
+
+/** Expand configuration
+ * \ingroup object */
+#define IUP_EXPAND_WIDTH (IUP_EXPAND_W1 | IUP_EXPAND_W0)
+/** Expand configuration
+ * \ingroup object */
+#define IUP_EXPAND_HEIGHT (IUP_EXPAND_H1 | IUP_EXPAND_H0)
+/** Expand configuration
+ * \ingroup object */
+#define IUP_EXPAND_BOTH (IUP_EXPAND_WIDTH | IUP_EXPAND_HEIGHT)
+
+
+/** A simple definition that do not depends on the native system,
+ but helps a lot when writing native code. See \ref iup_object.h for definitions.
+ * \ingroup object */
+#if defined(GTK_MAJOR_VERSION)
+typedef struct _GtkWidget InativeHandle;
+#elif defined(XmVERSION)
+typedef struct _WidgetRec InativeHandle;
+#elif defined(WINVER)
+typedef struct HWND__ InativeHandle;
+#else
+typedef struct _InativeHandle InativeHandle;
+#endif
+
+/** Each control may define its own structure in its private module.
+ * \ingroup object */
+typedef struct _IcontrolData IcontrolData;
+/** IcontrolData allocation utility.
+ * \ingroup object */
+#define iupALLOCCTRLDATA() ((IcontrolData*)calloc(1, sizeof(IcontrolData)))
+
+
+/** Structure used by all the elements.
+ * \ingroup object */
+struct Ihandle_
+{
+ char sig[4]; /**< IUP Signature, initialized with "IUP", cleared on destroy */
+ Iclass* iclass; /**< Ihandle Class */
+ Itable* attrib; /**< attributes table */
+ int serial; /**< serial number used for controls that need a numeric id, initialized with -1 */
+ InativeHandle* handle; /**< native handle. initialized when mapped. InativeHandle definition is system dependent. */
+ int expand; /**< expand configuration, a combination of \ref Iexpand, for containers is a combination of the children expand's */
+ int is_floating; /**< floating attribute */
+ int x, y; /**< upper-left corner relative to the native parent. always 0 for the dialog. */
+ int userwidth, userheight; /**< user defined size for the control using SIZE or RASTERSIZE */
+ int naturalwidth, naturalheight; /**< the calculated size based in the control contents and the user size */
+ int currentwidth, currentheight; /**< actual size of the control in pixels (window size, including decorations and margins). */
+ int has_maxsize, has_minsize; /**< indicates that the control has the attributes MAXSIZE and/or MINSIZE */
+ Ihandle* parent; /**< previous control in the hierarchy tree */
+ Ihandle* firstchild; /**< first child control in the hierarchy tree */
+ Ihandle* brother; /**< next control inside parent */
+ IcontrolData* data; /**< private control data. automatically freed if not NULL in destroy */
+};
+
+
+/* Creates an object. initializes iclass and nativetype.
+ * Called only from IupCreate and IupLoad. */
+Ihandle* iupObjectCreate(Iclass* ic, void** params);
+
+
+/** Utility that returns an array of parameters. Must call free for the returned value after usage.
+ * Used by the creation functions of objects that receives a NULL terminated array of parameters.
+ * \ingroup object */
+void** iupObjectGetParamList(void* first, va_list arglist);
+
+/** Checks if the handle is still valid based on the signature.
+ * \ingroup object */
+int iupObjectCheck(Ihandle* ih);
+
+
+/* Other functions declared in <iup.h> and implemented here.
+IupCreate
+IupCreatev
+IupCreatep
+IupDestroy
+*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_open.c b/iup/src/iup_open.c
new file mode 100755
index 0000000..e02561e
--- /dev/null
+++ b/iup/src/iup_open.c
@@ -0,0 +1,119 @@
+/** \file
+ * \brief Windows Driver Core
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_globalattrib.h"
+#include "iup_names.h"
+#include "iup_func.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_drvfont.h"
+#include "iup_predial.h"
+#include "iup_class.h"
+#include "iup_register.h"
+#include "iup_key.h"
+#include "iup_image.h"
+#include "iup_dlglist.h"
+#include "iup_assert.h"
+#include "iup_strmessage.h"
+
+
+static int iup_opened = 0;
+static int iup_dummy_argc = 0;
+static char ** iup_dummy_argv = {0};
+
+int iupIsOpened(void)
+{
+ return iup_opened;
+}
+
+int IupOpen(int *argc, char ***argv)
+{
+ if (iup_opened)
+ return IUP_OPENED;
+ iup_opened = 1;
+
+ if (!argc || !(*argc) || !argv)
+ {
+ argc = &iup_dummy_argc;
+ argv = &iup_dummy_argv;
+ }
+
+ iupNamesInit();
+ iupFuncInit();
+ iupStrMessageInit();
+ iupGlobalAttribInit();
+ iupRegisterInit();
+ iupKeyInit();
+ iupImageStockInit();
+
+ IupSetLanguage("ENGLISH");
+ IupSetGlobal("VERSION", IupVersion());
+ IupSetGlobal("COPYRIGHT", IUP_COPYRIGHT);
+
+ if (iupdrvOpen(argc, argv) == IUP_NOERROR)
+ {
+ char* value;
+
+ iupdrvFontInit();
+
+ IupStoreGlobal("SYSTEM", iupdrvGetSystemName());
+ IupStoreGlobal("SYSTEMVERSION", iupdrvGetSystemVersion());
+ IupStoreGlobal("COMPUTERNAME", iupdrvGetComputerName());
+ IupStoreGlobal("USERNAME", iupdrvGetUserName());
+ IupSetGlobal("DEFAULTFONT", iupdrvGetSystemFont()); /* Use SetGlobal because iupdrvGetSystemFont returns a static string */
+
+ iupRegisterInternalClasses();
+
+ value = getenv("IUP_QUIET");
+ if (value && !iupStrBoolean(value)) /* if not defined do NOT print */
+ printf("IUP %s %s\n", IupVersion(), IUP_COPYRIGHT);
+
+ value = getenv("IUP_VERSION");
+ if (iupStrBoolean(value))
+ iupVersionDlg();
+
+ return IUP_NOERROR;
+ }
+ else
+ {
+#ifdef IUP_ASSERT
+ /* can not use pre-defined dialogs here, so only output to console. */
+ fprintf(stderr, "IUP ERROR: IupOpen failed.\n");
+#endif
+ return IUP_ERROR;
+ }
+}
+
+void IupClose(void)
+{
+ if (!iup_opened)
+ return;
+ iup_opened = 0;
+
+ iupdrvSetIdleFunction(NULL); /* stop any idle */
+
+ iupDlgListDestroyAll(); /* destroy all dialogs */
+ iupNamesDestroyHandles(); /* destroy everything else that have names */
+ iupImageStockFinish(); /* release stock images hash table and the images */
+
+ iupRegisterFinish(); /* release native classes */
+
+ iupdrvFontFinish(); /* release font cache */
+ iupdrvClose(); /* release native handles and allocated memory */
+
+ iupGlobalAttribFinish(); /* release global hash table */
+ iupStrMessageFinish(); /* release messages hash table */
+ iupFuncFinish(); /* release callbacks hash table */
+ iupNamesFinish(); /* release names hash table */
+
+ iupStrGetMemory(-1); /* Frees internal buffer */
+}
diff --git a/iup/src/iup_predial.c b/iup/src/iup_predial.c
new file mode 100755
index 0000000..b48e246
--- /dev/null
+++ b/iup/src/iup_predial.c
@@ -0,0 +1,510 @@
+/** \file
+ * \brief pre-defined dialogs
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include "iup.h"
+
+#include "iup_predial.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_strmessage.h"
+
+
+static int CB_button_OK (Ihandle* ih)
+{
+ iupAttribSetStr(IupGetDialog(ih), "STATUS", "1");
+ return IUP_CLOSE;
+}
+
+static int CB_button_CANCEL (Ihandle* ih)
+{
+ iupAttribSetStr(IupGetDialog(ih), "STATUS", "-1");
+ return IUP_CLOSE;
+}
+
+static int CB_lista (Ihandle *h, char *n, int o, int v)
+{
+ static clock_t oldtimesel = 0;
+ static int oldopc = 0;
+ (void)n; /* not used */
+ if (v)
+ {
+ clock_t timesel = clock();
+
+ iupAttribSetStrf(IupGetDialog(h), "_IUP_LIST_NUMBER", "%d", o-1);
+
+ if (((timesel-oldtimesel) < 500) && (o == oldopc))
+ return IUP_CLOSE;
+
+ oldtimesel = timesel;
+ oldopc = o;
+ }
+ return IUP_DEFAULT;
+}
+
+int IupListDialog (int type, const char *title, int size, const char** list_str,
+ int op, int max_col, int max_lin, int* marks)
+{
+ Ihandle *lst, *ok, *dlg, *cancel, *dlg_box, *button_box;
+ int i, bt;
+ char attrib_str[20];
+ char *m=NULL;
+
+ if (size > 999)
+ size = 999;
+
+ lst = IupList(NULL);
+
+ for (i=0;i<size;i++)
+ {
+ sprintf(attrib_str,"%d",i+1);
+ IupSetAttribute(lst,attrib_str,list_str[i]);
+ }
+ sprintf(attrib_str,"%d",i+1);
+ IupSetAttribute(lst,attrib_str,NULL);
+ IupSetAttribute(lst,"EXPAND","YES");
+
+ ok = IupButton("OK", NULL);
+ IupSetAttribute(ok,"PADDING" ,"20x5");
+ IupSetCallback(ok, "ACTION", (Icallback)CB_button_OK);
+
+ cancel = IupButton(iupStrMessageGet("IUP_CANCEL"), NULL);
+ IupSetAttribute(cancel,"PADDING" ,"20x5");
+ IupSetCallback(cancel, "ACTION", (Icallback)CB_button_CANCEL);
+
+ button_box = IupHbox(
+ IupFill(),
+ ok,
+ cancel,
+ NULL);
+ IupSetAttribute(button_box,"MARGIN","0x0");
+ IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL");
+
+ dlg_box = IupVbox(
+ lst,
+ button_box,
+ NULL);
+
+ IupSetAttribute(dlg_box,"MARGIN","10x10");
+ IupSetAttribute(dlg_box,"GAP","10");
+
+ dlg = IupDialog(dlg_box);
+
+ if (type == 1)
+ {
+ if (op<1 || op>size) op=1;
+ iupAttribSetStrf(dlg, "_IUP_LIST_NUMBER", "%d", op-1);
+ IupSetfAttribute(lst,"VALUE","%d",op);
+ IupSetCallback(lst, "ACTION", (Icallback)CB_lista);
+ }
+ else if ((type == 2) && (marks != NULL))
+ {
+ m=(char *)marks;
+ for (i=0;i<size;i++)
+ m[i] = marks[i] ? '+' : '-';
+ m[i]='\0';
+ IupSetAttribute(lst,"MULTIPLE","YES");
+ IupSetAttribute(lst,"VALUE",m);
+ }
+
+ if (max_lin < 4) max_lin = 4;
+ IupSetfAttribute(lst, "VISIBLELINES", "%d", max_lin);
+ IupSetfAttribute(lst, "VISIBLECOLUMNS", "%d", max_col);
+
+ IupSetAttribute(dlg,"TITLE", title);
+ IupSetAttribute(dlg,"MINBOX","NO");
+ IupSetAttribute(dlg,"MAXBOX","NO");
+ IupSetAttributeHandle(dlg,"DEFAULTENTER", ok);
+ IupSetAttributeHandle(dlg,"DEFAULTESC", cancel);
+ IupSetAttribute(dlg,"PARENTDIALOG", IupGetGlobal("PARENTDIALOG"));
+ IupSetAttribute(dlg,"ICON", IupGetGlobal("ICON"));
+
+ IupPopup(dlg,IUP_CENTERPARENT,IUP_CENTERPARENT);
+
+ if ((type == 2) && (marks != NULL))
+ {
+ m=IupGetAttribute(lst,"VALUE");
+ for (i=0;i<size;i++)
+ marks[i] = (m[i] == '+');
+ }
+
+ bt = IupGetInt(dlg, "STATUS");
+ if (type == 1)
+ {
+ if (bt == 1)
+ bt = iupAttribGetInt(dlg, "_IUP_LIST_NUMBER");
+ else
+ bt = -1;
+ }
+ else
+ {
+ if (bt != 1)
+ bt = -1;
+ }
+
+ IupDestroy(dlg);
+
+ return bt;
+}
+
+static int iAlarmButtonAction_CB(Ihandle *ih)
+{
+ iupAttribSetStr(IupGetDialog(ih), "_IUP_BUTTON_NUMBER", iupAttribGet(ih, "_IUP_BUTTON_NUMBER"));
+ return IUP_CLOSE;
+}
+
+int IupAlarm(const char *title, const char *msg, const char *b1, const char *b2, const char *b3)
+{
+ Ihandle *dlg, *dlg_box, *button_box, *button, *default_esc, *default_enter;
+ int bt, len;
+ char* padding;
+
+ msg = msg? msg: "";
+
+ if (b1 == NULL)
+ return 0;
+
+ len = strlen(b1);
+ if (b2)
+ {
+ int len2 = strlen(b2);
+ if (len2 > len)
+ len = len2;
+ }
+ if (b3)
+ {
+ int len3 = strlen(b3);
+ if (len3 > len)
+ len = len3;
+ }
+
+ if (len > 7)
+ padding = "12x2";
+ else
+ padding = "18x5";
+
+ button_box = IupHbox(NULL);
+ IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL");
+ IupSetAttribute(button_box,"MARGIN","0x0");
+ IupAppend(button_box, IupFill()); /* to center the buttons */
+
+ button = IupButton(b1, NULL);
+ iupAttribSetStrf(button, "_IUP_BUTTON_NUMBER", "1");
+ IupSetAttribute(button, "PADDING", padding);
+ IupAppend(button_box, button);
+ IupSetCallback (button, "ACTION", (Icallback)iAlarmButtonAction_CB);
+ default_enter = button;
+ default_esc = button;
+
+ if (b2 != NULL)
+ {
+ button = IupButton(b2, NULL);
+ iupAttribSetStr(button, "_IUP_BUTTON_NUMBER", "2");
+ IupSetAttribute(button, "PADDING", padding);
+ IupAppend(button_box, button);
+ IupSetCallback (button, "ACTION", (Icallback)iAlarmButtonAction_CB);
+ default_esc = button;
+ }
+
+ if (b3 != NULL)
+ {
+ button = IupButton(b3, NULL);
+ iupAttribSetStr(button, "_IUP_BUTTON_NUMBER", "3");
+ IupSetAttribute(button, "PADDING", padding);
+ IupAppend(button_box, button);
+ IupSetCallback (button, "ACTION", (Icallback)iAlarmButtonAction_CB);
+ default_esc = button;
+ }
+
+ IupAppend(button_box, IupFill()); /* to center the buttons */
+
+ dlg_box = IupVbox(
+ IupLabel(msg),
+ IupSetAttributes(IupLabel(NULL), "SEPARATOR=HORIZONTAL"),
+ button_box,
+ NULL);
+
+ IupSetAttribute(dlg_box,"MARGIN","10x10");
+ IupSetAttribute(dlg_box,"GAP","10");
+
+ dlg = IupDialog(dlg_box);
+
+ IupSetAttribute(dlg,"TITLE", title);
+ IupSetAttribute(dlg,"DIALOGFRAME","YES");
+ IupSetAttribute(dlg,"DIALOGHINT","YES");
+ IupSetAttributeHandle(dlg,"DEFAULTENTER", default_enter);
+ IupSetAttributeHandle(dlg,"DEFAULTESC", default_esc);
+ IupSetAttribute(dlg,"PARENTDIALOG", IupGetGlobal("PARENTDIALOG"));
+ IupSetAttribute(dlg,"ICON", IupGetGlobal("ICON"));
+
+ IupPopup(dlg,IUP_CENTERPARENT,IUP_CENTERPARENT);
+
+ bt = iupAttribGetInt(dlg, "_IUP_BUTTON_NUMBER");
+
+ IupDestroy(dlg);
+
+ return bt;
+}
+
+int iupDataEntry(int maxlin,
+ int* maxcol,
+ int* maxscr,
+ char* title,
+ char** text,
+ char** data)
+{
+ int i, bt;
+ Ihandle *ok, *cancel, *dlg, *vb, *hb, **txt, **lbl, *button_box, *dlg_box;
+
+ txt = (Ihandle **)calloc(maxlin, sizeof(Ihandle*));
+ if (txt == NULL) return -2;
+ lbl = (Ihandle **)calloc(maxlin+1, sizeof(Ihandle*));
+
+ vb = IupVbox(NULL);
+
+ for (i=0; i<maxlin; i++)
+ {
+ txt[i] = IupText(NULL);
+ IupSetAttribute(txt[i],"VALUE",data[i]);
+ IupSetfAttribute(txt[i],"VISIBLECOLUMNS","%dx", maxscr[i]);
+ IupSetfAttribute(txt[i],"NC", "%d", maxcol[i]);
+ IupSetAttribute(txt[i],"EXPAND","HORIZONTAL");
+
+ hb = IupHbox(lbl[i] = IupLabel(text[i]), txt[i], NULL);
+ IupSetAttribute(hb,"MARGIN","0x0");
+ IupSetAttribute(hb,"ALIGNMENT","ACENTER");
+ IupAppend(vb, hb);
+ }
+ lbl[i] = NULL;
+ IupInsert(vb, NULL, IupNormalizerv(lbl));
+
+ ok = IupButton("OK", NULL);
+ IupSetAttribute(ok, "PADDING", "20x0");
+ IupSetCallback(ok, "ACTION", (Icallback)CB_button_OK);
+
+ cancel = IupButton(iupStrMessageGet("IUP_CANCEL"), NULL);
+ IupSetAttribute(cancel, "PADDING", "20x0");
+ IupSetCallback(cancel, "ACTION", (Icallback)CB_button_CANCEL);
+
+ button_box = IupHbox(
+ IupFill(),
+ ok,
+ cancel,
+ NULL);
+ IupSetAttribute(button_box,"MARGIN","0x0");
+ IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL");
+
+ dlg_box = IupVbox(
+ IupFrame(vb),
+ button_box,
+ NULL);
+ IupSetAttribute(dlg_box,"MARGIN","10x10");
+ IupSetAttribute(dlg_box,"GAP","5");
+
+ dlg = IupDialog(dlg_box);
+
+ IupSetAttribute(dlg,"TITLE",title);
+ IupSetAttribute(dlg,"MINBOX","NO");
+ IupSetAttribute(dlg,"MAXBOX","NO");
+ IupSetAttributeHandle(dlg,"DEFAULTENTER", ok);
+ IupSetAttributeHandle(dlg,"DEFAULTESC", cancel);
+ IupSetAttribute(dlg,"PARENTDIALOG",IupGetGlobal("PARENTDIALOG"));
+ IupSetAttribute(dlg,"ICON", IupGetGlobal("ICON"));
+
+ IupMap(dlg);
+
+ IupSetfAttribute(dlg,"MAXSIZE", "65535x%d", IupGetInt2(dlg, "RASTERSIZE"));
+ IupSetAttribute(dlg,"MINSIZE", IupGetAttribute(dlg, "RASTERSIZE"));
+
+ IupPopup(dlg,IUP_CENTERPARENT,IUP_CENTERPARENT);
+
+ for (i=0; i<maxlin; i++)
+ {
+ data[i] = (char *)iupStrDup(IupGetAttribute(txt[i], "VALUE"));
+ }
+
+ free(txt);
+
+ bt = IupGetInt(dlg, "STATUS");
+ IupDestroy(dlg);
+ return bt;
+}
+
+static void iupStrSplitFileName(const char* filename, char *dir, char *filter)
+{
+ int i, n = strlen(filename);
+
+ /* Look for last folder separator and split filter from directory */
+ for (i=n-1;i>=0; i--)
+ {
+ if (filename[i] == '\\' || filename[i] == '/')
+ {
+ if (dir)
+ {
+ strncpy(dir, filename, i+1);
+ dir[i+1] = 0;
+ }
+
+ if (filter)
+ {
+ strcpy(filter, filename+i+1);
+ filter[n-i] = 0;
+ }
+
+ return;
+ }
+ }
+}
+
+int IupGetFile(char* filename)
+{
+ Ihandle *dlg = 0;
+ int ret;
+ char filter[4096] = "*.*";
+ static char dir[4096] = ""; /* static will make the dir persist from one call to another if not defined */
+
+ if (!filename) return -1;
+
+ dlg = IupFileDlg();
+
+ iupStrSplitFileName(filename, dir, filter);
+
+ IupSetAttribute(dlg, "FILTER", filter);
+ IupSetAttribute(dlg, "DIRECTORY", dir);
+ IupSetAttribute(dlg, "ALLOWNEW", "YES");
+ IupSetAttribute(dlg, "NOCHANGEDIR", "YES");
+ IupSetAttribute(dlg, "PARENTDIALOG", IupGetGlobal("PARENTDIALOG"));
+ IupSetAttribute(dlg, "ICON", IupGetGlobal("ICON"));
+
+ IupPopup(dlg, IUP_CENTERPARENT, IUP_CENTERPARENT);
+
+ ret = IupGetInt(dlg, "STATUS");
+ if (ret != -1)
+ {
+ char* value = IupGetAttribute(dlg, "VALUE");
+ if (value)
+ {
+ strcpy(filename, value);
+ iupStrSplitFileName(filename, dir, NULL);
+ }
+ }
+
+ IupDestroy(dlg);
+
+ return ret;
+}
+
+int IupGetText(const char* title, char* text)
+{
+ Ihandle *ok, *cancel, *multi_text, *button_box, *dlg_box, *dlg;
+ int bt;
+
+ multi_text = IupMultiLine(NULL);
+ IupSetAttribute(multi_text,"EXPAND", "YES");
+ IupSetAttribute(multi_text,"VALUE", text);
+ IupSetAttribute(multi_text,"FONT", "Courier, 12");
+ IupSetAttribute(multi_text, "VISIBLELINES", "10");
+ IupSetAttribute(multi_text, "VISIBLECOLUMNS", "50");
+
+ ok = IupButton("OK", NULL);
+ IupSetAttribute(ok, "PADDING", "20x5");
+ IupSetCallback(ok, "ACTION", (Icallback)CB_button_OK);
+
+ cancel = IupButton(iupStrMessageGet("IUP_CANCEL"), NULL);
+ IupSetAttribute(cancel, "PADDING", "20x5");
+ IupSetCallback(cancel, "ACTION", (Icallback)CB_button_CANCEL);
+
+ button_box = IupHbox(
+ IupFill(),
+ ok,
+ cancel,
+ NULL);
+ IupSetAttribute(button_box,"MARGIN","0x0");
+ IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL");
+
+ dlg_box = IupVbox(
+ multi_text,
+ button_box,
+ NULL);
+
+ IupSetAttribute(dlg_box,"MARGIN","10x10");
+ IupSetAttribute(dlg_box,"GAP","10");
+
+ dlg = IupDialog (dlg_box);
+
+ IupSetAttribute(dlg,"TITLE", title);
+ IupSetAttribute(dlg,"MINBOX","NO");
+ IupSetAttribute(dlg,"MAXBOX","NO");
+ IupSetAttributeHandle(dlg,"DEFAULTENTER", ok);
+ IupSetAttributeHandle(dlg,"DEFAULTESC", cancel);
+ IupSetAttribute(dlg,"PARENTDIALOG", IupGetGlobal("PARENTDIALOG"));
+ IupSetAttribute(dlg,"ICON", IupGetGlobal("ICON"));
+
+ IupMap(dlg);
+
+ IupSetAttribute(multi_text, "VISIBLELINES", NULL);
+ IupSetAttribute(multi_text, "VISIBLECOLUMNS", NULL);
+
+ IupPopup(dlg, IUP_CENTERPARENT, IUP_CENTERPARENT);
+
+ bt = IupGetInt(dlg, "STATUS");
+ if (bt==1)
+ strcpy(text, IupGetAttribute(multi_text, "VALUE"));
+ else
+ bt = 0; /* return 0 instead of -1 */
+
+ IupDestroy(dlg);
+ return bt;
+}
+
+int IupGetColor(int x, int y, unsigned char *r, unsigned char *g, unsigned char *b)
+{
+ int ret;
+ Ihandle* dlg = IupColorDlg();
+
+ IupSetAttribute(dlg, "TITLE", iupStrMessageGet("IUP_GETCOLOR"));
+ IupSetfAttribute(dlg, "VALUE", "%d %d %d", *r, *g, *b);
+ IupSetAttribute(dlg, "PARENTDIALOG", IupGetGlobal("PARENTDIALOG"));
+ IupSetAttribute(dlg, "ICON", IupGetGlobal("ICON"));
+
+ IupPopup(dlg, x, y);
+
+ ret = IupGetInt(dlg, "STATUS");
+ if (ret)
+ iupStrToRGB(IupGetAttribute(dlg, "VALUE"), r, g, b);
+
+ IupDestroy(dlg);
+
+ return ret;
+}
+
+void iupVersionDlg(void)
+{
+ Ihandle* dlg;
+
+ dlg = IupDialog(IupVbox(IupFrame(IupVbox(
+ IupLabel(IupVersion()),
+ IupLabel(IUP_VERSION_DATE),
+ IupLabel(IUP_COPYRIGHT),
+ NULL)),
+ IupButton("OK", NULL),
+ NULL));
+
+ IupSetAttribute(dlg,"TITLE","IUP Version");
+ IupSetAttribute(dlg,"DIALOGFRAME","YES");
+ IupSetAttribute(dlg,"DIALOGHINT","YES");
+ IupSetAttribute(dlg,"GAP","10");
+ IupSetAttribute(dlg,"MARGIN","10x10");
+
+ IupPopup(dlg, IUP_CENTERPARENT, IUP_CENTERPARENT);
+ IupDestroy(dlg);
+}
diff --git a/iup/src/iup_predial.h b/iup/src/iup_predial.h
new file mode 100755
index 0000000..e282e53
--- /dev/null
+++ b/iup/src/iup_predial.h
@@ -0,0 +1,32 @@
+/** \file
+ * \brief IUP Core pre-defined dialogs.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_PREDIAL_H
+#define __IUP_PREDIAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Used by the IupScanf implementation */
+int iupDataEntry(int maxlin, int* maxcol, int* maxscr, char* title, char** text, char** data);
+
+/* Popups a dialog with IUP Version, used in IupOpen */
+void iupVersionDlg(void);
+
+/* Other functions declared in <iup.h> and implemented here.
+IupListDialog
+IupAlarm
+IupMessagef
+IupGetFile
+IupGetText
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_progressbar.c b/iup/src/iup_progressbar.c
new file mode 100755
index 0000000..76fdefc
--- /dev/null
+++ b/iup/src/iup_progressbar.c
@@ -0,0 +1,118 @@
+/** \file
+ * \brief ProgressBar control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_progressbar.h"
+
+
+void iProgressBarCropValue(Ihandle* ih)
+{
+ if(ih->data->value > ih->data->vmax)
+ ih->data->value = ih->data->vmax;
+ else if(ih->data->value < ih->data->vmin)
+ ih->data->value = ih->data->vmin;
+}
+
+char* iProgressBarGetValueAttrib(Ihandle* ih)
+{
+ char* value = iupStrGetMemory(30);
+ sprintf(value, "%g", ih->data->value);
+ return value;
+}
+
+char* iProgressBarGetDashedAttrib(Ihandle* ih)
+{
+ if(ih->data->dashed)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iProgressBarSetMinAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->vmin = atof(value);
+ iProgressBarCropValue(ih);
+ return 1;
+}
+
+static int iProgressBarSetMaxAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->vmax = atof(value);
+ iProgressBarCropValue(ih);
+ return 1;
+}
+
+static int iProgressBarCreateMethod(Ihandle* ih, void **params)
+{
+ (void)params;
+
+ ih->data = iupALLOCCTRLDATA();
+
+ /* default values */
+ ih->data->vmax = 1;
+ ih->data->dashed = 0;
+
+ /* progress bar natural size is 200x30 */
+ IupSetAttribute(ih, "RASTERSIZE", "200x30");
+
+ return IUP_NOERROR;
+}
+
+Iclass* iupProgressBarGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "progressbar";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = iProgressBarCreateMethod;
+
+ ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Common Callbacks */
+ iupClassRegisterCallback(ic, "MAP_CB", "");
+ iupClassRegisterCallback(ic, "UNMAP_CB", "");
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Visual */
+ iupBaseRegisterVisualAttrib(ic);
+
+ /* IupProgressBar only */
+ iupClassRegisterAttribute(ic, "MIN", NULL, iProgressBarSetMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MAX", NULL, iProgressBarSetMaxAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED);
+
+ iupdrvProgressBarInitClass(ic);
+
+ return ic;
+}
+
+Ihandle *IupProgressBar(void)
+{
+ return IupCreate("progressbar");
+}
diff --git a/iup/src/iup_progressbar.h b/iup/src/iup_progressbar.h
new file mode 100755
index 0000000..44ffb7f
--- /dev/null
+++ b/iup/src/iup_progressbar.h
@@ -0,0 +1,35 @@
+/** \file
+ * \brief ProgressBar Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_PROGRESSBAR_H
+#define __IUP_PROGRESSBAR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct _IcontrolData
+{
+ int dashed,
+ marquee;
+
+ double value, /* value is min < value < max */
+ vmin,
+ vmax;
+};
+
+void iProgressBarCropValue(Ihandle* ih);
+char* iProgressBarGetValueAttrib(Ihandle* ih);
+char* iProgressBarGetDashedAttrib(Ihandle* ih);
+
+void iupdrvProgressBarInitClass(Iclass* ic);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_radio.c b/iup/src/iup_radio.c
new file mode 100755
index 0000000..c6e7cdd
--- /dev/null
+++ b/iup/src/iup_radio.c
@@ -0,0 +1,195 @@
+/** \file
+ * \brief Radio Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+
+
+Ihandle *iupRadioFindToggleParent(Ihandle* ih_toggle)
+{
+ Ihandle *p;
+ for (p=ih_toggle; p->parent; p=p->parent)
+ {
+ if (p->iclass->nativetype == IUP_TYPEVOID &&
+ iupStrEqual(p->iclass->name, "radio"))
+ return p;
+ }
+
+ return NULL;
+}
+
+static int iRadioFindToggleChild(Ihandle* ih, Ihandle* ih_toggle)
+{
+ Ihandle* child;
+
+ if (ih == ih_toggle) /* found child that match the toggle */
+ return 1;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (iRadioFindToggleChild(child, ih_toggle))
+ return 1;
+ }
+
+ return 0;
+}
+
+static Ihandle* iRadioGetToggleChildOn(Ihandle* ih)
+{
+ Ihandle* child;
+
+ if (iupStrEqual(ih->iclass->name, "toggle") && /* found child that is a toggle and it is ON */
+ IupGetInt(ih, "VALUE"))
+ return ih;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ Ihandle* ih_toggle = iRadioGetToggleChildOn(child);
+ if (ih_toggle)
+ return ih_toggle;
+ }
+
+ return NULL;
+}
+
+/******************************************************************************/
+
+
+static int iRadioSetValueHandleAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle* ih_toggle = (Ihandle*)value;
+ if (!iupObjectCheck(ih_toggle))
+ return 0;
+
+ if (!iupStrEqual(ih_toggle->iclass->name, "toggle"))
+ return 0;
+
+ if (iRadioFindToggleChild(ih->firstchild, ih_toggle))
+ IupSetAttribute(ih_toggle, "VALUE", "ON");
+
+ return 0;
+}
+
+char* iRadioGetValueHandleAttrib(Ihandle* ih)
+{
+ return (char*)iRadioGetToggleChildOn(ih->firstchild);
+}
+
+static int iRadioSetValueAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle *ih_toggle;
+
+ if (!value)
+ return 0;
+
+ ih_toggle = IupGetHandle(value);
+ if (!ih_toggle)
+ return 0;
+
+ iRadioSetValueHandleAttrib(ih, (char*)ih_toggle);
+ return 0;
+}
+
+char* iRadioGetValueAttrib(Ihandle* ih)
+{
+ Ihandle *ih_toggle = (Ihandle*)iRadioGetValueHandleAttrib(ih);
+ if (!ih_toggle)
+ return NULL;
+
+ return IupGetName(ih_toggle);
+}
+
+/******************************************************************************/
+
+
+static int iRadioCreateMethod(Ihandle* ih, void** params)
+{
+ if (params)
+ {
+ Ihandle** iparams = (Ihandle**)params;
+ if (*iparams)
+ IupAppend(ih, *iparams);
+ }
+ return IUP_NOERROR;
+}
+
+static void iRadioComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ Ihandle* child = ih->firstchild;
+ if (child)
+ {
+ /* update child natural size first */
+ iupBaseComputeNaturalSize(child);
+
+ *expand = child->expand;
+ *w = child->naturalwidth;
+ *h = child->naturalheight;
+ }
+}
+
+static void iRadioSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink)
+{
+ iupBaseSetCurrentSize(ih->firstchild, ih->currentwidth, ih->currentheight, shrink);
+}
+
+static void iRadioSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ iupBaseSetPosition(ih->firstchild, x, y);
+}
+
+
+/******************************************************************************/
+
+
+Ihandle* IupRadio(Ihandle* child)
+{
+ void *params[2];
+ params[0] = (void*)child;
+ params[1] = NULL;
+ return IupCreatev("radio", params);
+}
+
+Iclass* iupRadioGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "radio";
+ ic->format = "H"; /* one optional ihandle */
+ ic->nativetype = IUP_TYPEVOID;
+ ic->childtype = IUP_CHILD_ONE;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = iRadioCreateMethod;
+ ic->Map = iupBaseTypeVoidMapMethod;
+ ic->ComputeNaturalSize = iRadioComputeNaturalSizeMethod;
+ ic->SetChildrenCurrentSize = iRadioSetChildrenCurrentSizeMethod;
+ ic->SetChildrenPosition = iRadioSetChildrenPositionMethod;
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", iupBaseGetRasterSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ /* Radio only */
+ iupClassRegisterAttribute(ic, "VALUE", iRadioGetValueAttrib, iRadioSetValueAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE_HANDLE", iRadioGetValueHandleAttrib, iRadioSetValueHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+
+ return ic;
+}
diff --git a/iup/src/iup_register.c b/iup/src/iup_register.c
new file mode 100755
index 0000000..4c58038
--- /dev/null
+++ b/iup/src/iup_register.c
@@ -0,0 +1,123 @@
+/** \file
+* \brief Register the Internal Controls
+*
+* See Copyright Notice in "iup.h"
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_register.h"
+#include "iup_stdcontrols.h"
+
+
+static Itable *iregister_table = NULL; /* table indexed by name containing Iclass* address */
+
+void iupRegisterInit(void)
+{
+ iregister_table = iupTableCreate(IUPTABLE_STRINGINDEXED);
+}
+
+void iupRegisterFinish(void)
+{
+ char* name = iupTableFirst(iregister_table);
+ while (name)
+ {
+ Iclass* ic = (Iclass*)iupTableGetCurr(iregister_table);
+ iupClassRelease(ic);
+ name = iupTableNext(iregister_table);
+ }
+
+ iupTableDestroy(iregister_table);
+ iregister_table = NULL;
+}
+
+int iupRegisterGetClasses(char *list[], int n)
+{
+ int i = 0;
+ char* name = iupTableFirst(iregister_table);
+
+ if (!list || !n)
+ return iupTableCount(iregister_table);
+
+ while (name)
+ {
+ list[i] = name;
+ i++;
+ if (i == n)
+ break;
+
+ name = iupTableNext(iregister_table);
+ }
+
+ return i;
+}
+
+Iclass* iupRegisterFindClass(const char* name)
+{
+ return (Iclass*)iupTableGet(iregister_table, name);
+}
+
+void iupRegisterClass(Iclass* ic)
+{
+ Iclass* old_ic = (Iclass*)iupTableGet(iregister_table, ic->name);
+ if (old_ic)
+ iupClassRelease(old_ic);
+
+ iupTableSet(iregister_table, ic->name, (void*)ic, IUPTABLE_POINTER);
+}
+
+
+/***************************************************************/
+
+void iupRegisterInternalClasses(void)
+{
+ iupRegisterClass(iupDialogGetClass());
+ iupRegisterClass(iupMessageDlgGetClass());
+ iupRegisterClass(iupColorDlgGetClass());
+ iupRegisterClass(iupFontDlgGetClass());
+ iupRegisterClass(iupFileDlgGetClass());
+
+ iupRegisterClass(iupTimerGetClass());
+ iupRegisterClass(iupImageGetClass());
+ iupRegisterClass(iupImageRGBGetClass());
+ iupRegisterClass(iupImageRGBAGetClass());
+ iupRegisterClass(iupUserGetClass());
+ iupRegisterClass(iupClipboardGetClass());
+
+ iupRegisterClass(iupRadioGetClass());
+ iupRegisterClass(iupFillGetClass());
+ iupRegisterClass(iupHboxGetClass());
+ iupRegisterClass(iupVboxGetClass());
+ iupRegisterClass(iupZboxGetClass());
+ iupRegisterClass(iupCboxGetClass());
+ iupRegisterClass(iupSboxGetClass());
+ iupRegisterClass(iupNormalizerGetClass());
+
+ iupRegisterClass(iupMenuGetClass());
+ iupRegisterClass(iupItemGetClass());
+ iupRegisterClass(iupSeparatorGetClass());
+ iupRegisterClass(iupSubmenuGetClass());
+
+ iupRegisterClass(iupLabelGetClass());
+ iupRegisterClass(iupButtonGetClass());
+ iupRegisterClass(iupToggleGetClass());
+ iupRegisterClass(iupCanvasGetClass());
+ iupRegisterClass(iupFrameGetClass());
+ iupRegisterClass(iupTextGetClass());
+ iupRegisterClass(iupMultilineGetClass());
+ iupRegisterClass(iupListGetClass());
+
+ iupRegisterClass(iupProgressBarGetClass());
+ iupRegisterClass(iupValGetClass());
+ iupRegisterClass(iupTabsGetClass());
+ iupRegisterClass(iupSpinGetClass());
+ iupRegisterClass(iupSpinboxGetClass());
+ iupRegisterClass(iupTreeGetClass());
+}
diff --git a/iup/src/iup_register.h b/iup/src/iup_register.h
new file mode 100755
index 0000000..b5e6907
--- /dev/null
+++ b/iup/src/iup_register.h
@@ -0,0 +1,47 @@
+/** \file
+ * \brief Register the Controls
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_REGISTER_H
+#define __IUP_REGISTER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup register Class Registration
+ * \par
+ * All controls are registered so the creation using IupCreate can work.
+ * \par
+ * See \ref iup_register.h
+ * \ingroup cpi */
+
+
+/** Returns a class instance from a class name. The class name must be previously registered using \ref iupRegisterClass.
+ * \ingroup register */
+Iclass* iupRegisterFindClass(const char* name);
+
+/** Register a class.
+ * \ingroup register */
+void iupRegisterClass(Iclass* ic);
+
+
+/* Register the internal classes. Called only from IupOpen. */
+void iupRegisterInternalClasses(void);
+
+/* Initializes the class registry. Called only from IupOpen. */
+void iupRegisterInit(void);
+void iupRegisterFinish(void);
+
+/* Get the registered classes. Used in documentation tests. */
+int iupRegisterGetClasses(char *list[], int n);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_sbox.c b/iup/src/iup_sbox.c
new file mode 100755
index 0000000..5a71d33
--- /dev/null
+++ b/iup/src/iup_sbox.c
@@ -0,0 +1,413 @@
+/** \file
+ * \brief iupsbox control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+#include "iupkey.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_childtree.h"
+
+
+#define ISBOX_THICK 5
+
+enum { ISBOX_NORTH, ISBOX_SOUTH, ISBOX_WEST, ISBOX_EAST };
+
+struct _IcontrolData
+{
+ int w, h;
+ int isholding;
+ int start_x, start_y;
+ int start_w, start_h;
+
+ int direction; /* one of the types: ISBOX_NORTH, ISBOX_SOUTH, ISBOX_WEST, ISBOX_EAST */
+};
+
+
+static int iSboxGetYborder(Ihandle* ih)
+{
+ if (ih->data->direction == ISBOX_NORTH || ih->data->direction == ISBOX_SOUTH)
+ return ISBOX_THICK;
+ else
+ return 0;
+}
+
+static int iSboxGetXborder(Ihandle* ih)
+{
+ if (ih->data->direction == ISBOX_EAST || ih->data->direction == ISBOX_WEST)
+ return ISBOX_THICK;
+ else
+ return 0;
+}
+
+static void iSboxSaveDimension(Ihandle* ih, int w, int h)
+{
+ ih->data->w = w;
+ ih->data->h = h;
+}
+
+static void iSboxAddDecorOffset(Ihandle* ih, int *x, int *y)
+{
+ /* skip north thumb if there is one */
+ if (ih->data->direction == ISBOX_NORTH)
+ *y += ISBOX_THICK;
+
+ /* skip west thumb if there is one */
+ if (ih->data->direction == ISBOX_WEST)
+ *x += ISBOX_THICK;
+}
+
+static void iSboxGetFinalSize(Ihandle* ih, int direction, int *w, int *h)
+{
+ int final_x, final_y;
+ int diff_x, diff_y;
+
+ iupStrToIntInt(IupGetGlobal("CURSORPOS"), &final_x, &final_y, 'x');
+
+ diff_x = final_x - ih->data->start_x;
+ diff_y = final_y - ih->data->start_y;
+
+ if(direction == ISBOX_WEST)
+ diff_x = -diff_x;
+
+ if(direction == ISBOX_NORTH)
+ diff_y = -diff_y;
+
+ *w = diff_x + ih->data->start_w;
+ *h = diff_y + ih->data->start_h;
+}
+
+static void iSboxShakeControls(Ihandle* ih)
+{
+ int new_w, new_h;
+
+ iSboxGetFinalSize(ih, ih->data->direction, &new_w, &new_h);
+
+ if (ih->data->direction == ISBOX_WEST || ih->data->direction == ISBOX_EAST)
+ {
+ if (new_w != ih->data->w)
+ {
+ if (new_w > ih->naturalwidth)
+ iSboxSaveDimension(ih, new_w, ih->data->h);
+ else
+ iSboxSaveDimension(ih, new_w, ih->naturalwidth);
+ }
+ }
+ else if (ih->data->direction == ISBOX_SOUTH || ih->data->direction == ISBOX_NORTH)
+ {
+ if(new_h != ih->data->h)
+ {
+ if (new_h > ih->naturalheight)
+ iSboxSaveDimension(ih, ih->data->w, new_h);
+ else
+ iSboxSaveDimension(ih, ih->naturalheight, new_h);
+ }
+ }
+
+ IupRefresh(ih); /* may affect all the elements in the dialog */
+}
+
+
+/*****************************************************************************\
+|* Callbacks of canvas bar *|
+\*****************************************************************************/
+
+
+static int iSboxMotion_CB(Ihandle* bar, int x, int y, char *r)
+{
+ Ihandle* ih = bar->parent;
+
+ if (ih->data->isholding)
+ iSboxShakeControls(ih);
+
+ (void)x;
+ (void)y;
+ (void)r;
+ return IUP_DEFAULT;
+}
+
+static int iSboxButton_CB(Ihandle* bar, int button, int pressed, int x, int y, char* status)
+{
+ Ihandle* ih = bar->parent;
+
+ if (button!=IUP_BUTTON1)
+ return IUP_DEFAULT;
+
+ if (!ih->data->isholding && pressed)
+ {
+ ih->data->isholding = 1;
+
+ /* Save the cursor position */
+ iupStrToIntInt(IupGetGlobal("CURSORPOS"), &ih->data->start_x, &ih->data->start_y, 'x');
+
+ /* Save the initial size */
+ ih->data->start_w = ih->data->w;
+ ih->data->start_h = ih->data->h;
+ }
+ else if (ih->data->isholding && !pressed)
+ ih->data->isholding = 0;
+
+ (void)x;
+ (void)y;
+ (void)status;
+ return IUP_DEFAULT;
+}
+
+static int iSboxFocus_CB(Ihandle* bar, int focus)
+{
+ Ihandle* ih = bar->parent;
+
+ if (!ih || focus) /* use only kill focus */
+ return IUP_DEFAULT;
+
+ if (ih->data->isholding)
+ ih->data->isholding = 0;
+
+ return IUP_DEFAULT;
+}
+
+
+/*****************************************************************************\
+|* Attributes *|
+\*****************************************************************************/
+
+
+static char* iSboxGetClientSizeAttrib(Ihandle* ih)
+{
+ int width, height;
+ char* str = iupStrGetMemory(20);
+ width = ih->currentwidth;
+ height = ih->currentheight;
+ width -= iSboxGetXborder(ih);
+ height -= iSboxGetYborder(ih);
+ if (width < 0) width = 0;
+ if (height < 0) height = 0;
+ sprintf(str, "%dx%d", width, height);
+ return str;
+}
+
+static int iSboxSetColorAttrib(Ihandle* ih, const char* value)
+{
+ IupSetAttribute(ih->firstchild, "BGCOLOR", value);
+ return 0; /* do not store value in hash table */
+}
+
+static int iSboxSetDirectionAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->handle) /* only before map */
+ return 0;
+
+ if (iupStrEqual(value, "NORTH"))
+ ih->data->direction = ISBOX_NORTH;
+ else if(iupStrEqual(value, "SOUTH"))
+ ih->data->direction = ISBOX_SOUTH;
+ else if(iupStrEqual(value, "WEST"))
+ ih->data->direction = ISBOX_WEST;
+ else /* Default = EAST */
+ ih->data->direction = ISBOX_EAST;
+
+ if (ih->data->direction == ISBOX_EAST || ih->data->direction == ISBOX_WEST)
+ IupSetAttribute(ih->firstchild, "CURSOR", "RESIZE_WE");
+ else
+ IupSetAttribute(ih->firstchild, "CURSOR", "RESIZE_NS");
+
+ return 0; /* do not store value in hash table */
+}
+
+
+/*****************************************************************************\
+|* Methods *|
+\*****************************************************************************/
+
+
+static void iSboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ int natural_w = ih->naturalwidth,
+ natural_h = ih->naturalheight;
+
+ /* only allow expand in the oposite direction, complement iupBaseContainerUpdateExpand */
+ if (ih->data->direction == ISBOX_EAST || ih->data->direction == ISBOX_WEST)
+ ih->expand &= ~IUP_EXPAND_WIDTH;
+ else
+ ih->expand &= ~IUP_EXPAND_HEIGHT;
+
+ /* always has at least one child, the bar */
+
+ /* This is an unusual element, the iupBaseComputeNaturalSize logic is done twice, one here and one back there. */
+
+ if (ih->firstchild->brother)
+ {
+ Ihandle* child = ih->firstchild->brother;
+
+ /* update child natural size first */
+ iupBaseComputeNaturalSize(child);
+
+ *expand = child->expand;
+
+ /* calculate as in iupBaseComputeNaturalSize */
+ natural_w = iupMAX(natural_w, child->naturalwidth + iSboxGetXborder(ih));
+ natural_h = iupMAX(natural_h, child->naturalheight + iSboxGetYborder(ih));
+ }
+
+ /* update control to fit its children according to direction */
+
+ /* bar */
+ if (ih->data->direction == ISBOX_EAST || ih->data->direction == ISBOX_WEST)
+ {
+ ih->data->w = iupMAX(natural_w, ih->data->w);
+ ih->data->h = natural_h;
+ }
+ else /* ISBOX_NORTH || ISBOX_SOUTH */
+ {
+ ih->data->w = natural_w;
+ ih->data->h = iupMAX(natural_h, ih->data->h);
+ }
+
+ /* child */
+ if (ih->firstchild->brother)
+ {
+ Ihandle* child = ih->firstchild->brother;
+ child->naturalwidth = ih->data->w - iSboxGetXborder(ih);
+ child->naturalheight = ih->data->h - iSboxGetYborder(ih);
+ }
+
+ *w = ih->data->w;
+ *h = ih->data->h;
+}
+
+static void iSboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink)
+{
+ /* bar */
+ if ((ih->data->direction == ISBOX_NORTH || ih->data->direction == ISBOX_SOUTH))
+ {
+ ih->firstchild->currentwidth = ih->currentwidth;
+ ih->firstchild->currentheight = ISBOX_THICK;
+ }
+ else
+ {
+ ih->firstchild->currentwidth = ISBOX_THICK;
+ ih->firstchild->currentheight = ih->currentheight;
+ }
+
+ /* child */
+ if (ih->firstchild->brother)
+ {
+ int width = ih->currentwidth-iSboxGetXborder(ih);
+ int height = ih->currentheight-iSboxGetYborder(ih);
+ if (width < 0) width = 0;
+ if (height < 0) height = 0;
+
+ iupBaseSetCurrentSize(ih->firstchild->brother, width, height, shrink);
+ }
+}
+
+static void iSboxSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ int posx = 0, posy = 0;
+
+ /* bar */
+ if (ih->data->direction == ISBOX_EAST)
+ {
+ posx = ih->data->w - ISBOX_THICK;
+ if (posx<0) posx = 0;
+ }
+ if (ih->data->direction == ISBOX_SOUTH)
+ {
+ posy = ih->data->h - ISBOX_THICK;
+ if (posy<0) posy = 0;
+ }
+
+ iupBaseSetPosition(ih->firstchild, x+posx, y+posy);
+
+ /* child */
+ if (ih->firstchild->brother)
+ {
+ iSboxAddDecorOffset(ih, &x, &y);
+ iupBaseSetPosition(ih->firstchild->brother, x, y);
+ }
+}
+
+static int iSboxCreateMethod(Ihandle* ih, void** params)
+{
+ Ihandle* bar;
+
+ ih->data = iupALLOCCTRLDATA();
+
+ ih->data->direction = ISBOX_EAST;
+ ih->data->h = -1;
+ ih->data->w = -1;
+
+ bar = IupCanvas(NULL);
+ iupChildTreeAppend(ih, bar); /* bar will always be the firstchild */
+
+ IupSetAttribute(bar, "BORDER", "YES");
+ IupSetAttribute(bar, "EXPAND", "NO");
+ IupSetAttribute(bar, "BGCOLOR", "192 192 192");
+
+ /* Setting callbacks */
+ IupSetCallback(bar, "BUTTON_CB", (Icallback) iSboxButton_CB);
+ IupSetCallback(bar, "FOCUS_CB", (Icallback) iSboxFocus_CB);
+ IupSetCallback(bar, "MOTION_CB", (Icallback) iSboxMotion_CB);
+
+ if (params)
+ {
+ Ihandle** iparams = (Ihandle**)params;
+ if (*iparams)
+ IupAppend(ih, *iparams);
+ }
+
+ return IUP_NOERROR;
+}
+
+Iclass* iupSboxGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "sbox";
+ ic->format = "H"; /* one optional ihandle */
+ ic->nativetype = IUP_TYPEVOID;
+ ic->childtype = IUP_CHILDMANY; /* should be IUP_CHILDONE but has the bar (a IupCanvas) as firstchild */
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = iSboxCreateMethod;
+ ic->Map = iupBaseTypeVoidMapMethod;
+
+ ic->ComputeNaturalSize = iSboxComputeNaturalSizeMethod;
+ ic->SetChildrenCurrentSize = iSboxSetChildrenCurrentSizeMethod;
+ ic->SetChildrenPosition = iSboxSetChildrenPositionMethod;
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", iSboxGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ /* IupSbox only */
+ iupClassRegisterAttribute(ic, "COLOR", NULL, iSboxSetColorAttrib, IUPAF_SAMEASSYSTEM, "192 192 192", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DIRECTION", NULL, iSboxSetDirectionAttrib, IUPAF_SAMEASSYSTEM, "EAST", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
+
+Ihandle* IupSbox(Ihandle* child)
+{
+ void *params[2];
+ params[0] = (void*)child;
+ params[1] = NULL;
+ return IupCreatev("sbox", params);
+}
diff --git a/iup/src/iup_scanf.c b/iup/src/iup_scanf.c
new file mode 100755
index 0000000..f8ef97b
--- /dev/null
+++ b/iup/src/iup_scanf.c
@@ -0,0 +1,200 @@
+/** \file
+ * \brief IupScanf implementation.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_predial.h"
+#include "iup_str.h"
+#include "iup_assert.h"
+
+
+#define ALLOC(n,t) ((t *)calloc((n),sizeof(t)))
+#define REQUIRE(b) {if (!(b)) goto cleanup;}
+
+int IupScanf (const char *format, ...)
+{
+ int i;
+ int fields_out_count=(-1); /* return code if not error (error < 0) */
+ int error=(-1); /* return code if error (error >= 0) */
+ int fields_in_count;
+ int *width=NULL;
+ int *scroll=NULL;
+ char **prompt=NULL;
+ char **text=NULL;
+ char *title=NULL;
+ char *s=NULL;
+ char *s1=NULL;
+ char *outf=NULL;
+ va_list va;
+
+ iupASSERT(format!=NULL);
+ if (!format)
+ return 0;
+
+ fields_in_count=iupStrCountChar(format,'\n')-1;
+ REQUIRE(fields_in_count>0);
+ width=ALLOC(fields_in_count, int);
+ REQUIRE(width!=NULL);
+ scroll=ALLOC(fields_in_count, int);
+ REQUIRE(scroll!=NULL);
+ prompt=ALLOC(fields_in_count, char *);
+ REQUIRE(prompt!=NULL);
+ text=ALLOC(fields_in_count, char *);
+ REQUIRE(text!=NULL);
+
+ va_start(va,format);
+ REQUIRE ((s1=s=(char *)iupStrDup(format)) != NULL);
+ title=iupStrCopyUntil(&s,'\n');
+ REQUIRE(title!=NULL);
+ for (i=0; i<fields_in_count; ++i)
+ {
+ int n;
+ prompt[i]=iupStrCopyUntil(&s,'%');
+ REQUIRE(prompt[i]!=NULL);
+ n=sscanf(s,"%d.%d",width+i,scroll+i);
+ REQUIRE(n==2);
+ s=strchr(s,'%');
+ REQUIRE(s!=NULL);
+ if (outf) free(outf);
+ outf = iupStrCopyUntil(&s, '\n');
+ text[i]=ALLOC(width[i]+1,char);
+ REQUIRE(text[i]!=NULL);
+
+ switch (s[-2])
+ {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ if (s[-3]=='l')
+ sprintf(text[i],outf,*((long *)va_arg(va,long *)));
+ else if (s[-3]=='h')
+ sprintf(text[i],outf,*((short *)va_arg(va,short *)));
+ else
+ sprintf(text[i],outf,*((int *)va_arg(va,int *)));
+ break;
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'E':
+ case 'G':
+ if (s[-3]=='l')
+ sprintf(text[i],outf,*((double *)va_arg(va,double *)));
+ else
+ sprintf(text[i],outf,*((float *)va_arg(va,float *)));
+ break;
+ case 's':
+ sprintf(text[i],outf,((char *)va_arg(va,char *)));
+ break;
+ default:
+ goto cleanup;
+ }
+ }
+ va_end(va);
+
+ REQUIRE(iupDataEntry(fields_in_count,width,scroll,title,prompt,text)>0);
+
+ fields_out_count=0;
+ va_start(va,format);
+ s=strchr(format,'\n')+1;
+ for (i=0; i<fields_in_count; ++i)
+ {
+ s=strchr(s,'\n')+1;
+ switch (s[-2])
+ {
+ case 'd':
+ case 'u':
+ if (s[-3]=='l')
+ {
+ if (sscanf(text[i],"%ld",((long *)va_arg(va,long *)))!=1)
+ if (error < 0) error = fields_out_count;
+ }
+ else if (s[-3]=='h')
+ {
+ if (sscanf(text[i],"%hd",((short *)va_arg(va,short *)))!=1)
+ if (error < 0) error = fields_out_count;
+ }
+ else
+ {
+ if (sscanf(text[i],"%d",((int *)va_arg(va,int *)))!=1)
+ if (error < 0) error = fields_out_count;
+ }
+ break;
+ case 'i':
+ case 'o':
+ case 'x':
+ case 'X':
+ if (s[-3]=='l')
+ {
+ if (sscanf(text[i],"%li",((long *)va_arg(va,long *)))!=1)
+ if (error < 0) error = fields_out_count;
+ }
+ else if (s[-3]=='h')
+ {
+ if (sscanf(text[i],"%hi",((short *)va_arg(va,short *)))!=1)
+ if (error < 0) error = fields_out_count;
+ }
+ else
+ {
+ if (sscanf(text[i],"%i",((int *)va_arg(va,int *)))!=1)
+ if (error < 0) error = fields_out_count;
+ }
+ break;
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'E':
+ case 'G':
+ if (s[-3]=='l')
+ {
+ if (sscanf(text[i],"%lg",((double *)va_arg(va,double *)))!=1)
+ if (error < 0) error = fields_out_count;
+ }
+ else
+ {
+ if (sscanf(text[i], "%g", ((float *)va_arg(va,float *)))!=1)
+ if (error < 0) error = fields_out_count;
+ }
+ break;
+ case 's':
+ {
+ char *s=(char *)va_arg(va,char *);
+ strcpy(s,text[i]);
+ }
+ break;
+ }
+ ++fields_out_count;
+ }
+ va_end(va);
+
+cleanup:
+ if (s1) free(s1);
+ if (title) free(title);
+ if (width) free(width);
+ if (scroll) free(scroll);
+ if (outf) free(outf);
+ if (prompt)
+ {
+ for (i=0; i<fields_in_count; ++i)
+ if (prompt[i]) free(prompt[i]);
+ free(prompt);
+ }
+ if (text)
+ {
+ for (i=0; i<fields_in_count; ++i)
+ if (text[i]) free(text[i]);
+ free(text);
+ }
+
+ return (error < 0) ? fields_out_count : error;
+}
diff --git a/iup/src/iup_show.c b/iup/src/iup_show.c
new file mode 100755
index 0000000..9ea1408
--- /dev/null
+++ b/iup/src/iup_show.c
@@ -0,0 +1,256 @@
+/** \file
+ * \brief show/popup/hide/map
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_class.h"
+#include "iup_dialog.h"
+#include "iup_menu.h"
+#include "iup_assert.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+
+
+void IupUnmap(Ihandle *ih)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+
+ /* Invalid if it is NOT mapped. */
+ if (!ih->handle)
+ return;
+
+ /* unmap children */
+ {
+ Ihandle* child = ih->firstchild;
+ while (child)
+ {
+ IupUnmap(child);
+ child = child->brother;
+ }
+ }
+
+ /* only call UNMAP_CB for controls that have a native representation */
+ if (ih->iclass->nativetype != IUP_TYPEVOID)
+ {
+ Icallback unmap_cb = IupGetCallback(ih, "UNMAP_CB");
+ if (unmap_cb) unmap_cb(ih);
+ }
+
+ /* unmap from the native system */
+ iupClassObjectUnMap(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));
+ if (!iupObjectCheck(ih))
+ return IUP_INVALID;
+
+ /* calculate position and size for all children */
+ if (ih->iclass->nativetype == IUP_TYPEDIALOG)
+ iupLayoutCompute(ih);
+
+ /* already mapped */
+ if (ih->handle)
+ {
+ if (ih->iclass->nativetype == IUP_TYPEDIALOG)
+ iupLayoutUpdate(ih);
+
+ return IUP_NOERROR;
+ }
+
+ /* map to the native system */
+ if (iupClassObjectMap(ih) == IUP_ERROR)
+ {
+ iupERROR("Error during IupMap.");
+ return IUP_ERROR;
+ }
+
+ /* update FONT, must be the before several others */
+ if (ih->iclass->nativetype != IUP_TYPEVOID &&
+ ih->iclass->nativetype != IUP_TYPEIMAGE &&
+ ih->iclass->nativetype != IUP_TYPEMENU)
+ iupUpdateStandardFontAttrib(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. */
+ iupAttribUpdate(ih);
+
+ /* updates attributes defined in the parent tree */
+ iupAttribUpdateFromParent(ih);
+
+ /* map children */
+ {
+ Ihandle* child = ih->firstchild;
+ while (child)
+ {
+ if (IupMap(child) == IUP_ERROR)
+ return IUP_ERROR;
+
+ child = child->brother;
+ }
+ }
+
+ /* 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)
+ iupLayoutUpdate(ih);
+
+ /* only call MAP_CB for controls that have a native representation */
+ if (ih->iclass->nativetype != IUP_TYPEVOID)
+ {
+ Icallback map_cb = IupGetCallback(ih, "MAP_CB");
+ if (map_cb) map_cb(ih);
+ }
+
+ return IUP_NOERROR;
+}
+
+int IupPopup(Ihandle *ih, int x, int y)
+{
+ int ret;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return IUP_INVALID;
+
+ if (ih->iclass->nativetype != IUP_TYPEDIALOG &&
+ ih->iclass->nativetype != IUP_TYPEMENU)
+ {
+ iupERROR("Must be a menu or dialog in IupPopup.");
+ return IUP_INVALID;
+ }
+
+ ret = IupMap(ih);
+ if (ret == IUP_ERROR)
+ return ret;
+
+ if (ih->iclass->nativetype == IUP_TYPEDIALOG)
+ ret = iupDialogPopup(ih, x, y);
+ else
+ ret = iupMenuPopup(ih, x, y);
+
+ if (ret != IUP_NOERROR)
+ {
+ iupERROR("Error during IupPopup.");
+ return ret;
+ }
+
+ return IUP_NOERROR;
+}
+
+int IupShowXY(Ihandle *ih, int x, int y)
+{
+ int ret;
+
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return IUP_INVALID;
+
+ if (ih->iclass->nativetype != IUP_TYPEDIALOG)
+ {
+ iupERROR("Must be a dialog in IupShowXY.");
+ return IUP_INVALID;
+ }
+
+ ret = IupMap(ih);
+ if (ret == IUP_ERROR)
+ return ret;
+
+ ret = iupDialogShowXY(ih, x, y);
+ if (ret != IUP_NOERROR)
+ {
+ iupERROR("Error during IupShowXY.");
+ return ret;
+ }
+
+ return IUP_NOERROR;
+}
+
+int IupShow(Ihandle* ih)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return IUP_INVALID;
+
+ if (ih->iclass->nativetype != IUP_TYPEDIALOG)
+ IupSetAttribute(ih, "VISIBLE", "YES");
+ else
+ {
+ int ret = IupMap(ih);
+ if (ret == IUP_ERROR)
+ return ret;
+
+ ret = iupDialogShowXY(ih, IUP_CURRENT, IUP_CURRENT);
+ if (ret != IUP_NOERROR)
+ {
+ iupERROR("Error during IupShow.");
+ return ret;
+ }
+ }
+
+ return IUP_NOERROR;
+}
+
+int IupHide(Ihandle* ih)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return IUP_INVALID;
+
+ if (ih->iclass->nativetype != IUP_TYPEDIALOG)
+ IupSetAttribute(ih, "VISIBLE", "NO");
+ else if (ih->handle)
+ iupDialogHide(ih);
+
+ return IUP_NOERROR;
+}
diff --git a/iup/src/iup_spin.c b/iup/src/iup_spin.c
new file mode 100755
index 0000000..6fadab4
--- /dev/null
+++ b/iup/src/iup_spin.c
@@ -0,0 +1,301 @@
+/** \file
+ * \brief Spin control
+ *
+ * See Copyright Notice in "iup.h"
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+#include "iupkey.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_stdcontrols.h"
+#include "iup_childtree.h"
+
+
+static Ihandle* spin_timer = NULL;
+
+
+static int iSpinCallCB(Ihandle* ih, int dub, int ten, int sign)
+{
+ IFni cb;
+
+ /* get the callback on the spin or on the spinbox */
+ Ihandle* spinbox = (Ihandle*)iupAttribGet(ih->parent, "_IUPSPIN_BOX");
+ if (spinbox)
+ ih = spinbox;
+ else
+ ih = ih->parent;
+
+ cb = (IFni) IupGetCallback(ih, "SPIN_CB");
+ if (cb)
+ {
+ return cb(ih, sign*(dub && ten ? 100 :
+ ten ? 10 :
+ dub ? 2 : 1));
+ }
+
+ return IUP_DEFAULT;
+}
+
+static int iSpinTimerCB(Ihandle* ih)
+{
+ Ihandle* spin_button = (Ihandle*)iupAttribGet(ih, "_IUPSPIN_BUTTON");
+ char* status = iupAttribGet(ih, "_IUPSPIN_STATUS");
+ int spin_dir = iupAttribGetInt(ih, "_IUPSPIN_DIR");
+ int count = iupAttribGetInt(ih, "_IUPSPIN_COUNT");
+ char* reconfig = NULL;
+
+ if(count == 0) /* first time */
+ reconfig = "50";
+ else if(count == 14) /* 300 + 14*50 = 1000 (1 second) */
+ reconfig = "25";
+ else if(count == 34) /* 300 + 14*50 + 20*50 = 2000 (2 seconds) */
+ reconfig = "10";
+
+ if (reconfig)
+ {
+ IupSetAttribute(ih, "RUN", "NO");
+ IupSetAttribute(ih, "TIME", reconfig);
+ IupSetAttribute(ih, "RUN", "YES");
+ }
+
+ iupAttribSetInt(ih, "_IUPSPIN_COUNT", count + 1);
+
+ return iSpinCallCB(spin_button, iup_isshift(status), iup_iscontrol(status), spin_dir);
+}
+
+static void iSpinPrepareTimer(Ihandle* ih, char* status, char* dir)
+{
+ (void)ih;
+
+ iupAttribSetStr(spin_timer, "_IUPSPIN_BUTTON", (char*)ih);
+
+ iupAttribStoreStr(spin_timer, "_IUPSPIN_STATUS", status);
+
+ iupAttribSetStr(spin_timer, "_IUPSPIN_DIR", dir);
+ iupAttribSetStr(spin_timer, "_IUPSPIN_COUNT", "0");
+
+ IupSetAttribute(spin_timer, "TIME", "400");
+ IupSetAttribute(spin_timer, "RUN", "YES");
+}
+
+static int iSpinK_SP(Ihandle* ih)
+{
+ int dir = iupAttribGetInt(ih, "_IUPSPIN_DIR");
+
+ return iSpinCallCB(ih, 0, 0, dir);
+}
+
+static int iSpinK_sSP(Ihandle* ih)
+{
+ int dir = iupAttribGetInt(ih, "_IUPSPIN_DIR");
+
+ return iSpinCallCB(ih, 1, 0, dir);
+}
+
+static int iSpinK_cSP(Ihandle* ih)
+{
+ int dir = iupAttribGetInt(ih, "_IUPSPIN_DIR");
+
+ return iSpinCallCB(ih, 0, 1, dir);
+}
+
+static int iSpinButtonCB(Ihandle* ih, int but, int pressed, int x, int y, char* status)
+{
+ (void)x;
+ (void)y;
+
+ if (pressed && but == IUP_BUTTON1)
+ {
+ int dir = iupAttribGetInt(ih, "_IUPSPIN_DIR");
+
+ iSpinPrepareTimer(ih, status, iupAttribGet(ih, "_IUPSPIN_DIR"));
+
+ return iSpinCallCB(ih, iup_isshift(status), iup_iscontrol(status), dir);
+ }
+ else if (!pressed && but == IUP_BUTTON1)
+ {
+ IupSetAttribute(spin_timer, "RUN", "NO");
+ }
+
+ return IUP_DEFAULT;
+}
+
+static int iSpinCreateMethod(Ihandle* ih, void** params)
+{
+ Ihandle* bt_up;
+ Ihandle* bt_down;
+ (void)params;
+
+ /* Button UP */
+ bt_up = IupButton(NULL, NULL);
+
+ IupSetAttribute(bt_up, "EXPAND", "NO");
+ IupSetAttribute(bt_up, "IMAGE", "IupSpinUpImage");
+ IupSetAttribute(bt_up, "_IUPSPIN_DIR", "1");
+ IupSetAttribute(bt_up, "CANFOCUS", "NO");
+
+ IupSetCallback(bt_up, "BUTTON_CB", (Icallback) iSpinButtonCB);
+ IupSetCallback(bt_up, "K_SP", (Icallback) iSpinK_SP);
+ IupSetCallback(bt_up, "K_sSP", (Icallback) iSpinK_sSP);
+ IupSetCallback(bt_up, "K_cSP", (Icallback) iSpinK_cSP);
+
+ /* Button DOWN */
+ bt_down = IupButton(NULL, NULL);
+
+ IupSetAttribute(bt_down, "EXPAND", "NO");
+ IupSetAttribute(bt_down, "IMAGE", "IupSpinDownImage");
+ IupSetAttribute(bt_down, "_IUPSPIN_DIR", "-1");
+ IupSetAttribute(bt_down, "CANFOCUS", "NO");
+
+ IupSetCallback(bt_down, "BUTTON_CB", (Icallback) iSpinButtonCB);
+ IupSetCallback(bt_down, "K_SP", (Icallback) iSpinK_SP);
+ IupSetCallback(bt_down, "K_sSP", (Icallback) iSpinK_sSP);
+ IupSetCallback(bt_down, "K_cSP", (Icallback) iSpinK_cSP);
+
+ /* manually add the buttons as a children */
+ ih->firstchild = bt_up;
+ bt_up->parent = ih;
+ bt_up->brother = bt_down;
+ bt_down->parent = ih;
+
+ IupSetAttribute(ih, "GAP", "0");
+ IupSetAttribute(ih, "MARGIN", "0x0");
+
+ return IUP_NOERROR;
+}
+
+static int iSpinboxCreateMethod(Ihandle* ih, void** params)
+{
+ Ihandle *spin, *ctrl;
+
+ if (!params || !(params[0]))
+ return IUP_ERROR;
+
+ IupSetAttribute(ih, "GAP", "0");
+ IupSetAttribute(ih, "MARGIN", "0x0");
+ IupSetAttribute(ih, "ALIGNMENT", "ACENTER");
+
+ ctrl = (Ihandle*)(params[0]);
+ iupChildTreeAppend(ih, ctrl);
+
+ spin = IupSpin();
+ iupChildTreeAppend(ih, spin);
+
+ iupAttribSetStr(spin, "_IUPSPIN_BOX", (char*)ih);
+
+ return IUP_NOERROR;
+}
+
+static void iSpinLoadImages(void)
+{
+ Ihandle* img;
+
+ /* Spin UP image */
+ unsigned char iupspin_up_img[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 0, 1, 1, 1, 1,
+ 1, 1, 1, 0, 0, 0, 1, 1, 1,
+ 1, 1, 0, 0, 0, 0, 0, 1, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ /* Spin DOWN image */
+ unsigned char iupspin_down_img[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 0, 0, 0, 1, 1, 1,
+ 1, 1, 1, 1, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1
+ };
+
+ img = IupImage(9, 6, iupspin_up_img);
+ IupSetAttribute(img, "0", "0 0 0");
+ IupSetAttribute(img, "1", "BGCOLOR");
+ IupSetHandle("IupSpinUpImage", img);
+
+ img = IupImage(9, 6, iupspin_down_img);
+ IupSetAttribute(img, "0", "0 0 0");
+ IupSetAttribute(img, "1", "BGCOLOR");
+ IupSetHandle("IupSpinDownImage", img);
+}
+
+static void iSpinReleaseMethod(Iclass* ic)
+{
+ (void)ic;
+
+ if (spin_timer)
+ {
+ /* no need to destroy the images, they will be destroyed by IupClose automatically */
+ IupDestroy(spin_timer);
+ spin_timer = NULL;
+ }
+}
+
+Iclass* iupSpinboxGetClass(void)
+{
+ Iclass* ic = iupClassNew(iupHboxGetClass());
+
+ ic->name = "spinbox";
+ ic->format = "h"; /* one Ihandle */
+ ic->nativetype = IUP_TYPEVOID;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ iupClassRegisterCallback(ic, "SPIN_CB", "i");
+
+ /* Class functions */
+ ic->Create = iSpinboxCreateMethod;
+
+ return ic;
+}
+
+Iclass* iupSpinGetClass(void)
+{
+ Iclass* ic = iupClassNew(iupVboxGetClass());
+
+ ic->name = "spin";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPEVOID;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = iSpinCreateMethod;
+ ic->Release = iSpinReleaseMethod;
+
+ iupClassRegisterCallback(ic, "SPIN_CB", "i");
+
+ if (!spin_timer)
+ {
+ iSpinLoadImages();
+
+ spin_timer = IupTimer();
+ IupSetCallback(spin_timer, "ACTION_CB", (Icallback) iSpinTimerCB);
+ }
+
+ return ic;
+}
+
+Ihandle* IupSpin(void)
+{
+ return IupCreate("spin");
+}
+
+Ihandle* IupSpinbox(Ihandle* ctrl)
+{
+ void *params[2];
+ params[0] = (void*)ctrl;
+ params[1] = NULL; /* must add NULL because spinbox inherit from Hbox */
+ return IupCreatev("spinbox", params);
+}
diff --git a/iup/src/iup_stdcontrols.h b/iup/src/iup_stdcontrols.h
new file mode 100755
index 0000000..11499ae
--- /dev/null
+++ b/iup/src/iup_stdcontrols.h
@@ -0,0 +1,76 @@
+/** \file
+ * \brief Standard Controls Class Initialization functions.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_STDCONTROLS_H
+#define __IUP_STDCONTROLS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+Iclass* iupDialogGetClass(void);
+Iclass* iupMessageDlgGetClass(void);
+Iclass* iupColorDlgGetClass(void);
+Iclass* iupFontDlgGetClass(void);
+Iclass* iupFileDlgGetClass(void);
+
+Iclass* iupLabelGetClass(void);
+Iclass* iupButtonGetClass(void);
+Iclass* iupToggleGetClass(void);
+Iclass* iupRadioGetClass(void);
+Iclass* iupCanvasGetClass(void);
+Iclass* iupFrameGetClass(void);
+Iclass* iupProgressBarGetClass(void);
+Iclass* iupTextGetClass(void);
+Iclass* iupMultilineGetClass(void);
+Iclass* iupValGetClass(void);
+Iclass* iupTabsGetClass(void);
+Iclass* iupSpinGetClass(void);
+Iclass* iupSpinboxGetClass(void);
+Iclass* iupListGetClass(void);
+Iclass* iupTreeGetClass(void);
+
+Iclass* iupMenuGetClass(void);
+Iclass* iupItemGetClass(void);
+Iclass* iupSeparatorGetClass(void);
+Iclass* iupSubmenuGetClass(void);
+
+Iclass* iupFillGetClass(void);
+Iclass* iupHboxGetClass(void);
+Iclass* iupVboxGetClass(void);
+Iclass* iupZboxGetClass(void);
+Iclass* iupCboxGetClass(void);
+Iclass* iupSboxGetClass(void);
+Iclass* iupNormalizerGetClass(void);
+
+Iclass* iupTimerGetClass(void);
+Iclass* iupImageGetClass(void);
+Iclass* iupImageRGBGetClass(void);
+Iclass* iupImageRGBAGetClass(void);
+Iclass* iupUserGetClass(void);
+Iclass* iupClipboardGetClass(void);
+
+/*************************************************/
+
+void iupdrvMessageDlgInitClass(Iclass* ic);
+void iupdrvColorDlgInitClass(Iclass* ic);
+void iupdrvFontDlgInitClass(Iclass* ic);
+void iupdrvFileDlgInitClass(Iclass* ic);
+
+/************************************************/
+
+/* Common definition of the canvas class */
+typedef struct _iupCanvas {
+ int sb; /* scrollbar configuration, valid only after map, use iupBaseGetScrollbar before map */
+ float posx, posy;
+} iupCanvas;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_str.c b/iup/src/iup_str.c
new file mode 100755
index 0000000..68976f1
--- /dev/null
+++ b/iup/src/iup_str.c
@@ -0,0 +1,716 @@
+/** \file
+ * \brief String Utilities
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "iup_str.h"
+
+
+/* Line breaks can be:
+\n - UNIX
+\r - Mac
+\r\n - DOS/Windows
+*/
+
+
+int iupStrEqual(const char* str1, const char* str2)
+{
+ if (str1 == str2) return 1;
+ if (!str1 || !str2 || *str1 != *str2) return 0;
+ return (strcmp(str1, str2)==0)? 1: 0;
+}
+
+int iupStrEqualNoCase(const char* str1, const char* str2)
+{
+ int i = 0;
+ if (str1 == str2) return 1;
+ if (!str1 || !str2 || tolower(*str1) != tolower(*str2)) return 0;
+
+ while (str1[i] && str2[i] && tolower(str1[i])==tolower(str2[i]))
+ i++;
+ if (str1[i] == str2[i]) return 1;
+
+ return 0;
+}
+
+int iupStrEqualPartial(const char* str1, const char* str2)
+{
+ if (str1 == str2) return 1;
+ if (!str1 || !str2 || *str1 != *str2) return 0;
+ return (strncmp(str1, str2, strlen(str2))==0)? 1: 0;
+}
+
+int iupStrBoolean(const char* str)
+{
+ if (!str || str[0]==0) return 0;
+ if (iupStrEqualNoCase(str, "1")) return 1;
+ if (iupStrEqualNoCase(str, "YES")) return 1;
+ if (iupStrEqualNoCase(str, "ON")) return 1;
+ if (iupStrEqualNoCase(str, "TRUE")) return 1;
+ return 0;
+}
+
+void iupStrLower(char* dstr, const char* sstr)
+{
+ for (; *sstr; sstr++, dstr++)
+ *dstr = (char)tolower(*sstr);
+ *dstr = 0;
+}
+
+char *iupStrDup(const char *str)
+{
+ if (str)
+ {
+ int size = strlen(str)+1;
+ char *newstr = malloc(size);
+ if (newstr) memcpy(newstr, str, size);
+ return newstr;
+ }
+ return NULL;
+}
+
+const char* iupStrNextLine(const char* str, int *len)
+{
+ *len = 0;
+
+ while(*str!=0 && *str!='\n' && *str!='\r')
+ {
+ (*len)++;
+ str++;
+ }
+
+ if (*str=='\r' && *(str+1)=='n') /* DOS line end */
+ return str+2;
+ else if (*str=='\n' || *str=='\r') /* UNIX or MAC line end */
+ return str+1;
+ else
+ return str; /* no next line */
+}
+
+int iupStrLineCount(const char* str)
+{
+ int num_lin = 1;
+
+ if (!str)
+ return num_lin;
+
+ while(*str != 0)
+ {
+ while(*str!=0 && *str!='\n' && *str!='\r')
+ str++;
+
+ if (*str=='\r' && *(str+1)=='n') /* DOS line end */
+ {
+ num_lin++;
+ str+=2;
+ }
+ else if (*str=='\n' || *str=='\r') /* UNIX or MAC line end */
+ {
+ num_lin++;
+ str++;
+ }
+ }
+
+ return num_lin;
+}
+
+int iupStrCountChar(const char *str, int c)
+{
+ int n;
+ if (!str) return 0;
+ for (n=0; *str; str++)
+ {
+ if (*str==(char)c)
+ n++;
+ }
+ return n;
+}
+
+void iupStrCopyN(char* dst_str, int dst_max_size, const char* src_str)
+{
+ int size = strlen(src_str)+1;
+ if (size > dst_max_size) size = dst_max_size;
+ memcpy(dst_str, src_str, size);
+}
+
+char *iupStrCopyUntil(char **str, int c)
+{
+ char *p_str,*new_str;
+ if (!str || *str==NULL)
+ return NULL;
+
+ p_str=strchr(*str,c);
+ if (!p_str) return NULL;
+
+ {
+ int i;
+ int sl=(int)(p_str - (*str));
+
+ new_str = (char *) malloc (sl + 1);
+ if (!new_str) return NULL;
+
+ for (i = 0; i < sl; ++i)
+ new_str[i] = (*str)[i];
+
+ new_str[sl] = 0;
+ }
+
+ *str = p_str+1;
+ return new_str;
+}
+
+char *iupStrCopyUntilNoCase(char **str, int c)
+{
+ char *p_str,*new_str;
+ if (!str || *str==NULL)
+ return NULL;
+
+ 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;
+ }
+
+ {
+ int i;
+ int sl=(int)(p_str - (*str));
+
+ new_str = (char *) malloc (sl + 1);
+ if (!new_str) return NULL;
+
+ for (i = 0; i < sl; ++i)
+ new_str[i] = (*str)[i];
+
+ new_str[sl] = 0;
+ }
+
+ *str = p_str+1;
+ return new_str;
+}
+
+char *iupStrGetMemory(int size)
+{
+#define MAX_BUFFERS 50
+ static char* buffers[MAX_BUFFERS];
+ static int buffers_sizes[MAX_BUFFERS];
+ static int buffers_index = -1;
+
+ int i;
+
+ if (size == -1) /* Frees memory */
+ {
+ buffers_index = -1;
+ for (i = 0; i < MAX_BUFFERS; i++)
+ {
+ if (buffers[i])
+ {
+ free(buffers[i]);
+ buffers[i] = NULL;
+ }
+ buffers_sizes[i] = 0;
+ }
+ return NULL;
+ }
+ else
+ {
+ char* ret_str;
+
+ if (buffers_index == -1)
+ {
+ memset(buffers, 0, sizeof(char*)*MAX_BUFFERS);
+ memset(buffers_sizes, 0, sizeof(int)*MAX_BUFFERS);
+ buffers_index = 0;
+ }
+
+ if (!(buffers[buffers_index]))
+ {
+ buffers_sizes[buffers_index] = size+1;
+ buffers[buffers_index] = (char*)malloc(buffers_sizes[buffers_index]);
+ }
+ else if (buffers_sizes[buffers_index] < size+1)
+ {
+ buffers_sizes[buffers_index] = size+1;
+ buffers[buffers_index] = (char*)realloc(buffers[buffers_index], buffers_sizes[buffers_index]);
+ }
+
+ memset(buffers[buffers_index], 0, buffers_sizes[buffers_index]);
+ ret_str = buffers[buffers_index];
+
+ buffers_index++;
+ if (buffers_index == MAX_BUFFERS)
+ buffers_index = 0;
+
+ return ret_str;
+ }
+}
+
+char *iupStrGetMemoryCopy(const char* str)
+{
+ if (str)
+ {
+ int size = strlen(str)+1;
+ char* ret_str = iupStrGetMemory(size);
+ memcpy(ret_str, str, size);
+ return ret_str;
+ }
+ else
+ return NULL;
+}
+
+int iupStrToRGBA(const char *str, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a)
+{
+ unsigned int ri = 0, gi = 0, bi = 0, ai = 0, ret;
+ if (!str) return 0;
+ ret = sscanf(str, "%u %u %u %u", &ri, &gi, &bi, &ai);
+ if (ret < 3) return 0;
+ if (ri > 255 || gi > 255 || bi > 255 || ai > 255) return 0;
+ *r = (unsigned char)ri;
+ *g = (unsigned char)gi;
+ *b = (unsigned char)bi;
+ if (ret == 4)
+ {
+ *a = (unsigned char)ai;
+ return 4;
+ }
+ else
+ return 3;
+}
+
+int iupStrToRGB(const char *str, unsigned char *r, unsigned char *g, unsigned char *b)
+{
+ unsigned int ri = 0, gi = 0, bi = 0;
+ if (!str) return 0;
+ if (sscanf(str, "%u %u %u", &ri, &gi, &bi) != 3) return 0;
+ if (ri > 255 || gi > 255 || bi > 255) return 0;
+ *r = (unsigned char)ri;
+ *g = (unsigned char)gi;
+ *b = (unsigned char)bi;
+ return 1;
+}
+
+int iupStrToInt(const char *str, int *i)
+{
+ if (!str) return 0;
+ if (sscanf(str, "%d", i) != 1) return 0;
+ return 1;
+}
+
+int iupStrToIntInt(const char *str, int *i1, int *i2, char sep)
+{
+ if (!str) return 0;
+
+ if (*str == sep || (isalpha(sep) && *str == toupper(sep))) /* no first value */
+ {
+ str++; /* skip separator */
+ if (sscanf(str, "%d", i2) != 1) return 0;
+ return 1;
+ }
+ else
+ {
+ char* p_str = iupStrCopyUntilNoCase((char**)&str, sep);
+
+ if (!p_str) /* no separator means no second value */
+ {
+ if (sscanf(str, "%d", i1) != 1) return 0;
+ return 1;
+ }
+ else if (*str==0) /* separator exists, but second value empty, also means no second value */
+ {
+ int ret = sscanf(p_str, "%d", i1);
+ free(p_str);
+ if (ret != 1) return 0;
+ return 1;
+ }
+ else
+ {
+ int ret = 0;
+ if (sscanf(p_str, "%d", i1) == 1) ret++;
+ if (sscanf(str, "%d", i2) == 1) ret++;
+ free(p_str);
+ return ret;
+ }
+ }
+}
+
+int iupStrToFloat(const char *str, float *f)
+{
+ if (!str) return 0;
+ if (sscanf(str, "%f", f) != 1) return 0;
+ return 1;
+}
+
+int iupStrToFloatFloat(const char *str, float *f1, float *f2, char sep)
+{
+ if (!str) return 0;
+
+ if (*str == sep || (isalpha(sep) && *str == toupper(sep))) /* no first value */
+ {
+ str++; /* skip separator */
+ if (sscanf(str, "%f", f2) != 1) return 0;
+ return 1;
+ }
+ else
+ {
+ char* p_str = iupStrCopyUntilNoCase((char**)&str, sep);
+
+ if (!p_str) /* no separator means no second value */
+ {
+ if (sscanf(str, "%f", f1) != 1) return 0;
+ return 1;
+ }
+ else if (*str==0) /* separator exists, but second value empty, also means no second value */
+ {
+ int ret = sscanf(p_str, "%f", f1);
+ free(p_str);
+ if (ret != 1) return 0;
+ return 1;
+ }
+ else
+ {
+ int ret = 0;
+ if (sscanf(p_str, "%f", f1) != 1) ret++;
+ if (sscanf(str, "%f", f2) != 1) ret++;
+ free(p_str);
+ return ret;
+ }
+ }
+}
+
+int iupStrToStrStr(const char *str, char *str1, char *str2, char sep)
+{
+ if (!str) return 0;
+
+ if (*str == sep || (isalpha(sep) && *str == toupper(sep))) /* no first value */
+ {
+ str++; /* skip separator */
+ strcpy(str2, str);
+ return 1;
+ }
+ else
+ {
+ char* p_str = iupStrCopyUntilNoCase((char**)&str, sep);
+
+ if (!p_str) /* no separator means no second value */
+ {
+ strcpy(str1, str);
+ return 1;
+ }
+ else if (*str==0) /* separator exists, but second value empty, also means no second value */
+ {
+ strcpy(str1, p_str);
+ free(p_str);
+ return 1;
+ }
+ else
+ {
+ strcpy(str1, p_str);
+ strcpy(str2, str);
+ free(p_str);
+ return 2;
+ }
+ }
+}
+
+char* iupStrFileGetPath(const char *file_name)
+{
+ /* Starts at the last character */
+ int len = strlen(file_name) - 1;
+ while (len != 0)
+ {
+ if (file_name[len] == '\\' || file_name[len] == '/')
+ {
+ len++;
+ break;
+ }
+
+ len--;
+ }
+
+ if (len == 0)
+ return NULL;
+
+ {
+ char* path = malloc(len+1);
+ memcpy(path, file_name, len);
+ path[len] = 0;
+
+ return path;
+ }
+}
+
+char* iupStrFileGetTitle(const char *file_name)
+{
+ /* Starts at the last character */
+ int len = strlen(file_name);
+ int offset = len - 1;
+ while (offset != 0)
+ {
+ if (file_name[offset] == '\\' || file_name[offset] == '/')
+ {
+ offset++;
+ break;
+ }
+
+ offset--;
+ }
+
+ {
+ int title_size = len - offset + 1;
+ char* file_title = malloc(title_size);
+ memcpy(file_title, file_name + offset, title_size);
+ return file_title;
+ }
+}
+
+char* iupStrFileGetExt(const char *file_name)
+{
+ /* Starts at the last character */
+ int len = strlen(file_name);
+ int offset = len - 1;
+ while (offset != 0)
+ {
+ /* if found a path separator stop. */
+ if (file_name[offset] == '\\' || file_name[offset] == '/')
+ return NULL;
+
+ if (file_name[offset] == '.')
+ {
+ offset++;
+ break;
+ }
+
+ offset--;
+ }
+
+ if (offset == 0)
+ return NULL;
+
+ {
+ int ext_size = len - offset + 1;
+ char* file_ext = (char*)malloc(ext_size);
+ memcpy(file_ext, file_name + offset, ext_size);
+ return file_ext;
+ }
+}
+
+char* iupStrFileMakeFileName(const char* path, const char* title)
+{
+ int size_path = strlen(path);
+ int size_title = strlen(title);
+ char *filename = malloc(size_path + size_title + 2);
+ memcpy(filename, path, size_path);
+
+ if (path[size_path-1] != '/')
+ {
+ filename[size_path] = '/';
+ size_path++;
+ }
+
+ memcpy(filename+size_path, title, size_title);
+ filename[size_path+size_title] = 0;
+
+ return filename;
+}
+
+int iupStrReplace(char* str, char src, char dst)
+{
+ int i = 0;
+ while (*str)
+ {
+ if (*str == src)
+ {
+ *str = dst;
+ i++;
+ }
+ str++;
+ }
+ return i;
+}
+
+void iupStrToUnix(char* str)
+{
+ char* pstr = str;
+
+ if (!str) return;
+
+ while (*str)
+ {
+ if (*str == '\r')
+ {
+ if (*(str+1) != '\n') /* MAC line end */
+ *pstr++ = '\n';
+ str++;
+ }
+ else
+ *pstr++ = *str++;
+ }
+
+ *pstr = *str;
+}
+
+char* iupStrToMac(const char* str)
+{
+ int at_start = 1;
+ char* pstr, *new_str;
+
+ if (!str) return NULL;
+
+ if (iupStrLineCount(str) == 1)
+ return (char*)str;
+
+ new_str = iupStrDup(str);
+ str = new_str;
+ pstr = new_str;
+
+ while (*str)
+ {
+ if (*str == '\n')
+ {
+ if (!at_start && *(str-1) != '\r') /* UNIX line end */
+ *pstr++ = '\r';
+ str++;
+ }
+ else
+ *pstr++ = *str++;
+ at_start = 0;
+ }
+
+ *pstr = *str;
+
+ return new_str;
+}
+
+char* iupStrToDos(const char* str)
+{
+ char *auxstr, *newstr;
+ int num_lin;
+
+ if (!str) return NULL;
+
+ num_lin = iupStrLineCount(str);
+ if (num_lin == 1)
+ return (char*)str;
+
+ newstr = malloc(num_lin + strlen(str) + 1);
+ auxstr = newstr;
+ while(*str)
+ {
+ if (*str == '\r' && *(str+1)=='\n') /* DOS line end */
+ {
+ *auxstr++ = *str++;
+ *auxstr++ = *str++;
+ }
+ else if (*str == '\r') /* MAC line end */
+ {
+ *auxstr++ = *str++;
+ *auxstr++ = '\n';
+ }
+ else if (*str == '\n') /* UNIX line end */
+ {
+ *auxstr++ = '\r';
+ *auxstr++ = *str++;
+ }
+ else
+ *auxstr++ = *str++;
+ }
+ *auxstr = 0;
+
+ return newstr;
+}
+
+void iupStrRemove(char* value, int start, int end, int dir)
+{
+ if (start == end)
+ {
+ if (dir==1)
+ end++;
+ else if (start == 0) /* there is nothing to remove before */
+ return;
+ else
+ start--;
+ }
+ value += start;
+ end -= start;
+ while (*value)
+ {
+ *value = *(value+end);
+ value++;
+ }
+}
+
+char* iupStrInsert(const char* value, const char* insert_value, int start, int end)
+{
+ char* new_value = (char*)value;
+ int insert_len = strlen(insert_value);
+ int len = strlen(value);
+ if (end==start || insert_len > end-start)
+ {
+ new_value = malloc(len - (end-start) + insert_len + 1);
+ memcpy(new_value, value, start);
+ memcpy(new_value+start, insert_value, insert_len);
+ memcpy(new_value+start+insert_len, value+end, len-end+1);
+ }
+ else
+ {
+ memcpy(new_value+start, insert_value, insert_len);
+ memcpy(new_value+start+insert_len, value+end, len-end+1);
+ }
+ return new_value;
+}
+
+char* iupStrProcessMnemonic(const char* str, char *c, int action)
+{
+ int i = 0, found = 0;
+ char* new_str, *orig_str = (char*)str;
+
+ if (!str) return NULL;
+
+ if (!strchr(str, '&'))
+ return (char*)str;
+
+ new_str = malloc(strlen(str)+1);
+ while (*str)
+ {
+ if (*str == '&')
+ {
+ if (*(str+1) == '&') /* remove & from the string, add next & to the string */
+ {
+ str++;
+ new_str[i++] = *str;
+ }
+ else if (!found) /* mnemonic found */
+ {
+ found = 1;
+
+ if (action == 1) /* replace & by c */
+ new_str[i++] = *c;
+ else if (action == -1) /* remove & and return in c */
+ *c = *(str+1); /* next is mnemonic */
+ /* else -- only remove & */
+ }
+ }
+ else
+ {
+ new_str[i++] = *str;
+ }
+
+ str++;
+ }
+ new_str[i] = 0;
+
+ if (!found)
+ {
+ free(new_str);
+ return orig_str;
+ }
+
+ return new_str;
+}
diff --git a/iup/src/iup_str.h b/iup/src/iup_str.h
new file mode 100755
index 0000000..1c2e7a5
--- /dev/null
+++ b/iup/src/iup_str.h
@@ -0,0 +1,183 @@
+/** \file
+ * \brief String Utilities
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#ifndef __IUP_STR_H
+#define __IUP_STR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup str String Utilities
+ * \par
+ * See \ref iup_str.h
+ * \ingroup util */
+
+/** Returns a copy of the given string.
+ * If str is NULL it will return NULL.
+ * \ingroup str */
+char* iupStrDup(const char* str);
+
+/** Returns a non zero value if the two strings are equal.
+ * str1 or str2 can be NULL.
+ * \ingroup str */
+int iupStrEqual(const char* str1, const char* str2);
+
+/** Returns a non zero value if the two strings are equal but ignores case.
+ * str1 or str2 can be NULL.
+ * \ingroup str */
+int iupStrEqualNoCase(const char* str1, const char* str2);
+
+/** Returns a non zero value if the two strings are equal
+ * up to a number of characters defined by the strlen of the second string.
+ * str1 or str2 can be NULL.
+ * \ingroup str */
+int iupStrEqualPartial(const char* str1, const char* str2);
+
+/** Returns 1 if the string is "1", "YES", "ON" or "TRUE". \n
+ * Returns 0 if the string is "0", "NO", "OFF" or "FALSE", or the string is NULL or empty.
+ * \ingroup str */
+int iupStrBoolean(const char* str);
+
+/** Returns the number of lines in a string.
+ * It works for UNIX, DOS and MAC line ends.
+ * \ingroup str */
+int iupStrLineCount(const char* str);
+
+/** Returns the a pointer to the next line and the size of the current line.
+ * It works for UNIX, DOS and MAC line ends. The size does not includes the line end.
+ * If str is NULL it will return NULL.
+ * \ingroup str */
+const char* iupStrNextLine(const char* str, int *len);
+
+/** Returns the number of repetitions of the character occours in the string.
+ * \ingroup str */
+int iupStrCountChar(const char *str, int c);
+
+/** Returns a new string containing a copy of the string up to the character.
+ * The string is then incremented to after the position of the character.
+ * \ingroup str */
+char *iupStrCopyUntil(char **str, int c);
+
+/** Copy the string to the buffer, but limited to the max_size of the buffer.
+ * buffer is always porperly ended.
+ * \ingroup str */
+void iupStrCopyN(char* dst_str, int dst_max_size, const char* src_str);
+
+/** Returns a buffer with the specified size+1. \n
+ * The buffer is resused after 50 calls. It must NOT be freed.
+ * Use size=-1 to free all the internal buffers.
+ * \ingroup str */
+char *iupStrGetMemory(int size);
+
+/** Returns a buffer that contains a copy of the given buffer using \ref iupStrGetMemory.
+ * \ingroup str */
+char *iupStrGetMemoryCopy(const char* str);
+
+/** Converts a string into lower case.
+ * \ingroup str */
+void iupStrLower(char* dstr, const char* sstr);
+
+/** Extract a RGB triple from the string. Returns 0 or 1.
+ * \ingroup str */
+int iupStrToRGB(const char *str, unsigned char *r, unsigned char *g, unsigned char *b);
+
+/** Extract a RGBA quad from the string, alpha is optional. Returns 0, 3 or 4.
+ * \ingroup str */
+int iupStrToRGBA(const char *str, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a);
+
+/** Converts the string to an int. The string must contains only the integer value.
+ * Returns a a non zero value if sucessfull.
+ * \ingroup str */
+int iupStrToInt(const char *str, int *i);
+
+/** Converts the string to two int. The string must contains two integer values in sequence,
+ * separated by the given character (usually 'x' or ':').
+ * Returns the number of converted values.
+ * Values not extracted are not changed.
+ * \ingroup str */
+int iupStrToIntInt(const char *str, int *i1, int *i2, char sep);
+
+/** Converts the string to an float. The string must contains only the real value.
+ * Returns a a non zero value if sucessfull.
+ * \ingroup str */
+int iupStrToFloat(const char *str, float *f);
+
+/** Converts the string to two float. The string must contains two real values in sequence,
+ * separated by the given character (usually 'x' or ':').
+ * Returns the number of converted values.
+ * Values not extracted are not changed.
+ * \ingroup str */
+int iupStrToFloatFloat(const char *str, float *f1, float *f2, char sep);
+
+/** Extract two strings from the string.
+ * separated by the given character (usually 'x' or ':').
+ * Returns the number of converted values.
+ * Values not extracted are not changed.
+ * \ingroup str */
+int iupStrToStrStr(const char *str, char *str1, char *str2, char sep);
+
+/** Returns the file extension of a file name.
+ * Supports UNIX and Windows directory separators.
+ * \ingroup str */
+char* iupStrFileGetExt(const char *file_name);
+
+/** Returns the file title of a file name.
+ * Supports UNIX and Windows directory separators.
+ * \ingroup str */
+char* iupStrFileGetTitle(const char *file_name);
+
+/** Returns the file path of a file name.
+ * Supports UNIX and Windows directory separators.
+ * \ingroup str */
+char* iupStrFileGetPath(const char *file_name);
+
+/** Concat path and title addind '/' between if path does not have it.
+ * \ingroup str */
+char* iupStrFileMakeFileName(const char* path, const char* title);
+
+/** Replace a character in a string.
+ * Returns the number of occurrences.
+ * \ingroup str */
+int iupStrReplace(char* str, char src, char dst);
+
+/** Convert line ends to UNIX format in place (one \n per line).
+ * \ingroup str */
+void iupStrToUnix(char* str);
+
+/** Convert line ends to MAC format (one \r per line).
+ * If returned pointer different than input it must be freed.
+ * \ingroup str */
+char* iupStrToMac(const char* str);
+
+/** Convert line ends to DOS/Windows format (the sequence \r\n per line).
+ * If returned pointer different than input it must be freed.
+ * \ingroup str */
+char* iupStrToDos(const char* str);
+
+/** Remove the interval from the string. Done in place.
+ * \ingroup str */
+void iupStrRemove(char* value, int start, int end, int dir);
+
+/** Remove the interval from the string and insert the new string at the start.
+ * \ingroup str */
+char* iupStrInsert(const char* value, const char* insert_value, int start, int end);
+
+/** Process the mnemonic in the string. If not found returns str.
+ * If found returns a new string. Action can be:
+- 1: replace & by c
+- -1: remove & and return in c
+- 0: remove &
+ * \ingroup str */
+char* iupStrProcessMnemonic(const char* str, char *c, int action);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_strmessage.c b/iup/src/iup_strmessage.c
new file mode 100755
index 0000000..5f23528
--- /dev/null
+++ b/iup/src/iup_strmessage.c
@@ -0,0 +1,137 @@
+/** \file
+ * \brief String Utilities
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_strmessage.h"
+#include "iup_table.h"
+
+
+static Itable *istrmessage_table = NULL; /* the function hast table indexed by the name string */
+
+void iupStrMessageInit(void)
+{
+ istrmessage_table = iupTableCreate(IUPTABLE_STRINGINDEXED);
+}
+
+void iupStrMessageFinish(void)
+{
+ iupTableDestroy(istrmessage_table);
+ istrmessage_table = NULL;
+}
+
+char* iupStrMessageGet(const char* message)
+{
+ return (char*)iupTableGet(istrmessage_table, message);
+}
+
+static void iStrMessageSet(const char* message, const char* str)
+{
+ iupTableSet(istrmessage_table, message, (char*)str, IUPTABLE_POINTER);
+}
+
+void iupStrMessageShowError(Ihandle* parent, const char* message)
+{
+ Ihandle* dlg = IupMessageDlg();
+ char* title = NULL, *str_message;
+
+ if (parent)
+ {
+ IupSetAttributeHandle(dlg, "PARENTDIALOG", parent);
+ title = IupGetAttribute(parent, "TITLE");
+ }
+
+ if (!title)
+ title = iupStrMessageGet("IUP_ERROR");
+
+ IupSetAttribute(dlg, "TITLE", title);
+ IupSetAttribute(dlg, "DIALOGTYPE", "ERROR");
+ IupSetAttribute(dlg, "BUTTONS", "OK");
+
+ str_message = iupStrMessageGet(message);
+ if (!str_message)
+ str_message = (char*)message;
+ IupSetAttribute(dlg, "VALUE", str_message);
+
+ IupPopup(dlg, IUP_CURRENT, IUP_CURRENT);
+
+ IupDestroy(dlg);
+}
+
+typedef struct _IstdMessage
+{
+ const char* code;
+ const char* lng_msg[3]; /* 2+1 for expansion */
+} IstdMessage;
+
+/* Edit this table to add support for more languages */
+
+static IstdMessage iStdMessages[] =
+{
+ {"IUP_ERROR", {"Error", "Erro", NULL}},
+ {"IUP_YES", {"Yes", "Sim", NULL}},
+ {"IUP_NO", {"No", "Não", NULL}},
+ {"IUP_INVALIDDIR", {"Invalid directory.", "Diretório inválido.", NULL}},
+ {"IUP_FILEISDIR", {"The selected name is a directory.", "O nome selecionado é um diretório.", NULL}},
+ {"IUP_FILENOTEXIST", {"File does not exist.", "Arquivo inexistente.", NULL}},
+ {"IUP_FILEOVERWRITE", {"Overwrite existing file?", "Sobrescrever arquivo?", NULL}},
+ {"IUP_CREATEFOLDER", {"Create Folder", "Criar Diretório", NULL}},
+ {"IUP_NAMENEWFOLDER", {"Name of the new folder:", "Nome do novo diretório:", NULL}},
+ {"IUP_SAVEAS", {"Save As", "Salvar Como", NULL}},
+ {"IUP_OPEN", {"Open", "Abrir", NULL}},
+ {"IUP_SELECTDIR", {"Select Directory", "Selecionar Diretório", NULL}},
+ {"IUP_CANCEL", {"Cancel", "Cancela", NULL}},
+ {"IUP_GETCOLOR", {"Color Selection", "Seleção de Cor", NULL}},
+ {"IUP_HELP", {"Help", "Ajuda", NULL}},
+ {"IUP_RED", {"&Red:", "&Vermelho:", NULL}},
+ {"IUP_GREEN", {"&Green:", "V&erde:", NULL}},
+ {"IUP_BLUE", {"&Blue:", "&Azul:", NULL}},
+ {"IUP_HUE", {"&Hue:", "&Matiz:", NULL}},
+ {"IUP_SATURATION", {"&Saturation:", "&Saturação:", NULL}},
+ {"IUP_INTENSITY", {"&Intensity:", "&Intensidade:", NULL}},
+ {"IUP_OPACITY", {"&Opacity:", "&Opacidade:", NULL}},
+ {"IUP_PALETTE", {"&Palette:", "&Paleta:", NULL}},
+ {"IUP_TRUE", {"True", "Verdadeiro", NULL}},
+ {"IUP_FALSE", {"False", "Falso", NULL}},
+ {NULL, {NULL, NULL, NULL}}
+};
+
+static void iStrRegisterInternalMessages(int lng)
+{
+ IstdMessage* messages = iStdMessages;
+ while (messages->code)
+ {
+ iStrMessageSet(messages->code, messages->lng_msg[lng]);
+ messages++;
+ }
+}
+
+void iupStrMessageUpdateLanguage(const char* language)
+{
+ int lng = 0;
+ if (iupStrEqualNoCase(language, "PORTUGUESE"))
+ lng = 1;
+ iStrRegisterInternalMessages(lng);
+}
+
+void IupSetLanguage(const char *language)
+{
+ IupStoreGlobal("LANGUAGE", language);
+}
+
+char *IupGetLanguage(void)
+{
+ return IupGetGlobal("LANGUAGE");
+}
diff --git a/iup/src/iup_strmessage.h b/iup/src/iup_strmessage.h
new file mode 100755
index 0000000..dbd0374
--- /dev/null
+++ b/iup/src/iup_strmessage.h
@@ -0,0 +1,45 @@
+/** \file
+ * \brief Language Dependent String Messages
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#ifndef __IUP_STRMESSAGE_H
+#define __IUP_STRMESSAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup strmessage Language Dependent String Messages
+ * \par
+ * String database that is dependend of the selected language.
+ * \par
+ * See \ref iup_strmessage.h
+ * \ingroup util */
+
+/** Pre-defined dialog to show an error message. Based in IupMessageDlg.
+ * Message can be a registered coded message or a commom string.
+ * \ingroup strmessage */
+void iupStrMessageShowError(Ihandle* parent, const char* message);
+
+/** Returns a common string from a registered coded message.
+ * The returned string depends on the global LANGUAGE attribute.
+ * \ingroup strmessage */
+char* iupStrMessageGet(const char* message);
+
+/* Called from iup_global */
+void iupStrMessageUpdateLanguage(const char* language);
+
+/* called only in IupOpen and IupClose */
+void iupStrMessageInit(void);
+void iupStrMessageFinish(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_table.c b/iup/src/iup_table.c
new file mode 100755
index 0000000..9e97ff5
--- /dev/null
+++ b/iup/src/iup_table.c
@@ -0,0 +1,736 @@
+/** \file
+ * \brief iupTable functions.
+ * Implementation by Danny Reinhold and Antonio Scuri.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+
+#include "iup_table.h"
+#include "iup_str.h"
+#include "iup_assert.h"
+
+/* #define DEBUGTABLE 1 */
+
+/* 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_itemGrow = 5;
+
+/* Iteration context.
+ */
+typedef struct ItableContext
+{
+ unsigned int entryIndex; /* index at the Itable::entries array */
+ unsigned int itemIndex; /* index at the ItableEntry::items array */
+} ItableContext;
+
+/* A key of an item.
+ * To avoid lots of string comparisions we store
+ * a keyindex as an integer.
+ * To find a key in an item list we only have to
+ * do integer comparisions.
+ * Additionally the key itself is stored in
+ * keyStr. In a string indexed hashtable this is
+ * a duplicated string, in a pointer indexed hash table
+ * this is simply the pointer (in this case keyIndex
+ * and keyStr are equal).
+*/
+typedef struct ItableKey
+{
+ unsigned long keyIndex; /* the secondary hash number */
+ const char *keyStr;
+}
+ItableKey;
+
+/* An item in the hash table.
+ * Such an item is stored in the item list of
+ * an entry.
+ */
+typedef struct ItableItem
+{
+ Itable_Types itemType;
+ ItableKey key;
+ void *value;
+}
+ItableItem;
+
+/* An entry in the hash table.
+ * An entry is chosen by an index in the hash table
+ * and contains a list of items.
+ * The number of items in this list is stored
+ * in nextItemIndex.
+ * size is the current size of the items array.
+ */
+typedef struct ItableEntry
+{
+ unsigned int nextItemIndex;
+ unsigned int size;
+ 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
+{
+ unsigned int size;
+ unsigned int numberOfEntries;
+ unsigned int tableSizeIndex; /* index into itable_hashTableSize array */
+ Itable_IndexTypes indexType;
+ ItableEntry *entries;
+ ItableContext context;
+};
+
+
+/* Prototypes of private functions */
+
+static void iTableFreeItemArray(Itable_IndexTypes indexType, unsigned int nextFreeIndex,
+ ItableItem *items);
+static unsigned int iTableGetEntryIndex(Itable *it, const char *key, unsigned long *keyIndex);
+static unsigned int iTableFindItem(Itable *it, const char *key, ItableEntry **entry,
+ unsigned int *itemIndex,
+ unsigned long *keyIndex);
+static unsigned int iTableResize(Itable *it);
+static void iTableAdd(Itable *it, ItableKey *key, void *value, Itable_Types itemType);
+static void iTableUpdateArraySize(ItableEntry *entry);
+
+#ifdef DEBUGTABLE
+static void iTableShowStatistics(Itable *it);
+static void iTableCheckDuplicated(ItableItem *item, unsigned int nextItemIndex,
+ const char *key,
+ unsigned long keyIndex);
+#endif
+
+
+Itable *iupTableCreate(Itable_IndexTypes indexType)
+{
+ return iupTableCreateSized(indexType, 1); /* 101 shows to be a better start for IUP */
+}
+
+
+Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSizeIndex)
+{
+ Itable *it = (Itable *)malloc(sizeof(struct Itable));
+
+ iupASSERT(it!=NULL);
+ if (!it)
+ return 0;
+
+ if (initialSizeIndex > itable_maxTableSizeIndex)
+ initialSizeIndex = itable_maxTableSizeIndex;
+
+ it->size = itable_hashTableSize[initialSizeIndex];
+ it->tableSizeIndex = initialSizeIndex;
+ it->numberOfEntries = 0;
+ it->indexType = indexType;
+
+ it->entries = (ItableEntry *)malloc(it->size * sizeof(ItableEntry));
+ iupASSERT(it->entries!=NULL);
+ if (!it->entries)
+ {
+ free(it);
+ return 0;
+ }
+
+ memset(it->entries, 0, it->size * sizeof(ItableEntry));
+
+ it->context.entryIndex = (unsigned int)-1;
+ it->context.itemIndex = (unsigned int)-1;
+
+ return it;
+}
+
+void iupTableClear(Itable *it)
+{
+ unsigned int i;
+
+ if (!it)
+ return;
+
+ for (i = 0; i < it->size; i++)
+ {
+ ItableEntry *entry = &(it->entries[i]);
+ if (entry->items)
+ iTableFreeItemArray(it->indexType, entry->nextItemIndex, entry->items);
+ }
+
+ it->numberOfEntries = 0;
+
+ memset(it->entries, 0, it->size * sizeof(ItableEntry));
+
+ it->context.entryIndex = (unsigned int)-1;
+ it->context.itemIndex = (unsigned int)-1;
+}
+
+void iupTableDestroy(Itable *it)
+{
+ if (!it)
+ return;
+
+#ifdef DEBUGTABLE
+ iTableShowStatistics(it);
+#endif
+
+ iupTableClear(it);
+
+ if (it->entries)
+ free(it->entries);
+
+ free(it);
+}
+
+int iupTableCount(Itable *it)
+{
+ iupASSERT(it!=NULL);
+ if (!it)
+ return 0;
+ return it->numberOfEntries;
+}
+
+void iupTableSetFunc(Itable *it, const char *key, Ifunc func)
+{
+ iupTableSet(it, key, (void*)func, IUPTABLE_FUNCPOINTER); /* type cast from function pointer to void* */
+}
+
+void iupTableSet(Itable *it, const char *key, void *value, Itable_Types itemType)
+{
+ unsigned int itemIndex,
+ itemFound;
+ unsigned long keyIndex;
+ ItableEntry *entry;
+ ItableItem *item;
+ void *v;
+
+ iupASSERT(it!=NULL);
+ iupASSERT(key!=NULL);
+ if (!it || !key || !value)
+ return;
+
+ itemFound = iTableFindItem(it, key, &entry, &itemIndex, &keyIndex);
+
+#ifdef DEBUGTABLE
+ if (it->indexType == IUPTABLE_STRINGINDEXED)
+ iTableCheckDuplicated(&(entry->items[0]), entry->nextItemIndex, key, keyIndex);
+#endif
+
+ if (!itemFound)
+ {
+ /* create a new item */
+
+ /* first check if the hash table has to be reorganized */
+ if (iTableResize(it))
+ {
+ /* We have to search for the entry again, since it may
+ * have been moved by iTableResize. */
+ iTableFindItem(it, key, &entry, &itemIndex, &keyIndex);
+ }
+
+ iTableUpdateArraySize(entry);
+
+ /* add the item at the end of the item array */
+ if (itemType == IUPTABLE_STRING)
+ v = iupStrDup(value);
+ else
+ v = value;
+
+ item = &(entry->items[entry->nextItemIndex]);
+
+ item->itemType = itemType;
+ item->key.keyIndex = keyIndex;
+ item->key.keyStr = it->indexType == IUPTABLE_STRINGINDEXED? iupStrDup(key) : key;
+ item->value = v;
+
+ entry->nextItemIndex++;
+ it->numberOfEntries++;
+ }
+ else
+ {
+ /* change an existing item */
+ void *v;
+ item = &(entry->items[itemIndex]);
+
+ if (itemType == IUPTABLE_STRING && item->itemType == IUPTABLE_STRING)
+ {
+ /* this will avoid to free + alloc of a new pointer */
+ if (iupStrEqual((char*)item->value, (char*)value))
+ return;
+ }
+
+ if (itemType == IUPTABLE_STRING)
+ v = iupStrDup(value);
+ else
+ v = value;
+
+ if (item->itemType == IUPTABLE_STRING)
+ free(item->value);
+
+ item->value = v;
+ item->itemType = itemType;
+ }
+}
+
+static void iTableRemoveItem(Itable *it, ItableEntry *entry, unsigned int itemIndex)
+{
+ ItableItem *item;
+ unsigned int i;
+
+ item = &(entry->items[itemIndex]);
+
+ if (it->indexType == IUPTABLE_STRINGINDEXED)
+ free((void *)item->key.keyStr);
+
+ if (item->itemType == IUPTABLE_STRING)
+ free(item->value);
+
+ /* 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));
+
+ entry->nextItemIndex--;
+ it->numberOfEntries--;
+}
+
+void iupTableRemove(Itable *it, const char *key)
+{
+ unsigned int itemFound,
+ itemIndex;
+ unsigned long keyIndex;
+ ItableEntry *entry;
+
+ iupASSERT(it!=NULL);
+ iupASSERT(key!=NULL);
+ if (!it || !key)
+ return;
+
+ itemFound = iTableFindItem(it, key, &entry, &itemIndex, &keyIndex);
+ if (itemFound)
+ iTableRemoveItem(it, entry, itemIndex);
+}
+
+void *iupTableGet(Itable *it, const char *key)
+{
+ unsigned int itemFound,
+ itemIndex;
+ unsigned long keyIndex;
+ ItableEntry *entry;
+ void *value = 0;
+
+ iupASSERT(it!=NULL);
+ iupASSERT(key!=NULL);
+ if (!it || !key)
+ return 0;
+
+ itemFound = iTableFindItem(it, key, &entry, &itemIndex, &keyIndex);
+ if (itemFound)
+ value = entry->items[itemIndex].value;
+
+ return value;
+}
+
+Ifunc iupTableGetFunc(Itable *it, const char *key, void **value)
+{
+ Itable_Types itemType = IUPTABLE_POINTER;
+ *value = iupTableGetTyped(it, key, &itemType);
+ if (itemType == IUPTABLE_FUNCPOINTER)
+ return (Ifunc)(*value); /* type cast from void* to function pointer */
+ else
+ return (Ifunc)0;
+}
+
+void *iupTableGetTyped(Itable *it, const char *key, Itable_Types *itemType)
+{
+ unsigned int itemFound,
+ itemIndex;
+ unsigned long keyIndex;
+ ItableEntry *entry;
+ void *value = 0;
+
+ iupASSERT(it!=NULL);
+ iupASSERT(key!=NULL);
+ if (!it || !key)
+ return 0;
+
+ itemFound = iTableFindItem(it, key, &entry, &itemIndex, &keyIndex);
+ if (itemFound)
+ {
+ value = entry->items[itemIndex].value;
+ if (itemType)
+ *itemType = entry->items[itemIndex].itemType;
+ }
+
+ return value;
+}
+
+void *iupTableGetCurr(Itable *it)
+{
+ iupASSERT(it!=NULL);
+ if (!it || it->context.entryIndex == (unsigned int)-1
+ || it->context.itemIndex == (unsigned int)-1)
+ return 0;
+
+ return it->entries[it->context.entryIndex].items[it->context.itemIndex].value;
+}
+
+
+char *iupTableFirst(Itable *it)
+{
+ unsigned int entryIndex;
+
+ iupASSERT(it!=NULL);
+ if (!it)
+ return 0;
+
+ it->context.entryIndex = (unsigned int)-1;
+ it->context.itemIndex = (unsigned int)-1;
+
+ /* find the first used entry */
+ for (entryIndex = 0; entryIndex < it->size; entryIndex++)
+ {
+ if (it->entries[entryIndex].nextItemIndex > 0)
+ {
+ it->context.entryIndex = entryIndex;
+ it->context.itemIndex = 0;
+ return (char*)it->entries[entryIndex].items[0].key.keyStr;
+ }
+ }
+
+ return 0;
+}
+
+
+char *iupTableNext(Itable *it)
+{
+ unsigned int entryIndex;
+
+ iupASSERT(it!=NULL);
+ if (!it || it->context.entryIndex == (unsigned int)-1
+ || it->context.itemIndex == (unsigned int)-1)
+ return 0;
+
+ if (it->context.itemIndex + 1 < it->entries[it->context.entryIndex].nextItemIndex)
+ {
+ /* key in the current entry */
+ it->context.itemIndex++;
+ return (char*)it->entries[it->context.entryIndex].items[it->context.itemIndex].key.keyStr;
+ }
+ else
+ {
+ /* find the next used entry */
+ for (entryIndex = it->context.entryIndex+1; entryIndex < it->size; entryIndex++)
+ {
+ if (it->entries[entryIndex].nextItemIndex > 0)
+ {
+ it->context.entryIndex = entryIndex;
+ it->context.itemIndex = 0;
+ return (char*)it->entries[entryIndex].items[0].key.keyStr;
+ }
+ }
+ }
+
+ return 0;
+}
+
+char *iupTableRemoveCurr(Itable *it)
+{
+ char* key;
+ unsigned int entryIndex;
+ ItableEntry *entry;
+ unsigned int itemIndex;
+
+ iupASSERT(it!=NULL);
+ if (!it || it->context.entryIndex == (unsigned int)-1
+ || it->context.itemIndex == (unsigned int)-1)
+ return 0;
+
+ entry = &it->entries[it->context.entryIndex];
+ itemIndex = it->context.itemIndex;
+
+ if (it->context.itemIndex + 1 < it->entries[it->context.entryIndex].nextItemIndex)
+ {
+ /* key in the current entry */
+ it->context.itemIndex++;
+ key = (char*)it->entries[it->context.entryIndex].items[it->context.itemIndex].key.keyStr;
+
+ iTableRemoveItem(it, entry, itemIndex);
+ return key;
+ }
+ else
+ {
+ /* find the next used entry */
+ for (entryIndex = it->context.entryIndex+1; entryIndex < it->size; entryIndex++)
+ {
+ if (it->entries[entryIndex].nextItemIndex > 0)
+ {
+ it->context.entryIndex = entryIndex;
+ it->context.itemIndex = 0;
+ key = (char*)it->entries[entryIndex].items[0].key.keyStr;
+
+ iTableRemoveItem(it, entry, itemIndex);
+ return key;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/********************************************/
+/* Private functions */
+/********************************************/
+
+
+static void iTableFreeItemArray(Itable_IndexTypes indexType, unsigned int nextFreeIndex, ItableItem *items)
+{
+ unsigned int i;
+
+ iupASSERT(items!=NULL);
+ if (!items)
+ return;
+
+ if (indexType == IUPTABLE_STRINGINDEXED)
+ {
+ for (i = 0; i < nextFreeIndex; i++)
+ free((void *)(items[i].key.keyStr));
+ }
+
+ for (i = 0; i < nextFreeIndex; i++)
+ {
+ if (items[i].itemType == IUPTABLE_STRING)
+ free(items[i].value);
+ }
+
+ free(items);
+}
+
+
+static unsigned int iTableGetEntryIndex(Itable *it, const char *key, unsigned long *keyIndex)
+{
+ if (it->indexType == IUPTABLE_STRINGINDEXED)
+ {
+ register unsigned int checksum = 0;
+
+/* Orignal version
+ unsigned int i;
+ for (i = 0; key[i]; i++)
+ checksum = checksum*31 + key[i];
+*/
+
+ while (*key)
+ {
+ checksum *= 31;
+ checksum += *key;
+ key++;
+ }
+
+ *keyIndex = checksum; /* this could NOT be dependent from table size */
+ }
+ else
+ {
+ /* Pointer indexed */
+ *keyIndex = (unsigned long)key; /* this could NOT be dependent from table size */
+ }
+
+ return (unsigned int)((*keyIndex) % it->size);
+}
+
+#ifdef DEBUGTABLE
+static void iTableCheckDuplicated(ItableItem *item, unsigned int nextItemIndex, const char *key,
+ unsigned long keyIndex)
+{
+ unsigned int i;
+ for (i = 0; i < nextItemIndex; i++, item++)
+ {
+ if (!iupStrEqual((char*)item->key.keyStr, (char*)key) &&
+ item->key.keyIndex == keyIndex)
+ {
+ fprintf(stderr, "#ERROR# Duplicated key index (%ld): %s %s \n", keyIndex,
+ (char*)item->key.keyStr,
+ (char*)key);
+ }
+ }
+}
+#endif
+
+static unsigned int iTableFindItem(Itable *it, const char *key, ItableEntry **entry,
+ unsigned int *itemIndex,
+ unsigned long *keyIndex)
+{
+ unsigned int entryIndex,
+ itemFound,
+ i;
+ ItableItem *item;
+
+ entryIndex = iTableGetEntryIndex(it, key, keyIndex);
+
+ *entry = &(it->entries[entryIndex]);
+
+ item = &((*entry)->items[0]);
+ for (i = 0; i < (*entry)->nextItemIndex; i++, item++)
+ {
+ if (it->indexType == IUPTABLE_STRINGINDEXED)
+ itemFound = item->key.keyIndex == *keyIndex;
+/* itemFound = iupStrEqual(item->key.keyStr, key); This is the original safe version */
+ else
+ itemFound = item->key.keyStr == key;
+
+ if (itemFound)
+ {
+ *itemIndex = i;
+ return 1;
+ }
+ }
+
+ /* if not found "entry", "itemIndex" and "keyIndex" will have the new insert position. */
+
+ *itemIndex = i;
+ return 0;
+}
+
+static void iTableUpdateArraySize(ItableEntry *entry)
+{
+ if (entry->nextItemIndex >= entry->size)
+ {
+ /* we have to expand the item array */
+ unsigned int newSize;
+
+ newSize = entry->size + 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));
+
+ entry->size = newSize;
+ }
+}
+
+
+static void iTableAdd(Itable *it, ItableKey *key, void *value, Itable_Types itemType)
+{
+ unsigned int entryIndex;
+ unsigned long keyIndex;
+ ItableEntry *entry;
+ ItableItem* item;
+
+ entryIndex = iTableGetEntryIndex(it, key->keyStr, &keyIndex);
+
+ entry = &(it->entries[entryIndex]);
+ iTableUpdateArraySize(entry);
+
+ /* add a new item at the end of the item array without duplicating memory. */
+ item = &(entry->items[entry->nextItemIndex]);
+ item->itemType = itemType;
+ item->key.keyIndex = keyIndex;
+ item->key.keyStr = key->keyStr;
+ item->value = value;
+
+ entry->nextItemIndex++;
+ it->numberOfEntries++;
+}
+
+static unsigned int iTableResize(Itable *it)
+{
+ unsigned int newSizeIndex,
+ entryIndex,
+ i;
+ Itable *newTable;
+ ItableEntry *entry;
+ ItableItem *item;
+
+ /* 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)
+ return 0;
+
+ /* create a new hash table and copy the contents of
+ * the current table into the new one
+ */
+ newSizeIndex = it->tableSizeIndex + 1;
+ newTable = iupTableCreateSized(it->indexType, newSizeIndex);
+
+ for (entryIndex = 0; entryIndex < it->size; entryIndex++)
+ {
+ entry = &(it->entries[entryIndex]);
+
+ if (entry->items)
+ {
+ item = &(entry->items[0]);
+
+ for (i = 0; i < entry->nextItemIndex; i++, item++)
+ {
+ iTableAdd(newTable, &(item->key), item->value, item->itemType);
+ }
+
+ free(entry->items);
+ }
+ }
+
+ free(it->entries);
+
+ it->size = newTable->size;
+ it->tableSizeIndex = newTable->tableSizeIndex;
+ it->numberOfEntries = newTable->numberOfEntries;
+ it->entries = newTable->entries;
+
+ free(newTable);
+
+ return 1;
+}
+
+#ifdef DEBUGTABLE
+static void iTableShowStatistics(Itable *it)
+{
+ unsigned int nofSlots = 0;
+ unsigned int nofKeys = 0;
+ double optimalNofKeysPerSlot = 0.0;
+ unsigned int nofSlotsWithMoreKeys = 0;
+ unsigned int nofSlotsWithLessKeys = 0;
+
+ unsigned int entryIndex;
+ fprintf(stderr, "\n--- HASH TABLE STATISTICS ---\n");
+ if (!it)
+ {
+ fprintf(stderr, "no hash table...\n");
+ return;
+ }
+
+ nofSlots = it->size;
+ nofKeys = it->numberOfEntries;
+ optimalNofKeysPerSlot = (double)nofKeys / (double)nofSlots;
+
+ for (entryIndex = 0; entryIndex < it->size; entryIndex++)
+ {
+ ItableEntry *entry = &(it->entries[entryIndex]);
+
+ if (entry->nextItemIndex > optimalNofKeysPerSlot + 3)
+ nofSlotsWithMoreKeys++;
+ else if (entry->nextItemIndex < optimalNofKeysPerSlot - 3)
+ nofSlotsWithLessKeys++;
+ }
+
+ fprintf(stderr, "Number of slots: %d\n", nofSlots);
+ fprintf(stderr, "Number of keys: %d\n", nofKeys);
+ fprintf(stderr, "Optimal number of keys per slot: %f\n", optimalNofKeysPerSlot);
+ fprintf(stderr, "Number of slots with much more keys: %d\n", nofSlotsWithMoreKeys);
+ fprintf(stderr, "Number of slots with far less keys: %d\n", nofSlotsWithLessKeys);
+ fprintf(stderr, "\n");
+}
+#endif
diff --git a/iup/src/iup_table.h b/iup/src/iup_table.h
new file mode 100755
index 0000000..5222160
--- /dev/null
+++ b/iup/src/iup_table.h
@@ -0,0 +1,143 @@
+/** \file
+ * \brief Simple hash table C API.
+ * Does not allow 0 values for items...
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_TABLE_H
+#define __IUP_TABLE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** \defgroup table Hash Table
+ * \par
+ * The hash table can be indexed by strings or pointer address,
+ * and each value can contain strings, pointers or function pointers.
+ * \par
+ * See \ref iup_table.h
+ * \ingroup util */
+
+
+/** How the table key is interpreted.
+ * \ingroup table */
+typedef enum _Itable_IndexTypes
+{
+ IUPTABLE_POINTERINDEXED = 10, /**< a pointer address is used as key. */
+ IUPTABLE_STRINGINDEXED /**< a string as key */
+} Itable_IndexTypes;
+
+/** How the value is interpreted.
+ * \ingroup table */
+typedef enum _Itable_Types
+{
+ IUPTABLE_POINTER, /**< regular pointer for strings and other pointers */
+ IUPTABLE_STRING, /**< string duplicated internally */
+ IUPTABLE_FUNCPOINTER /**< function pointer */
+} Itable_Types;
+
+
+typedef void (*Ifunc)(void);
+
+struct Itable;
+typedef struct Itable Itable;
+
+
+/** Creates a hash table with an initial default size.
+ * This function is equivalent to iupTableCreateSized(0);
+ * \ingroup table */
+Itable *iupTableCreate(Itable_IndexTypes indexType);
+
+/** Creates a hash table with the specified initial size.
+ * Use this function if you expect the table to become very large.
+ * initialSizeIndex is an array into the (internal) list of
+ * possible hash table sizes. Currently only indexes from 0 to 8
+ * are supported. If you specify a higher value here, the maximum
+ * allowed value will be used.
+ * \ingroup table */
+Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSizeIndex);
+
+/** Destroys the Itable.
+ * Calls \ref iupTableClear.
+ * \ingroup table */
+void iupTableDestroy(Itable *n);
+
+/** Removes all items in the table.
+ * This function does also free the memory of strings contained in the table!!!!
+ * \ingroup table */
+void iupTableClear(Itable *it);
+
+/** Returns the number of keys stored in the table.
+ * \ingroup table */
+int iupTableCount(Itable *it);
+
+/** Store an element in the table.
+ * \ingroup table */
+void iupTableSet(Itable *n, 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);
+
+/** Retrieves an element from the table.
+ * Returns NULL if not found.
+ * \ingroup table */
+void *iupTableGet(Itable *n, 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);
+
+/** Retrieves an element from the table and its type.
+ * \ingroup table */
+void *iupTableGetTyped(Itable *n, 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);
+
+/** Key iteration function. Returns a key.
+ * To iterate over all keys call iupTableFirst at the first
+ * and call iupTableNext in a loop
+ * until 0 is returned...
+ * Do NOT change the content of the hash table during iteration.
+ * During an iteration you can use context with
+ * iupTableGetCurr() to access the value of the key
+ * very fast.
+ * \ingroup table */
+char *iupTableFirst(Itable *it);
+
+/** Key iteration function. See \ref iupTableNext.
+ * \ingroup table */
+char *iupTableNext(Itable *it);
+
+/** Returns the value at the current position.
+ * The current context is an iterator
+ * that is filled by iupTableNext().
+ * iupTableGetCur() is faster then iupTableGet(),
+ * so when you want to access an item stored
+ * at a key returned by iupTableNext(),
+ * use this function instead of iupTableGet().
+ * \ingroup table */
+void *iupTableGetCurr(Itable *it);
+
+/** Removes the current element and returns the next key.
+ * Use this function to remove an element during an iteration.
+ * \ingroup table */
+char *iupTableRemoveCurr(Itable *it);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/iup/src/iup_tabs.c b/iup/src/iup_tabs.c
new file mode 100755
index 0000000..77b2cf5
--- /dev/null
+++ b/iup/src/iup_tabs.c
@@ -0,0 +1,471 @@
+/** \file
+* \brief iuptabs control
+*
+* See Copyright Notice in "iup.h"
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_image.h"
+#include "iup_tabs.h"
+
+
+
+char* iupTabsGetPaddingAttrib(Ihandle* ih)
+{
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding);
+ return str;
+}
+
+char* iupTabsAttribGetStrId(Ihandle* ih, const char* name, int pos)
+{
+ char str[50];
+ sprintf(str, "%s%d", name, pos);
+ return iupAttribGet(ih, str);
+}
+
+static int iTabsGetMaxWidth(Ihandle* ih)
+{
+ int max_width = 0, width, pos;
+ char *tabtitle, *tabimage;
+ Ihandle* child;
+
+ for (pos = 0, child = ih->firstchild; child; child = child->brother, pos++)
+ {
+ tabtitle = iupAttribGet(child, "TABTITLE");
+ if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos);
+ tabimage = iupAttribGet(child, "TABIMAGE");
+ if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos);
+ if (!tabtitle && !tabimage)
+ tabtitle = " ";
+
+ width = 0;
+ if (tabtitle)
+ width += iupdrvFontGetStringWidth(ih, tabtitle);
+
+ if (tabimage)
+ {
+ void* img = iupImageGetImage(tabimage, ih, 0);
+ if (img)
+ {
+ int w;
+ iupdrvImageGetInfo(img, &w, NULL, NULL);
+ width += w;
+ }
+ }
+
+ if (width > max_width) max_width = width;
+ }
+
+ return max_width;
+}
+
+static int iTabsGetMaxHeight(Ihandle* ih)
+{
+ int max_height = 0, h, pos;
+ char *tabimage;
+ Ihandle* child;
+
+ for (pos = 0, child = ih->firstchild; child; child = child->brother, pos++)
+ {
+ tabimage = iupAttribGet(child, "TABIMAGE");
+ if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos);
+
+ if (tabimage)
+ {
+ void* img = iupImageGetImage(tabimage, ih, 0);
+ if (img)
+ {
+ iupdrvImageGetInfo(img, NULL, &h, NULL);
+ if (h > max_height) max_height = h;
+ }
+ }
+ }
+
+ iupdrvFontGetCharSize(ih, NULL, &h);
+ if (h > max_height) max_height = h;
+
+ return max_height;
+}
+
+static void iTabsGetDecorSize(Ihandle* ih, int *width, int *height)
+{
+ if (ih->data->type == ITABS_LEFT || ih->data->type == ITABS_RIGHT)
+ {
+ if (ih->data->orientation == ITABS_HORIZONTAL)
+ {
+ int max_width = iTabsGetMaxWidth(ih);
+ *width = 4 + (3 + max_width + 3) + 2 + 4;
+ *height = 4 + 4;
+
+ if (iupdrvTabsExtraDecor(ih))
+ {
+ int h;
+ iupdrvFontGetCharSize(ih, NULL, &h);
+ *height += h + 4;
+ }
+ }
+ else
+ {
+ int max_height = iTabsGetMaxHeight(ih);
+ *width = 4 + (3 + max_height + 3) + 2 + 4;
+ *height = 4 + 4;
+
+ if (ih->handle && ih->data->is_multiline)
+ {
+ int num_lin = iupdrvTabsGetLineCountAttrib(ih);
+ *width += (num_lin-1)*(3 + max_height + 3 + 1);
+ }
+ }
+ }
+ else /* "BOTTOM" or "TOP" */
+ {
+ if (ih->data->orientation == ITABS_HORIZONTAL)
+ {
+ int max_height = iTabsGetMaxHeight(ih);
+ *width = 4 + 4;
+ *height = 4 + (3 + max_height + 3) + 2 + 4;
+
+ if (ih->handle && ih->data->is_multiline)
+ {
+ int num_lin = iupdrvTabsGetLineCountAttrib(ih);
+ *height += (num_lin-1)*(3 + max_height + 3 + 1);
+ }
+
+ if (iupdrvTabsExtraDecor(ih))
+ {
+ int h;
+ iupdrvFontGetCharSize(ih, NULL, &h);
+ *width += h + 4;
+ }
+ }
+ else
+ {
+ int max_width = iTabsGetMaxWidth(ih);
+ *width = 4 + 4;
+ *height = 4 + (3 + max_width + 3) + 2 + 4;
+ }
+ }
+
+ *width += ih->data->horiz_padding;
+ *height += ih->data->vert_padding;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* TABS - Sets and Gets - Accessors */
+/* ------------------------------------------------------------------------- */
+
+static int iTabsSetValueHandleAttrib(Ihandle* ih, const char* value)
+{
+ int pos;
+ Ihandle *child;
+
+ child = (Ihandle*)value;
+ if (!iupObjectCheck(child))
+ return 0;
+
+ pos = IupGetChildPos(ih, child);
+ if (pos != -1) /* found child */
+ {
+ if (ih->handle)
+ iupdrvTabsSetCurrentTab(ih, pos);
+ else
+ iupAttribSetStr(ih, "_IUPTABS_VALUE_HANDLE", (char*)child);
+ }
+
+ return 0;
+}
+
+char* iupTabsGetTabTypeAttrib(Ihandle* ih)
+{
+ switch(ih->data->type)
+ {
+ case ITABS_BOTTOM:
+ return "BOTTOM";
+ case ITABS_LEFT:
+ return "LEFT";
+ case ITABS_RIGHT:
+ return "RIGHT";
+ default:
+ return "TOP";
+ }
+}
+
+char* iupTabsGetTabOrientationAttrib(Ihandle* ih)
+{
+ if (ih->data->orientation == ITABS_HORIZONTAL)
+ return "HORIZONTAL";
+ else
+ return "VERTICAL";
+}
+
+static char* iTabsGetValueHandleAttrib(Ihandle* ih)
+{
+ if (ih->handle)
+ {
+ int pos = iupdrvTabsGetCurrentTab(ih);
+ return (char*)IupGetChild(ih, pos);
+ }
+ else
+ return iupAttribGet(ih, "_IUPTABS_VALUE_HANDLE");
+}
+
+static int iTabsSetValuePosAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle* child;
+ int pos;
+
+ if (!iupStrToInt(value, &pos))
+ return 0;
+
+ child = IupGetChild(ih, pos);
+ if (child) /* found child */
+ {
+ if (ih->handle)
+ iupdrvTabsSetCurrentTab(ih, pos);
+ else
+ iupAttribSetStr(ih, "_IUPTABS_VALUE_HANDLE", (char*)child);
+ }
+
+ return 0;
+}
+
+static char* iTabsGetValuePosAttrib(Ihandle* ih)
+{
+ if (ih->handle)
+ {
+ int pos = iupdrvTabsGetCurrentTab(ih);
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%d", pos);
+ return str;
+ }
+ else
+ {
+ Ihandle* child = (Ihandle*)iupAttribGet(ih, "_IUPTABS_VALUE_HANDLE");
+ int pos = IupGetChildPos(ih, child);
+ if (pos != -1) /* found child */
+ {
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%d", pos);
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+static int iTabsSetValueAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle *child;
+
+ if (!value)
+ return 0;
+
+ child = IupGetHandle(value);
+ if (!child)
+ return 0;
+
+ iTabsSetValueHandleAttrib(ih, (char*)child);
+
+ return 0;
+}
+
+static char* iTabsGetValueAttrib(Ihandle* ih)
+{
+ Ihandle* child = (Ihandle*)iTabsGetValueHandleAttrib(ih);
+ return IupGetName(child);
+}
+
+static char* iTabsGetClientSizeAttrib(Ihandle* ih)
+{
+ int width, height, decorwidth, decorheight;
+ char* str = iupStrGetMemory(20);
+ width = ih->currentwidth;
+ height = ih->currentheight;
+ iTabsGetDecorSize(ih, &decorwidth, &decorheight);
+ width -= decorwidth;
+ height -= decorheight;
+ if (width < 0) width = 0;
+ if (height < 0) height = 0;
+ sprintf(str, "%dx%d", width, height);
+ return str;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* TABS - Methods */
+/* ------------------------------------------------------------------------- */
+
+static void iTabsComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ Ihandle* child;
+ int children_expand,
+ children_naturalwidth, children_naturalheight;
+ int decorwidth, decorheight;
+
+ /* calculate total children natural size (even for hidden children) */
+ children_expand = 0;
+ children_naturalwidth = 0;
+ children_naturalheight = 0;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ /* update child natural size first */
+ iupBaseComputeNaturalSize(child);
+
+ children_expand |= child->expand;
+ children_naturalwidth = iupMAX(children_naturalwidth, child->naturalwidth);
+ children_naturalheight = iupMAX(children_naturalheight, child->naturalheight);
+ }
+
+ iTabsGetDecorSize(ih, &decorwidth, &decorheight);
+
+ *expand = children_expand;
+ *w = children_naturalwidth + decorwidth;
+ *h = children_naturalheight + decorheight;
+}
+
+static void iTabsSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink)
+{
+ Ihandle* child;
+ int width, height, decorwidth, decorheight;
+
+ iTabsGetDecorSize(ih, &decorwidth, &decorheight);
+
+ width = ih->currentwidth-decorwidth;
+ height = ih->currentheight-decorheight;
+ if (width < 0) width = 0;
+ if (height < 0) height = 0;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ iupBaseSetCurrentSize(child, width, height, shrink);
+ }
+}
+
+static void iTabsSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ /* IupTabs is the native parent of its children,
+ so the position is restarted at (0,0).
+ In all systems, each tab is a native window covering the client area.
+ Child coordinates are relative to client left-top corner of the tab page. */
+ Ihandle* child;
+ (void)x;
+ (void)y;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ iupBaseSetPosition(child, 0, 0);
+ }
+}
+
+static void* iTabsGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child)
+{
+ while (child && child->parent != ih)
+ child = child->parent;
+ if (child)
+ return iupAttribGet(child, "_IUPTAB_CONTAINER");
+ else
+ return NULL;
+}
+
+static int iTabsCreateMethod(Ihandle* ih, void **params)
+{
+ ih->data = iupALLOCCTRLDATA();
+
+ /* add children */
+ if(params)
+ {
+ Ihandle** iparams = (Ihandle**)params;
+ while (*iparams)
+ {
+ IupAppend(ih, *iparams);
+ iparams++;
+ }
+ }
+ return IUP_NOERROR;
+}
+
+Iclass* iupTabsGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "tabs";
+ ic->format = "g"; /* array of Ihandle */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDMANY;
+ ic->is_interactive = 1;
+ ic->has_attrib_id = 1;
+
+ /* Class functions */
+ ic->Create = iTabsCreateMethod;
+ ic->GetInnerNativeContainerHandle = iTabsGetInnerNativeContainerHandleMethod;
+
+ ic->ComputeNaturalSize = iTabsComputeNaturalSizeMethod;
+ ic->SetChildrenCurrentSize = iTabsSetChildrenCurrentSizeMethod;
+ ic->SetChildrenPosition = iTabsSetChildrenPositionMethod;
+
+ ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* IupTabs Callbacks */
+ iupClassRegisterCallback(ic, "TABCHANGE_CB", "nn");
+
+ /* Common Callbacks */
+ iupBaseRegisterCommonCallbacks(ic);
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Visual */
+ iupBaseRegisterVisualAttrib(ic);
+
+ /* IupTabs only */
+ iupClassRegisterAttribute(ic, "VALUE", iTabsGetValueAttrib, iTabsSetValueAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUEPOS", iTabsGetValuePosAttrib, iTabsSetValuePosAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE_HANDLE", iTabsGetValueHandleAttrib, iTabsSetValueHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", iTabsGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupdrvTabsInitClass(ic);
+
+ return ic;
+}
+
+Ihandle* IupTabs(Ihandle* first,...)
+{
+ Ihandle **params;
+ Ihandle *ih;
+
+ va_list arglist;
+ va_start(arglist, first);
+ params = (Ihandle**)iupObjectGetParamList(first, arglist);
+ va_end(arglist);
+
+ ih = IupCreatev("tabs", (void**)params);
+ free(params);
+
+ return ih;
+}
+
+Ihandle* IupTabsv(Ihandle** params)
+{
+ return IupCreatev("tabs", (void**)params);
+}
diff --git a/iup/src/iup_tabs.h b/iup/src/iup_tabs.h
new file mode 100755
index 0000000..7f5df2e
--- /dev/null
+++ b/iup/src/iup_tabs.h
@@ -0,0 +1,50 @@
+/** \file
+ * \brief Tabs Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_TABS_H
+#define __IUP_TABS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+char* iupTabsGetTabOrientationAttrib(Ihandle* ih);
+char* iupTabsGetTabTypeAttrib(Ihandle* ih);
+char* iupTabsAttribGetStrId(Ihandle* ih, const char* name, int pos);
+char* iupTabsGetPaddingAttrib(Ihandle* ih);
+
+int iupdrvTabsExtraDecor(Ihandle* ih);
+int iupdrvTabsGetLineCountAttrib(Ihandle* ih);
+void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos);
+int iupdrvTabsGetCurrentTab(Ihandle* ih);
+void iupdrvTabsInitClass(Iclass* ic);
+
+typedef enum
+{
+ ITABS_TOP, ITABS_BOTTOM, ITABS_LEFT, ITABS_RIGHT
+} ItabsType;
+
+typedef enum
+{
+ ITABS_HORIZONTAL, ITABS_VERTICAL
+} ItabsOrientation;
+
+/* Control context */
+struct _IcontrolData
+{
+ ItabsType type;
+ ItabsOrientation orientation;
+ int horiz_padding, vert_padding; /* tab title margin */
+ int is_multiline; /* used only in Windows */
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_text.c b/iup/src/iup_text.c
new file mode 100755
index 0000000..6cd7235
--- /dev/null
+++ b/iup/src/iup_text.c
@@ -0,0 +1,513 @@
+/** \file
+ * \brief Text Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_mask.h"
+#include "iup_array.h"
+#include "iup_text.h"
+#include "iup_assert.h"
+
+
+char* iupTextGetFormattingAttrib(Ihandle* ih)
+{
+ if (ih->data->has_formatting)
+ return "YES";
+ else
+ return "NO";
+}
+
+int iupTextSetFormattingAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->handle) /* only before map */
+ return 0;
+
+ ih->data->has_formatting = iupStrBoolean(value);
+
+ return 0;
+}
+
+static void iTextDestroyFormatTags(Ihandle* ih)
+{
+ /* called if the element was destroyed before it was mapped */
+ int i, count = iupArrayCount(ih->data->formattags);
+ Ihandle** tag_array = (Ihandle**)iupArrayGetData(ih->data->formattags);
+ for (i = 0; i < count; i++)
+ IupDestroy(tag_array[i]);
+ iupArrayDestroy(ih->data->formattags);
+ ih->data->formattags = NULL;
+}
+
+static void iTextUpdateValueAttrib(Ihandle* ih)
+{
+ char* value = iupAttribGet(ih, "VALUE");
+ if (value)
+ {
+ int inherit;
+ iupClassObjectSetAttribute(ih, "VALUE", value, &inherit);
+
+ iupAttribSetStr(ih, "VALUE", NULL); /* clear hash table */
+ }
+}
+
+char* iupTextGetNCAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(100);
+ sprintf(str, "%d", ih->data->nc);
+ return str;
+}
+
+void iupTextUpdateFormatTags(Ihandle* ih)
+{
+ /* called when the element is mapped */
+ int i, count = iupArrayCount(ih->data->formattags);
+ Ihandle** tag_array = (Ihandle**)iupArrayGetData(ih->data->formattags);
+
+ /* must update VALUE before updating the format */
+ iTextUpdateValueAttrib(ih);
+
+ for (i = 0; i < count; i++)
+ {
+ iupdrvTextAddFormatTag(ih, tag_array[i]);
+ IupDestroy(tag_array[i]);
+ }
+ iupArrayDestroy(ih->data->formattags);
+ ih->data->formattags = NULL;
+}
+
+int iupTextSetAddFormatTagHandleAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle* formattag = (Ihandle*)value;
+ if (!iupObjectCheck(formattag))
+ return 0;
+
+ if (ih->handle)
+ {
+ /* must update VALUE before updating the format */
+ iTextUpdateValueAttrib(ih);
+
+ iupdrvTextAddFormatTag(ih, formattag);
+ IupDestroy(formattag);
+ }
+ else
+ {
+ Ihandle** tag_array;
+ int i;
+
+ if (!ih->data->formattags)
+ ih->data->formattags = iupArrayCreate(10, sizeof(Ihandle*));
+
+ i = iupArrayCount(ih->data->formattags);
+ tag_array = (Ihandle**)iupArrayInc(ih->data->formattags);
+ tag_array[i] = formattag;
+ }
+ return 0;
+}
+
+int iupTextSetAddFormatTagAttrib(Ihandle* ih, const char* value)
+{
+ return iupTextSetAddFormatTagHandleAttrib(ih, (char*)IupGetHandle(value));
+}
+
+static char* iTextGetMaskDataAttrib(Ihandle* ih)
+{
+ /* Used only by the OLD iupmask API */
+ return (char*)ih->data->mask;
+}
+
+static char* iTextGetMaskAttrib(Ihandle* ih)
+{
+ if (ih->data->mask)
+ return iupMaskGetStr(ih->data->mask);
+ else
+ return NULL;
+}
+
+static int iTextSetMaskAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ if (ih->data->mask)
+ {
+ iupMaskDestroy(ih->data->mask);
+ ih->data->mask = NULL;
+ }
+ }
+ else
+ {
+ int casei = iupAttribGetInt(ih, "MASKCASEI");
+ Imask* mask = iupMaskCreate(value,casei);
+ if (mask)
+ {
+ if (ih->data->mask)
+ iupMaskDestroy(ih->data->mask);
+
+ ih->data->mask = mask;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int iTextSetMaskIntAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ if (ih->data->mask)
+ {
+ iupMaskDestroy(ih->data->mask);
+ ih->data->mask = NULL;
+ }
+ }
+ else
+ {
+ Imask* mask;
+ int min, max;
+
+ if (iupStrToIntInt(value, &min, &max, ':')!=2)
+ return 0;
+
+ mask = iupMaskCreateInt(min,max);
+
+ if (ih->data->mask)
+ iupMaskDestroy(ih->data->mask);
+
+ ih->data->mask = mask;
+ }
+
+ return 0;
+}
+
+static int iTextSetMaskFloatAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ if (ih->data->mask)
+ {
+ iupMaskDestroy(ih->data->mask);
+ ih->data->mask = NULL;
+ }
+ }
+ else
+ {
+ Imask* mask;
+ float min, max;
+
+ if (iupStrToFloatFloat(value, &min, &max, ':')!=2)
+ return 0;
+
+ mask = iupMaskCreateFloat(min,max);
+
+ if (ih->data->mask)
+ iupMaskDestroy(ih->data->mask);
+
+ ih->data->mask = mask;
+ }
+
+ return 0;
+}
+
+static int iTextSetMultilineAttrib(Ihandle* ih, const char* value)
+{
+ /* valid only before map */
+ if (ih->handle)
+ return 0;
+
+ if (iupStrBoolean(value))
+ {
+ ih->data->is_multiline = 1;
+ ih->data->sb = IUP_SB_HORIZ | IUP_SB_VERT; /* reset SCROLLBAR to YES */
+ }
+ else
+ ih->data->is_multiline = 0;
+
+ return 0;
+}
+
+static char* iTextGetMultilineAttrib(Ihandle* ih)
+{
+ if (ih->data->is_multiline)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iTextSetAppendNewlineAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ ih->data->append_newline = 1;
+ else
+ ih->data->append_newline = 0;
+ return 0;
+}
+
+static char* iTextGetAppendNewlineAttrib(Ihandle* ih)
+{
+ if (ih->data->append_newline)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iTextSetScrollbarAttrib(Ihandle* ih, const char* value)
+{
+ /* valid only before map */
+ if (ih->handle || !ih->data->is_multiline)
+ return 0;
+
+ if (!value)
+ value = "YES"; /* default, if multiline, is YES */
+
+ if (iupStrEqualNoCase(value, "YES"))
+ ih->data->sb = IUP_SB_HORIZ | IUP_SB_VERT;
+ else if (iupStrEqualNoCase(value, "HORIZONTAL"))
+ ih->data->sb = IUP_SB_HORIZ;
+ else if (iupStrEqualNoCase(value, "VERTICAL"))
+ ih->data->sb = IUP_SB_VERT;
+ else
+ ih->data->sb = IUP_SB_NONE;
+
+ return 0;
+}
+
+static char* iTextGetScrollbarAttrib(Ihandle* ih)
+{
+ if (ih->data->sb == (IUP_SB_HORIZ | IUP_SB_VERT))
+ return "YES";
+ if (ih->data->sb &= IUP_SB_HORIZ)
+ return "HORIZONTAL";
+ if (ih->data->sb == IUP_SB_VERT)
+ return "VERTICAL";
+ return "NO"; /* IUP_SB_NONE */
+}
+
+char* iupTextGetPaddingAttrib(Ihandle* ih)
+{
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding);
+ return str;
+}
+
+
+/********************************************************************/
+
+
+static int iTextCreateMethod(Ihandle* ih, void** params)
+{
+ if (params)
+ {
+ if (params[0]) iupAttribStoreStr(ih, "ACTION", (char*)(params[0]));
+ }
+ ih->data = iupALLOCCTRLDATA();
+ ih->data->append_newline = 1;
+ return IUP_NOERROR;
+}
+
+static int iMultilineCreateMethod(Ihandle* ih, void** params)
+{
+ iTextCreateMethod(ih, params);
+ ih->data->is_multiline = 1;
+ ih->data->sb = IUP_SB_HORIZ | IUP_SB_VERT;
+ return IUP_NOERROR;
+}
+
+static void iTextComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ int natural_w = 0,
+ natural_h = 0,
+ visiblecolumns = iupAttribGetInt(ih, "VISIBLECOLUMNS"),
+ visiblelines = iupAttribGetInt(ih, "VISIBLELINES");
+ (void)expand; /* unset if not a container */
+
+ /* Since the contents can be changed by the user, the size can not be dependent on it. */
+ if (ih->data->is_multiline)
+ {
+ iupdrvFontGetCharSize(ih, NULL, &natural_h); /* one line height */
+ natural_w = iupdrvFontGetStringWidth(ih, "WWWWWWWWWW");
+ natural_w = (visiblecolumns*natural_w)/10;
+ natural_h = visiblelines*natural_h;
+ }
+ else
+ {
+ iupdrvFontGetCharSize(ih, NULL, &natural_h); /* one line height */
+ natural_w = iupdrvFontGetStringWidth(ih, "WWWWWWWWWW");
+ natural_w = (visiblecolumns*natural_w)/10;
+ }
+
+ /* compute the borders space */
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ iupdrvTextAddBorders(&natural_w, &natural_h);
+
+ if (iupAttribGetBoolean(ih, "SPIN"))
+ iupdrvTextAddSpin(&natural_w, natural_h);
+
+ natural_w += 2*ih->data->horiz_padding;
+ natural_h += 2*ih->data->vert_padding;
+
+ /* add scrollbar */
+ if (ih->data->is_multiline && ih->data->sb)
+ {
+ int sb_size = iupdrvGetScrollbarSize();
+ if (ih->data->sb & IUP_SB_HORIZ)
+ natural_w += sb_size;
+ if (ih->data->sb & IUP_SB_VERT)
+ natural_h += sb_size;
+ }
+
+ *w = natural_w;
+ *h = natural_h;
+}
+
+static void iTextDestroyMethod(Ihandle* ih)
+{
+ if (ih->data->formattags)
+ iTextDestroyFormatTags(ih);
+ if (ih->data->mask)
+ iupMaskDestroy(ih->data->mask);
+}
+
+
+/******************************************************************************/
+
+
+void IupTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+
+ if (!ih->handle)
+ return;
+
+ if (iupStrEqual(ih->iclass->name, "text") ||
+ iupStrEqual(ih->iclass->name, "multiline"))
+ {
+ if (ih->data->is_multiline)
+ iupdrvTextConvertLinColToPos(ih, lin, col, pos);
+ else
+ *pos = col - 1; /* IUP starts at 1 */
+ }
+}
+
+void IupTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col)
+{
+ iupASSERT(iupObjectCheck(ih));
+ if (!iupObjectCheck(ih))
+ return;
+
+ if (!ih->handle)
+ return;
+
+ if (iupStrEqual(ih->iclass->name, "text") ||
+ iupStrEqual(ih->iclass->name, "multiline"))
+ {
+ if (ih->data->is_multiline)
+ iupdrvTextConvertPosToLinCol(ih, pos, lin, col);
+ else
+ {
+ *col = pos + 1; /* IUP starts at 1 */
+ *lin = 1;
+ }
+ }
+}
+
+Ihandle* IupText(const char* action)
+{
+ void *params[2];
+ params[0] = (void*)action;
+ params[1] = NULL;
+ return IupCreatev("text", params);
+}
+
+Ihandle* IupMultiLine(const char* action)
+{
+ void *params[2];
+ params[0] = (void*)action;
+ params[1] = NULL;
+ return IupCreatev("multiline", params);
+}
+
+Iclass* iupTextGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "text";
+ ic->format = "A"; /* one optional callback name */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 1;
+
+ /* Class functions */
+ ic->Create = iTextCreateMethod;
+ ic->Destroy = iTextDestroyMethod;
+ ic->ComputeNaturalSize = iTextComputeNaturalSizeMethod;
+ ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "CARET_CB", "iii");
+ iupClassRegisterCallback(ic, "ACTION", "is");
+ iupClassRegisterCallback(ic, "DROPFILES_CB", "siii");
+ iupClassRegisterCallback(ic, "BUTTON_CB", "iiiis");
+ iupClassRegisterCallback(ic, "MOTION_CB", "iis");
+ iupClassRegisterCallback(ic, "SPIN_CB", "i");
+ iupClassRegisterCallback(ic, "VALUECHANGED_CB", "");
+
+
+ /* Common Callbacks */
+ iupBaseRegisterCommonCallbacks(ic);
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Visual */
+ iupBaseRegisterVisualAttrib(ic);
+
+ /* IupText only */
+ iupClassRegisterAttribute(ic, "SCROLLBAR", iTextGetScrollbarAttrib, iTextSetScrollbarAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MULTILINE", iTextGetMultilineAttrib, iTextSetMultilineAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPENDNEWLINE", iTextGetAppendNewlineAttrib, iTextSetAppendNewlineAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "MASKCASEI", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MASK", iTextGetMaskAttrib, iTextSetMaskAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MASKINT", NULL, iTextSetMaskIntAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MASKFLOAT", NULL, iTextSetMaskFloatAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "OLD_MASK_DATA", iTextGetMaskDataAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "BORDER", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPIN", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINALIGN", NULL, NULL, IUPAF_SAMEASSYSTEM, "RIGHT", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINAUTO", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINWRAP", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VISIBLECOLUMNS", NULL, NULL, IUPAF_SAMEASSYSTEM, "5", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VISIBLELINES", NULL, NULL, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "WORDWRAP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
+
+ iupdrvTextInitClass(ic);
+
+ return ic;
+}
+
+Iclass* iupMultilineGetClass(void)
+{
+ Iclass* ic = iupTextGetClass();
+ ic->Create = iMultilineCreateMethod;
+ ic->name = "multiline"; /* register the multiline name, so LED will work */
+ return ic;
+}
diff --git a/iup/src/iup_text.h b/iup/src/iup_text.h
new file mode 100755
index 0000000..e018961
--- /dev/null
+++ b/iup/src/iup_text.h
@@ -0,0 +1,48 @@
+/** \file
+ * \brief Text Controls Private Declarations
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_TEXT_H
+#define __IUP_TEXT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void iupdrvTextInitClass(Iclass* ic);
+void iupdrvTextAddBorders(int *w, int *h);
+void iupdrvTextAddSpin(int *w, int h);
+void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag);
+void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos);
+void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col);
+
+void iupTextUpdateFormatTags(Ihandle* ih);
+char* iupTextGetPaddingAttrib(Ihandle* ih);
+char* iupTextGetNCAttrib(Ihandle* ih);
+int iupTextSetFormattingAttrib(Ihandle* ih, const char* value);
+char* iupTextGetFormattingAttrib(Ihandle* ih);
+int iupTextSetAddFormatTagAttrib(Ihandle* ih, const char* value);
+int iupTextSetAddFormatTagHandleAttrib(Ihandle* ih, const char* value);
+
+struct _IcontrolData
+{
+ int is_multiline,
+ has_formatting,
+ append_newline,
+ nc,
+ sb, /* scrollbar configuration, can be changed only before map */
+ horiz_padding, vert_padding, /* button margin */
+ last_caret_pos;
+ Iarray* formattags;
+ Imask* mask;
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_timer.c b/iup/src/iup_timer.c
new file mode 100755
index 0000000..9a003b4
--- /dev/null
+++ b/iup/src/iup_timer.c
@@ -0,0 +1,80 @@
+/** \file
+ * \brief Timer Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_str.h"
+#include "iup_stdcontrols.h"
+#include "iup_timer.h"
+
+
+static int iTimerSetRunAttrib(Ihandle *ih, const char *value)
+{
+ if (iupStrBoolean(value))
+ iupdrvTimerRun(ih);
+ else
+ iupdrvTimerStop(ih);
+
+ return 0;
+}
+
+static char* iTimerGetRunAttrib(Ihandle *ih)
+{
+ if (ih->serial > 0)
+ return "YES";
+ else
+ return "NO";
+}
+
+static char* iTimerGetWidAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(50);
+ sprintf(str, "%d", ih->serial);
+ return str;
+}
+
+static void iTimerDestroyMethod(Ihandle* ih)
+{
+ iupdrvTimerStop(ih);
+}
+
+/******************************************************************************/
+
+Ihandle* IupTimer(void)
+{
+ return IupCreate("timer");
+}
+
+Iclass* iupTimerGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "timer";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Destroy = iTimerDestroyMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "ACTION_CB", "");
+
+ /* Attribute functions */
+ iupClassRegisterAttribute(ic, "WID", iTimerGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "RUN", iTimerGetRunAttrib, iTimerSetRunAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TIME", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupdrvTimerInitClass(ic);
+
+ return ic;
+}
diff --git a/iup/src/iup_timer.h b/iup/src/iup_timer.h
new file mode 100755
index 0000000..8a61f5f
--- /dev/null
+++ b/iup/src/iup_timer.h
@@ -0,0 +1,24 @@
+/** \file
+ * \brief Timer Resource Private Declarations
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_TIMER_H
+#define __IUP_TIMER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void iupdrvTimerStop(Ihandle* ih);
+void iupdrvTimerRun(Ihandle* ih);
+void iupdrvTimerInitClass(Iclass* ic);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_toggle.c b/iup/src/iup_toggle.c
new file mode 100755
index 0000000..9a09f52
--- /dev/null
+++ b/iup/src/iup_toggle.c
@@ -0,0 +1,140 @@
+/** \file
+ * \brief Toggle Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_toggle.h"
+#include "iup_image.h"
+
+
+static char* iToggleGetRadioAttrib(Ihandle* ih)
+{
+ if (ih->data->radio)
+ return "YES";
+ else
+ return "NO";
+}
+
+char* iupToggleGetPaddingAttrib(Ihandle* ih)
+{
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding);
+ return str;
+}
+
+static int iToggleCreateMethod(Ihandle* ih, void** params)
+{
+ if (params)
+ {
+ if (params[0]) iupAttribStoreStr(ih, "TITLE", (char*)(params[0]));
+ if (params[1]) iupAttribStoreStr(ih, "ACTION", (char*)(params[1]));
+ }
+ ih->data = iupALLOCCTRLDATA();
+ return IUP_NOERROR;
+}
+
+static void iToggleComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ int natural_w = 0,
+ natural_h = 0,
+ type = ih->data->type;
+ (void)expand; /* unset if not a container */
+
+ if (!ih->handle)
+ {
+ /* if not mapped must initialize the internal values */
+ char* value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ type = IUP_TOGGLE_IMAGE;
+ else
+ type = IUP_TOGGLE_TEXT;
+ }
+
+ if (type == IUP_TOGGLE_IMAGE)
+ {
+ iupImageGetInfo(iupAttribGet(ih, "IMAGE"), &natural_w, &natural_h, NULL);
+
+ /* even when IMPRESS is set, must compute the borders space */
+ iupdrvButtonAddBorders(&natural_w, &natural_h);
+
+ natural_w += 2*ih->data->horiz_padding;
+ natural_h += 2*ih->data->vert_padding;
+ }
+ else /* IUP_TOGGLE_TEXT */
+ {
+ /* must use IupGetAttribute to check from the native implementation */
+ char* title = IupGetAttribute(ih, "TITLE");
+ char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */
+ iupdrvFontGetMultiLineStringSize(ih, str, &natural_w, &natural_h);
+ if (str && str!=title) free(str);
+
+ iupdrvToggleAddCheckBox(&natural_w, &natural_h);
+ }
+
+ *w = natural_w;
+ *h = natural_h;
+}
+
+
+/******************************************************************************/
+
+
+Ihandle* IupToggle(const char* title, const char* action)
+{
+ void *params[3];
+ params[0] = (void*)title;
+ params[1] = (void*)action;
+ params[2] = NULL;
+ return IupCreatev("toggle", params);
+}
+
+Iclass* iupToggleGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "toggle";
+ ic->format = "SA"; /* one optional string and one optional callback name */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 1;
+
+ /* Class functions */
+ ic->Create = iToggleCreateMethod;
+ ic->ComputeNaturalSize = iToggleComputeNaturalSizeMethod;
+ ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "ACTION", "i");
+ iupClassRegisterCallback(ic, "VALUECHANGED_CB", "");
+
+ /* Common Callbacks */
+ iupBaseRegisterCommonCallbacks(ic);
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Visual */
+ iupBaseRegisterVisualAttrib(ic);
+
+ iupClassRegisterAttribute(ic, "RADIO", iToggleGetRadioAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "3STATE", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ iupdrvToggleInitClass(ic);
+
+ return ic;
+}
diff --git a/iup/src/iup_toggle.h b/iup/src/iup_toggle.h
new file mode 100755
index 0000000..08e14b0
--- /dev/null
+++ b/iup/src/iup_toggle.h
@@ -0,0 +1,37 @@
+/** \file
+ * \brief Toggle Controls Private Declarations
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_TOGGLE_H
+#define __IUP_TOGGLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void iupdrvButtonAddBorders(int *x, int *y); /* reuse button borders */
+
+void iupdrvToggleInitClass(Iclass* ic);
+void iupdrvToggleAddCheckBox(int *x, int *y);
+
+Ihandle *iupRadioFindToggleParent(Ihandle* ih_toggle);
+char* iupToggleGetPaddingAttrib(Ihandle* ih);
+
+enum {IUP_TOGGLE_IMAGE, IUP_TOGGLE_TEXT};
+
+struct _IcontrolData
+{
+ int type, /* the 2 toggle possibilities */
+ radio,
+ horiz_padding, vert_padding; /* toggle margin for images */
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_tree.c b/iup/src/iup_tree.c
new file mode 100755
index 0000000..c06e573
--- /dev/null
+++ b/iup/src/iup_tree.c
@@ -0,0 +1,499 @@
+/** \file
+ * \brief Tree control
+ *
+ * See Copyright Notice in iup.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_tree.h"
+#include "iup_assert.h"
+
+
+#define ITREE_IMG_WIDTH 16
+#define ITREE_IMG_HEIGHT 16
+
+static void iTreeInitializeImages(void)
+{
+ Ihandle *image_leaf, *image_blank, *image_paper;
+ Ihandle *image_collapsed, *image_expanded;
+
+ unsigned char img_leaf[ITREE_IMG_WIDTH*ITREE_IMG_HEIGHT] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 4, 4, 5, 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 4, 5, 5, 1, 6, 1, 5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 3, 4, 4, 5, 5, 1, 6, 1, 5, 0, 0, 0, 0,
+ 0, 0, 0, 3, 4, 4, 4, 5, 5, 1, 1, 5, 0, 0, 0, 0,
+ 0, 0, 0, 2, 3, 4, 4, 4, 5, 5, 5, 4, 0, 0, 0, 0,
+ 0, 0, 0, 2, 3, 3, 4, 4, 4, 5, 4, 4, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 3, 3, 4, 4, 4, 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ unsigned char img_collapsed[ITREE_IMG_WIDTH*ITREE_IMG_HEIGHT] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 2, 6, 5, 5, 7, 7, 2, 3, 0, 0, 0, 0, 0, 0, 0,
+ 2, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0, 0,
+ 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 4, 3, 0,
+ 2, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 4, 3, 0,
+ 2, 5, 7, 7, 7, 7, 7, 7, 7, 1, 7, 1, 7, 4, 3, 0,
+ 2, 5, 7, 7, 7, 7, 7, 7, 7, 7, 1, 7, 1, 4, 3, 0,
+ 2, 5, 7, 7, 7, 7, 7, 1, 7, 1, 7, 1, 7, 4, 3, 0,
+ 2, 5, 7, 7, 7, 7, 7, 7, 1, 7, 1, 7, 1, 4, 3, 0,
+ 2, 5, 7, 7, 7, 1, 7, 1, 7, 1, 7, 1, 1, 4, 3, 0,
+ 2, 5, 1, 7, 1, 7, 1, 7, 1, 7, 1, 1, 1, 4, 3, 0,
+ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ unsigned char img_expanded[ITREE_IMG_WIDTH*ITREE_IMG_HEIGHT] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 2, 1, 3, 3, 3, 3, 3, 1, 2, 2, 2, 2, 2, 2, 0,
+ 0, 2, 1, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 6, 4,
+ 0, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 4,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 3, 6, 4,
+ 2, 1, 3, 3, 3, 3, 3, 3, 5, 3, 5, 6, 4, 6, 6, 4,
+ 2, 1, 3, 3, 3, 3, 5, 3, 3, 5, 3, 6, 4, 6, 6, 4,
+ 0, 2, 0, 3, 3, 3, 3, 3, 5, 3, 5, 5, 2, 4, 2, 4,
+ 0, 2, 0, 3, 3, 5, 3, 5, 3, 5, 5, 5, 6, 4, 2, 4,
+ 0, 0, 2, 0, 5, 3, 5, 3, 5, 5, 5, 5, 6, 2, 4, 4,
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4,
+ 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ unsigned char img_blank[ITREE_IMG_WIDTH*ITREE_IMG_HEIGHT] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 0, 0, 0, 0,
+ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 5, 4, 0, 0, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 4, 0, 0,
+ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 0,
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0
+ };
+
+ unsigned char img_paper[ITREE_IMG_WIDTH*ITREE_IMG_HEIGHT] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 0, 0, 0, 0,
+ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 5, 4, 0, 0, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 4, 0, 0,
+ 0, 0, 3, 1, 4, 3, 4, 3, 4, 3, 4, 2, 2, 2, 2, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 3, 1, 3, 4, 3, 4, 3, 4, 3, 4, 1, 5, 2, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 3, 1, 4, 3, 4, 3, 4, 3, 4, 3, 1, 5, 2, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 3, 1, 3, 4, 3, 4, 3, 4, 3, 4, 1, 5, 2, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 3, 1, 4, 3, 4, 3, 4, 3, 4, 3, 1, 5, 2, 0,
+ 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0,
+ 0, 0, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 0,
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0
+ };
+
+ image_leaf = IupImage(ITREE_IMG_WIDTH, ITREE_IMG_HEIGHT, img_leaf);
+ image_collapsed = IupImage(ITREE_IMG_WIDTH, ITREE_IMG_HEIGHT, img_collapsed);
+ image_expanded = IupImage(ITREE_IMG_WIDTH, ITREE_IMG_HEIGHT, img_expanded);
+ image_blank = IupImage(ITREE_IMG_WIDTH, ITREE_IMG_HEIGHT, img_blank);
+ image_paper = IupImage(ITREE_IMG_WIDTH, ITREE_IMG_HEIGHT, img_paper);
+
+ IupSetAttribute(image_leaf, "0", "BGCOLOR");
+ IupSetAttribute(image_leaf, "1", "192 192 192");
+ IupSetAttribute(image_leaf, "2", "56 56 56");
+ IupSetAttribute(image_leaf, "3", "99 99 99");
+ IupSetAttribute(image_leaf, "4", "128 128 128");
+ IupSetAttribute(image_leaf, "5", "161 161 161");
+ IupSetAttribute(image_leaf, "6", "222 222 222");
+
+ IupSetAttribute(image_collapsed, "0", "BGCOLOR");
+ IupSetAttribute(image_collapsed, "1", "255 206 156");
+ IupSetAttribute(image_collapsed, "2", "156 156 0");
+ IupSetAttribute(image_collapsed, "3", "0 0 0");
+ IupSetAttribute(image_collapsed, "4", "206 206 99");
+ IupSetAttribute(image_collapsed, "5", "255 255 206");
+ IupSetAttribute(image_collapsed, "6", "247 247 247");
+ IupSetAttribute(image_collapsed, "7", "255 255 156");
+
+ IupSetAttribute(image_expanded, "0", "BGCOLOR");
+ IupSetAttribute(image_expanded, "1", "255 255 255");
+ IupSetAttribute(image_expanded, "2", "156 156 0");
+ IupSetAttribute(image_expanded, "3", "255 255 156");
+ IupSetAttribute(image_expanded, "4", "0 0 0");
+ IupSetAttribute(image_expanded, "5", "255 206 156");
+ IupSetAttribute(image_expanded, "6", "206 206 99");
+
+ IupSetAttribute(image_blank, "0", "BGCOLOR");
+ IupSetAttribute(image_blank, "1", "255 255 255");
+ IupSetAttribute(image_blank, "2", "000 000 000");
+ IupSetAttribute(image_blank, "3", "119 119 119");
+ IupSetAttribute(image_blank, "4", "136 136 136");
+ IupSetAttribute(image_blank, "5", "187 187 187");
+
+ IupSetAttribute(image_paper, "0", "BGCOLOR");
+ IupSetAttribute(image_paper, "1", "255 255 255");
+ IupSetAttribute(image_paper, "2", "000 000 000");
+ IupSetAttribute(image_paper, "3", "119 119 119");
+ IupSetAttribute(image_paper, "4", "136 136 136");
+ IupSetAttribute(image_paper, "5", "187 187 187");
+
+ IupSetHandle("IMGLEAF", image_leaf);
+ IupSetHandle("IMGCOLLAPSED", image_collapsed);
+ IupSetHandle("IMGEXPANDED", image_expanded);
+ IupSetHandle("IMGBLANK", image_blank);
+ IupSetHandle("IMGPAPER", image_paper);
+}
+
+void iupTreeUpdateImages(Ihandle *ih)
+{
+ int inherit;
+
+ char* value = iupAttribGet(ih, "IMAGELEAF");
+ if (!value) value = "IMGLEAF";
+ iupClassObjectSetAttribute(ih, "IMAGELEAF", value, &inherit);
+
+ value = iupAttribGet(ih, "IMAGEBRANCHCOLLAPSED");
+ if (!value) value = "IMGCOLLAPSED";
+ iupClassObjectSetAttribute(ih, "IMAGEBRANCHCOLLAPSED", value, &inherit);
+
+ value = iupAttribGet(ih, "IMAGEBRANCHEXPANDED");
+ if (!value) value = "IMGEXPANDED";
+ iupClassObjectSetAttribute(ih, "IMAGEBRANCHEXPANDED", value, &inherit);
+}
+
+char* iupTreeGetSpacingAttrib(Ihandle* ih)
+{
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%d", ih->data->spacing);
+ return str;
+}
+
+static char* iTreeGetMarkModeAttrib(Ihandle* ih)
+{
+ if (ih->data->mark_mode==ITREE_MARK_SINGLE)
+ return "SINGLE";
+ else
+ return "MULTIPLE";
+}
+
+static int iTreeSetMarkModeAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrEqualNoCase(value, "MULTIPLE"))
+ ih->data->mark_mode = ITREE_MARK_MULTIPLE;
+ else
+ ih->data->mark_mode = ITREE_MARK_SINGLE;
+ if (ih->handle)
+ iupdrvTreeUpdateMarkMode(ih);
+ return 0;
+}
+
+static int iTreeSetShiftAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value) && iupAttribGetBoolean(ih, "CTRL"))
+ iTreeSetMarkModeAttrib(ih, "MULTIPLE");
+ else
+ iTreeSetMarkModeAttrib(ih, "SINGLE");
+ return 1;
+}
+
+static int iTreeSetCtrlAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value) && iupAttribGetBoolean(ih, "SHIFT"))
+ iTreeSetMarkModeAttrib(ih, "MULTIPLE");
+ else
+ iTreeSetMarkModeAttrib(ih, "SINGLE");
+ return 1;
+}
+
+static char* iTreeGetShowRenameAttrib(Ihandle* ih)
+{
+ if (ih->data->show_rename)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iTreeSetShowRenameAttrib(Ihandle* ih, const char* value)
+{
+ /* valid only before map */
+ if (ih->handle)
+ return 0;
+
+ if (iupStrBoolean(value))
+ ih->data->show_rename = 1;
+ else
+ ih->data->show_rename = 0;
+
+ return 0;
+}
+
+static char* iTreeGetShowDragDropAttrib(Ihandle* ih)
+{
+ if (ih->data->show_dragdrop)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iTreeSetShowDragDropAttrib(Ihandle* ih, const char* value)
+{
+ /* valid only before map */
+ if (ih->handle)
+ return 0;
+
+ if (iupStrBoolean(value))
+ ih->data->show_dragdrop = 1;
+ else
+ ih->data->show_dragdrop = 0;
+
+ return 0;
+}
+
+static int iTreeSetAddLeafAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ iupdrvTreeAddNode(ih, name_id, ITREE_LEAF, value, 1);
+ return 0;
+}
+
+static int iTreeSetAddBranchAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ iupdrvTreeAddNode(ih, name_id, ITREE_BRANCH, value, 1);
+ return 0;
+}
+
+static int iTreeSetInsertLeafAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ iupdrvTreeAddNode(ih, name_id, ITREE_LEAF, value, 0);
+ return 0;
+}
+
+static int iTreeSetInsertBranchAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ iupdrvTreeAddNode(ih, name_id, ITREE_BRANCH, value, 0);
+ return 0;
+}
+
+static char* iTreeGetAddExpandedAttrib(Ihandle* ih)
+{
+ if (ih->data->add_expanded)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iTreeSetAddExpandedAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ ih->data->add_expanded = 1;
+ else
+ ih->data->add_expanded = 0;
+
+ return 0;
+}
+
+static int iTreeCreateMethod(Ihandle* ih, void **params)
+{
+ (void)params;
+
+ ih->data = iupALLOCCTRLDATA();
+
+ IupSetAttribute(ih, "RASTERSIZE", "400x200");
+ IupSetAttribute(ih, "EXPAND", "YES");
+
+ ih->data->add_expanded = 1;
+
+ return IUP_NOERROR;
+}
+
+Ihandle* IupTree(void)
+{
+ return IupCreate("tree");
+}
+
+Iclass* iupTreeGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "tree";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 1;
+ ic->has_attrib_id = 1; /* has attributes with IDs that must be parsed */
+
+ /* Class functions */
+ ic->Create = iTreeCreateMethod;
+ ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "SELECTION_CB", "ii");
+ iupClassRegisterCallback(ic, "MULTISELECTION_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");
+ iupClassRegisterCallback(ic, "RIGHTCLICK_CB", "i");
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Visual */
+ 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);
+
+ /* IupTree Attributes - MARKS */
+ iupClassRegisterAttribute(ic, "CTRL", NULL, iTreeSetCtrlAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "SHIFT", NULL, iTreeSetShiftAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "MARKMODE", iTreeGetMarkModeAttrib, iTreeSetMarkModeAttrib, IUPAF_SAMEASSYSTEM, "SINGLE", IUPAF_NOT_MAPPED);
+
+ /* IupTree Attributes - ACTION */
+ iupClassRegisterAttributeId(ic, "ADDLEAF", NULL, iTreeSetAddLeafAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ 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);
+
+ /* Default node images */
+ iTreeInitializeImages();
+
+ iupdrvTreeInitClass(ic);
+
+ return ic;
+}
+
+
+/********************************************************************************************/
+
+
+void IupTreeSetAttribute(Ihandle* ih, const char* a, int id, 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)
+{
+ char* attr = iupStrGetMemory(50);
+ sprintf(attr, "%s%d", a, id);
+ IupStoreAttribute(ih, attr, v);
+}
+
+char* IupTreeGetAttribute(Ihandle* ih, const char* a, int id)
+{
+ char* attr = iupStrGetMemory(50);
+ sprintf(attr, "%s%d", a, id);
+ return IupGetAttribute(ih, attr);
+}
+
+int IupTreeGetInt(Ihandle* ih, const char* a, int id)
+{
+ char* attr = iupStrGetMemory(50);
+ sprintf(attr, "%s%d", a, id);
+ return IupGetInt(ih, attr);
+}
+
+float IupTreeGetFloat(Ihandle* ih, const char* a, int id)
+{
+ char* attr = iupStrGetMemory(50);
+ sprintf(attr, "%s%d", a, id);
+ return IupGetFloat(ih, attr);
+}
+
+void IupTreeSetfAttribute(Ihandle* ih, const char* a, int id, char* f, ...)
+{
+ static char v[SHRT_MAX];
+ char* attr = iupStrGetMemory(50);
+ va_list arglist;
+ sprintf(attr, "%s%d", a, id);
+ va_start(arglist, f);
+ vsprintf(v, f, arglist);
+ va_end(arglist);
+ 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;
+}
+
+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;
+
+ iupStrToInt(value, &id);
+ return id;
+}
+
+void* IupTreeGetUserId(Ihandle* ih, int id)
+{
+ char attr[30];
+ sprintf(attr,"USERDATA%d",id);
+ return IupGetAttribute(ih, attr);
+}
diff --git a/iup/src/iup_tree.h b/iup/src/iup_tree.h
new file mode 100755
index 0000000..f96a698
--- /dev/null
+++ b/iup/src/iup_tree.h
@@ -0,0 +1,57 @@
+/** \file
+ * \brief iuptree control internal definitions.
+ *
+ * See Copyright Notice in iup.h
+ */
+
+#ifndef __IUP_TREE_H
+#define __IUP_TREE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Kinds of node */
+#define ITREE_BRANCH 0
+#define ITREE_LEAF 1
+
+#define ITREE_MARK_SINGLE 0
+#define ITREE_MARK_MULTIPLE 1
+
+#define ITREE_UPDATEIMAGE_LEAF 1
+#define ITREE_UPDATEIMAGE_COLLAPSED 2
+#define ITREE_UPDATEIMAGE_EXPANDED 3
+
+void iupdrvTreeInitClass(Iclass* ic);
+void iupTreeUpdateImages(Ihandle *ih);
+void iupdrvTreeAddNode(Ihandle* ih, const char* id_string, int kind, const char* title, int add);
+void iupdrvTreeUpdateMarkMode(Ihandle *ih);
+
+char* iupTreeGetSpacingAttrib(Ihandle* ih);
+
+/* Structure of the tree */
+struct _IcontrolData
+{
+ int mark_mode,
+ add_expanded,
+ show_dragdrop,
+ show_rename,
+ spacing;
+
+ void* def_image_leaf; /* Default image leaf */
+ void* def_image_collapsed; /* Default image collapsed */
+ void* def_image_expanded; /* Default image expanded */
+
+ void* def_image_leaf_mask; /* Motif Only */
+ void* def_image_collapsed_mask;
+ void* def_image_expanded_mask;
+
+ int id_control; /* auxiliary variable for computing or finding the id of a node */
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_user.c b/iup/src/iup_user.c
new file mode 100755
index 0000000..842f436
--- /dev/null
+++ b/iup/src/iup_user.c
@@ -0,0 +1,41 @@
+/** \file
+ * \brief User Element.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_stdcontrols.h"
+
+
+static int iUserSetClearAttributesAttrib(Ihandle* ih, const char* value)
+{
+ (void)value;
+ iupTableClear(ih->attrib);
+ return 0;
+}
+
+Ihandle* IupUser(void)
+{
+ return IupCreate("user");
+}
+
+Iclass* iupUserGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "user";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPEVOID;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ iupClassRegisterAttribute(ic, "CLEARATTRIBUTES", NULL, iUserSetClearAttributesAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
diff --git a/iup/src/iup_val.c b/iup/src/iup_val.c
new file mode 100755
index 0000000..521e35a
--- /dev/null
+++ b/iup/src/iup_val.c
@@ -0,0 +1,209 @@
+/** \file
+ * \brief Valuator Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+#include "iupkey.h"
+#include "iupcontrols.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_val.h"
+
+
+void iupValCropValue(Ihandle* ih)
+{
+ if (ih->data->val > ih->data->vmax)
+ ih->data->val = ih->data->vmax;
+ else if (ih->data->val < ih->data->vmin)
+ ih->data->val = ih->data->vmin;
+}
+
+char* iupValGetShowTicksAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(30);
+ sprintf(str, "%d", ih->data->show_ticks);
+ return str;
+}
+
+char* iupValGetValueAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(30);
+ sprintf(str, "%g", ih->data->val);
+ return str;
+}
+
+char* iupValGetStepAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(30);
+ sprintf(str, "%g", ih->data->step);
+ return str;
+}
+
+char* iupValGetPageStepAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(30);
+ sprintf(str, "%g", ih->data->pagestep);
+ return str;
+}
+
+static int iValSetMaxAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->vmax = atof(value);
+ iupValCropValue(ih);
+ return 0; /* do not store value in hash table */
+}
+
+static char* iValGetMaxAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(30);
+ sprintf(str, "%g", ih->data->vmax);
+ return str;
+}
+
+static int iValSetMinAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->vmin = atof(value);
+ iupValCropValue(ih);
+ return 0; /* do not store value in hash table */
+}
+
+static char* iValGetMinAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(30);
+ sprintf(str, "%g", ih->data->vmin);
+ return str;
+}
+
+static int iValSetTypeAttrib(Ihandle* ih, const char *value)
+{
+ int min_w, min_h;
+
+ /* valid only before map */
+ if (ih->handle)
+ return 0;
+
+ iupdrvValGetMinSize(ih, &min_w, &min_h);
+
+ if (iupStrEqualNoCase(value, "VERTICAL"))
+ {
+ /* val natural vertical size is MinWx100 */
+ IupSetfAttribute(ih, "RASTERSIZE", "%dx%d", min_w, 100);
+ ih->data->type = IVAL_VERTICAL;
+ }
+ else /* "HORIZONTAL" */
+ {
+ /* val natural horizontal size is 100xMinH */
+ IupSetfAttribute(ih, "RASTERSIZE", "%dx%d", 100, min_h);
+ ih->data->type = IVAL_HORIZONTAL;
+ }
+
+ return 0; /* do not store value in hash table */
+}
+
+static char* iValGetTypeAttrib(Ihandle* ih)
+{
+ if (ih->data->type == IVAL_HORIZONTAL)
+ return "HORIZONTAL";
+ else /* (ih->data->type == IVAL_VERTICAL) */
+ return "VERTICAL";
+}
+
+static int iValSetInvertedAttrib(Ihandle* ih, const char *value)
+{
+ /* valid only before map */
+ if (ih->handle)
+ return 0;
+
+ if (iupStrBoolean(value))
+ ih->data->inverted = 1;
+ else
+ ih->data->inverted = 0;
+
+ return 0; /* do not store value in hash table */
+}
+
+static char* iValGetInvertedAttrib(Ihandle* ih)
+{
+ if (ih->data->inverted)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int iValCreateMethod(Ihandle* ih, void **params)
+{
+ char* type = "HORIZONTAL";
+ if (params && params[0])
+ type = params[0];
+
+ ih->data = iupALLOCCTRLDATA();
+
+ iValSetTypeAttrib(ih, type);
+ if (ih->data->type == IVAL_VERTICAL)
+ ih->data->inverted = 1; /* default is YES when vertical */
+
+ ih->data->vmax = 1.00;
+ ih->data->step = 0.01;
+ ih->data->pagestep = 0.10;
+
+ return IUP_NOERROR;
+}
+
+Iclass* iupValGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "val";
+ ic->format = "S"; /* one optional string */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 1;
+
+ /* Class functions */
+ ic->Create = iValCreateMethod;
+ ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Callbacks */
+ iupClassRegisterCallback(ic, "VALUECHANGED_CB", "");
+
+ /* Common Callbacks */
+ iupBaseRegisterCommonCallbacks(ic);
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Visual */
+ iupBaseRegisterVisualAttrib(ic);
+
+ /* IupVal only */
+ iupClassRegisterAttribute(ic, "MAX", iValGetMaxAttrib, iValSetMaxAttrib, IUPAF_SAMEASSYSTEM, "1.0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "MIN", iValGetMinAttrib, iValSetMinAttrib, IUPAF_SAMEASSYSTEM, "0.0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "TYPE", iValGetTypeAttrib, iValSetTypeAttrib, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INVERTED", iValGetInvertedAttrib, iValSetInvertedAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ iupdrvValInitClass(ic);
+
+ return ic;
+}
+
+Ihandle *IupVal(const char *type)
+{
+ void *params[2];
+ params[0] = (void*)type;
+ params[1] = NULL;
+ return IupCreatev("val", params);
+}
diff --git a/iup/src/iup_val.h b/iup/src/iup_val.h
new file mode 100755
index 0000000..dea8df4
--- /dev/null
+++ b/iup/src/iup_val.h
@@ -0,0 +1,42 @@
+/** \file
+ * \brief Valuator Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUP_VAL_H
+#define __IUP_VAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {IVAL_VERTICAL, IVAL_HORIZONTAL};
+
+struct _IcontrolData
+{
+ int type;
+ int show_ticks; /* Windows and Motif only - can be used only after map */
+ int inverted;
+ double val;
+ double step;
+ double pagestep;
+ double vmin;
+ double vmax;
+};
+
+void iupValCropValue(Ihandle* ih);
+char* iupValGetValueAttrib(Ihandle* ih);
+char* iupValGetStepAttrib(Ihandle* ih);
+char* iupValGetPageStepAttrib(Ihandle* ih);
+char* iupValGetShowTicksAttrib(Ihandle* ih);
+
+void iupdrvValInitClass(Iclass* ic);
+void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/iup_vbox.c b/iup/src/iup_vbox.c
new file mode 100755
index 0000000..f71aa51
--- /dev/null
+++ b/iup/src/iup_vbox.c
@@ -0,0 +1,311 @@
+/** \file
+ * \brief Vbox Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+#include "iup_box.h"
+
+
+static int iVboxSetRasterSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ ih->userwidth = 0;
+ ih->userheight = 0;
+ }
+ else
+ {
+ int s = 0;
+ iupStrToInt(value, &s);
+ if (s > 0)
+ {
+ ih->userheight = s;
+ ih->userwidth = 0;
+ }
+ }
+ iupAttribSetStr(ih, "SIZE", NULL); /* clear SIZE in hash table */
+ return 0;
+}
+
+static int iVboxSetSizeAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ {
+ ih->userwidth = 0;
+ ih->userheight = 0;
+ }
+ else
+ {
+ int s = 0;
+ iupStrToInt(value, &s);
+ if (s > 0)
+ {
+ int charwidth, charheight;
+ iupdrvFontGetCharSize(ih, &charwidth, &charheight);
+ ih->userheight = iupHEIGHT2RASTER(s, charheight);
+ ih->userwidth = 0;
+ }
+ }
+ return 1;
+}
+
+static int iVboxSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrEqualNoCase(value, "ARIGHT"))
+ ih->data->alignment = IUP_ALIGN_ARIGHT;
+ else if (iupStrEqualNoCase(value, "ACENTER"))
+ ih->data->alignment = IUP_ALIGN_ACENTER;
+ else if (iupStrEqualNoCase(value, "ALEFT"))
+ ih->data->alignment = IUP_ALIGN_ALEFT;
+ return 0;
+}
+
+static char* iVboxGetAlignmentAttrib(Ihandle* ih)
+{
+ char* align2str[3] = {"ALEFT", "ACENTER", "ARIGHT"};
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%s", align2str[ih->data->alignment]);
+ return str;
+}
+
+static void iVboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ Ihandle* child;
+ int children_naturalwidth, children_naturalheight;
+
+ /* calculate total children natural size */
+ int children_expand = 0;
+ int children_count = 0;
+ int children_natural_maxwidth = 0;
+ int children_natural_maxheight = 0;
+ int children_natural_totalheight = 0;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ /* update child natural size first */
+ iupBaseComputeNaturalSize(child);
+
+ if (!child->is_floating)
+ {
+ children_expand |= child->expand;
+ children_natural_maxwidth = iupMAX(children_natural_maxwidth, child->naturalwidth);
+ children_natural_maxheight = iupMAX(children_natural_maxheight, child->naturalheight);
+ children_count++;
+ }
+ }
+
+ /* reset to max natural width and/or height if NORMALIZESIZE is defined */
+ if (ih->data->normalize_size)
+ iupNormalizeSizeBoxChild(ih, ih->data->normalize_size, children_natural_maxwidth, children_natural_maxheight);
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating)
+ children_natural_totalheight += child->naturalheight;
+ }
+
+ /* leave room at the element for the maximum natural size of the children when is_homogeneous */
+ if (ih->data->is_homogeneous)
+ children_natural_totalheight = children_natural_maxheight*children_count;
+
+ /* compute the Vbox contents natural size */
+ children_naturalwidth = children_natural_maxwidth + 2*ih->data->margin_x;
+ children_naturalheight = children_natural_totalheight + (children_count-1)*ih->data->gap + 2*ih->data->margin_y;
+
+ /* Store to be used in iVboxCalcEmptyHeight */
+ ih->data->children_naturalsize = children_naturalheight;
+
+ *expand = children_expand;
+ *w = children_naturalwidth;
+ *h = children_naturalheight;
+}
+
+static int iHboxCalcHomogeneousHeight(Ihandle *ih)
+{
+ /* This is the space that the child can be expanded. */
+ Ihandle* child;
+ int homogeneous_height;
+
+ int children_count=0;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating)
+ children_count++;
+ }
+ if (children_count == 0)
+ return 0;
+
+ /* equal spaces for all elements */
+ homogeneous_height = (ih->currentheight - (children_count-1)*ih->data->gap - 2*ih->data->margin_y)/children_count;
+ if (homogeneous_height < 0) homogeneous_height = 0;
+ return homogeneous_height;
+}
+
+static int iVboxCalcEmptyHeight(Ihandle *ih, int expand)
+{
+ /* This is the space that the child can be expanded. */
+ Ihandle* child;
+ int empty_height;
+
+ int expand_count=0;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating && child->expand & expand)
+ expand_count++;
+ }
+ if (expand_count == 0)
+ return 0;
+
+ /* equal spaces for all expandable elements */
+ empty_height = (ih->currentheight - ih->data->children_naturalsize)/expand_count;
+ if (empty_height < 0) empty_height = 0;
+ return empty_height;
+}
+
+static void iVboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink)
+{
+ Ihandle* child;
+ int empty_h0 = 0, empty_h1 = 0, client_width;
+
+ if (ih->data->expand_children)
+ ih->expand |= ih->data->expand_children;
+
+ if (ih->data->is_homogeneous)
+ ih->data->homogeneous_size = iHboxCalcHomogeneousHeight(ih);
+ else
+ {
+ ih->data->homogeneous_size = 0;
+
+ /* must calculate the space left for each control to grow inside the container */
+ /* H1 means there is an EXPAND enabled inside */
+ if (ih->expand & IUP_EXPAND_H1)
+ empty_h1 = iVboxCalcEmptyHeight(ih, IUP_EXPAND_H1);
+ /* Not H1 and H0 means that EXPAND is not enabled, but there are some IupFill inside */
+ else if (ih->expand & IUP_EXPAND_H0)
+ empty_h0 = iVboxCalcEmptyHeight(ih, IUP_EXPAND_H0);
+ }
+
+ client_width = ih->currentwidth - 2*ih->data->margin_x;
+ if (client_width<0) client_width=0;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating)
+ {
+ int old_expand = child->expand;
+ if (ih->data->expand_children)
+ child->expand |= ih->data->expand_children;
+
+ if (ih->data->homogeneous_size)
+ iupBaseSetCurrentSize(child, client_width, ih->data->homogeneous_size, shrink);
+ else
+ {
+ int empty = (child->expand & IUP_EXPAND_H1)? empty_h1: ((child->expand & IUP_EXPAND_H0)? empty_h0: 0);
+ iupBaseSetCurrentSize(child, client_width, child->naturalheight+empty, shrink);
+ }
+
+ if (ih->data->expand_children)
+ child->expand = old_expand;
+ }
+ else
+ {
+ /* update children to their own natural size */
+ iupBaseSetCurrentSize(child, child->naturalwidth, child->naturalheight, shrink);
+ }
+ }
+}
+
+static void iVboxSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ int dx, client_width;
+ Ihandle* child;
+
+ x += ih->data->margin_x;
+ y += ih->data->margin_y;
+
+ client_width = ih->currentwidth - 2*ih->data->margin_x;
+ if (client_width<0) client_width=0;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating)
+ {
+ if (ih->data->alignment == IUP_ALIGN_ACENTER)
+ dx = (client_width - child->currentwidth)/2;
+ else if (ih->data->alignment == IUP_ALIGN_ARIGHT)
+ dx = client_width - child->currentwidth;
+ else /* IUP_ALIGN_ALEFT */
+ dx = 0;
+ if (dx<0) dx = 0;
+
+ /* update child */
+ iupBaseSetPosition(child, x+dx, y);
+
+ /* calculate next */
+ if (ih->data->homogeneous_size)
+ y += ih->data->homogeneous_size + ih->data->gap;
+ else
+ y += child->currentheight + ih->data->gap;
+ }
+ }
+}
+
+
+/******************************************************************************/
+
+
+Ihandle *IupVboxv(Ihandle **children)
+{
+ return IupCreatev("vbox", (void**)children);
+}
+
+Ihandle *IupVbox(Ihandle* child, ...)
+{
+ Ihandle **children;
+ Ihandle *ih;
+
+ va_list arglist;
+ va_start(arglist, child);
+ children = (Ihandle **)iupObjectGetParamList(child, arglist);
+ va_end(arglist);
+
+ ih = IupCreatev("vbox", (void**)children);
+ free(children);
+
+ return ih;
+}
+
+Iclass* iupVboxGetClass(void)
+{
+ Iclass* ic = iupBoxClassBase();
+
+ ic->name = "vbox";
+
+ /* Class functions */
+ ic->ComputeNaturalSize = iVboxComputeNaturalSizeMethod;
+ ic->SetChildrenCurrentSize = iVboxSetChildrenCurrentSizeMethod;
+ ic->SetChildrenPosition = iVboxSetChildrenPositionMethod;
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "SIZE", iupBaseGetSizeAttrib, iVboxSetSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, iVboxSetRasterSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ /* Vbox only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", iVboxGetAlignmentAttrib, iVboxSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
diff --git a/iup/src/iup_zbox.c b/iup/src/iup_zbox.c
new file mode 100755
index 0000000..3f79892
--- /dev/null
+++ b/iup/src/iup_zbox.c
@@ -0,0 +1,375 @@
+/** \file
+ * \brief Zbox Control.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_layout.h"
+
+
+enum{IZBOX_ALIGN_NORTH, IZBOX_ALIGN_SOUTH, IZBOX_ALIGN_WEST, IZBOX_ALIGN_EAST,
+ IZBOX_ALIGN_NE, IZBOX_ALIGN_SE, IZBOX_ALIGN_NW, IZBOX_ALIGN_SW,
+ IZBOX_ALIGN_ACENTER};
+
+struct _IcontrolData
+{
+ int alignment;
+ Ihandle* value_handle;
+};
+
+static int iZboxCreateMethod(Ihandle* ih, void** params)
+{
+ ih->data = iupALLOCCTRLDATA();
+
+ ih->data->alignment = IZBOX_ALIGN_NW;
+
+ if (params)
+ {
+ Ihandle** iparams = (Ihandle**)params;
+ while (*iparams)
+ {
+ IupAppend(ih, *iparams);
+ iparams++;
+ }
+ }
+
+ return IUP_NOERROR;
+}
+
+static void iZboxChildAddedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (!ih->data->value_handle)
+ {
+ IupSetAttribute(child, "VISIBLE", "YES");
+ ih->data->value_handle = child;
+ }
+ else
+ IupSetAttribute(child, "VISIBLE", "NO");
+}
+
+static void iZboxChildRemovedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (child == ih->data->value_handle)
+ {
+ /* reset to the first child, even if it is NULL */
+ if (ih->firstchild)
+ IupSetAttribute(ih->firstchild, "VISIBLE", "YES");
+ ih->data->value_handle = ih->firstchild;
+ }
+}
+
+static int iZboxSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrEqualNoCase(value, "NORTH") || iupStrEqualNoCase(value, "ATOP"))
+ ih->data->alignment = IZBOX_ALIGN_NORTH;
+ else if (iupStrEqualNoCase(value, "SOUTH") || iupStrEqualNoCase(value, "ABOTTOM"))
+ ih->data->alignment = IZBOX_ALIGN_SOUTH;
+ else if (iupStrEqualNoCase(value, "WEST") || iupStrEqualNoCase(value, "ALEFT"))
+ ih->data->alignment = IZBOX_ALIGN_WEST;
+ else if (iupStrEqualNoCase(value, "EAST") || iupStrEqualNoCase(value, "ARIGHT"))
+ ih->data->alignment = IZBOX_ALIGN_EAST;
+ else if (iupStrEqualNoCase(value, "NE"))
+ ih->data->alignment = IZBOX_ALIGN_NE;
+ else if (iupStrEqualNoCase(value, "SE"))
+ ih->data->alignment = IZBOX_ALIGN_SE;
+ else if (iupStrEqualNoCase(value, "NW"))
+ ih->data->alignment = IZBOX_ALIGN_NW;
+ else if (iupStrEqualNoCase(value, "SW"))
+ ih->data->alignment = IZBOX_ALIGN_SW;
+ else if (iupStrEqualNoCase(value, "ACENTER"))
+ ih->data->alignment = IZBOX_ALIGN_ACENTER;
+ return 0;
+}
+
+static char* iZboxGetAlignmentAttrib(Ihandle* ih)
+{
+ static char* align2str[9] = {"NORTH", "SOUTH", "WEST", "EAST",
+ "NE", "SE", "NW", "SW",
+ "ACENTER"};
+ return align2str[ih->data->alignment];
+}
+
+static int iZboxSetValueHandleAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle* old_handle, *new_handle, *child;
+
+ new_handle = (Ihandle*)value;
+ if (!iupObjectCheck(new_handle))
+ return 0;
+
+ old_handle = ih->data->value_handle;
+ if (!iupObjectCheck(old_handle))
+ old_handle = NULL;
+
+ if (old_handle == new_handle)
+ return 0;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (child == new_handle) /* found child */
+ {
+ if (old_handle && old_handle != new_handle)
+ IupSetAttribute(old_handle, "VISIBLE", "NO");
+
+ IupSetAttribute(new_handle, "VISIBLE", "YES");
+ ih->data->value_handle = new_handle;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int iZboxSetValuePosAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle* child;
+ int pos, i;
+
+ if (!iupStrToInt(value, &pos))
+ return 0;
+
+ for (i=0, child=ih->firstchild; child; child = child->brother, i++)
+ {
+ if (i == pos) /* found child */
+ {
+ iZboxSetValueHandleAttrib(ih, (char*)child);
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static char* iZboxGetValuePosAttrib(Ihandle* ih)
+{
+ Ihandle* child;
+ int pos;
+
+ if (!iupObjectCheck(ih->data->value_handle))
+ return NULL;
+
+ for (pos=0, child = ih->firstchild; child; child = child->brother, pos++)
+ {
+ if (child == ih->data->value_handle) /* found child */
+ {
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%d", pos);
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+static int iZboxSetValueAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle *new_handle;
+
+ if (!value)
+ return 0;
+
+ new_handle = IupGetHandle(value);
+ if (!new_handle)
+ return 0;
+
+ iZboxSetValueHandleAttrib(ih, (char*)new_handle);
+
+ return 0;
+}
+
+static char* iZboxGetValueAttrib(Ihandle* ih)
+{
+ Ihandle* child;
+ int pos;
+
+ if (!iupObjectCheck(ih->data->value_handle))
+ return NULL;
+
+ for (pos=0, child = ih->firstchild; child; child = child->brother, pos++)
+ {
+ if (child == ih->data->value_handle) /* found child, just cheking */
+ return IupGetName(ih->data->value_handle);
+ }
+
+ return NULL;
+}
+
+static int iZboxSetVisibleAttrib(Ihandle* ih, const char* value)
+{
+ if (iupObjectCheck(ih->data->value_handle))
+ IupSetAttribute(ih->data->value_handle, "VISIBLE", (char*)value);
+ return 0;
+}
+
+static void iZboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand)
+{
+ Ihandle* child;
+ int children_expand,
+ children_naturalwidth, children_naturalheight;
+
+ /* calculate total children natural size (even for hidden children) */
+ children_expand = 0;
+ children_naturalwidth = 0;
+ children_naturalheight = 0;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ /* update child natural size first */
+ iupBaseComputeNaturalSize(child);
+
+ if (!child->is_floating)
+ {
+ children_expand |= child->expand;
+ children_naturalwidth = iupMAX(children_naturalwidth, child->naturalwidth);
+ children_naturalheight = iupMAX(children_naturalheight, child->naturalheight);
+ }
+ }
+
+ *expand = children_expand;
+ *w = children_naturalwidth;
+ *h = children_naturalheight;
+}
+
+static void iZboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink)
+{
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating)
+ iupBaseSetCurrentSize(child, ih->currentwidth, ih->currentheight, shrink);
+ }
+}
+
+static void iZboxSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ int dx = 0, dy = 0;
+ Ihandle* child;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ if (!child->is_floating)
+ {
+ switch (ih->data->alignment)
+ {
+ case IZBOX_ALIGN_ACENTER:
+ dx=(ih->currentwidth-child->currentwidth)/2;
+ dy=(ih->currentheight-child->currentheight)/2;
+ break;
+ case IZBOX_ALIGN_NORTH:
+ dx=(ih->currentwidth-child->currentwidth)/2;
+ dy=0;
+ break;
+ case IZBOX_ALIGN_SOUTH:
+ dx=(ih->currentwidth-child->currentwidth)/2;
+ dy=ih->currentheight-child->currentheight;
+ break;
+ case IZBOX_ALIGN_WEST:
+ dx=0;
+ dy=(ih->currentheight-child->currentheight)/2;
+ break;
+ case IZBOX_ALIGN_EAST:
+ dx=ih->currentwidth-child->currentwidth;
+ dy=(ih->currentheight-child->currentheight)/2;
+ break;
+ case IZBOX_ALIGN_NE:
+ dx=ih->currentwidth-child->currentwidth;
+ dy=0;
+ break;
+ case IZBOX_ALIGN_SE:
+ dx=ih->currentwidth-child->currentwidth;
+ dy=ih->currentheight-child->currentheight;
+ break;
+ case IZBOX_ALIGN_SW:
+ dx=0;
+ dy=ih->currentheight-child->currentheight;
+ break;
+ case IZBOX_ALIGN_NW:
+ default:
+ dx=0;
+ dy=0;
+ break;
+ }
+ if (dx<0) dx = 0;
+ if (dy<0) dy = 0;
+
+ /* update child */
+ iupBaseSetPosition(child, x+dx, y+dy);
+ }
+ }
+}
+
+
+/******************************************************************************/
+
+
+Ihandle *IupZboxv(Ihandle **children)
+{
+ return IupCreatev("zbox", (void**)children);
+}
+
+Ihandle *IupZbox(Ihandle* child, ...)
+{
+ Ihandle **children;
+ Ihandle *ih;
+
+ va_list arglist;
+ va_start(arglist, child);
+ children = (Ihandle **)iupObjectGetParamList(child, arglist);
+ va_end(arglist);
+
+ ih = IupCreatev("zbox", (void**)children);
+ free(children);
+
+ return ih;
+}
+
+Iclass* iupZboxGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "zbox";
+ ic->format = "g"; /* array of Ihandle */
+ ic->nativetype = IUP_TYPEVOID;
+ ic->childtype = IUP_CHILDMANY;
+ ic->is_interactive = 0;
+
+ /* Class functions */
+ ic->Create = iZboxCreateMethod;
+ ic->Map = iupBaseTypeVoidMapMethod;
+ ic->ChildAdded = iZboxChildAddedMethod;
+ ic->ChildRemoved = iZboxChildRemovedMethod;
+
+ ic->ComputeNaturalSize = iZboxComputeNaturalSizeMethod;
+ ic->SetChildrenCurrentSize = iZboxSetChildrenCurrentSizeMethod;
+ ic->SetChildrenPosition = iZboxSetChildrenPositionMethod;
+
+ /* Common */
+ iupBaseRegisterCommonAttrib(ic);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", iupBaseGetRasterSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ /* Zbox only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", iZboxGetAlignmentAttrib, iZboxSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "NW", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE", iZboxGetValueAttrib, iZboxSetValueAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ 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);
+
+ return ic;
+}
diff --git a/iup/src/iupgtk.dep b/iup/src/iupgtk.dep
new file mode 100644
index 0000000..4e2bb45
--- /dev/null
+++ b/iup/src/iupgtk.dep
@@ -0,0 +1,259 @@
+$(OBJDIR)/iup_array.o: iup_array.c iup_array.h iup_assert.h
+$(OBJDIR)/iup_callback.o: iup_callback.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_assert.h
+$(OBJDIR)/iup_dlglist.o: iup_dlglist.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_dlglist.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_assert.h
+$(OBJDIR)/iup_attrib.o: iup_attrib.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_childtree.h iup_str.h iup_ledlex.h iup_attrib.h \
+ iup_assert.h
+$(OBJDIR)/iup_focus.o: iup_focus.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_focus.h iup_assert.h iup_attrib.h \
+ iup_str.h iup_drv.h
+$(OBJDIR)/iup_font.o: iup_font.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h iup_drvfont.h iup_assert.h iup_attrib.h \
+ iup_class.h iup_table.h iup_classbase.h
+$(OBJDIR)/iup_globalattrib.o: iup_globalattrib.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h iup_table.h iup_globalattrib.h \
+ iup_drv.h iup_drvfont.h iup_assert.h iup_str.h
+$(OBJDIR)/iup_object.o: iup_object.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_assert.h iup_register.h iup_names.h
+$(OBJDIR)/iup_key.o: iup_key.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_key.h iup_str.h \
+ iup_object.h iup_class.h iup_table.h iup_classbase.h iup_drv.h \
+ iup_focus.h
+$(OBJDIR)/iup_layout.o: iup_layout.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_drv.h iup_attrib.h iup_str.h iup_layout.h \
+ iup_assert.h
+$(OBJDIR)/iup_ledlex.o: iup_ledlex.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_class.h iup_table.h iup_classbase.h \
+ iup_ledlex.h iup_str.h iup_register.h
+$(OBJDIR)/iup_names.o: iup_names.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h iup_table.h iup_names.h iup_object.h \
+ iup_class.h iup_classbase.h iup_assert.h
+$(OBJDIR)/iup_open.o: iup_open.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h iup_globalattrib.h iup_names.h iup_func.h \
+ iup_drv.h iup_drvinfo.h iup_drvfont.h iup_predial.h iup_class.h \
+ iup_table.h iup_classbase.h iup_register.h iup_key.h iup_image.h \
+ iup_dlglist.h iup_assert.h iup_strmessage.h
+$(OBJDIR)/iup_ledparse.o: iup_ledparse.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_ledlex.h iup_str.h iup_assert.h
+$(OBJDIR)/iup_predial.o: iup_predial.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_predial.h iup_attrib.h iup_str.h \
+ iup_strmessage.h
+$(OBJDIR)/iup_register.o: iup_register.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_register.h iup_stdcontrols.h
+$(OBJDIR)/iup_scanf.o: iup_scanf.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_predial.h iup_str.h iup_assert.h
+$(OBJDIR)/iup_show.o: iup_show.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_layout.h iup_attrib.h iup_dialog.h iup_menu.h \
+ iup_assert.h iup_str.h iup_drv.h iup_drvfont.h
+$(OBJDIR)/iup_str.o: iup_str.c iup_str.h
+$(OBJDIR)/iup_table.o: iup_table.c iup_table.h iup_str.h iup_assert.h
+$(OBJDIR)/iup_func.o: iup_func.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h iup_table.h iup_func.h iup_drv.h \
+ iup_assert.h
+$(OBJDIR)/iup_childtree.o: iup_childtree.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_dlglist.h iup_childtree.h iup_attrib.h iup_assert.h \
+ iup_str.h iup_drv.h
+$(OBJDIR)/iup.o: iup.c ../include/iup.h ../include/iupkey.h ../include/iupdef.h
+$(OBJDIR)/iup_classattrib.o: iup_classattrib.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h iup_attrib.h \
+ iup_assert.h iup_register.h iup_globalattrib.h
+$(OBJDIR)/iup_dialog.o: iup_dialog.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_class.h iup_table.h \
+ iup_classbase.h iup_object.h iup_dlglist.h iup_layout.h iup_attrib.h \
+ iup_drv.h iup_drvinfo.h iup_drvfont.h iup_focus.h iup_str.h \
+ iup_dialog.h
+$(OBJDIR)/iup_assert.o: iup_assert.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_assert.h iup_attrib.h iup_str.h \
+ iup_strmessage.h
+$(OBJDIR)/iup_canvas.o: iup_canvas.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_canvas.h
+$(OBJDIR)/iup_messagedlg.o: iup_messagedlg.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_stdcontrols.h
+$(OBJDIR)/iup_timer.o: iup_timer.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_str.h iup_stdcontrols.h iup_timer.h
+$(OBJDIR)/iup_image.o: iup_image.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_image.h iup_assert.h \
+ iup_stdcontrols.h
+$(OBJDIR)/iup_label.o: iup_label.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_label.h iup_image.h
+$(OBJDIR)/iup_fill.o: iup_fill.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h
+$(OBJDIR)/iup_zbox.o: iup_zbox.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h
+$(OBJDIR)/iup_colordlg.o: iup_colordlg.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h
+$(OBJDIR)/iup_fontdlg.o: iup_fontdlg.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h
+$(OBJDIR)/iup_filedlg.o: iup_filedlg.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h
+$(OBJDIR)/iup_strmessage.o: iup_strmessage.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_attrib.h iup_str.h iup_strmessage.h iup_table.h
+$(OBJDIR)/iup_menu.o: iup_menu.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_dialog.h iup_str.h iup_assert.h \
+ iup_key.h iup_stdcontrols.h iup_drvinfo.h iup_menu.h
+$(OBJDIR)/iup_frame.o: iup_frame.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_frame.h
+$(OBJDIR)/iup_user.o: iup_user.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_stdcontrols.h
+$(OBJDIR)/iup_button.o: iup_button.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_button.h iup_image.h
+$(OBJDIR)/iup_radio.o: iup_radio.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h
+$(OBJDIR)/iup_toggle.o: iup_toggle.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_toggle.h iup_image.h
+$(OBJDIR)/iup_progressbar.o: iup_progressbar.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_progressbar.h
+$(OBJDIR)/iup_text.o: iup_text.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_mask.h iup_array.h \
+ iup_text.h iup_assert.h
+$(OBJDIR)/iup_val.o: iup_val.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h ../include/iupcontrols.h \
+ iup_object.h iup_class.h iup_table.h iup_classbase.h iup_attrib.h \
+ iup_str.h iup_drv.h iup_stdcontrols.h iup_layout.h iup_val.h
+$(OBJDIR)/iup_box.o: iup_box.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h
+$(OBJDIR)/iup_hbox.o: iup_hbox.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h
+$(OBJDIR)/iup_vbox.o: iup_vbox.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h
+$(OBJDIR)/iup_cbox.o: iup_cbox.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h
+$(OBJDIR)/iup_class.o: iup_class.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h iup_attrib.h \
+ iup_assert.h
+$(OBJDIR)/iup_classbase.o: iup_classbase.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h \
+ iup_attrib.h iup_assert.h
+$(OBJDIR)/iup_maskmatch.o: iup_maskmatch.c iup_maskparse.h iup_maskmatch.h
+$(OBJDIR)/iup_mask.o: iup_mask.c iup_maskparse.h iup_mask.h iup_str.h
+$(OBJDIR)/iup_maskparse.o: iup_maskparse.c iup_maskparse.h iup_maskmatch.h
+$(OBJDIR)/iup_tabs.o: iup_tabs.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_image.h iup_tabs.h
+$(OBJDIR)/iup_spin.o: iup_spin.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h \
+ iup_childtree.h
+$(OBJDIR)/iup_list.o: iup_list.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_assert.h iup_object.h \
+ iup_class.h iup_table.h iup_classbase.h iup_attrib.h iup_str.h \
+ iup_drv.h iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_mask.h \
+ iup_list.h
+$(OBJDIR)/iup_getparam.o: iup_getparam.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_attrib.h iup_str.h iup_strmessage.h \
+ iup_drvfont.h
+$(OBJDIR)/iup_sbox.o: iup_sbox.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_stdcontrols.h iup_layout.h iup_childtree.h
+$(OBJDIR)/iup_normalizer.o: iup_normalizer.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_array.h iup_stdcontrols.h
+$(OBJDIR)/iup_tree.o: iup_tree.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \
+ iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_tree.h iup_assert.h
+$(OBJDIR)/iupgtk_focus.o: gtk/iupgtk_focus.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_focus.h iup_attrib.h iup_drv.h iup_assert.h \
+ gtk/iupgtk_drv.h
+$(OBJDIR)/iupgtk_font.o: gtk/iupgtk_font.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h iup_attrib.h iup_array.h iup_object.h \
+ iup_class.h iup_table.h iup_classbase.h iup_drv.h iup_drvfont.h \
+ iup_assert.h gtk/iupgtk_drv.h
+$(OBJDIR)/iupgtk_key.o: gtk/iupgtk_key.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_key.h gtk/iupgtk_drv.h
+$(OBJDIR)/iupgtk_loop.o: gtk/iupgtk_loop.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h
+$(OBJDIR)/iupgtk_open.o: gtk/iupgtk_open.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h iup_drv.h iup_drvinfo.h iup_object.h \
+ iup_class.h iup_table.h iup_classbase.h iup_globalattrib.h \
+ gtk/iupgtk_drv.h
+$(OBJDIR)/iupgtk_messagedlg.o: gtk/iupgtk_messagedlg.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_dialog.h \
+ gtk/iupgtk_drv.h
+$(OBJDIR)/iupgtk_timer.o: gtk/iupgtk_timer.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_attrib.h iup_str.h iup_assert.h iup_timer.h
+$(OBJDIR)/iupgtk_colordlg.o: gtk/iupgtk_colordlg.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_dialog.h \
+ gtk/iupgtk_drv.h
+$(OBJDIR)/iupgtk_fontdlg.o: gtk/iupgtk_fontdlg.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_dialog.h \
+ gtk/iupgtk_drv.h
+$(OBJDIR)/iupgtk_progressbar.o: gtk/iupgtk_progressbar.c ../include/iup.h \
+ ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \
+ iup_object.h iup_class.h iup_table.h iup_classbase.h iup_layout.h \
+ iup_attrib.h iup_str.h iup_progressbar.h iup_drv.h gtk/iupgtk_drv.h
+$(OBJDIR)/iupgtk_val.o: gtk/iupgtk_val.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_layout.h iup_attrib.h iup_str.h \
+ iup_val.h iup_drv.h iup_drvfont.h iup_key.h gtk/iupgtk_drv.h
+$(OBJDIR)/iupgtk_frame.o: gtk/iupgtk_frame.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_object.h iup_class.h iup_table.h \
+ iup_classbase.h iup_layout.h iup_attrib.h iup_str.h iup_dialog.h \
+ iup_drv.h iup_drvfont.h iup_stdcontrols.h gtk/iupgtk_drv.h
+$(OBJDIR)/iupgtk_menu.o: gtk/iupgtk_menu.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \
+ iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \
+ iup_str.h iup_label.h iup_drv.h iup_drvfont.h iup_image.h iup_menu.h \
+ gtk/iupgtk_drv.h
+$(OBJDIR)/iupgtk_help.o: gtk/iupgtk_help.c ../include/iup.h ../include/iupkey.h \
+ ../include/iupdef.h iup_str.h
+$(OBJDIR)/iupunix_info.o: mot/iupunix_info.c iup_str.h iup_drvinfo.h
diff --git a/iup/src/iupstub.mak b/iup/src/iupstub.mak
new file mode 100755
index 0000000..9ca920f
--- /dev/null
+++ b/iup/src/iupstub.mak
@@ -0,0 +1,12 @@
+PROJNAME = iup
+LIBNAME = iupstub
+OPT = YES
+
+USE_DLL = Yes
+
+INCLUDES = ../include
+
+SRC = win/iupwindows_main.c
+
+iupstup-dll:
+ @move /y ..\lib\vc6\iupstub.lib ..\lib\dll
diff --git a/iup/src/make_uname b/iup/src/make_uname
new file mode 100755
index 0000000..7fec9f8
--- /dev/null
+++ b/iup/src/make_uname
@@ -0,0 +1,4 @@
+#This builds all the libraries of the folder for 1 uname
+
+tecmake $1 $2 $3 $4 $5 $6 $7
+tecmake USE_GTK=Yes $1 $2 $3 $4 $5 $6 $7
diff --git a/iup/src/make_uname.bat b/iup/src/make_uname.bat
new file mode 100755
index 0000000..1a79780
--- /dev/null
+++ b/iup/src/make_uname.bat
@@ -0,0 +1,55 @@
+@echo off
+REM This builds all the libraries of the folder for 1 uname
+
+call tecmake %1 %2 %3 %4 %5 %6
+call tecmake %1 "USE_GTK=Yes" %2 %3 %4 %5 %6
+
+if "%1"=="dll" goto stub_dll
+if "%1"=="dll7" goto stub_dll7
+if "%1"=="dll8" goto stub_dll8
+if "%1"=="dll8_64" goto stub_dll8_64
+if "%1"=="dll9" goto stub_dll9
+if "%1"=="dll9_64" goto stub_dll9_64
+if "%1"=="all" goto all_dll
+goto fim
+
+:stub_dll
+call tecmake vc6 "MF=iupstub" %2 %3 %4 %5 %6 %7
+move /y ..\lib\vc6\iupstub.lib ..\lib\dll
+goto fim
+
+:stub_dll7
+call tecmake vc7 "MF=iupstub" %2 %3 %4 %5 %6 %7
+move /y ..\lib\vc7\iupstub.lib ..\lib\dll7
+goto fim
+
+:stub_dll8
+call tecmake vc8 "MF=iupstub" %2 %3 %4 %5 %6 %7
+move /y ..\lib\vc8\iupstub.lib ..\lib\dll8
+goto fim
+
+:stub_dll8_64
+call tecmake vc8_64 "MF=iupstub" %2 %3 %4 %5 %6 %7
+move /y ..\lib\vc8_64\iupstub.lib ..\lib\dll8_64
+goto fim
+
+:stub_dll9
+call tecmake vc9 "MF=iupstub" %2 %3 %4 %5 %6 %7
+move /y ..\lib\vc9\iupstub.lib ..\lib\dll9
+goto fim
+
+:stub_dll9_64
+call tecmake vc9_64 "MF=iupstub" %2 %3 %4 %5 %6 %7
+move /y ..\lib\vc9_64\iupstub.lib ..\lib\dll9_64
+goto fim
+
+:all_dll
+call make_uname dll %2 %3 %4 %5 %6
+call make_uname dll7 %2 %3 %4 %5 %6
+call make_uname dll8 %2 %3 %4 %5 %6
+call make_uname dll8_64 %2 %3 %4 %5 %6
+call make_uname dll9 %2 %3 %4 %5 %6
+call make_uname dll9_64 %2 %3 %4 %5 %6
+goto fim
+
+:fim
diff --git a/iup/src/mot/iupmot_button.c b/iup/src/mot/iupmot_button.c
new file mode 100755
index 0000000..2d93588
--- /dev/null
+++ b/iup/src/mot/iupmot_button.c
@@ -0,0 +1,301 @@
+/** \file
+ * \brief Button Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <Xm/PushB.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_button.h"
+#include "iup_drv.h"
+#include "iup_image.h"
+#include "iup_key.h"
+
+#include "iupmot_drv.h"
+
+
+void iupdrvButtonAddBorders(int *x, int *y)
+{
+ int border_size = 2*5;
+ (*x) += border_size;
+ (*y) += border_size;
+}
+
+static int motButtonSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_BUTTON_TEXT)
+ {
+ iupmotSetMnemonicTitle(ih, value);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int motButtonSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char align;
+ char value1[30]="", value2[30]="";
+
+ iupStrToStrStr(value, value1, value2, ':'); /* value2 is ignored, NOT supported in Motif */
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ align = XmALIGNMENT_END;
+ else if (iupStrEqualNoCase(value1, "ACENTER"))
+ align = XmALIGNMENT_CENTER;
+ else /* "ALEFT" */
+ align = XmALIGNMENT_BEGINNING;
+
+ XtVaSetValues (ih->handle, XmNalignment, align, NULL);
+ return 1;
+}
+
+static int motButtonSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_BUTTON_IMAGE)
+ {
+ iupmotSetPixmap(ih, value, XmNlabelPixmap, 0);
+
+ if (!iupAttribGet(ih, "IMINACTIVE"))
+ {
+ /* if not active and IMINACTIVE is not defined
+ then automaticaly create one based on IMAGE */
+ iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 1); /* make_inactive */
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int motButtonSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_BUTTON_IMAGE)
+ {
+ iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 0);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int motButtonSetImPressAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_BUTTON_IMAGE)
+ {
+ iupmotSetPixmap(ih, value, XmNarmPixmap, 0);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int motButtonSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle)
+ {
+ XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding,
+ XmNmarginWidth, ih->data->horiz_padding, NULL);
+ }
+ return 0;
+}
+
+static int motButtonSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ if (iupAttribGet(ih, "IMPRESS") || iupAttribGetBoolean(ih, "FLAT"))
+ {
+ /* ignore given value, must use only from parent */
+ value = iupBaseNativeParentGetBgColor(ih);
+
+ if (iupdrvBaseSetBgColorAttrib(ih, value))
+ return 1;
+ }
+
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+}
+
+static int motButtonSetBackgroundAttrib(Ihandle* ih, const char* value)
+{
+ if (iupAttribGet(ih, "IMPRESS") || iupAttribGetBoolean(ih, "FLAT"))
+ {
+ /* ignore given value, must use only from parent */
+ value = iupAttribGetInheritNativeParent(ih, "BACKGROUND");
+
+ if (iupdrvBaseSetBgColorAttrib(ih, value))
+ return 1;
+ else
+ {
+ Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0);
+ if (pixmap)
+ {
+ XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static void motButtonActivateCallback(Widget w, Ihandle* ih, XtPointer call_data)
+{
+ Icallback cb;
+
+ /* Must manually hide the tip if the button is pressed. */
+ iupmotTipLeaveNotify();
+
+ cb = IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ if (cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+ }
+ (void)w;
+ (void)call_data;
+}
+
+static void motButtonEnterLeaveWindowEvent(Widget w, Ihandle* ih, XEvent *evt, Boolean *cont)
+{
+ iupmotEnterLeaveWindowEvent(w, ih, evt, cont);
+
+ if (evt->type == EnterNotify)
+ XtVaSetValues(ih->handle, XmNshadowThickness, 2, NULL);
+ else if (evt->type == LeaveNotify)
+ XtVaSetValues(ih->handle, XmNshadowThickness, 0, NULL);
+}
+
+static int motButtonMapMethod(Ihandle* ih)
+{
+ char* value;
+ int num_args = 0;
+ Arg args[30];
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ {
+ ih->data->type = IUP_BUTTON_IMAGE;
+ iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP);
+ }
+ else
+ {
+ ih->data->type = IUP_BUTTON_TEXT;
+ iupmotSetArg(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 */
+ /* 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);
+ /* PushButton */
+ iupmotSetArg(args, num_args, XmNfillOnArm, False);
+
+ /* Primitive */
+ if (iupAttribGetBoolean(ih, "FOCUSONCLICK"))
+ {
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ iupmotSetArg(args, num_args, XmNtraversalOn, True);
+ else
+ iupmotSetArg(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);
+
+ ih->handle = XtCreateManagedWidget(
+ iupDialogGetChildIdStr(ih), /* child identifier */
+ xmPushButtonWidgetClass, /* widget class */
+ iupChildTreeGetNativeParentHandle(ih), /* widget parent */
+ args, num_args);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupDialogGetChildId(ih); /* must be after using the string */
+
+ XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih);
+
+ value = iupAttribGet(ih, "IMPRESS");
+ if (iupAttribGetBoolean(ih, "FLAT") && !value)
+ {
+ XtVaSetValues(ih->handle, XmNshadowThickness, 0, NULL);
+ XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)motButtonEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)motButtonEnterLeaveWindowEvent, (XtPointer)ih);
+ }
+ else
+ {
+ if (value && !iupAttribGetStr(ih, "IMPRESSBORDER"))
+ XtVaSetValues(ih->handle, XmNshadowThickness, 0, NULL);
+ else
+ XtVaSetValues(ih->handle, XmNshadowThickness, 2, NULL);
+ XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ }
+
+ XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih);
+
+ XtAddCallback(ih->handle, XmNactivateCallback, (XtCallbackProc)motButtonActivateCallback, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih);
+
+ /* Disable Drag Source */
+ iupmotDisableDragSource(ih->handle);
+
+ /* initialize the widget */
+ XtRealizeWidget(ih->handle);
+
+ if (ih->data->type == IUP_BUTTON_TEXT)
+ iupmotSetString(ih->handle, XmNlabelString, "");
+
+ return IUP_NOERROR;
+}
+
+void iupdrvButtonInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motButtonMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", iupmotGetBgColorAttrib, motButtonSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motButtonSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, motButtonSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupButton only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, motButtonSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, motButtonSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, motButtonSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, motButtonSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FOCUSONCLICK", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupButtonGetPaddingAttrib, motButtonSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+}
diff --git a/iup/src/mot/iupmot_canvas.c b/iup/src/mot/iupmot_canvas.c
new file mode 100755
index 0000000..7777cf3
--- /dev/null
+++ b/iup/src/mot/iupmot_canvas.c
@@ -0,0 +1,639 @@
+/** \file
+ * \brief Canvas Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <Xm/ScrolledW.h>
+#include <Xm/DrawingA.h>
+#include <Xm/ScrollBar.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_canvas.h"
+#include "iup_key.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+
+static void motDialogScrollbarCallback(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ int op = (int)client_data, ipage, ipos;
+ Ihandle *ih;
+ IFniff cb;
+ double posx, posy;
+ (void)call_data;
+
+ XtVaGetValues(w, XmNuserData, &ih, NULL);
+ if (!ih) return;
+
+ XtVaGetValues(w,
+ XmNvalue, &ipos,
+ XmNpageIncrement, &ipage,
+ NULL);
+
+ if (op > IUP_SBDRAGV)
+ {
+ iupCanvasCalcScrollRealPos(iupAttribGetFloat(ih,"XMIN"), iupAttribGetFloat(ih,"XMAX"), &posx,
+ IUP_SB_MIN, IUP_SB_MAX, ipage, &ipos);
+ ih->data->posx = (float)posx;
+ posy = ih->data->posy;
+ }
+ else
+ {
+ iupCanvasCalcScrollRealPos(iupAttribGetFloat(ih,"YMIN"), iupAttribGetFloat(ih,"YMAX"), &posy,
+ IUP_SB_MIN, IUP_SB_MAX, ipage, &ipos);
+ ih->data->posy = (float)posy;
+ posx = ih->data->posx;
+ }
+
+ cb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ if (cb)
+ cb(ih, op, (float)posx, (float)posy);
+ else
+ {
+ IFnff cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ cb (ih, (float)posx, (float)posy);
+ }
+}
+
+static void motCanvasResizeCallback(Widget w, Ihandle *ih, XtPointer call_data)
+{
+ Dimension width, height;
+ IFnii cb;
+ (void)call_data;
+
+ if (!XtWindow(w) || !ih) return;
+
+ /* client size */
+ XtVaGetValues(w, XmNwidth, &width,
+ XmNheight, &height,
+ NULL);
+
+ cb = (IFnii)IupGetCallback(ih,"RESIZE_CB");
+ if (cb)
+ cb(ih,width,height);
+}
+
+static int motCanvasSetBgColorAttrib(Ihandle* ih, const char* value);
+
+static void motCanvasExposeCallback(Widget w, Ihandle *ih, XtPointer call_data)
+{
+ IFnff cb;
+ (void)call_data;
+
+ if (!XtWindow(w) || !ih) return;
+
+ cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ {
+ if (!iupAttribGet(ih, "_IUPMOT_NO_BGCOLOR"))
+ motCanvasSetBgColorAttrib(ih, iupAttribGetStr(ih, "BGCOLOR")); /* reset to update window attributes */
+
+ cb (ih, ih->data->posx, ih->data->posy);
+ }
+}
+
+static void motCanvasInputCallback(Widget w, Ihandle *ih, XtPointer call_data)
+{
+ XEvent *evt = ((XmDrawingAreaCallbackStruct*)call_data)->event;
+
+ if (!XtWindow(w) || !ih) return;
+
+ switch (evt->type)
+ {
+ case ButtonPress:
+ /* Force focus on canvas click */
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ XmProcessTraversal(w, XmTRAVERSE_CURRENT);
+ /* break missing on purpose... */
+ case ButtonRelease:
+ {
+ XButtonEvent *but_evt = (XButtonEvent*)evt;
+ Boolean cont = True;
+ iupmotButtonPressReleaseEvent(w, ih, evt, &cont);
+ if (cont == False)
+ return;
+
+ if ((evt->type==ButtonPress) && (but_evt->button==Button4 || but_evt->button==Button5))
+ {
+ IFnfiis wcb = (IFnfiis)IupGetCallback(ih, "WHEEL_CB");
+ if (wcb)
+ {
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ int delta = but_evt->button==Button4? 1: -1;
+ iupmotButtonKeySetStatus(but_evt->state, but_evt->button, status, 0);
+
+ wcb(ih, (float)delta, but_evt->x, but_evt->y, status);
+ }
+ else
+ {
+ IFniff scb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ float posy = ih->data->posy;
+ int delta = but_evt->button==Button4? 1: -1;
+ int op = but_evt->button==Button4? IUP_SBUP: IUP_SBDN;
+ posy -= delta*iupAttribGetFloat(ih, "DY")/10.0f;
+ IupSetfAttribute(ih, "POSY", "%g", posy);
+ if (scb)
+ scb(ih,op,ih->data->posx,ih->data->posy);
+ }
+ }
+ }
+ break;
+ }
+}
+
+static void motCanvasSetScrollInfo(Widget sb, int imin, int imax, int ipos, int ipage, int iline)
+{
+ XtVaSetValues(sb,
+ XmNminimum, imin,
+ XmNmaximum, imax,
+ XmNvalue, ipos,
+ XmNincrement, iline,
+ XmNpageIncrement, ipage,
+ XmNsliderSize, ipage, /* to make the thumb proportional */
+ NULL);
+}
+
+static int motCanvasSetDXAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ double posx, xmin, xmax, linex;
+ float dx;
+ int iposx, ipagex, ilinex;
+ Widget sb_horiz, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb_horiz, NULL);
+ if (!sb_horiz) return 1;
+
+ if (!iupStrToFloat(value, &dx))
+ return 1;
+
+ xmin = iupAttribGetFloat(ih, "XMIN");
+ xmax = iupAttribGetFloat(ih, "XMAX");
+ posx = ih->data->posx;
+
+ iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx);
+
+ if (!iupAttribGet(ih,"LINEX"))
+ {
+ ilinex = ipagex/10;
+ if (!ilinex)
+ ilinex = 1;
+ }
+ else
+ {
+ /* line and page convertions are the same */
+ linex = iupAttribGetFloat(ih,"LINEX");
+ iupCanvasCalcScrollIntPos(xmin, xmax, linex, 0,
+ IUP_SB_MIN, IUP_SB_MAX, &ilinex, NULL);
+ }
+
+ if (dx >= (xmax-xmin))
+ {
+ if (iupAttribGetBoolean(ih, "XAUTOHIDE"))
+ XtUnmanageChild(sb_horiz);
+ else
+ XtSetSensitive(sb_horiz, 0);
+ return 1;
+ }
+ else
+ {
+ if (!XtIsManaged(sb_horiz))
+ XtManageChild(sb_horiz);
+ XtSetSensitive(sb_horiz, 1);
+ }
+
+ motCanvasSetScrollInfo(sb_horiz, IUP_SB_MIN, IUP_SB_MAX, iposx, ipagex, ilinex);
+
+ /* update position because it could be corrected */
+ iupCanvasCalcScrollRealPos(xmin, xmax, &posx,
+ IUP_SB_MIN, IUP_SB_MAX, ipagex, &iposx);
+
+ ih->data->posx = (float)posx;
+ }
+ return 1;
+}
+
+static int motCanvasSetPosXAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ double xmin, xmax, dx;
+ float posx;
+ int iposx, ipagex;
+ Widget sb_horiz, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb_horiz, NULL);
+ if (!sb_horiz) return 1;
+
+ if (!iupStrToFloat(value, &posx))
+ return 1;
+
+ xmin = iupAttribGetFloat(ih, "XMIN");
+ xmax = iupAttribGetFloat(ih, "XMAX");
+ dx = iupAttribGetFloat(ih, "DX");
+
+ if (posx < xmin) posx = (float)xmin;
+ if (posx > (xmax - dx)) posx = (float)(xmax - dx);
+ ih->data->posx = posx;
+
+ iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx);
+
+ XtVaSetValues(sb_horiz, XmNvalue, iposx, NULL);
+ }
+ return 1;
+}
+
+static int motCanvasSetDYAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ double posy, ymin, ymax, liney;
+ float dy;
+ int iposy, ipagey, iliney;
+ Widget sb_vert, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ XtVaGetValues(sb_win, XmNverticalScrollBar, &sb_vert, NULL);
+ if (!sb_vert) return 1;
+
+ if (!iupStrToFloat(value, &dy))
+ return 1;
+
+ ymin = iupAttribGetFloat(ih, "YMIN");
+ ymax = iupAttribGetFloat(ih, "YMAX");
+ posy = ih->data->posy;
+
+ iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy);
+
+ if (!iupAttribGet(ih,"LINEY"))
+ {
+ iliney = ipagey/10;
+ if (!iliney)
+ iliney = 1;
+ }
+ else
+ {
+ /* line and page convertions are the same */
+ liney = iupAttribGetFloat(ih,"LINEY");
+ iupCanvasCalcScrollIntPos(ymin, ymax, liney, 0,
+ IUP_SB_MIN, IUP_SB_MAX, &iliney, NULL);
+ }
+
+ if (dy >= (ymax-ymin))
+ {
+ if (iupAttribGetBoolean(ih, "YAUTOHIDE"))
+ XtUnmanageChild(sb_vert);
+ else
+ XtSetSensitive(sb_vert, 0);
+ return 1;
+ }
+ else
+ {
+ if (!XtIsManaged(sb_vert))
+ XtManageChild(sb_vert);
+ XtSetSensitive(sb_vert, 1);
+ }
+
+ motCanvasSetScrollInfo(sb_vert, IUP_SB_MIN, IUP_SB_MAX, iposy, ipagey, iliney);
+
+ /* update position because it could be corrected */
+ iupCanvasCalcScrollRealPos(ymin, ymax, &posy,
+ IUP_SB_MIN, IUP_SB_MAX, ipagey, &iposy);
+
+ ih->data->posy = (float)posy;
+ }
+ return 1;
+}
+
+static int motCanvasSetPosYAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ double ymin, ymax, dy;
+ float posy;
+ int iposy, ipagey;
+ Widget sb_vert, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ XtVaGetValues(sb_win, XmNverticalScrollBar, &sb_vert, NULL);
+ if (!sb_vert) return 1;
+
+ if (!iupStrToFloat(value, &posy))
+ return 1;
+
+ ymin = iupAttribGetFloat(ih, "YMIN");
+ ymax = iupAttribGetFloat(ih, "YMAX");
+ dy = iupAttribGetFloat(ih, "DY");
+
+ if (posy < ymin) posy = (float)ymin;
+ if (posy > (ymax - dy)) posy = (float)(ymax - dy);
+ ih->data->posy = posy;
+
+ iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy);
+
+ XtVaSetValues(sb_vert, XmNvalue, iposy, NULL);
+ }
+ return 1;
+}
+
+static char* motCanvasGetXDisplayAttrib(Ihandle *ih)
+{
+ (void)ih;
+ return (char*)iupmot_display;
+}
+
+static char* motCanvasGetXScreenAttrib(Ihandle *ih)
+{
+ (void)ih;
+ return (char*)iupmot_screen;
+}
+
+static char* motCanvasGetXWindowAttrib(Ihandle *ih)
+{
+ return (char*)XtWindow(ih->handle);
+}
+
+static char* motCanvasGetClientSizeAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+
+ Dimension width, height;
+ XtVaGetValues(ih->handle, XmNwidth, &width,
+ XmNheight, &height,
+ NULL);
+
+ sprintf(str, "%dx%d", (int)width, (int)height);
+ return str;
+}
+
+static int motCanvasSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color;
+
+ /* ignore given value, must use only from parent for the scrollbars */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ color = iupmotColorGetPixelStr(parent_value);
+ if (color != (Pixel)-1)
+ {
+ Widget sb;
+ Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+
+ iupmotSetBgColor(sb_win, color);
+
+ XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL);
+ if (sb) iupmotSetBgColor(sb, color);
+
+ XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL);
+ if (sb) iupmotSetBgColor(sb, color);
+ }
+
+ if (!IupGetCallback(ih, "ACTION"))
+ iupdrvBaseSetBgColorAttrib(ih, value); /* Use the given value only here */
+ else
+ {
+ XSetWindowAttributes attrs;
+ attrs.background_pixmap = None;
+ XChangeWindowAttributes(iupmot_display, XtWindow(ih->handle), CWBackPixmap, &attrs);
+ iupAttribSetStr(ih, "_IUPMOT_NO_BGCOLOR", "1");
+ }
+
+ return 1;
+}
+
+static void motCanvasLayoutUpdateMethod(Ihandle *ih)
+{
+ Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ Dimension border;
+
+ /* IMPORTANT:
+ The ScrolledWindow border, added by the Core, is NOT included in the Motif size.
+ So when setting the size, we must compensate the border,
+ so the actual size will be the size we expect.
+ */
+
+ XtVaGetValues(sb_win, XmNborderWidth, &border, NULL);
+
+ XtVaSetValues(sb_win,
+ XmNx, (XtArgVal)ih->x,
+ XmNy, (XtArgVal)ih->y,
+ XmNwidth, (XtArgVal)(ih->currentwidth-2*border),
+ XmNheight, (XtArgVal)(ih->currentheight-2*border),
+ NULL);
+}
+
+static int motCanvasMapMethod(Ihandle* ih)
+{
+ Widget sb_win;
+ char *visual;
+ int num_args = 0;
+ Arg args[20];
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ ih->data->sb = iupBaseGetScrollbar(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);
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ {
+ iupmotSetArg(args, num_args, XmNborderWidth, 1);
+ iupmotSetArg(args, num_args, XmNborderColor, iupmotColorGetPixelStr("0 0 0"));
+ }
+ else
+ iupmotSetArg(args, num_args, XmNborderWidth, 0);
+
+ sb_win = XtCreateManagedWidget(
+ iupDialogGetChildIdStr(ih), /* child identifier */
+ xmScrolledWindowWidgetClass, /* widget class */
+ iupChildTreeGetNativeParentHandle(ih), /* widget parent */
+ args, num_args);
+
+ if (!sb_win)
+ return IUP_ERROR;
+
+ ih->serial = iupDialogGetChildId(ih); /* must be after using the string */
+
+ /****************************/
+ /* Create the drawing area */
+ /****************************/
+
+ 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 */
+ if (ih->iclass->is_interactive)
+ {
+ iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); /* include in navigation */
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ iupmotSetArg(args, num_args, XmNtraversalOn, True);
+ else
+ iupmotSetArg(args, num_args, XmNtraversalOn, False);
+ }
+ else
+ {
+ iupmotSetArg(args, num_args, XmNnavigationType, XmNONE);
+ iupmotSetArg(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 */
+
+ 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);
+
+ iupmotDialogSetVisual(ih, visual);
+ }
+
+ ih->handle = XtCreateManagedWidget(
+ "draw_area", /* child identifier */
+ xmDrawingAreaWidgetClass, /* widget class */
+ sb_win, /* widget parent */
+ args, num_args);
+
+ if (!ih->handle)
+ {
+ XtDestroyWidget(sb_win);
+ return IUP_ERROR;
+ }
+
+ if (visual)
+ iupmotDialogResetVisual(ih);
+
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)sb_win);
+ XtVaSetValues(sb_win, XmNworkWindow, ih->handle, NULL);
+
+ {
+ XSetWindowAttributes attrs;
+ attrs.bit_gravity = ForgetGravity; /* For the DrawingArea widget gets Expose events when you resize it to be smaller. */
+
+ if (iupAttribGetBoolean(ih, "BACKINGSTORE"))
+ attrs.backing_store = WhenMapped;
+ else
+ attrs.backing_store = NotUseful;
+
+ XChangeWindowAttributes(iupmot_display, XtWindow(ih->handle), CWBitGravity|CWBackingStore, &attrs);
+ }
+
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ Widget sb_horiz = XtVaCreateManagedWidget("sb_horiz",
+ xmScrollBarWidgetClass, sb_win,
+ XmNorientation, XmHORIZONTAL,
+ XmNsliderMark, XmTHUMB_MARK,
+ XmNuserData, ih,
+ NULL);
+
+ XtAddCallback(sb_horiz, XmNvalueChangedCallback, motDialogScrollbarCallback, (void*)IUP_SBPOSH);
+ XtAddCallback(sb_horiz, XmNdragCallback, motDialogScrollbarCallback, (void*)IUP_SBDRAGH);
+ XtAddCallback(sb_horiz, XmNdecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBLEFT);
+ XtAddCallback(sb_horiz, XmNincrementCallback, motDialogScrollbarCallback, (void*)IUP_SBRIGHT);
+ XtAddCallback(sb_horiz, XmNpageDecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGLEFT);
+ XtAddCallback(sb_horiz, XmNpageIncrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGRIGHT);
+
+ XtVaSetValues(sb_win, XmNhorizontalScrollBar, sb_horiz, NULL);
+ }
+
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ Widget sb_vert = XtVaCreateManagedWidget("sb_vert",
+ xmScrollBarWidgetClass, sb_win,
+ XmNorientation, XmVERTICAL,
+ XmNsliderMark, XmTHUMB_MARK,
+ XmNuserData, ih,
+ NULL);
+
+ XtAddCallback(sb_vert, XmNvalueChangedCallback, motDialogScrollbarCallback, (void*)IUP_SBPOSV);
+ XtAddCallback(sb_vert, XmNdragCallback, motDialogScrollbarCallback, (void*)IUP_SBDRAGV);
+ XtAddCallback(sb_vert, XmNdecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBUP);
+ XtAddCallback(sb_vert, XmNincrementCallback, motDialogScrollbarCallback, (void*)IUP_SBDN);
+ XtAddCallback(sb_vert, XmNpageDecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGUP);
+ XtAddCallback(sb_vert, XmNpageIncrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGDN);
+
+ XtVaSetValues(sb_win, XmNverticalScrollBar, sb_vert, NULL);
+ }
+
+ XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNexposeCallback, (XtCallbackProc)motCanvasExposeCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNresizeCallback, (XtCallbackProc)motCanvasResizeCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNinputCallback, (XtCallbackProc)motCanvasInputCallback, (XtPointer)ih);
+
+ XtAddEventHandler(ih->handle, EnterWindowMask, False,(XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, LeaveWindowMask, False,(XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+
+ XtAddEventHandler(ih->handle, FocusChangeMask, False,(XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, KeyReleaseMask, False, (XtEventHandler)iupmotCanvasKeyReleaseEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih);
+
+ /* initialize the widget */
+ XtRealizeWidget(sb_win);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvCanvasInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motCanvasMapMethod;
+ ic->LayoutUpdate = motCanvasLayoutUpdateMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motCanvasSetBgColorAttrib, "255 255 255", NULL, IUPAF_DEFAULT); /* force new default value */
+
+ /* IupCanvas only */
+ iupClassRegisterAttribute(ic, "DRAWSIZE", motCanvasGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CURSOR", NULL, iupdrvBaseSetCursorAttrib, IUPAF_SAMEASSYSTEM, "ARROW", IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "DX", NULL, motCanvasSetDXAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "DY", NULL, motCanvasSetDYAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "POSX", iupCanvasGetPosXAttrib, motCanvasSetPosXAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "POSY", iupCanvasGetPosYAttrib, motCanvasSetPosYAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "YAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "XAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED);
+
+ /* IupCanvas X only */
+ iupClassRegisterAttribute(ic, "XWINDOW", motCanvasGetXWindowAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "XDISPLAY", motCanvasGetXDisplayAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "XSCREEN", motCanvasGetXScreenAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "BACKINGSTORE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED);
+}
diff --git a/iup/src/mot/iupmot_clipboard.c b/iup/src/mot/iupmot_clipboard.c
new file mode 100755
index 0000000..43a0087
--- /dev/null
+++ b/iup/src/mot/iupmot_clipboard.c
@@ -0,0 +1,208 @@
+/** \file
+ * \brief Clipboard for the Motif Driver.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <Xm/Xm.h>
+#include <Xm/CutPaste.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+
+#include "iupmot_drv.h"
+
+
+static Window motClipboardGetWindow(void)
+{
+ Ihandle* focus = IupGetFocus();
+ Ihandle* dlg;
+ if (!focus) return (Window)NULL;
+ dlg = IupGetDialog(focus);
+ if (dlg)
+ return XtWindow(dlg->handle);
+ else
+ return (Window)NULL;
+}
+
+static int motClipboardSetTextAttrib(Ihandle *ih, const char *value)
+{
+ long item_id = 0;
+ Window window = motClipboardGetWindow();
+ XmString clip_label = XmStringCreateLocalized ("IupClipboard");
+ (void)ih;
+
+ if (XmClipboardStartCopy(iupmot_display, window, clip_label, CurrentTime, NULL, NULL, &item_id)!=ClipboardSuccess)
+ {
+ XmStringFree(clip_label);
+ return 0;
+ }
+
+ XmStringFree(clip_label);
+
+ XmClipboardCopy(iupmot_display, window, item_id, "STRING", (char*)value, (long)strlen(value)+1, 0, NULL);
+ XmClipboardEndCopy(iupmot_display, window, item_id);
+ return 0;
+}
+
+static char* motClipboardGetTextAttrib(Ihandle *ih)
+{
+ unsigned long size;
+ char* str;
+ Window window = motClipboardGetWindow();
+ (void)ih;
+
+ if (XmClipboardInquireLength(iupmot_display, window, "STRING", &size)!=ClipboardSuccess)
+ return NULL;
+
+ str = iupStrGetMemory(size+1);
+
+ if (XmClipboardRetrieve(iupmot_display, window, "STRING", str, size+1, NULL, NULL)!=ClipboardSuccess)
+ return NULL;
+
+ return str;
+}
+
+static int motClipboardSetImageAttrib(Ihandle *ih, const char *value)
+{
+ Pixmap pixmap;
+ long item_id = 0;
+ Window window = motClipboardGetWindow();
+ XmString clip_label = XmStringCreateLocalized ("IupClipboard");
+
+ if (XmClipboardStartCopy(iupmot_display, window, clip_label, CurrentTime, NULL, NULL, &item_id)!=ClipboardSuccess)
+ {
+ XmStringFree(clip_label);
+ return 0;
+ }
+
+ XmStringFree(clip_label);
+
+ pixmap = (Pixmap)iupImageGetImage(value, ih, 0);
+
+ XmClipboardCopy(iupmot_display, window, item_id, "PIXMAP", (char*)&pixmap, sizeof(Pixmap), 0, NULL);
+ XmClipboardEndCopy(iupmot_display, window, item_id);
+
+ (void)ih;
+ return 0;
+}
+
+static int motClipboardSetNativeImageAttrib(Ihandle *ih, const char *value)
+{
+ long item_id = 0;
+ Window window = motClipboardGetWindow();
+ XmString clip_label = XmStringCreateLocalized ("IupClipboard");
+ Pixmap pixmap = (Pixmap)value;
+
+ if (XmClipboardStartCopy(iupmot_display, window, clip_label, CurrentTime, NULL, NULL, &item_id)!=ClipboardSuccess)
+ {
+ XmStringFree(clip_label);
+ return 0;
+ }
+
+ XmStringFree(clip_label);
+
+ XmClipboardCopy(iupmot_display, window, item_id, "PIXMAP", (char*)&pixmap, sizeof(Pixmap), 0, NULL);
+ XmClipboardEndCopy(iupmot_display, window, item_id);
+
+ (void)ih;
+ return 0;
+}
+
+static char* motClipboardGetNativeImageAttrib(Ihandle *ih)
+{
+ unsigned long size;
+ void* data;
+ Pixmap pixmap;
+ Window window = motClipboardGetWindow();
+ (void)ih;
+
+ if (XmClipboardInquireLength(iupmot_display, window, "PIXMAP", &size)!=ClipboardSuccess)
+ return NULL;
+
+ data = XtMalloc(size);
+
+ if (XmClipboardRetrieve(iupmot_display, window, "PIXMAP", data, size, NULL, NULL)!=ClipboardSuccess)
+ return NULL;
+
+ pixmap = *((Pixmap*)data);
+ XtFree(data);
+ return (char*)pixmap;
+}
+
+static int motClipboardIsAvailable(const char* format_name)
+{
+ Window window = motClipboardGetWindow();
+ int count, i;
+ unsigned long max_length, length;
+ char* str;
+
+ if (XmClipboardInquireCount(iupmot_display, window, &count, &max_length) != ClipboardSuccess)
+ return 0;
+
+ str = iupStrGetMemory(max_length+1);
+
+ for (i = 1; i<=count; i++)
+ {
+ if (XmClipboardInquireFormat(iupmot_display, window, i, str, max_length+1, &length)==ClipboardSuccess)
+ {
+ if (iupStrEqualNoCase(str, format_name))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static char* motClipboardGetTextAvailableAttrib(Ihandle *ih)
+{
+ (void)ih;
+ if (motClipboardIsAvailable("STRING"))
+ return "YES";
+ else
+ return "NO";
+}
+
+static char* motClipboardGetImageAvailableAttrib(Ihandle *ih)
+{
+ (void)ih;
+ if (motClipboardIsAvailable("PIXMAP"))
+ return "YES";
+ else
+ return "NO";
+}
+
+/******************************************************************************/
+
+Ihandle* IupClipboard(void)
+{
+ return IupCreate("clipboard");
+}
+
+Iclass* iupClipboardGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "clipboard";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Attribute functions */
+ iupClassRegisterAttribute(ic, "TEXT", motClipboardGetTextAttrib, motClipboardSetTextAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "NATIVEIMAGE", motClipboardGetNativeImageAttrib, motClipboardSetNativeImageAttrib, NULL, NULL, IUPAF_NO_STRING|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, motClipboardSetImageAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TEXTAVAILABLE", motClipboardGetTextAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEAVAILABLE", motClipboardGetImageAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
diff --git a/iup/src/mot/iupmot_color.c b/iup/src/mot/iupmot_color.c
new file mode 100755
index 0000000..276bccc
--- /dev/null
+++ b/iup/src/mot/iupmot_color.c
@@ -0,0 +1,380 @@
+/** \file
+ * \brief Motif Driver color management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <Xm/Xm.h>
+#include <X11/Xproto.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drvinfo.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+
+/* local variables */
+
+typedef struct _Icolor
+{
+ Colormap colormap; /* colormap for all canvas, dialogs and menus */
+ XColor color_table[256]; /* colormap colors */
+ int num_colors; /* number of colors in colormap */
+
+ int rshift; /* red shift for truecolor */
+ int gshift; /* green shift for truecolor */
+ int bshift; /* blue shift for truecolor */
+
+ int direct_conv[256]; /* used with directColor visuals */
+} Icolor;
+
+static Icolor mot_color;
+
+
+/*******************************************
+ NOT TrueColor Functions
+*******************************************/
+
+static int motColor8BppErrorHandler(Display* dpy, XErrorEvent *err)
+{
+ char msg[80];
+
+ /* BadAcess in XFreeColors is OK */
+ if (err->request_code==X_FreeColors && err->error_code==BadAccess)
+ return 0;
+
+ XGetErrorText(dpy, err->error_code, msg, 80 );
+ fprintf(stderr,"IUP Motif error handler: Xlib request %d: %s\n", err->request_code, msg);
+
+ return 0;
+}
+
+static unsigned long motColorNearestRGB(XColor* xc1)
+{
+ static int nearest_try = 0;
+
+ int pos = 0, i;
+ unsigned long min_dist = ULONG_MAX, this_dist;
+ int dr, dg, db;
+ XColor* xc2;
+
+ for (i=0; i<mot_color.num_colors; i++)
+ {
+ xc2 = &(mot_color.color_table[i]);
+
+ dr = (xc1->red - xc2->red) / 850; /* 0.30 / 255 */
+ dg = (xc1->green - xc2->green) / 432; /* 0.59 / 255 */
+ db = (xc1->blue - xc2->blue) / 2318; /* 0.11 / 255 */
+
+ this_dist = dr*dr + dg*dg + db*db;
+
+ if (this_dist < min_dist)
+ {
+ min_dist = this_dist;
+ pos = i;
+ }
+ }
+
+ /* verifico se a cor ainda esta alocada */
+ /* Try to allocate the closest match color. This should only
+ fail if the cell is read/write. Otherwise, we're incrementing
+ the cell's reference count. (comentario extraido da biblioteca Mesa) */
+ if (!XAllocColor(iupmot_display, mot_color.colormap,
+ &(mot_color.color_table[pos])))
+ {
+ /* nao esta, preciso atualizar a tabela e procurar novamente */
+ /* isto acontece porque a cor encontrada pode ter sido de uma aplicacao que nao existe mais */
+ /* uma vez atualizada, o problema nao ocorrera' na nova procura */
+ /* ou a celula e' read write */
+
+ if (nearest_try == 1)
+ {
+ nearest_try = 0;
+ return mot_color.color_table[pos].pixel;
+ }
+
+ XQueryColors(iupmot_display, mot_color.colormap, mot_color.color_table, mot_color.num_colors);
+
+ nearest_try = 1; /* garante que so' vai tentar isso uma vez */
+ return motColorNearestRGB(xc1);
+ }
+
+ return mot_color.color_table[pos].pixel;
+}
+
+static unsigned long motColorGetPixel_NotTrueColor(unsigned char cr, unsigned char cg, unsigned char cb)
+{
+ unsigned long pixel;
+ XColor xc;
+ xc.red = iupCOLOR8TO16(cr);
+ xc.green = iupCOLOR8TO16(cg);
+ xc.blue = iupCOLOR8TO16(cb);
+ xc.flags = DoRed | DoGreen | DoBlue;
+
+ /* verificamos se a nova cor ja' esta' disponivel */
+ if (!XAllocColor(iupmot_display, mot_color.colormap, &xc))
+ {
+ /* nao estava disponivel, procuro pela mais proxima na tabela de cores */
+ pixel = motColorNearestRGB(&xc);
+ }
+ else
+ {
+ /* ja' estava disponivel */
+ /* atualizo a tabela de cores */
+ mot_color.color_table[xc.pixel] = xc;
+ pixel = xc.pixel;
+ }
+
+ return pixel;
+}
+
+static void motColorGetRGB_NotTrueColor(unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue)
+{
+ XColor xc;
+ xc.pixel = pixel;
+ XQueryColor(iupmot_display, mot_color.colormap, &xc);
+ *red = (unsigned char)xc.red;
+ *green = (unsigned char)xc.green;
+ *blue = (unsigned char)xc.blue;
+}
+
+static void motColorReserveColors(void)
+{
+ unsigned char r, g, b;
+ unsigned long background, foreground, shadow, highlight, selection;
+ XtVaGetValues(iupmot_appshell, XmNbackground, &background, NULL);
+ XmGetColors(DefaultScreenOfDisplay(iupmot_display), mot_color.colormap,
+ background, &foreground, &highlight, &shadow, &selection);
+ motColorGetRGB_NotTrueColor(background, &r, &g, &b);
+ motColorGetPixel_NotTrueColor(r, g, b);
+ motColorGetRGB_NotTrueColor(foreground, &r, &g, &b);
+ motColorGetPixel_NotTrueColor(r, g, b);
+ motColorGetRGB_NotTrueColor(shadow, &r, &g, &b);
+ motColorGetPixel_NotTrueColor(r, g, b);
+ motColorGetRGB_NotTrueColor(highlight, &r, &g, &b);
+ motColorGetPixel_NotTrueColor(r, g, b);
+ motColorGetRGB_NotTrueColor(selection, &r, &g, &b);
+ motColorGetPixel_NotTrueColor(r, g, b);
+}
+
+
+/*******************************************
+ TrueColor Functions
+*******************************************/
+
+
+static void motColorGetRGB_TrueColor(unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue)
+{
+ unsigned long r = pixel & iupmot_visual->red_mask;
+ unsigned long g = pixel & iupmot_visual->green_mask;
+ unsigned long b = pixel & iupmot_visual->blue_mask;
+ if (mot_color.rshift<0) r = r >> (-mot_color.rshift);
+ else r = r << mot_color.rshift;
+ if (mot_color.gshift<0) g = g >> (-mot_color.gshift);
+ else g = g << mot_color.gshift;
+ if (mot_color.bshift<0) b = b >> (-mot_color.bshift);
+ else b = b << mot_color.bshift;
+ *red = iupCOLOR16TO8(r);
+ *green = iupCOLOR16TO8(g);
+ *blue = iupCOLOR16TO8(b);
+}
+
+static unsigned long motColorGetPixel_TrueColor(unsigned char cr, unsigned char cg, unsigned char cb)
+{
+ unsigned long r = iupCOLOR8TO16(cr);
+ unsigned long g = iupCOLOR8TO16(cg);
+ unsigned long b = iupCOLOR8TO16(cb);
+
+ if (mot_color.rshift<0)
+ r = r << (-mot_color.rshift);
+ else
+ r = r >> mot_color.rshift;
+
+ if (mot_color.gshift<0)
+ g = g << (-mot_color.gshift);
+ else
+ g = g >> mot_color.gshift;
+
+ if (mot_color.bshift<0)
+ b = b << (-mot_color.bshift);
+ else
+ b = b >> mot_color.bshift;
+
+ r = r & iupmot_visual->red_mask;
+ g = g & iupmot_visual->green_mask;
+ b = b & iupmot_visual->blue_mask;
+
+ return r | g | b;
+}
+
+static int motColorHighBit(unsigned long ul)
+{
+/* returns position of highest set bit in 'ul' as an integer (0-31),
+ or -1 if none */
+ int i; unsigned long hb;
+
+ hb = 0x80; hb = hb << 24; /* hb = 0x80000000UL */
+ for (i=31; ((ul & hb) == 0) && i>=0; i--, ul<<=1);
+ return i;
+}
+
+static void motColorMakeDirectCmap(Colormap cmap)
+{
+ int i, cmaplen, numgot;
+ unsigned char origgot[256];
+ XColor c;
+ unsigned long rmask, gmask, bmask;
+ int rshift, gshift, bshift;
+
+ rmask = iupmot_visual->red_mask;
+ gmask = iupmot_visual->green_mask;
+ bmask = iupmot_visual->blue_mask;
+
+ rshift = motColorHighBit(rmask) - 15;
+ gshift = motColorHighBit(gmask) - 15;
+ bshift = motColorHighBit(bmask) - 15;
+
+ if (rshift<0) rmask = rmask << (-rshift);
+ else rmask = rmask >> rshift;
+
+ if (gshift<0) gmask = gmask << (-gshift);
+ else gmask = gmask >> gshift;
+
+ if (bshift<0) bmask = bmask << (-bshift);
+ else bmask = bmask >> bshift;
+
+ cmaplen = iupmot_visual->map_entries;
+ if (cmaplen>256) cmaplen=256;
+
+ /* try to alloc a 'cmaplen' long grayscale colormap. May not get all
+ entries for whatever reason. Build table 'mot_color.direct_conv[]' that
+ maps range [0..(cmaplen-1)] into set of colors we did get */
+
+ for (i=0; i<256; i++) { origgot[i] = 0; mot_color.direct_conv[i] = i; }
+
+ for (i=numgot=0; i<cmaplen; i++)
+ {
+ c.red = c.green = c.blue = (unsigned short)((i * 0xffff) / (cmaplen - 1));
+ c.red = (unsigned short)(c.red & rmask);
+ c.green = (unsigned short)(c.green & gmask);
+ c.blue = (unsigned short)(c.blue & bmask);
+ c.flags = DoRed | DoGreen | DoBlue;
+
+ if (XAllocColor(iupmot_display, cmap, &c))
+ {
+ origgot[i] = 1;
+ numgot++;
+ }
+ }
+
+ if (numgot == 0)
+ return;
+
+ /* mot_color.direct_conv may or may not have holes in it. */
+ for (i=0; i<cmaplen; i++)
+ {
+ if (!origgot[i])
+ {
+ int numbak, numfwd;
+ numbak = numfwd = 0;
+ while ((i - numbak) >= 0 && !origgot[i-numbak]) numbak++;
+ while ((i + numfwd) < cmaplen && !origgot[i+numfwd]) numfwd++;
+
+ if (i-numbak<0 || !origgot[i-numbak]) numbak = 999;
+ if (i+numfwd>=cmaplen || !origgot[i+numfwd]) numfwd = 999;
+
+ if (numbak<numfwd) mot_color.direct_conv[i] = mot_color.direct_conv[i-numbak];
+ else if (numfwd<999) mot_color.direct_conv[i] = mot_color.direct_conv[i+numfwd];
+ }
+ }
+}
+
+
+/*******************************************
+ Exported Functions
+*******************************************/
+
+unsigned long (* iupmotColorGetPixel)(unsigned char r, unsigned char g, unsigned char b) = 0;
+void (* iupmotColorGetRGB)(unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue) = 0;
+
+void iupmotColorInit(void)
+{
+ int depth = iupdrvGetScreenDepth();
+
+ if (depth > 8)
+ {
+ iupmotColorGetRGB = motColorGetRGB_TrueColor;
+ iupmotColorGetPixel = motColorGetPixel_TrueColor;
+
+ /* make linear colormap for DirectColor visual */
+ if (iupmot_visual->class == DirectColor)
+ motColorMakeDirectCmap(DefaultColormap(iupmot_display, iupmot_screen));
+
+ mot_color.rshift = 15 - motColorHighBit(iupmot_visual->red_mask);
+ mot_color.gshift = 15 - motColorHighBit(iupmot_visual->green_mask);
+ mot_color.bshift = 15 - motColorHighBit(iupmot_visual->blue_mask);
+
+ mot_color.num_colors = 0;
+ mot_color.colormap = 0;
+ }
+ else
+ {
+ int i;
+ iupmotColorGetRGB = motColorGetRGB_NotTrueColor;
+ iupmotColorGetPixel = motColorGetPixel_NotTrueColor;
+
+ mot_color.colormap = DefaultColormap(iupmot_display, iupmot_screen);
+ mot_color.num_colors = 1L << depth;
+
+ for (i=0; i<mot_color.num_colors; i++)
+ mot_color.color_table[i].pixel = i;
+
+ XQueryColors(iupmot_display, mot_color.colormap, mot_color.color_table, mot_color.num_colors);
+ XSetErrorHandler(motColor8BppErrorHandler);
+
+ motColorReserveColors();
+ }
+}
+
+void iupmotColorFinish(void)
+{
+ if (mot_color.colormap)
+ {
+ unsigned long pixels[256];
+ int i;
+
+ /* release colors */
+ for (i = 0; i < mot_color.num_colors; i++)
+ pixels[i] = mot_color.color_table[i].pixel;
+
+ XFreeColors(iupmot_display, mot_color.colormap, pixels, mot_color.num_colors, 0);
+
+ /* release palette */
+ if (mot_color.colormap != DefaultColormap(iupmot_display, iupmot_screen))
+ XFreeColormap(iupmot_display, mot_color.colormap);
+ }
+}
+
+Colormap iupmotColorMap(void)
+{
+ return mot_color.colormap;
+}
+
+unsigned long iupmotColorGetPixelStr(const char* color)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(color, &r, &g, &b))
+ return (unsigned long)-1;
+
+ return iupmotColorGetPixel(r, g, b);
+}
diff --git a/iup/src/mot/iupmot_color.h b/iup/src/mot/iupmot_color.h
new file mode 100755
index 0000000..a306fd3
--- /dev/null
+++ b/iup/src/mot/iupmot_color.h
@@ -0,0 +1,36 @@
+/** \file
+ * \brief Motif Color Management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPMOT_COLOR_H
+#define __IUPMOT_COLOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Returns a pixel value from a RGB triple. */
+extern unsigned long (* iupmotColorGetPixel)(unsigned char r, unsigned char g, unsigned char b);
+
+/* Returns a RGB triple from a pixel value. */
+extern void (* iupmotColorGetRGB)(unsigned long pixel, unsigned char *r, unsigned char *g, unsigned char *b);
+
+/* initialize the toplevel colormap and the iupmotColorGet* functions */
+void iupmotColorInit(void);
+void iupmotColorFinish(void);
+
+/* returns the toplevel colormap */
+Colormap iupmotColorMap(void);
+
+/* Returns a pixel value from a IUP color description. */
+unsigned long iupmotColorGetPixelStr(const char* color);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/mot/iupmot_colordlg.c b/iup/src/mot/iupmot_colordlg.c
new file mode 100755
index 0000000..7a949bf
--- /dev/null
+++ b/iup/src/mot/iupmot_colordlg.c
@@ -0,0 +1,31 @@
+/** \file
+ * \brief IupColorDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drvinfo.h"
+#include "iup_dialog.h"
+
+#include "iupmot_drv.h"
+
+
+static int motColorDlgPopup(Ihandle* ih, int x, int y)
+{
+ (void)ih;
+ (void)x;
+ (void)y;
+ return IUP_ERROR;
+}
+
+void iupdrvColorDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = motColorDlgPopup;
+}
diff --git a/iup/src/mot/iupmot_common.c b/iup/src/mot/iupmot_common.c
new file mode 100755
index 0000000..7b3f8b7
--- /dev/null
+++ b/iup/src/mot/iupmot_common.c
@@ -0,0 +1,630 @@
+/** \file
+ * \brief Motif Base Functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <Xm/Xm.h>
+#include <Xm/ScrollBar.h>
+#include <X11/cursorfont.h>
+
+#include "iup.h"
+#include "iupkey.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_key.h"
+#include "iup_str.h"
+#include "iup_class.h"
+#include "iup_attrib.h"
+#include "iup_focus.h"
+#include "iup_key.h"
+#include "iup_drv.h"
+#include "iup_image.h"
+#include "iup_drv.h"
+
+#include "iupmot_color.h"
+#include "iupmot_drv.h"
+
+
+
+void iupdrvActivate(Ihandle* ih)
+{
+ if (iupStrEqual(ih->iclass->name, "text") || iupStrEqual(ih->iclass->name, "multiline"))
+ XmProcessTraversal(ih->handle, XmTRAVERSE_CURRENT);
+ else
+ XtCallActionProc(ih->handle, "ArmAndActivate", 0, 0, 0 );
+}
+
+static int motActivateMnemonic(Ihandle *dialog, int c)
+{
+ Ihandle *ih;
+ char attrib[19] = "_IUPMOT_MNEMONIC_ ";
+ attrib[17] = (char)c;
+ ih = (Ihandle*)iupAttribGet(dialog, attrib);
+ if (iupObjectCheck(ih))
+ {
+ iupdrvActivate(ih);
+ return IUP_IGNORE;
+ }
+ return IUP_CONTINUE;
+}
+
+void iupmotSetMnemonicTitle(Ihandle *ih, const char* value)
+{
+ char c;
+ char* str;
+
+ if (!value)
+ value = "";
+
+ str = iupStrProcessMnemonic(value, &c, -1); /* remove & and return in c */
+ if (str != value)
+ {
+ KeySym keysym = iupmotKeyCharToKeySym(c);
+ XtVaSetValues(ih->handle, XmNmnemonic, keysym, NULL); /* works only for menus, but underlines the letter */
+
+ if (ih->iclass->nativetype != IUP_TYPEMENU)
+ {
+ Ihandle* dialog = IupGetDialog(ih);
+ char attrib[22] = "_IUPMOT_MNEMONIC_ \0CB";
+ attrib[17] = (char)toupper(c);
+
+ /* used by motActivateMnemonic */
+ if (iupStrEqual(ih->iclass->name, "label"))
+ iupAttribSetStr(dialog, attrib, (char*)iupFocusNextInteractive(ih));
+ else
+ iupAttribSetStr(dialog, attrib, (char*)ih);
+
+ /* used by iupmotKeyPressEvent */
+ attrib[18] = '_';
+ IupSetCallback(dialog, attrib, (Icallback)motActivateMnemonic);
+ }
+
+ iupmotSetString(ih->handle, XmNlabelString, str);
+ free(str);
+ }
+ else
+ {
+ XtVaSetValues (ih->handle, XmNmnemonic, NULL, NULL);
+ iupmotSetString(ih->handle, XmNlabelString, str);
+ }
+}
+
+void iupmotSetString(Widget w, const char *resource, const char* value)
+{
+ XmString xm_str = XmStringCreateLocalized((String)value);
+ XtVaSetValues(w, resource, xm_str, NULL);
+ XmStringFree(xm_str);
+}
+
+char* iupmotConvertString(XmString str)
+{
+ char* text = (char*)XmStringUnparse(str, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
+ char* buf = iupStrGetMemoryCopy(text);
+ XtFree(text);
+ return buf;
+}
+
+#ifdef OLD_CONVERT
+char* iupmotConvertString(XmString str)
+{
+ XmStringContext context;
+ char *text, *p, *buf;
+ unsigned int length;
+ XmStringComponentType type;
+
+ if (!XmStringInitContext (&context, str))
+ return NULL;
+
+ buf = iupStrGetMemory(XmStringLength(str)); /* always greatter than strlen */
+
+ /* p keeps a running pointer through buf as text is read */
+ p = buf;
+ while ((type = XmStringGetNextTriple(context, &length, (XtPointer)&text)) != XmSTRING_COMPONENT_END)
+ {
+ switch (type)
+ {
+ case XmSTRING_COMPONENT_TEXT:
+ memcpy(p, text, length);
+ p += length;
+ *p = 0;
+ break;
+ case XmSTRING_COMPONENT_TAB:
+ *p++ = '\t';
+ *p = 0;
+ break;
+ case XmSTRING_COMPONENT_SEPARATOR:
+ *p++ = '\n';
+ *p = 0;
+ break;
+ }
+ XtFree(text);
+ }
+
+ XmStringFreeContext(context);
+
+ return buf;
+}
+#endif
+
+void iupdrvReparent(Ihandle* ih)
+{
+ Widget native_parent = iupChildTreeGetNativeParentHandle(ih);
+ Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+ XReparentWindow(iupmot_display, XtWindow(widget), XtWindow(native_parent), 0, 0);
+}
+
+void iupdrvBaseLayoutUpdateMethod(Ihandle *ih)
+{
+ Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+
+ XtVaSetValues(widget,
+ XmNx, (XtArgVal)ih->x,
+ XmNy, (XtArgVal)ih->y,
+ XmNwidth, (XtArgVal)ih->currentwidth,
+ XmNheight, (XtArgVal)ih->currentheight,
+ NULL);
+}
+
+void iupdrvBaseUnMapMethod(Ihandle* ih)
+{
+ Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+
+ XtUnrealizeWidget(widget); /* To match the call to XtRealizeWidget */
+ XtDestroyWidget(widget); /* To match the call to XtCreateManagedWidget */
+}
+
+void iupdrvDisplayUpdate(Ihandle *ih)
+{
+ XExposeEvent evt;
+ Dimension w, h;
+
+ XtVaGetValues(ih->handle, XmNwidth, &w,
+ XmNheight, &h,
+ NULL);
+
+ evt.type = Expose;
+ evt.display = iupmot_display;
+ evt.send_event = True;
+ evt.window = XtWindow(ih->handle);
+
+ evt.x = 0;
+ evt.y = 0;
+ evt.width = w;
+ evt.height = h;
+
+ evt.count = 0;
+
+ /* POST a Redraw */
+ XSendEvent(iupmot_display, XtWindow(ih->handle), False, ExposureMask, (XEvent*)&evt);
+}
+
+void iupdrvDisplayRedraw(Ihandle *ih)
+{
+ Widget w;
+
+ /* POST a Redraw */
+ iupdrvDisplayUpdate(ih);
+
+ /* if this element has an inner native parent (like IupTabs),
+ then redraw that native parent if different from the element. */
+ w = (Widget)iupClassObjectGetInnerNativeContainerHandle(ih, (Ihandle*)IupGetAttribute(ih, "VALUE_HANDLE"));
+ if (w && w != ih->handle)
+ {
+ Widget handle = ih->handle;
+ ih->handle = w;
+ iupdrvDisplayUpdate(ih);
+ ih->handle = handle;
+ }
+
+ /* flush exposure events. */
+ XmUpdateDisplay(ih->handle);
+}
+
+void iupdrvScreenToClient(Ihandle* ih, int *x, int *y)
+{
+ Window child;
+ XTranslateCoordinates(iupmot_display, RootWindow(iupmot_display, iupmot_screen),
+ XtWindow(ih->handle),
+ *x, *y, x, y, &child);
+}
+
+void iupmotHelpCallback(Widget w, Ihandle *ih, XtPointer call_data)
+{
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+
+ (void)call_data;
+ (void)w;
+}
+
+void iupmotEnterLeaveWindowEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont)
+{
+ Icallback cb = NULL;
+ (void)cont;
+ (void)w;
+
+ if (evt->type == EnterNotify)
+ {
+ iupmotTipEnterNotify(ih);
+
+ cb = IupGetCallback(ih, "ENTERWINDOW_CB");
+ }
+ else if (evt->type == LeaveNotify)
+ {
+ iupmotTipLeaveNotify();
+
+ cb = IupGetCallback(ih, "LEAVEWINDOW_CB");
+ }
+
+ if (cb)
+ cb(ih);
+}
+
+int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value)
+{
+ if (iupdrvIsVisible(ih))
+ {
+ if (iupStrEqualNoCase(value, "TOP"))
+ XRaiseWindow(iupmot_display, XtWindow(ih->handle));
+ else
+ XLowerWindow(iupmot_display, XtWindow(ih->handle));
+ }
+
+ return 0;
+}
+
+void iupdrvSetVisible(Ihandle* ih, int visible)
+{
+ Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+
+ if (visible)
+ XtMapWidget(widget);
+ else
+ XtUnmapWidget(widget);
+}
+
+int iupdrvIsVisible(Ihandle* ih)
+{
+ XWindowAttributes wa;
+ XGetWindowAttributes(iupmot_display, XtWindow(ih->handle), &wa);
+ return (wa.map_state == IsViewable);
+}
+
+int iupdrvIsActive(Ihandle* ih)
+{
+ return XtIsSensitive(ih->handle);
+}
+
+void iupdrvSetActive(Ihandle* ih, int enable)
+{
+ Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+
+ XtSetSensitive(widget, enable);
+}
+
+char* iupmotGetXWindowAttrib(Ihandle *ih)
+{
+ return (char*)XtWindow(ih->handle);
+}
+
+char* iupdrvBaseGetXAttrib(Ihandle *ih)
+{
+ int x, y;
+ Window child;
+ char* str = iupStrGetMemory(20);
+ Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+
+ /* Translating to absolute screen coordinates */
+ /* source destination */
+ XTranslateCoordinates(iupmot_display,
+ XtWindow(widget), RootWindow(iupmot_display, iupmot_screen),
+ 0, 0, &x, &y,
+ &child);
+
+ sprintf(str, "%d", x);
+ return str;
+}
+
+char* iupdrvBaseGetYAttrib(Ihandle *ih)
+{
+ int x, y;
+ Window child;
+ char* str = iupStrGetMemory(20);
+ Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+
+ /* Translating to absolute screen coordinates */
+ /* source destination */
+ XTranslateCoordinates(iupmot_display,
+ XtWindow(widget), RootWindow(iupmot_display, iupmot_screen),
+ 0, 0, &x, &y,
+ &child);
+
+ sprintf(str, "%d", y);
+ return str;
+}
+
+void iupmotSetBgColor(Widget w, Pixel color)
+{
+ Pixel fgcolor;
+ XtVaGetValues(w, XmNforeground, &fgcolor, NULL);
+ XmChangeColor(w, color);
+ /* XmChangeColor also sets the XmNforeground color, so we must reset to the previous one. */
+ XtVaSetValues(w, XmNforeground, fgcolor, NULL);
+ XtVaSetValues(w, XmNbackgroundPixmap, XmUNSPECIFIED_PIXMAP, NULL);
+}
+
+int iupdrvBaseSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ {
+ iupmotSetBgColor(ih->handle, color);
+
+ /* update internal image cache for controls that have the IMAGE attribute */
+ iupImageUpdateParent(ih);
+ }
+ return 1;
+}
+
+char* iupmotGetBgColorAttrib(Ihandle* ih)
+{
+ unsigned char r, g, b;
+ Pixel color;
+ char* str = iupStrGetMemory(20);
+ XtVaGetValues(ih->handle, XmNbackground, &color, NULL);
+ iupmotColorGetRGB(color, &r, &g, &b);
+ sprintf(str, "%d %d %d", (int)r, (int)g, (int)b);
+ return str;
+}
+
+int iupdrvBaseSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ XtVaSetValues(ih->handle, XmNforeground, color, NULL);
+ return 1;
+}
+
+void iupmotGetWindowSize(Ihandle *ih, int *width, int *height)
+{
+ Dimension w, h;
+ XtVaGetValues(ih->handle, XmNwidth, &w,
+ XmNheight, &h,
+ NULL);
+ *width = w;
+ *height = h;
+}
+
+static Cursor motEmptyCursor(Ihandle* ih)
+{
+ /* creates an empty cursor */
+ XColor cursor_color = {0L,0,0,0,0,0};
+ char bitsnull[1] = {0x00};
+ Pixmap pixmapnull;
+ Cursor cur;
+
+ pixmapnull = XCreateBitmapFromData(iupmot_display,
+ XtWindow(ih->handle),
+ bitsnull,
+ 1,1);
+
+ cur = XCreatePixmapCursor(iupmot_display,
+ pixmapnull,
+ pixmapnull,
+ &cursor_color,
+ &cursor_color,
+ 0,0);
+
+ XFreePixmap(iupmot_display, pixmapnull);
+
+ return cur;
+}
+
+static Cursor motGetCursor(Ihandle* ih, const char* name)
+{
+ static struct {
+ const char* iupname;
+ int sysname;
+ } table[] = {
+ { "NONE", 0},
+ { "NULL", 0},
+ { "ARROW", XC_left_ptr},
+ { "BUSY", XC_watch},
+ { "CROSS", XC_crosshair},
+ { "HAND", XC_hand2},
+ { "HELP", XC_question_arrow},
+ { "IUP", XC_question_arrow},
+ { "MOVE", XC_fleur},
+ { "PEN", XC_pencil},
+ { "RESIZE_N", XC_top_side},
+ { "RESIZE_S", XC_bottom_side},
+ { "RESIZE_NS", XC_sb_v_double_arrow},
+ { "RESIZE_W", XC_left_side},
+ { "RESIZE_E", XC_right_side},
+ { "RESIZE_WE", XC_sb_h_double_arrow},
+ { "RESIZE_NE", XC_top_right_corner},
+ { "RESIZE_SE", XC_bottom_right_corner},
+ { "RESIZE_NW", XC_top_left_corner},
+ { "RESIZE_SW", XC_bottom_left_corner},
+ { "TEXT", XC_xterm},
+ { "UPARROW", XC_center_ptr}
+ };
+
+ Cursor cur;
+ char str[50];
+ int i, count = sizeof(table)/sizeof(table[0]);
+
+ /* check the cursor cache first (per control)*/
+ sprintf(str, "_IUPMOT_CURSOR_%s", name);
+ cur = (Cursor)iupAttribGet(ih, str);
+ if (cur)
+ return cur;
+
+ /* check the pre-defined IUP names first */
+ for (i = 0; i < count; i++)
+ {
+ if (iupStrEqualNoCase(name, table[i].iupname))
+ {
+ if (table[i].sysname)
+ cur = XCreateFontCursor(iupmot_display, table[i].sysname);
+ else
+ cur = motEmptyCursor(ih);
+
+ break;
+ }
+ }
+
+ if (i == count)
+ {
+ /* check for a name defined cursor */
+ cur = (Cursor)iupImageGetCursor(name);
+ }
+
+ iupAttribSetStr(ih, str, (char*)cur);
+ return cur;
+}
+
+int iupdrvBaseSetCursorAttrib(Ihandle* ih, const char* value)
+{
+ Cursor cur = motGetCursor(ih, value);
+ if (cur)
+ {
+ XDefineCursor(iupmot_display, XtWindow(ih->handle), cur);
+ return 1;
+ }
+ return 0;
+}
+
+#include <Xm/XmP.h>
+#include <Xm/DrawP.h>
+
+void iupdrvDrawFocusRect(Ihandle* ih, void* _gc, int x, int y, int w, int h)
+{
+ Drawable wnd = (Drawable)IupGetAttribute(ih, "XWINDOW"); /* Use IupGetAttribute to consult the native implemetation */
+ GC gc = (GC)_gc;
+ XmeDrawHighlight(iupmot_display, wnd, gc, x, y, w, h, 1);
+}
+
+void iupdrvBaseRegisterCommonAttrib(Iclass* ic)
+{
+ iupClassRegisterAttribute(ic, "XMFONTLIST", iupmotGetFontListAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "XFONTSTRUCT", iupmotGetFontStructAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "XFONTID", iupmotGetFontIdAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+}
+
+static void motDoNothing(Widget w, XEvent* evt, String* params, Cardinal* num_params)
+{
+ (void)w;
+ (void)evt;
+ (void)params;
+ (void)num_params;
+}
+
+void iupmotDisableDragSource(Widget w)
+{
+ char dragTranslations[] = "#override <Btn2Down>: iupDoNothing()";
+ static int do_nothing_rec = 0;
+ if (!do_nothing_rec)
+ {
+ XtActionsRec rec = {"iupDoNothing", (XtActionProc)motDoNothing};
+ XtAppAddActions(iupmot_appcontext, &rec, 1);
+ do_nothing_rec = 1;
+ }
+ XtOverrideTranslations(w, XtParseTranslationTable(dragTranslations));
+}
+
+int iupdrvGetScrollbarSize(void)
+{
+ return 15;
+}
+
+void iupmotSetPixmap(Ihandle* ih, const char* name, const char* prop, int make_inactive)
+{
+ if (name)
+ {
+ Pixmap old_pixmap;
+ Pixmap pixmap = (Pixmap)iupImageGetImage(name, ih, make_inactive);
+ if (!pixmap)
+ pixmap = XmUNSPECIFIED_PIXMAP;
+ XtVaGetValues(ih->handle, prop, &old_pixmap, NULL);
+ if (pixmap != old_pixmap)
+ XtVaSetValues(ih->handle, prop, pixmap, NULL);
+ return;
+ }
+
+ /* if not defined */
+ XtVaSetValues(ih->handle, prop, XmUNSPECIFIED_PIXMAP, NULL);
+}
+
+void iupmotButtonPressReleaseEvent(Widget w, Ihandle* ih, XEvent* evt, Boolean* cont)
+{
+ unsigned long elapsed;
+ static Time last = 0;
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ IFniiiis cb;
+
+ XButtonEvent *but_evt = (XButtonEvent*)evt;
+ if (but_evt->button!=Button1 &&
+ but_evt->button!=Button2 &&
+ but_evt->button!=Button3 &&
+ but_evt->button!=Button4 &&
+ but_evt->button!=Button5)
+ return;
+
+ cb = (IFniiiis) IupGetCallback(ih,"BUTTON_CB");
+ if (cb)
+ {
+ int ret, doubleclick = 0;
+ int b = IUP_BUTTON1+(but_evt->button-1);
+
+ /* Double/Single Click */
+ if (but_evt->type==ButtonPress)
+ {
+ elapsed = but_evt->time - last;
+ last = but_evt->time;
+ if ((int)elapsed <= XtGetMultiClickTime(iupmot_display))
+ doubleclick = 1;
+ }
+
+ iupmotButtonKeySetStatus(but_evt->state, but_evt->button, status, doubleclick);
+
+ ret = cb(ih, b, (but_evt->type==ButtonPress), but_evt->x, but_evt->y, status);
+ if (ret==IUP_CLOSE)
+ IupExitLoop();
+ else if (ret==IUP_IGNORE)
+ *cont=False;
+ }
+
+ (void)w;
+}
+
+void iupmotPointerMotionEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont)
+{
+ IFniis cb = (IFniis)IupGetCallback(ih,"MOTION_CB");
+ if (cb)
+ {
+ XMotionEvent *motion_evt = (XMotionEvent*)evt;
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ iupmotButtonKeySetStatus(motion_evt->state, 0, status, 0);
+ cb(ih, motion_evt->x, motion_evt->y, status);
+ }
+
+ (void)w;
+ (void)cont;
+}
diff --git a/iup/src/mot/iupmot_dialog.c b/iup/src/mot/iupmot_dialog.c
new file mode 100755
index 0000000..4eeb834
--- /dev/null
+++ b/iup/src/mot/iupmot_dialog.c
@@ -0,0 +1,1069 @@
+/** \file
+ * \brief IupDialog class
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <Xm/BulletinB.h>
+#include <Xm/MwmUtil.h>
+#include <Xm/AtomMgr.h>
+#include <Xm/Protocols.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_class.h"
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_dlglist.h"
+#include "iup_attrib.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_drvinfo.h"
+#include "iup_focus.h"
+#include "iup_str.h"
+#define _IUPDLG_PRIVATE
+#include "iup_dialog.h"
+#include "iup_image.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+Atom iupmot_wm_deletewindow = 0; /* used also by IupMessageDlg */
+
+static int motDialogSetBgColorAttrib(Ihandle* ih, const char* value);
+
+/****************************************************************
+ Utilities
+****************************************************************/
+
+
+int iupdrvDialogIsVisible(Ihandle* ih)
+{
+ return iupdrvIsVisible(ih) || ih->data->show_state == IUP_MINIMIZE;
+}
+
+void iupdrvDialogUpdateSize(Ihandle* ih)
+{
+ Dimension width, height;
+ XtVaGetValues(ih->handle, XmNwidth, &width, XmNheight, &height, NULL);
+ ih->currentwidth = width;
+ ih->currentheight = height;
+}
+
+void iupdrvDialogGetSize(InativeHandle* handle, int *w, int *h)
+{
+ Dimension width, height;
+ XtVaGetValues(handle, XmNwidth, &width, XmNheight, &height, NULL);
+ if (w) *w = width;
+ if (h) *h = height;
+}
+
+void iupmotDialogSetVisual(Ihandle* ih, void* visual)
+{
+ Ihandle *dialog = IupGetDialog(ih);
+ XtVaSetValues(dialog->handle, XmNvisual, visual, NULL);
+}
+
+void iupmotDialogResetVisual(Ihandle* ih)
+{
+ Ihandle *dialog = IupGetDialog(ih);
+ XtVaSetValues(dialog->handle, XmNvisual, iupmot_visual, NULL);
+}
+
+void iupdrvDialogSetVisible(Ihandle* ih, int visible)
+{
+ if (visible)
+ {
+ XtMapWidget(ih->handle);
+ XRaiseWindow(iupmot_display, XtWindow(ih->handle));
+ while (!iupdrvDialogIsVisible(ih)); /* waits until window get mapped */
+ }
+ else
+ {
+ /* if iupdrvIsVisible reports hidden, then it should be minimized */
+ if (!iupdrvIsVisible(ih)) /* can NOT hide a minimized window, so map it first. */
+ {
+ XtMapWidget(ih->handle);
+ XRaiseWindow(iupmot_display, XtWindow(ih->handle));
+ while (!iupdrvDialogIsVisible(ih)); /* waits until window get mapped */
+ }
+
+ XtUnmapWidget(ih->handle);
+ while (iupdrvDialogIsVisible(ih)); /* waits until window gets unmapped */
+ }
+}
+
+void iupdrvDialogGetPosition(InativeHandle* handle, int *x, int *y)
+{
+ Dimension cur_x, cur_y;
+ XtVaGetValues(handle, XmNx, &cur_x,
+ XmNy, &cur_y,
+ NULL);
+ if (x) *x = cur_x;
+ if (y) *y = cur_y;
+}
+
+void iupdrvDialogSetPosition(Ihandle *ih, int x, int y)
+{
+ XtVaSetValues(ih->handle,
+ XmNx, (XtArgVal)x,
+ XmNy, (XtArgVal)y,
+ NULL);
+}
+
+static int motDialogGetMenuSize(Ihandle* ih)
+{
+ if (ih->data->menu)
+ return iupdrvMenuGetMenuBarSize(ih->data->menu);
+ else
+ return 0;
+}
+
+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_border = has_caption ||
+ iupAttribGetBoolean(ih, "RESIZE") ||
+ iupAttribGetBoolean(ih, "BORDER");
+
+ *menu = motDialogGetMenuSize(ih);
+
+ if (ih->handle && iupdrvDialogIsVisible(ih))
+ {
+ int win_border, win_caption;
+ if (iupdrvGetWindowDecor((void*)XtWindow(ih->handle), &win_border, &win_caption))
+ {
+ *border = 0;
+ if (has_border)
+ *border = win_border;
+
+ *caption = 0;
+ if (has_caption)
+ *caption = win_caption;
+
+ if (!native_border && *border)
+ native_border = win_border;
+
+ if (!native_caption && *caption)
+ native_caption = win_caption;
+
+ return;
+ }
+ }
+
+ /* I could not set the size of the window including the decorations when the dialog is hidden */
+ /* So we have to estimate the size of borders and caption when the dialog is hidden */
+
+ *border = 0;
+ if (has_border)
+ {
+ if (native_border)
+ *border = native_border;
+ else
+ *border = 5;
+ }
+
+ *caption = 0;
+ if (has_caption)
+ {
+ if (native_caption)
+ *caption = native_caption;
+ else
+ *caption = 20;
+ }
+}
+
+static int motDialogQueryWMspecSupport(Atom feature)
+{
+ static Atom netsuppport = 0;
+ Atom type;
+ Atom *atoms;
+ int format;
+ unsigned long after, natoms, i;
+
+ if (!netsuppport)
+ netsuppport = XmInternAtom(iupmot_display, "_NET_SUPPORTED", False);
+
+ /* get all the features */
+ XGetWindowProperty(iupmot_display, RootWindow(iupmot_display, iupmot_screen),
+ netsuppport, 0, LONG_MAX, False, XA_ATOM, &type, &format, &natoms,
+ &after, (unsigned char **)&atoms);
+ if (type != XA_ATOM || atoms == NULL)
+ {
+ if (atoms) XFree(atoms);
+ return 0;
+ }
+
+ /* Lookup the feature we want */
+ for (i = 0; i < natoms; i++)
+ {
+ if (atoms[i] == feature)
+ {
+ XFree(atoms);
+ return 1;
+ }
+ }
+
+ XFree(atoms);
+ return 0;
+}
+
+static void motDialogSetWindowManagerStyle(Ihandle* ih)
+{
+ MwmHints hints;
+ static Atom xwmhint = 0;
+ if (!xwmhint)
+ xwmhint = XmInternAtom(iupmot_display, "_MOTIF_WM_HINTS", False);
+
+ hints.flags = (MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS);
+ hints.functions = 0;
+ hints.decorations = 0;
+ hints.input_mode = 0;
+ hints.status = 0;
+
+ if (IupGetAttribute(ih, "TITLE")) { /* must use IupGetAttribute to check from the native implementation */
+ hints.functions |= MWM_FUNC_MOVE;
+ hints.decorations |= MWM_DECOR_TITLE;
+ }
+
+ if (iupAttribGetBoolean(ih, "MENUBOX")) {
+ hints.functions |= MWM_FUNC_CLOSE;
+ hints.decorations |= MWM_DECOR_MENU;
+ }
+
+ if (iupAttribGetBoolean(ih, "MINBOX")) {
+ hints.functions |= MWM_FUNC_MINIMIZE;
+ hints.decorations |= MWM_DECOR_MINIMIZE;
+ }
+
+ if (iupAttribGetBoolean(ih, "MAXBOX")) {
+ hints.functions |= MWM_FUNC_MAXIMIZE;
+ hints.decorations |= MWM_DECOR_MAXIMIZE;
+ }
+
+ if (iupAttribGetBoolean(ih, "RESIZE")) {
+ hints.functions |= MWM_FUNC_RESIZE;
+ hints.decorations |= MWM_DECOR_RESIZEH;
+ }
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ hints.decorations |= MWM_DECOR_BORDER;
+
+ XChangeProperty(iupmot_display, XtWindow(ih->handle),
+ xwmhint, xwmhint,
+ 32, PropModeReplace,
+ (const unsigned char *) &hints,
+ PROP_MOTIF_WM_HINTS_ELEMENTS);
+}
+
+static void motDialogChangeWMState(Ihandle* ih, Atom state1, Atom state2, int operation)
+{
+ static Atom wmstate = 0;
+ if (!wmstate)
+ wmstate = XmInternAtom(iupmot_display, "_NET_WM_STATE", False);
+
+ if (iupdrvDialogIsVisible(ih))
+ {
+ XEvent evt;
+ evt.type = ClientMessage;
+ evt.xclient.type = ClientMessage;
+ evt.xclient.serial = 0;
+ evt.xclient.send_event = True;
+ evt.xclient.display = iupmot_display;
+ evt.xclient.window = XtWindow(ih->handle);
+ evt.xclient.message_type = wmstate;
+ evt.xclient.format = 32;
+ evt.xclient.data.l[0] = operation;
+ evt.xclient.data.l[1] = state1;
+ evt.xclient.data.l[2] = state2;
+ evt.xclient.data.l[3] = 0;
+ evt.xclient.data.l[4] = 0;
+
+ XSendEvent(iupmot_display, RootWindow(iupmot_display, iupmot_screen), False,
+ SubstructureRedirectMask | SubstructureNotifyMask, &evt);
+ }
+ else
+ {
+ if (operation)
+ {
+ if (state1 && state2)
+ {
+ Atom atoms[2];
+ atoms[0] = state1;
+ atoms[0] = state2;
+
+ XChangeProperty(iupmot_display, XtWindow(ih->handle),
+ wmstate, XA_ATOM,
+ 32, PropModeReplace,
+ (const unsigned char *)&atoms, 2);
+ }
+ else
+ {
+ XChangeProperty(iupmot_display, XtWindow(ih->handle),
+ wmstate, XA_ATOM,
+ 32, PropModeReplace,
+ (const unsigned char *)&state1, 1);
+ }
+ }
+ else
+ {
+ /* TODO: This is not working. The property is not correctly removed. */
+ /* XDeleteProperty(iupmot_display, XtWindow(ih->handle), wmstate); */
+
+ /* Maybe the right way to do it is to retrieve all the atoms */
+ /* and change again with all atoms except the one to remove */
+ }
+ }
+}
+
+static int motDialogSetFullScreen(Ihandle* ih, int fullscreen)
+{
+ static int support_fullscreen = -1; /* WARNING: The WM can be changed dinamically */
+
+ static Atom xwmfs = 0;
+ if (!xwmfs)
+ xwmfs = XmInternAtom(iupmot_display, "_NET_WM_STATE_FULLSCREEN", False);
+
+ if (support_fullscreen == -1)
+ support_fullscreen = motDialogQueryWMspecSupport(xwmfs);
+
+ if (support_fullscreen)
+ {
+ motDialogChangeWMState(ih, xwmfs, 0, fullscreen);
+ return 1;
+ }
+
+ return 0;
+}
+
+int iupdrvDialogSetPlacement(Ihandle* ih)
+{
+ char* placement;
+ ih->data->show_state = IUP_SHOW;
+
+ if (iupAttribGetBoolean(ih, "FULLSCREEN"))
+ return 1;
+
+ placement = iupAttribGet(ih, "PLACEMENT");
+ if (!placement)
+ return 0;
+
+ if (iupStrEqualNoCase(placement, "MINIMIZED"))
+ {
+ if (iupdrvDialogIsVisible(ih))
+ XIconifyWindow(iupmot_display, XtWindow(ih->handle), iupmot_screen);
+ else
+ {
+ /* TODO: This is not working, so force a minimize after visible. */
+ /*XWMHints wm_hints; */
+ /*wm_hints.flags = StateHint; */
+ /*wm_hints.initial_state = IconicState; */
+ /*XSetWMHints(iupmot_display, XtWindow(ih->handle), &wm_hints); */
+
+ XtMapWidget(ih->handle);
+ XIconifyWindow(iupmot_display, XtWindow(ih->handle), iupmot_screen);
+ }
+ }
+ else if (iupStrEqualNoCase(placement, "MAXIMIZED"))
+ {
+ static Atom maxatoms[2] = {0, 0};
+ if (!(maxatoms[0]))
+ {
+ maxatoms[0] = XmInternAtom(iupmot_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
+ maxatoms[1] = XmInternAtom(iupmot_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+ }
+
+ motDialogChangeWMState(ih, maxatoms[0], maxatoms[1], 1);
+ }
+ else if (iupStrEqualNoCase(placement, "FULL"))
+ {
+ int width, height, x, y;
+ int border, caption, menu;
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ /* position the decoration outside the screen */
+ x = -(border);
+ y = -(border+caption+menu);
+
+ /* the dialog client area will cover the task bar */
+ iupdrvGetFullSize(&width, &height);
+
+ height += menu; /* the menu is included in the client area size in Motif. */
+
+ /* set the new size and position */
+ /* The resize event will update the layout */
+ XtVaSetValues(ih->handle,
+ XmNx, (XtArgVal)x, /* outside border */
+ XmNy, (XtArgVal)y,
+ XmNwidth, (XtArgVal)width, /* client size */
+ XmNheight, (XtArgVal)height,
+ NULL);
+ }
+
+ iupAttribSetStr(ih, "PLACEMENT", NULL); /* reset to NORMAL */
+
+ return 1;
+}
+
+/****************************************************************************
+ Attributes
+****************************************************************************/
+
+
+static int motDialogSetMinSizeAttrib(Ihandle* ih, const char* value)
+{
+ int decorwidth = 0, decorheight = 0;
+ int min_w = 1, min_h = 1; /* MINSIZE default value */
+ iupStrToIntInt(value, &min_w, &min_h, 'x');
+
+ /* The minmax size restricts the client area */
+ iupDialogGetDecorSize(ih, &decorwidth, &decorheight);
+
+ if (min_w > decorwidth)
+ XtVaSetValues(ih->handle, XmNminWidth, min_w-decorwidth, NULL);
+ if (min_h > decorheight)
+ XtVaSetValues(ih->handle, XmNminHeight, min_h-decorheight, NULL);
+
+ return 1;
+}
+
+static int motDialogSetMaxSizeAttrib(Ihandle* ih, const char* value)
+{
+ int decorwidth = 0, decorheight = 0;
+ int max_w = 65535, max_h = 65535; /* MAXSIZE default value */
+ iupStrToIntInt(value, &max_w, &max_h, 'x');
+
+ /* The minmax size restricts the client area */
+ iupDialogGetDecorSize(ih, &decorwidth, &decorheight);
+
+ if (max_w > decorwidth)
+ XtVaSetValues(ih->handle, XmNmaxWidth, max_w-decorwidth, NULL);
+ if (max_h > decorheight)
+ XtVaSetValues(ih->handle, XmNmaxHeight, max_h-decorheight, NULL);
+
+ return 1;
+}
+
+static char* motDialogGetXAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+
+ int x;
+ iupdrvDialogGetPosition(ih->handle, &x, NULL);
+
+ sprintf(str, "%d", x);
+ return str;
+}
+
+static char* motDialogGetYAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+
+ int y;
+ iupdrvDialogGetPosition(ih->handle, &y, NULL);
+
+ sprintf(str, "%d", y);
+ return str;
+}
+
+static int motDialogSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ value = "";
+
+ XtVaSetValues(ih->handle, XmNtitle, value,
+ XmNiconName, value,
+ NULL);
+ return 0;
+}
+
+static char* motDialogGetTitleAttrib(Ihandle* ih)
+{
+ char* title;
+ XtVaGetValues(ih->handle, XmNtitle, &title, NULL);
+
+ if (!title || title[0] == 0)
+ return NULL;
+ else
+ {
+ char* str = iupStrGetMemory(200);
+ strcpy(str, title);
+ return str;
+ }
+}
+
+static char* motDialogGetClientSizeAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+
+ Dimension manager_width, manager_height;
+ Widget dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager");
+ XtVaGetValues(dialog_manager, XmNwidth, &manager_width,
+ XmNheight, &manager_height,
+ NULL);
+
+ sprintf(str, "%dx%d", (int)manager_width, (int)manager_height - motDialogGetMenuSize(ih));
+ return str;
+}
+
+static int motDialogSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ {
+ Widget dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager");
+ XtVaSetValues(dialog_manager, XmNbackground, color, NULL);
+ XtVaSetValues(dialog_manager, XmNbackgroundPixmap, XmUNSPECIFIED_PIXMAP, NULL);
+ return 1;
+ }
+ return 0;
+}
+
+static int motDialogSetBackgroundAttrib(Ihandle* ih, const char* value)
+{
+ if (motDialogSetBgColorAttrib(ih, value))
+ return 1;
+ else
+ {
+ Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0);
+ if (pixmap)
+ {
+ Widget dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager");
+ XtVaSetValues(dialog_manager, XmNbackgroundPixmap, pixmap, NULL);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int motDialogSetFullScreenAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ {
+ if (!iupAttribGet(ih, "_IUPMOT_FS_STYLE"))
+ {
+ int visible = iupdrvDialogIsVisible(ih);
+ if (visible)
+ iupAttribSetStr(ih, "_IUPMOT_FS_STYLE", "VISIBLE");
+ else
+ iupAttribSetStr(ih, "_IUPMOT_FS_STYLE", "HIDDEN");
+
+ /* save the previous decoration attributes */
+ /* during fullscreen these attributes can be consulted by the application */
+ iupAttribStoreStr(ih, "_IUPMOT_FS_MAXBOX", iupAttribGet(ih, "MAXBOX"));
+ iupAttribStoreStr(ih, "_IUPMOT_FS_MINBOX", iupAttribGet(ih, "MINBOX"));
+ iupAttribStoreStr(ih, "_IUPMOT_FS_MENUBOX",iupAttribGet(ih, "MENUBOX"));
+ iupAttribStoreStr(ih, "_IUPMOT_FS_RESIZE", iupAttribGet(ih, "RESIZE"));
+ iupAttribStoreStr(ih, "_IUPMOT_FS_BORDER", iupAttribGet(ih, "BORDER"));
+ iupAttribStoreStr(ih, "_IUPMOT_FS_TITLE", IupGetAttribute(ih, "TITLE")); /* must use IupGetAttribute to check from the native implementation */
+
+ /* remove the decorations attributes */
+ iupAttribSetStr(ih, "MAXBOX", "NO");
+ iupAttribSetStr(ih, "MINBOX", "NO");
+ iupAttribSetStr(ih, "MENUBOX", "NO");
+ IupSetAttribute(ih, "TITLE", NULL); iupAttribSetStr(ih, "TITLE", NULL); /* remove from the hash table if we are during IupMap */
+ iupAttribSetStr(ih, "RESIZE", "NO");
+ iupAttribSetStr(ih, "BORDER", "NO");
+
+ /* use WM fullscreen support */
+ if (!motDialogSetFullScreen(ih, 1))
+ {
+ /* or configure fullscreen manually */
+ int decor;
+ int width, height;
+
+ /* hide before changing decorations */
+ if (visible)
+ {
+ iupAttribSetStr(ih, "_IUPMOT_SHOW_STATE", NULL); /* To avoid a SHOW_CB notification */
+ XtUnmapWidget(ih->handle);
+ }
+
+ /* save the previous position and size */
+ iupAttribStoreStr(ih, "_IUPMOT_FS_X", IupGetAttribute(ih, "X")); /* must use IupGetAttribute to check from the native implementation */
+ iupAttribStoreStr(ih, "_IUPMOT_FS_Y", IupGetAttribute(ih, "Y"));
+ iupAttribStoreStr(ih, "_IUPMOT_FS_SIZE", IupGetAttribute(ih, "RASTERSIZE"));
+
+ /* save the previous decoration */
+ XtVaGetValues(ih->handle, XmNmwmDecorations, &decor, NULL);
+ iupAttribSetStr(ih, "_IUPMOT_FS_DECOR", (char*)decor);
+
+ /* remove the decorations */
+ XtVaSetValues(ih->handle, XmNmwmDecorations, (XtArgVal)0, NULL);
+ motDialogSetWindowManagerStyle(ih);
+
+ /* get full screen size */
+ iupdrvGetFullSize(&width, &height);
+
+ /* set position and size */
+ XtVaSetValues(ih->handle, XmNwidth, (XtArgVal)width,
+ XmNheight, (XtArgVal)height,
+ XmNx, (XtArgVal)0,
+ XmNy, (XtArgVal)0,
+ NULL);
+
+ /* layout will be updated in motDialogConfigureNotify */
+ if (visible)
+ XtMapWidget(ih->handle);
+ }
+ }
+ }
+ else
+ {
+ char* fs_style = iupAttribGet(ih, "_IUPMOT_FS_STYLE");
+ if (fs_style)
+ {
+ /* can only switch back from full screen if window was visible */
+ /* when fullscreen was set */
+ if (iupStrEqualNoCase(fs_style, "VISIBLE"))
+ {
+ iupAttribSetStr(ih, "_IUPMOT_FS_STYLE", NULL);
+
+ /* restore the decorations attributes */
+ iupAttribStoreStr(ih, "MAXBOX", iupAttribGet(ih, "_IUPMOT_FS_MAXBOX"));
+ iupAttribStoreStr(ih, "MINBOX", iupAttribGet(ih, "_IUPMOT_FS_MINBOX"));
+ iupAttribStoreStr(ih, "MENUBOX",iupAttribGet(ih, "_IUPMOT_FS_MENUBOX"));
+ IupSetAttribute(ih, "TITLE", iupAttribGet(ih, "_IUPMOT_FS_TITLE")); /* TITLE is not stored in the HashTable */
+ iupAttribStoreStr(ih, "RESIZE", iupAttribGet(ih, "_IUPMOT_FS_RESIZE"));
+ iupAttribStoreStr(ih, "BORDER", iupAttribGet(ih, "_IUPMOT_FS_BORDER"));
+
+ if (!motDialogSetFullScreen(ih, 0))
+ {
+ int border, caption, menu, x, y;
+ int visible = iupdrvDialogIsVisible(ih);
+ if (visible)
+ XtUnmapWidget(ih->handle);
+
+ /* restore the decorations */
+ XtVaSetValues(ih->handle, XmNmwmDecorations, (XtArgVal)(int)iupAttribGet(ih, "_IUPMOT_FS_DECOR"), NULL);
+ motDialogSetWindowManagerStyle(ih);
+
+ /* the dialog decoration will not be considered yet in the next XtVaSetValues */
+ /* so compensate the decoration when restoring the position and size */
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+ x = iupAttribGetInt(ih, "_IUPMOT_FS_X") - (border);
+ y = iupAttribGetInt(ih, "_IUPMOT_FS_Y") - (border+caption+menu);
+
+ /* restore position and size */
+ XtVaSetValues(ih->handle,
+ XmNx, (XtArgVal)x,
+ XmNy, (XtArgVal)y,
+ XmNwidth, (XtArgVal)(IupGetInt(ih, "_IUPMOT_FS_SIZE") - (2*border)),
+ XmNheight, (XtArgVal)(IupGetInt2(ih, "_IUPMOT_FS_SIZE") - (2*border+caption)),
+ NULL);
+
+ /* layout will be updated in motDialogConfigureNotify */
+ if (visible)
+ XtMapWidget(ih->handle);
+
+ /* remove auxiliar attributes */
+ iupAttribSetStr(ih, "_IUPMOT_FS_X", NULL);
+ iupAttribSetStr(ih, "_IUPMOT_FS_Y", NULL);
+ iupAttribSetStr(ih, "_IUPMOT_FS_SIZE", NULL);
+ iupAttribSetStr(ih, "_IUPMOT_FS_DECOR", NULL);
+ }
+
+ /* remove auxiliar attributes */
+ iupAttribSetStr(ih, "_IUPMOT_FS_MAXBOX", NULL);
+ iupAttribSetStr(ih, "_IUPMOT_FS_MINBOX", NULL);
+ iupAttribSetStr(ih, "_IUPMOT_FS_MENUBOX",NULL);
+ iupAttribSetStr(ih, "_IUPMOT_FS_RESIZE", NULL);
+ iupAttribSetStr(ih, "_IUPMOT_FS_BORDER", NULL);
+ iupAttribSetStr(ih, "_IUPMOT_FS_TITLE", NULL);
+ }
+ }
+ }
+ return 1;
+}
+
+static int motDialogSetIconAttrib(Ihandle* ih, const char *value)
+{
+ if (!value)
+ XtVaSetValues(ih->handle, XmNiconPixmap, NULL, NULL);
+ else
+ {
+ Pixmap icon = (Pixmap)iupImageGetIcon(value);
+ Pixmap icon_mask = (Pixmap)iupImageGetMask(value);
+ if (icon)
+ XtVaSetValues(ih->handle, XmNiconPixmap, icon, NULL);
+ if (icon_mask)
+ XtVaSetValues(ih->handle, XmNiconMask, icon, NULL);
+ }
+ return 1;
+}
+
+/****************************************************************
+ Callbacks and Events
+****************************************************************/
+
+
+static void motDialogCBclose(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Icallback cb;
+ Ihandle *ih = (Ihandle*)client_data;
+ if (!ih) return;
+ (void)call_data;
+ (void)w;
+
+ /* even when ACTIVE=NO the dialog gets this event */
+ if (!iupdrvIsActive(ih))
+ return;
+
+ cb = IupGetCallback(ih, "CLOSE_CB");
+ if (cb)
+ {
+ int ret = cb(ih);
+ if (ret == IUP_IGNORE)
+ return;
+ if (ret == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ IupHide(ih); /* default: close the window */
+}
+
+static void motDialogConfigureNotify(Widget w, XEvent *evt, String* s, Cardinal *card)
+{
+ IFnii cb;
+ int border, caption, menu;
+ XConfigureEvent *cevent = (XConfigureEvent *)evt;
+ Ihandle* ih;
+ (void)s;
+ (void)card;
+
+ XtVaGetValues(w, XmNuserData, &ih, NULL);
+ if (!ih) return;
+
+ if (ih->data->menu && ih->data->menu->handle)
+ {
+ XtVaSetValues(ih->data->menu->handle,
+ XmNwidth, (XtArgVal)(cevent->width),
+ NULL);
+ }
+
+ if (ih->data->ignore_resize) return;
+
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ /* update dialog size */
+ ih->currentwidth = cevent->width + 2*border;
+ ih->currentheight = cevent->height + 2*border + caption; /* menu is inside the dialog_manager */
+
+ cb = (IFnii)IupGetCallback(ih, "RESIZE_CB");
+ if (!cb || cb(ih, cevent->width, cevent->height - menu)!=IUP_IGNORE) /* width and height here are for the client area */
+ {
+ ih->data->ignore_resize = 1;
+ IupRefresh(ih);
+ ih->data->ignore_resize = 0;
+ }
+}
+
+static void motDialogCBStructureNotifyEvent(Widget w, XtPointer data, XEvent *evt, Boolean *cont)
+{
+ Ihandle *ih = (Ihandle*)data;
+ int state = -1;
+ (void)cont;
+ (void)w;
+
+ switch(evt->type)
+ {
+ case MapNotify:
+ {
+ if (ih->data->show_state == IUP_MINIMIZE) /* it is a RESTORE. */
+ state = IUP_RESTORE;
+ break;
+ }
+ case UnmapNotify:
+ {
+ if (ih->data->show_state != IUP_HIDE) /* it is a MINIMIZE. */
+ state = IUP_MINIMIZE;
+ break;
+ }
+ }
+
+ if (state < 0)
+ return;
+
+ if (ih->data->show_state != state)
+ {
+ IFni cb;
+ ih->data->show_state = state;
+
+ cb = (IFni)IupGetCallback(ih, "SHOW_CB");
+ if (cb && cb(ih, state) == IUP_CLOSE)
+ IupExitLoop();
+ }
+}
+
+static void motDialogDestroyCallback(Widget w, Ihandle *ih, XtPointer call_data)
+{
+ /* If the IUP dialog was not destroyed, destroy it here. */
+ if (iupObjectCheck(ih))
+ IupDestroy(ih);
+
+ /* this callback is usefull to destroy children dialogs when the parent is destroyed. */
+ /* The application is responsable for destroying the children before this happen. */
+ (void)w;
+ (void)call_data;
+}
+
+
+/****************************************************************
+ Idialog
+****************************************************************/
+
+/* replace the common dialog SetChildrenPosition method because of
+ the menu that it is inside the dialog. */
+static void motDialogSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ int menu_h = motDialogGetMenuSize(ih);
+ (void)x;
+ (void)y;
+
+ /* Child coordinates are relative to client left-top corner. */
+ iupBaseSetPosition(ih->firstchild, 0, menu_h);
+}
+
+static void* motDialogGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child)
+{
+ (void)child;
+ return XtNameToWidget(ih->handle, "*dialog_manager");
+}
+
+static int motDialogMapMethod(Ihandle* ih)
+{
+ Widget dialog_manager;
+ InativeHandle* parent;
+ int mwm_decor = 0;
+ int num_args = 0;
+ Arg args[20];
+
+ if (iupAttribGetBoolean(ih, "DIALOGFRAME"))
+ {
+ iupAttribSetStr(ih, "RESIZE", "NO");
+ iupAttribSetStr(ih, "MAXBOX", "NO");
+ iupAttribSetStr(ih, "MINBOX", "NO");
+ }
+
+ /****************************/
+ /* Create the dialog shell */
+ /****************************/
+
+ if (iupAttribGet(ih, "TITLE"))
+ mwm_decor |= MWM_DECOR_TITLE;
+ if (iupAttribGetBoolean(ih, "MENUBOX"))
+ mwm_decor |= MWM_DECOR_MENU;
+ if (iupAttribGetBoolean(ih, "MINBOX"))
+ mwm_decor |= MWM_DECOR_MINIMIZE;
+ if (iupAttribGetBoolean(ih, "MAXBOX"))
+ mwm_decor |= MWM_DECOR_MAXIMIZE;
+ 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);
+
+ if (iupmotColorMap())
+ iupmotSetArg(args, num_args, XmNcolormap, iupmotColorMap());
+
+ if (mwm_decor != 0x7E)
+ iupmotSetArg(args, num_args, XmNmwmDecorations, mwm_decor);
+
+ if (iupAttribGetBoolean(ih, "SAVEUNDER"))
+ iupmotSetArg(args, num_args, XmNsaveUnder, True);
+
+ parent = iupDialogGetNativeParent(ih);
+ if (parent)
+ ih->handle = XtCreatePopupShell(NULL, topLevelShellWidgetClass, (Widget)parent, args, num_args);
+ else
+ ih->handle = XtAppCreateShell(NULL, "dialog", topLevelShellWidgetClass, iupmot_display, args, num_args);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ XmAddWMProtocolCallback(ih->handle, iupmot_wm_deletewindow, motDialogCBclose, (XtPointer)ih);
+
+ XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, StructureNotifyMask, False, (XtEventHandler)motDialogCBStructureNotifyEvent, (XtPointer)ih);
+
+ XtAddCallback(ih->handle, XmNdestroyCallback, (XtCallbackProc)motDialogDestroyCallback, (XtPointer)ih);
+
+ /*****************************/
+ /* Create the dialog manager */
+ /*****************************/
+
+ dialog_manager = XtVaCreateManagedWidget(
+ "dialog_manager",
+ xmBulletinBoardWidgetClass,
+ ih->handle,
+ XmNmarginWidth, 0,
+ XmNmarginHeight, 0,
+ XmNwidth, 100, /* set this to avoid size calculation problems */
+ XmNheight, 100,
+ XmNborderWidth, 0,
+ XmNshadowThickness, 0,
+ XmNnoResize, iupAttribGetBoolean(ih, "RESIZE")? False: True,
+ XmNresizePolicy, XmRESIZE_NONE, /* no automatic resize of children */
+ XmNuserData, ih, /* used only in motDialogConfigureNotify */
+ XmNnavigationType, XmTAB_GROUP,
+ NULL);
+
+ XtOverrideTranslations(dialog_manager, XtParseTranslationTable("<Configure>: iupDialogConfigure()"));
+ XtAddCallback(dialog_manager, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih);
+ XtAddEventHandler(dialog_manager, KeyPressMask, False,(XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih);
+
+ /* initialize the widget */
+ XtRealizeWidget(ih->handle);
+
+ /* child dialogs must be always on top of the parent */
+ if (parent)
+ XSetTransientForHint(iupmot_display, XtWindow(ih->handle), XtWindow(parent));
+
+ if (mwm_decor != 0x7E) /* some decoration was changed */
+ motDialogSetWindowManagerStyle(ih);
+
+ /* Ignore VISIBLE before mapping */
+ iupAttribSetStr(ih, "VISIBLE", NULL);
+
+ if (IupGetGlobal("_IUP_RESET_DLGBGCOLOR"))
+ {
+ iupmotSetGlobalColorAttrib(dialog_manager, XmNbackground, "DLGBGCOLOR");
+ iupmotSetGlobalColorAttrib(dialog_manager, XmNforeground, "DLGFGCOLOR");
+ IupSetGlobal("_IUP_RESET_DLGBGCOLOR", NULL);
+ }
+
+ return IUP_NOERROR;
+}
+
+static void motDialogUnMapMethod(Ihandle* ih)
+{
+ Widget dialog_manager;
+ if (ih->data->menu)
+ {
+ ih->data->menu->handle = NULL; /* the dialog will destroy the native menu */
+ IupDestroy(ih->data->menu);
+ }
+
+ dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager");
+ XtVaSetValues(dialog_manager, XmNuserData, NULL, NULL);
+
+ XtRemoveEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih);
+ XtRemoveEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih);
+ XtRemoveEventHandler(ih->handle, StructureNotifyMask, False, (XtEventHandler)motDialogCBStructureNotifyEvent, (XtPointer)ih);
+ XtRemoveCallback(ih->handle, XmNdestroyCallback, (XtCallbackProc)motDialogDestroyCallback, (XtPointer)ih);
+
+ XtRemoveEventHandler(dialog_manager, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih);
+ XtRemoveCallback(dialog_manager, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih);
+
+ iupdrvBaseUnMapMethod(ih);
+}
+
+static void motDialogLayoutUpdateMethod(Ihandle *ih)
+{
+ int border, caption, menu;
+
+ if (ih->data->ignore_resize ||
+ iupAttribGet(ih, "_IUPMOT_FS_STYLE"))
+ return;
+
+ /* for dialogs the position is not updated here */
+ ih->data->ignore_resize = 1;
+
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ if (!iupAttribGetBoolean(ih, "RESIZE"))
+ {
+ int width = ih->currentwidth - 2*border;
+ int height = ih->currentheight - 2*border - caption;
+ XtVaSetValues(ih->handle,
+ XmNwidth, width,
+ XmNheight, height,
+ XmNminWidth, width,
+ XmNminHeight, height,
+ XmNmaxWidth, width,
+ XmNmaxHeight, height,
+ NULL);
+ }
+ else
+ {
+ XtVaSetValues(ih->handle,
+ XmNwidth, (XtArgVal)(ih->currentwidth - 2*border), /* excluding the border */
+ XmNheight, (XtArgVal)(ih->currentheight - 2*border - caption),
+ NULL);
+ }
+
+ ih->data->ignore_resize = 0;
+}
+
+/***************************************************************/
+
+void iupdrvDialogInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class methods */
+ ic->Map = motDialogMapMethod;
+ ic->UnMap = motDialogUnMapMethod;
+ ic->LayoutUpdate = motDialogLayoutUpdateMethod;
+ ic->SetChildrenPosition = motDialogSetChildrenPositionMethod;
+ ic->GetInnerNativeContainerHandle = motDialogGetInnerNativeContainerHandleMethod;
+
+ if (!iupmot_wm_deletewindow)
+ {
+ /* Set up a translation table that captures "Resize" events
+ (also called ConfigureNotify or Configure events). */
+ XtActionsRec rec = {"iupDialogConfigure", motDialogConfigureNotify};
+ XtAppAddActions(iupmot_appcontext, &rec, 1);
+
+ /* register atom to intercept the close button in the window frame */
+ iupmot_wm_deletewindow = XmInternAtom(iupmot_display, "WM_DELETE_WINDOW", False);
+ }
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motDialogSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "X", motDialogGetXAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "Y", motDialogGetYAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", motDialogGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "TITLE", motDialogGetTitleAttrib, motDialogSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupDialog only */
+ iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motDialogSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "ICON", NULL, motDialogSetIconAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FULLSCREEN", NULL, motDialogSetFullScreenAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MINSIZE", NULL, motDialogSetMinSizeAttrib, IUPAF_SAMEASSYSTEM, "1x1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MAXSIZE", NULL, motDialogSetMaxSizeAttrib, IUPAF_SAMEASSYSTEM, "65535x65535", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SAVEUNDER", NULL, NULL, "YES", NULL, IUPAF_NO_INHERIT);
+
+ /* IupDialog X Only */
+ iupClassRegisterAttribute(ic, "XWINDOW", iupmotGetXWindowAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+}
diff --git a/iup/src/mot/iupmot_drv.h b/iup/src/mot/iupmot_drv.h
new file mode 100755
index 0000000..8a536ef
--- /dev/null
+++ b/iup/src/mot/iupmot_drv.h
@@ -0,0 +1,75 @@
+/** \file
+ * \brief Motif Driver
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPMOT_DRV_H
+#define __IUPMOT_DRV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* global variables, declared in iupmot_open.c */
+extern Widget iupmot_appshell;
+extern Display* iupmot_display;
+extern int iupmot_screen;
+extern XtAppContext iupmot_appcontext;
+extern Visual* iupmot_visual;
+extern Atom iupmot_wm_deletewindow;
+
+/* dialog */
+void iupmotDialogSetVisual(Ihandle* ih, void* visual);
+void iupmotDialogResetVisual(Ihandle* ih);
+
+/* focus */
+void iupmotFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont);
+
+/* key */
+void iupmotCanvasKeyReleaseEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont);
+void iupmotKeyPressEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont);
+KeySym iupmotKeyCharToKeySym(char c);
+void iupmotButtonKeySetStatus(unsigned int state, unsigned int but, char* status, int doubleclick);
+void iupmotKeyEncode(int key, unsigned int *keyval, unsigned int *state);
+
+/* font */
+char* iupmotGetFontListAttrib(Ihandle *ih);
+XmFontList iupmotGetFontList(const char* foundry, const char* value);
+char* iupmotFindFontList(XmFontList fontlist);
+char* iupmotGetFontStructAttrib(Ihandle *ih);
+char* iupmotGetFontIdAttrib(Ihandle *ih);
+
+/* tips */
+/* called from Enter/Leave events to check if a TIP is present. */
+void iupmotTipEnterNotify(Ihandle* ih);
+void iupmotTipLeaveNotify(void);
+void iupmotTipsFinish(void);
+
+/* common */
+void iupmotPointerMotionEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont);
+void iupmotButtonPressReleaseEvent(Widget w, Ihandle* ih, XEvent* evt, Boolean* cont);
+void iupmotEnterLeaveWindowEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont);
+void iupmotHelpCallback(Widget w, Ihandle *ih, XtPointer call_data);
+void iupmotSetString(Widget w, const char *resource, const char* value);
+char* iupmotConvertString(XmString str);
+void iupmotSetMnemonicTitle(Ihandle *ih, const char* value);
+void iupmotDisableDragSource(Widget w);
+void iupmotSetPixmap(Ihandle* ih, const char* name, const char* prop, int make_inactive);
+void iupmotSetGlobalColorAttrib(Widget w, const char* xmname, const char* name);
+void iupmotSetBgColor(Widget w, Pixel color);
+char* iupmotGetBgColorAttrib(Ihandle* ih);
+
+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)++)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/mot/iupmot_filedlg.c b/iup/src/mot/iupmot_filedlg.c
new file mode 100755
index 0000000..768dd2b
--- /dev/null
+++ b/iup/src/mot/iupmot_filedlg.c
@@ -0,0 +1,578 @@
+/** \file
+ * \brief Motif IupFileDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <Xm/Xm.h>
+#include <Xm/MwmUtil.h>
+#include <Xm/FileSB.h>
+#include <Xm/Protocols.h>
+#include <Xm/SelectioB.h>
+#include <Xm/MessageB.h>
+#include <Xm/DrawingA.h>
+#include <Xm/PushB.h>
+#include <Xm/Frame.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drvinfo.h"
+#include "iup_dialog.h"
+#include "iup_strmessage.h"
+#include "iup_drvinfo.h"
+
+#include "iupmot_drv.h"
+
+
+enum {IUP_DIALOGOPEN, IUP_DIALOGSAVE, IUP_DIALOGDIR};
+
+static void motFileDlgAskUserCallback(Widget w, int* ret_code, XmSelectionBoxCallbackStruct* cbs)
+{
+ if (cbs->reason == XmCR_OK)
+ *ret_code = 1;
+ else
+ *ret_code = -1;
+ XtDestroyWidget(XtParent(w));
+}
+
+static int motFileDlgAskUser(Widget parent, const char* message)
+{
+ Widget questionbox;
+ Arg args[3];
+ int ret_code = 0;
+ XmString title;
+
+ XtSetArg(args[0], XmNautoUnmanage, False);
+ XtSetArg(args[1], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
+ XtSetArg(args[2], XmNnoResize, True);
+ questionbox = XmCreateQuestionDialog(parent, "filedlg_question", args, 3);
+ iupmotSetString(questionbox, XmNmessageString, message);
+ XtVaGetValues(parent, XmNdialogTitle, &title, NULL);
+ XtVaSetValues(questionbox, XmNdialogTitle, title, NULL);
+
+ XtAddCallback(questionbox, XmNokCallback, (XtCallbackProc)motFileDlgAskUserCallback, (XtPointer)&ret_code);
+ XtAddCallback(questionbox, XmNcancelCallback, (XtCallbackProc)motFileDlgAskUserCallback, (XtPointer)&ret_code);
+ XtUnmanageChild(XmMessageBoxGetChild(questionbox, XmDIALOG_HELP_BUTTON));
+ XtManageChild(questionbox);
+
+ while (ret_code == 0)
+ XtAppProcessEvent(iupmot_appcontext, XtIMAll);
+
+ XtUnmanageChild(questionbox);
+
+ if (ret_code == 1)
+ return 1;
+ else
+ return 0;
+}
+
+static int motFileDlgCheckValue(Ihandle* ih, Widget w)
+{
+ char* value = iupAttribGet(ih, "VALUE");
+ int dialogtype = iupAttribGetInt(ih, "_IUPDLG_DIALOGTYPE");
+
+ if (dialogtype == IUP_DIALOGDIR)
+ {
+ if (!iupdrvIsDirectory(value)) /* if does not exist or not a directory */
+ {
+ iupStrMessageShowError(ih, "IUP_INVALIDDIR");
+ return 0;
+ }
+ }
+ else
+ {
+ if (iupdrvIsDirectory(value)) /* selected a directory */
+ {
+ iupStrMessageShowError(ih, "IUP_INVALIDDIR");
+ return 0;
+ }
+ else if (!iupdrvIsFile(value)) /* new file */
+ {
+ value = iupAttribGet(ih, "ALLOWNEW");
+ if (!value)
+ {
+ if (dialogtype == IUP_DIALOGSAVE)
+ value = "YES";
+ else
+ value = "NO";
+ }
+
+ if (!iupStrBoolean(value))
+ {
+ iupStrMessageShowError(ih, "IUP_FILENOTEXIST");
+ return 0;
+ }
+ }
+ else if (dialogtype == IUP_DIALOGSAVE && !iupAttribGetInt(ih, "NOOVERWRITEPROMPT"))
+ {
+ if (!motFileDlgAskUser(w, iupStrMessageGet("IUP_FILEOVERWRITE")))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void motFileDlgCBclose(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Ihandle *ih = (Ihandle*)client_data;
+ if (!ih) return;
+ (void)call_data;
+ (void)w;
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "STATUS", "-1");
+ iupAttribSetStr(ih, "_IUP_WM_DELETE", "1");
+}
+
+static void motFileDlgCallback(Widget w, Ihandle* ih, XmFileSelectionBoxCallbackStruct* call_data)
+{
+ (void)w;
+ if (call_data->reason == XmCR_OK)
+ {
+ int dialogtype = iupAttribGetInt(ih, "_IUPDLG_DIALOGTYPE");
+ char* filename;
+ XmStringGetLtoR(call_data->value, XmSTRING_DEFAULT_CHARSET, &filename);
+ iupAttribStoreStr(ih, "VALUE", filename);
+ XtFree(filename);
+
+ if (!motFileDlgCheckValue(ih, w))
+ return;
+
+ if (dialogtype == IUP_DIALOGDIR)
+ {
+ iupAttribSetStr(ih, "STATUS", "0");
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ }
+ else
+ {
+ IFnss file_cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (file_cb && file_cb(ih, iupAttribGet(ih, "VALUE"), "OK") == IUP_IGNORE)
+ return;
+
+ if (iupdrvIsFile(iupAttribGet(ih, "VALUE"))) /* check if file exists */
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "YES");
+ iupAttribSetStr(ih, "STATUS", "0");
+ }
+ else
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "NO");
+ iupAttribSetStr(ih, "STATUS", "1");
+ }
+ }
+
+ if (!iupAttribGetBoolean(ih, "NOCHANGEDIR")) /* do change the current directory */
+ {
+ /* XmFileSelection does not change the current directory */
+ XmString xm_dir;
+ char* dir;
+ XtVaGetValues(w, XmNdirectory, &xm_dir, NULL);
+ XmStringGetLtoR(xm_dir, XmSTRING_DEFAULT_CHARSET, &dir);
+ iupdrvSetCurrentDirectory(dir);
+ XtFree(dir);
+ }
+ }
+ else if (call_data->reason == XmCR_CANCEL)
+ {
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "STATUS", "-1");
+ }
+}
+
+static void motFileDlgHelpCallback(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Ihandle *ih = (Ihandle*)client_data;
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ {
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "STATUS", "-1");
+ }
+
+ (void)call_data;
+ (void)w;
+}
+
+typedef struct _ImotPromt
+{
+ XmString xm_dir;
+ int ret_code;
+} ImotPromt;
+
+static void motFileDlgPromptCallback(Widget w, ImotPromt* prompt, XmSelectionBoxCallbackStruct* cbs)
+{
+ if (cbs->reason == XmCR_OK)
+ prompt->xm_dir = XmStringCopy(cbs->value);
+
+ prompt->ret_code = 1;
+ XtDestroyWidget(XtParent(w));
+}
+
+static XmString motFileDlgPrompt(Widget parent, const char* message)
+{
+ Widget promptbox;
+ Arg args[2];
+ ImotPromt prompt;
+ XmString title;
+
+ XtSetArg(args[0], XmNautoUnmanage, False);
+ XtSetArg(args[1], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
+ promptbox = XmCreatePromptDialog(parent, "filedlg_prompt", args, 2);
+ iupmotSetString(promptbox, XmNselectionLabelString, message);
+ XtVaGetValues(parent, XmNdialogTitle, &title, NULL);
+ XtVaSetValues(promptbox, XmNdialogTitle, title, NULL);
+
+ prompt.ret_code = 0;
+ prompt.xm_dir = NULL;
+
+ XtAddCallback(promptbox, XmNokCallback, (XtCallbackProc)motFileDlgPromptCallback, (XtPointer)&prompt);
+ XtAddCallback(promptbox, XmNcancelCallback, (XtCallbackProc)motFileDlgPromptCallback, (XtPointer)&prompt);
+ XtUnmanageChild(XmSelectionBoxGetChild(promptbox, XmDIALOG_HELP_BUTTON));
+ XtManageChild(promptbox);
+
+ while (prompt.ret_code == 0)
+ XtAppProcessEvent(iupmot_appcontext, XtIMAll);
+
+ XtUnmanageChild(promptbox);
+
+ return prompt.xm_dir;
+}
+
+static void motFileDlgNewFolderCallback(Widget w, Widget filebox, XtPointer call_data)
+{
+ XmString xm_new_dir = motFileDlgPrompt(filebox, iupStrMessageGet("IUP_NAMENEWFOLDER"));
+ if (xm_new_dir)
+ {
+ XmString xm_dir;
+ XtVaGetValues(filebox, XmNdirectory, &xm_dir, NULL);
+ xm_dir = XmStringConcat(xm_dir, xm_new_dir);
+
+ {
+ char* dir;
+ XmStringGetLtoR(xm_dir, XmSTRING_DEFAULT_CHARSET, &dir);
+ iupdrvMakeDirectory(dir);
+ XtFree(dir);
+ }
+
+ XtVaSetValues(filebox, XmNdirectory, xm_dir, NULL);
+
+ XmStringFree(xm_dir);
+ XmStringFree(xm_new_dir);
+ }
+
+ (void)call_data;
+ (void)w;
+}
+
+static void motFileDlgPreviewCanvasResizeCallback(Widget w, Ihandle *ih, XtPointer call_data)
+{
+ Dimension width, height;
+ XtVaGetValues(w, XmNwidth, &width,
+ XmNheight, &height,
+ NULL);
+
+ iupAttribSetInt(ih, "PREVIEWWIDTH", width);
+ iupAttribSetInt(ih, "PREVIEWHEIGHT", height);
+
+ (void)call_data;
+}
+
+static void motFileDlgUpdatePreviewGLCanvas(Ihandle* ih)
+{
+ Ihandle* glcanvas = IupGetAttributeHandle(ih, "PREVIEWGLCANVAS");
+ if (glcanvas)
+ {
+ iupAttribSetStr(glcanvas, "XWINDOW", iupAttribGet(ih, "XWINDOW"));
+ glcanvas->iclass->Map(glcanvas);
+ }
+}
+
+static void motFileDlgPreviewCanvasInit(Ihandle *ih, Widget w)
+{
+ XSetWindowAttributes attrs;
+ GC gc = XCreateGC(iupmot_display, XtWindow(w), 0, NULL);
+ iupAttribSetStr(ih, "PREVIEWDC", (char*)gc);
+ iupAttribSetStr(ih, "WID", (char*)w);
+
+ iupAttribSetStr(ih, "XWINDOW", (char*)XtWindow(w));
+ iupAttribSetStr(ih, "XDISPLAY", (char*)iupmot_display);
+ motFileDlgUpdatePreviewGLCanvas(ih);
+
+ attrs.bit_gravity = ForgetGravity; /* For the DrawingArea widget gets Expose events when you resize it to be smaller. */
+ attrs.background_pixmap = None;
+ XChangeWindowAttributes(iupmot_display, XtWindow(w), CWBitGravity|CWBackPixmap, &attrs);
+}
+
+static void motFileDlgPreviewCanvasExposeCallback(Widget w, Ihandle *ih, XtPointer call_data)
+{
+ Widget filebox = (Widget)iupAttribGet(ih, "_IUPDLG_FILEBOX");
+ char* filename;
+ XmString xm_file;
+ IFnss cb;
+
+ if (!iupAttribGet(ih, "PREVIEWDC"))
+ motFileDlgPreviewCanvasInit(ih, w);
+
+ XtVaGetValues(filebox, XmNdirSpec, &xm_file, NULL);
+ XmStringGetLtoR(xm_file, XmSTRING_DEFAULT_CHARSET, &filename);
+
+ cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (iupdrvIsFile(filename))
+ cb(ih, filename, "PAINT");
+ else
+ cb(ih, NULL, "PAINT");
+
+ XtFree(filename);
+ (void)call_data;
+ (void)w;
+}
+
+static void motFileDlgBrowseSelectionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* list_data)
+{
+ char* filename;
+
+ XmStringGetLtoR(list_data->item, XmSTRING_DEFAULT_CHARSET, &filename);
+
+ if (iupdrvIsFile(filename))
+ {
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ cb(ih, filename, "SELECT");
+ }
+
+ XtFree(filename);
+ (void)w;
+}
+
+static int motFileDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ Widget filebox, dialog;
+ int dialogtype, style = XmDIALOG_FULL_APPLICATION_MODAL;
+ IFnss file_cb = NULL;
+ Widget preview_canvas = NULL;
+ char* value;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ value = iupAttribGetStr(ih, "DIALOGTYPE");
+ if (iupStrEqualNoCase(value, "SAVE"))
+ dialogtype = IUP_DIALOGSAVE;
+ else if (iupStrEqualNoCase(value, "DIR"))
+ dialogtype = IUP_DIALOGDIR;
+ else
+ dialogtype = IUP_DIALOGOPEN;
+ iupAttribSetInt(ih, "_IUPDLG_DIALOGTYPE", dialogtype);
+
+ if (parent)
+ {
+ filebox = XmCreateFileSelectionDialog(parent, "filedialog", NULL, 0);
+ dialog = XtParent(filebox);
+ }
+ else
+ {
+ dialog = XtAppCreateShell(NULL, "filedialog", topLevelShellWidgetClass, iupmot_display, NULL, 0);
+ filebox = XmCreateFileSelectionBox(dialog, "filebox", NULL, 0);
+ style = XmDIALOG_MODELESS;
+ XtVaSetValues(dialog,
+ XmNmwmInputMode, MWM_INPUT_FULL_APPLICATION_MODAL,
+ XmNmappedWhenManaged, False,
+ XmNsaveUnder, True,
+ NULL);
+ }
+ if (!filebox)
+ return IUP_NOERROR;
+
+ if (!iupAttribGetBoolean(ih, "SHOWHIDDEN"))
+ XtVaSetValues(filebox, XmNfileFilterStyle, XmFILTER_HIDDEN_FILES, NULL);
+
+ value = iupAttribGet(ih, "TITLE");
+ if (!value)
+ {
+ if (dialogtype == IUP_DIALOGSAVE)
+ value = "IUP_SAVEAS";
+ else if (dialogtype == IUP_DIALOGOPEN)
+ value = "IUP_OPEN";
+ else
+ value = "IUP_SELECTDIR";
+ iupAttribSetStr(ih, "TITLE", iupStrMessageGet(value));
+ }
+ iupmotSetString(filebox, XmNdialogTitle, value);
+
+ XtVaSetValues(filebox,
+ XmNdialogStyle, style,
+ XmNautoUnmanage, False,
+ NULL);
+
+ if (dialogtype == IUP_DIALOGDIR)
+ XtVaSetValues(filebox, XmNfileTypeMask, XmFILE_DIRECTORY, NULL);
+
+ /* just check for the path inside FILE */
+ value = iupAttribGet(ih, "FILE");
+ if (value && value[0] == '/')
+ {
+ char* dir = iupStrFileGetPath(value);
+ iupAttribStoreStr(ih, "DIRECTORY", dir);
+ free(dir);
+ }
+
+ /* set XmNdirectory before XmNpattern and before XmNdirSpec */
+
+ value = iupAttribGet(ih, "DIRECTORY");
+ if (value)
+ iupmotSetString(filebox, XmNdirectory, value);
+
+ value = iupAttribGet(ih, "FILTER");
+ if (value)
+ {
+ char *filter = value;
+ char *p = strchr(value, ';');
+ if (p)
+ {
+ int size = p-value;
+ filter = (char*)malloc(size+1);
+ memcpy(filter, value, size);
+ filter[size] = 0;
+ }
+
+ iupmotSetString(filebox, XmNpattern, filter);
+
+ if (filter != value)
+ free(filter);
+ }
+
+ value = iupAttribGet(ih, "FILE");
+ if (value)
+ {
+ char* file = value;
+
+ if (value[0] != '/') /* if does not contains a full path, then add the directory */
+ {
+ char* cur_dir = NULL;
+ char* dir = iupAttribGet(ih, "DIRECTORY");
+ if (!dir)
+ {
+ cur_dir = iupdrvGetCurrentDirectory();
+ dir = cur_dir;
+ }
+
+ file = iupStrFileMakeFileName(dir, value);
+
+ if (cur_dir)
+ free(cur_dir);
+ }
+
+ /* clear value before setting. Do not know why we have to do this,
+ but if not cleared it will fail to set the XmNdirSpec value. */
+ iupmotSetString(filebox, XmNdirSpec, "");
+ iupmotSetString(filebox, XmNdirSpec, file);
+
+ if (file != value)
+ free(file);
+ }
+
+ if (!IupGetCallback(ih, "HELP_CB"))
+ XtUnmanageChild(XmFileSelectionBoxGetChild(filebox, XmDIALOG_HELP_BUTTON));
+
+ XtAddCallback(filebox, XmNokCallback, (XtCallbackProc)motFileDlgCallback, (XtPointer)ih);
+ XtAddCallback(filebox, XmNcancelCallback, (XtCallbackProc)motFileDlgCallback, (XtPointer)ih);
+ XtAddCallback(filebox, XmNhelpCallback, (XtCallbackProc)motFileDlgHelpCallback, (XtPointer)ih);
+
+ if (dialogtype == IUP_DIALOGDIR)
+ {
+ Widget new_folder = XtVaCreateManagedWidget("new_folder", xmPushButtonWidgetClass, filebox,
+ XmNlabelType, XmSTRING,
+ NULL);
+ iupmotSetString(new_folder, XmNlabelString, iupStrMessageGet("IUP_CREATEFOLDER"));
+ XtAddCallback(new_folder, XmNactivateCallback, (XtCallbackProc)motFileDlgNewFolderCallback, (XtPointer)filebox);
+ }
+ else
+ {
+ 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);
+
+ if (iupAttribGetBoolean(ih, "SHOWPREVIEW"))
+ {
+ Widget frame = XtVaCreateManagedWidget("preview_canvas", xmFrameWidgetClass, filebox,
+ XmNshadowType, XmSHADOW_ETCHED_IN,
+ NULL);
+
+ preview_canvas = XtVaCreateManagedWidget("preview_canvas", xmDrawingAreaWidgetClass, frame,
+ XmNwidth, 180,
+ XmNheight, 150,
+ XmNresizePolicy, XmRESIZE_GROW,
+ NULL);
+
+ XtAddCallback(preview_canvas, XmNexposeCallback, (XtCallbackProc)motFileDlgPreviewCanvasExposeCallback, (XtPointer)ih);
+ XtAddCallback(preview_canvas, XmNresizeCallback, (XtCallbackProc)motFileDlgPreviewCanvasResizeCallback, (XtPointer)ih);
+
+ iupAttribSetStr(ih, "_IUPDLG_FILEBOX", (char*)filebox);
+ }
+ }
+ }
+
+ XmAddWMProtocolCallback(dialog, iupmot_wm_deletewindow, motFileDlgCBclose, (XtPointer)ih);
+ XtManageChild(filebox);
+
+ XtRealizeWidget(dialog);
+ ih->handle = dialog;
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+
+ if (file_cb)
+ {
+ if (preview_canvas)
+ motFileDlgPreviewCanvasInit(ih, preview_canvas);
+
+ file_cb(ih, NULL, "INIT");
+ }
+
+ if (style == XmDIALOG_MODELESS)
+ XtPopup(dialog, XtGrabExclusive);
+
+ /* while the user hasn't provided an answer, simulate main loop.
+ ** The answer changes as soon as the user selects one of the
+ ** buttons and the callback routine changes its value. */
+ iupAttribSetStr(ih, "STATUS", NULL);
+ while (iupAttribGet(ih, "STATUS") == NULL)
+ XtAppProcessEvent(iupmot_appcontext, XtIMAll);
+
+ if (file_cb)
+ {
+ if (preview_canvas)
+ XFreeGC(iupmot_display, (GC)iupAttribGet(ih, "PREVIEWDC"));
+
+ file_cb(ih, NULL, "FINISH");
+ }
+
+ if (!iupAttribGet(ih, "_IUP_WM_DELETE"))
+ {
+ XtUnmanageChild(filebox);
+
+ if (style == XmDIALOG_MODELESS)
+ {
+ XtPopdown(dialog);
+ XtDestroyWidget(dialog);
+ }
+ }
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFileDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = motFileDlgPopup;
+}
diff --git a/iup/src/mot/iupmot_focus.c b/iup/src/mot/iupmot_focus.c
new file mode 100755
index 0000000..5b09bd9
--- /dev/null
+++ b/iup/src/mot/iupmot_focus.c
@@ -0,0 +1,35 @@
+/** \file
+ * \brief Motif Focus
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_focus.h"
+#include "iup_attrib.h"
+#include "iup_assert.h"
+#include "iup_drv.h"
+
+#include "iupmot_drv.h"
+
+void iupdrvSetFocus(Ihandle *ih)
+{
+ XmProcessTraversal(ih->handle, XmTRAVERSE_CURRENT);
+}
+
+void iupmotFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont)
+{
+ (void)w;
+ (void)cont;
+
+ if (evt->type == FocusIn)
+ iupCallGetFocusCb(ih);
+ else if (evt->type == FocusOut)
+ iupCallKillFocusCb(ih);
+}
diff --git a/iup/src/mot/iupmot_font.c b/iup/src/mot/iupmot_font.c
new file mode 100755
index 0000000..8da06dd
--- /dev/null
+++ b/iup/src/mot/iupmot_font.c
@@ -0,0 +1,443 @@
+/** \file
+ * \brief Motif Font mapping
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <Xm/Xm.h>
+#include <Xm/XmP.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_attrib.h"
+#include "iup_array.h"
+#include "iup_object.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_assert.h"
+
+#include "iupmot_drv.h"
+
+
+typedef struct _ImotFont
+{
+ char standardfont[1024];
+ char xlfd[1024]; /* X-Windows Font Description */
+ XmFontList fontlist; /* same as XmRenderTable */
+ XFontStruct *fontstruct;
+ int charwidth, charheight;
+} ImotFont;
+
+static Iarray* mot_fonts = NULL;
+
+static int motGetFontSize(char* font_name)
+{
+ int i = 0;
+ while (i < 8)
+ {
+ font_name = strchr(font_name, '-')+1;
+ i++;
+ }
+
+ *(strchr(font_name, '-')) = 0;
+ return atoi(font_name);
+}
+
+static XFontStruct* motLoadFont(const char* foundry, const char *typeface, int size, int bold, int italic, char *xlfd)
+{
+ XFontStruct* fontstruct;
+ char font_name[1024];
+ char **font_names_list;
+ char *weight, *slant;
+ int i, num_fonts, font_size, near_size;
+
+ /* no underline or strikeout support */
+
+ if (iupStrEqualNoCase(typeface, "System"))
+ typeface = "fixed";
+
+ if (!foundry) foundry = "*";
+
+ if (iupStrEqualNoCase(typeface, "fixed"))
+ foundry = "misc";
+
+ if (bold)
+ weight = "bold";
+ else
+ weight = "medium";
+
+ if (italic)
+ slant = "i";
+ else
+ slant = "r";
+
+ sprintf(font_name,"-%s-%s-%s-%s-*-*-*-*-*-*-*-*-*-*", foundry, typeface, weight, slant);
+
+ font_names_list = XListFonts(iupmot_display, font_name, 32767, &num_fonts);
+ if (!num_fonts)
+ {
+ /* try changing 'i' to 'o', for italic */
+ if (italic)
+ {
+ slant = "o";
+ strstr(font_name, "-i-")[1] = 'o';
+ font_names_list = XListFonts(iupmot_display, font_name, 32767, &num_fonts);
+ }
+
+ if (!num_fonts)
+ return NULL;
+ }
+
+ if (size < 0) /* if in pixels convert to points */
+ {
+ double res = ((double)DisplayWidth(iupmot_display, iupmot_screen) / (double)DisplayWidthMM(iupmot_display, iupmot_screen)); /* pixels/mm */
+ /* 1 point = 1/72 inch 1 inch = 25.4 mm */
+ /* pixel = ((point/72)*25.4)*pixel/mm */
+ size = (int)((-size/res)*2.83464567 + 0.5); /* from pixels to points */
+ }
+
+ size *= 10; /* convert to deci-points */
+
+ near_size = -1000;
+ for (i=0; i<num_fonts; i++)
+ {
+ font_size = motGetFontSize(font_names_list[i]);
+
+ if (font_size == size)
+ {
+ near_size = font_size;
+ break;
+ }
+
+ if (abs(font_size-size) < abs(near_size-size))
+ near_size = font_size;
+ }
+
+ XFreeFontNames(font_names_list);
+
+ sprintf(font_name,"-%s-%s-%s-%s-*-*-*-%d-*-*-*-*-*-*", foundry, typeface, weight, slant, near_size);
+ fontstruct = XLoadQueryFont(iupmot_display, font_name);
+
+ if (fontstruct)
+ strcpy(xlfd, font_name);
+
+ return fontstruct;
+}
+
+static XmFontList motFontCreateRenderTable(XFontStruct* fontstruct, int is_underline, int is_strikeout)
+{
+ XmFontList fontlist;
+ XmRendition rendition;
+ 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);
+
+ if (is_underline)
+ iupmotSetArg(args, num_args, XmNunderlineType, XmSINGLE_LINE);
+ else
+ iupmotSetArg(args, num_args, XmNunderlineType, XmNO_LINE);
+
+ if (is_strikeout)
+ iupmotSetArg(args, num_args, XmNstrikethruType, XmSINGLE_LINE);
+ else
+ iupmotSetArg(args, num_args, XmNstrikethruType, XmNO_LINE);
+
+ rendition = XmRenditionCreate(NULL, "", args, num_args);
+
+ fontlist = XmRenderTableAddRenditions(NULL, &rendition, 1, XmDUPLICATE);
+
+ XmRenditionFree(rendition);
+
+ return fontlist;
+}
+
+static int motFontCalcCharWidth(XFontStruct *fontstruct)
+{
+ if (fontstruct->per_char)
+ {
+ int i, all=0;
+ int first = fontstruct->min_char_or_byte2;
+ int last = fontstruct->max_char_or_byte2;
+ if (first < 32) first = 32; /* space */
+ if (last > 126) last = 126; /* tilde */
+ for (i=first; i<=last; i++)
+ all += fontstruct->per_char[i].width;
+ return all/(last-first + 1); /* average character width */
+ }
+ else
+ return fontstruct->max_bounds.width;
+}
+
+static ImotFont* motFindFont(const char* foundry, const char *standardfont)
+{
+ char xlfd[1024];
+ XFontStruct* fontstruct;
+ int i, count = iupArrayCount(mot_fonts);
+ int is_underline = 0, is_strikeout = 0;
+
+ ImotFont* fonts = (ImotFont*)iupArrayGetData(mot_fonts);
+
+ /* Check if the standardfont already exists in cache */
+ for (i = 0; i < count; i++)
+ {
+ if (iupStrEqualNoCase(standardfont, fonts[i].standardfont))
+ return &fonts[i];
+ }
+
+ /* not found, create a new one */
+ if (standardfont[0] == '-')
+ {
+ fontstruct = XLoadQueryFont(iupmot_display, standardfont);
+ if (!fontstruct) return NULL;
+ strcpy(xlfd, standardfont);
+ }
+ else
+ {
+ int size = 0,
+ is_bold = 0,
+ is_italic = 0;
+ char typeface[1024];
+ const char* mapped_name;
+
+ if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return NULL;
+
+ mapped_name = iupFontGetXName(typeface);
+ if (mapped_name)
+ strcpy(typeface, mapped_name);
+
+ fontstruct = motLoadFont(foundry, typeface, size, is_bold, is_italic, xlfd);
+ if (!fontstruct) return NULL;
+ }
+
+ /* create room in the array */
+ fonts = (ImotFont*)iupArrayInc(mot_fonts);
+
+ strcpy(fonts[i].standardfont, standardfont);
+ strcpy(fonts[i].xlfd, xlfd);
+ fonts[i].fontstruct = fontstruct;
+ fonts[i].fontlist = motFontCreateRenderTable(fontstruct, is_underline, is_strikeout);
+ fonts[i].charwidth = motFontCalcCharWidth(fontstruct);
+ fonts[i].charheight = fontstruct->ascent + fontstruct->descent;
+
+ return &fonts[i];
+}
+
+char* iupdrvGetSystemFont(void)
+{
+ static char systemfont[200] = "";
+ ImotFont* motfont = NULL;
+ char* font = XGetDefault(iupmot_display, "Iup", "fontList");
+ if (font)
+ motfont = motFindFont(NULL, font);
+
+ if (!motfont)
+ {
+ font = "Fixed, 11";
+ motfont = motFindFont("misc", font);
+ }
+
+ strcpy(systemfont, font);
+ return systemfont;
+}
+
+char* iupmotFindFontList(XmFontList fontlist)
+{
+ int i, count = iupArrayCount(mot_fonts);
+ ImotFont* fonts = (ImotFont*)iupArrayGetData(mot_fonts);
+
+ /* Check if the standardfont already exists in cache */
+ for (i = 0; i < count; i++)
+ {
+ if (fontlist == fonts[i].fontlist)
+ return fonts[i].standardfont;
+ }
+
+ return NULL;
+}
+
+XmFontList iupmotGetFontList(const char* foundry, const char* value)
+{
+ ImotFont *motfont = motFindFont(foundry, value);
+ if (!motfont)
+ {
+ iupERROR1("Failed to create Font: %s", value);
+ return NULL;
+ }
+
+ return motfont->fontlist;
+}
+
+static ImotFont* motFontCreateNativeFont(Ihandle* ih, const char* value)
+{
+ ImotFont *motfont = motFindFont(iupAttribGet(ih, "FOUNDRY"), value);
+ if (!motfont)
+ {
+ iupERROR1("Failed to create Font: %s", value);
+ return NULL;
+ }
+
+ iupAttribSetStr(ih, "_IUPMOT_FONT", (char*)motfont);
+ iupAttribSetStr(ih, "XLFD", motfont->xlfd);
+ return motfont;
+}
+
+static ImotFont* motGetFont(Ihandle *ih)
+{
+ ImotFont* motfont = (ImotFont*)iupAttribGet(ih, "_IUPMOT_FONT");
+ if (!motfont)
+ motfont = motFontCreateNativeFont(ih, iupGetFontAttrib(ih));
+ return motfont;
+}
+
+char* iupmotGetFontListAttrib(Ihandle *ih)
+{
+ ImotFont* motfont = motGetFont(ih);
+ if (!motfont)
+ return NULL;
+ else
+ return (char*)motfont->fontlist;
+}
+
+char* iupmotGetFontStructAttrib(Ihandle *ih)
+{
+ ImotFont* motfont = motGetFont(ih);
+ if (!motfont)
+ return NULL;
+ else
+ return (char*)motfont->fontstruct;
+}
+
+char* iupmotGetFontIdAttrib(Ihandle *ih)
+{
+ ImotFont* motfont = motGetFont(ih);
+ if (!motfont)
+ return NULL;
+ else
+ return (char*)motfont->fontstruct->fid;
+}
+
+int iupdrvSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ ImotFont *motfont = motFontCreateNativeFont(ih, value);
+ if (!motfont)
+ return 1;
+
+ /* If FONT is changed, must update the SIZE attribute */
+ iupBaseUpdateSizeFromFont(ih);
+
+ /* FONT attribute must be able to be set before mapping,
+ so the font is enable for size calculation. */
+ if (ih->handle && (ih->iclass->nativetype != IUP_TYPEVOID))
+ XtVaSetValues(ih->handle, XmNrenderTable, motfont->fontlist, NULL);
+
+ return 1;
+}
+
+int iupdrvFontGetStringWidth(Ihandle* ih, const char* str)
+{
+ XFontStruct* fontstruct;
+ int len;
+ char* line_end;
+
+ if (!str || str[0]==0)
+ return 0;
+
+ fontstruct = (XFontStruct*)iupmotGetFontStructAttrib(ih);
+ if (!fontstruct)
+ return 0;
+
+ line_end = strchr(str, '\n');
+ if (line_end)
+ len = line_end-str;
+ else
+ len = strlen(str);
+
+ return XTextWidth(fontstruct, str, len);
+}
+
+void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h)
+{
+ int num_lin, max_w;
+
+ ImotFont* motfont = motGetFont(ih);
+ if (!motfont)
+ {
+ if (w) *w = 0;
+ if (h) *h = 0;
+ return;
+ }
+
+ if (!str)
+ {
+ if (w) *w = 0;
+ if (h) *h = motfont->charheight * 1;
+ return;
+ }
+
+ max_w = 0;
+ num_lin = 1;
+ if (str[0])
+ {
+ int len, lw;
+ const char *nextstr;
+ const char *curstr = str;
+ do
+ {
+ nextstr = iupStrNextLine(curstr, &len);
+ lw = XTextWidth(motfont->fontstruct, curstr, len);
+ max_w = iupMAX(max_w, lw);
+
+ curstr = nextstr;
+ if (*nextstr)
+ num_lin++;
+ } while(*nextstr);
+ }
+
+ if (w) *w = max_w;
+ if (h) *h = motfont->charheight * num_lin;
+}
+
+
+void iupdrvFontGetCharSize(Ihandle* ih, int *charwidth, int *charheight)
+{
+ ImotFont* motfont = motGetFont(ih);
+ if (!motfont)
+ {
+ if (charwidth) *charwidth = 0;
+ if (charheight) *charheight = 0;
+ return;
+ }
+
+ if (charheight)
+ *charheight = motfont->charheight;
+
+ if (charwidth)
+ *charwidth = motfont->charwidth;
+}
+
+void iupdrvFontInit(void)
+{
+ mot_fonts = iupArrayCreate(50, sizeof(ImotFont));
+}
+
+void iupdrvFontFinish(void)
+{
+ int i, count = iupArrayCount(mot_fonts);
+ ImotFont* fonts = (ImotFont*)iupArrayGetData(mot_fonts);
+ for (i = 0; i < count; i++)
+ {
+ XmFontListFree(fonts[i].fontlist);
+ fonts[i].fontlist = NULL;
+ XFreeFont(iupmot_display, fonts[i].fontstruct);
+ fonts[i].fontstruct = NULL;
+ }
+ iupArrayDestroy(mot_fonts);
+}
diff --git a/iup/src/mot/iupmot_fontdlg.c b/iup/src/mot/iupmot_fontdlg.c
new file mode 100755
index 0000000..42767b2
--- /dev/null
+++ b/iup/src/mot/iupmot_fontdlg.c
@@ -0,0 +1,31 @@
+/** \file
+ * \brief IupFontDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drvinfo.h"
+#include "iup_dialog.h"
+
+#include "iupmot_drv.h"
+
+
+static int motFontDlgPopup(Ihandle* ih, int x, int y)
+{
+ (void)ih;
+ (void)x;
+ (void)y;
+ return IUP_ERROR;
+}
+
+void iupdrvFontDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = motFontDlgPopup;
+}
diff --git a/iup/src/mot/iupmot_frame.c b/iup/src/mot/iupmot_frame.c
new file mode 100755
index 0000000..39de5d8
--- /dev/null
+++ b/iup/src/mot/iupmot_frame.c
@@ -0,0 +1,257 @@
+/** \file
+ * \brief Frame Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <Xm/Frame.h>
+#include <Xm/Label.h>
+#include <Xm/BulletinB.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+#include "iup_image.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y)
+{
+ (void)ih;
+ *x = 0;
+ *y = 0;
+}
+
+static int motFrameSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color;
+
+ /* 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);
+
+ 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);
+
+ return 1;
+ }
+ return 0;
+}
+
+static int motFrameSetBackgroundAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color;
+
+ /* ignore given value, must use only from parent */
+ value = iupAttribGetInheritNativeParent(ih, "BACKGROUND");
+
+ color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ {
+ Widget title_label, child_manager;
+
+ iupmotSetBgColor(ih->handle, 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);
+
+ return 1;
+ }
+ else
+ {
+ Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0);
+ if (pixmap)
+ {
+ Widget child_manager = XtNameToWidget(ih->handle, "*child_manager");
+ Widget title_label = XtNameToWidget(ih->handle, "*title_label");
+
+ XtVaSetValues(child_manager, XmNbackgroundPixmap, pixmap, NULL);
+ if (title_label)
+ XtVaSetValues(title_label, XmNbackgroundPixmap, pixmap, NULL);
+
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int motFrameSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ {
+ Widget title_label = XtNameToWidget(ih->handle, "*title_label");
+ if (!title_label) return 0;
+ XtVaSetValues(title_label, XmNforeground, color, NULL);
+ return 1;
+ }
+ return 0;
+}
+
+static int motFrameSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+
+ if (ih->handle)
+ {
+ XmFontList fontlist;
+ Widget title_label = XtNameToWidget(ih->handle, "*title_label");
+ if (!title_label) return 1;
+
+ fontlist = (XmFontList)iupmotGetFontListAttrib(ih);
+ XtVaSetValues(title_label, XmNrenderTable, fontlist, NULL);
+ }
+
+ return 1;
+}
+
+static int motFrameSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ Widget title_label = XtNameToWidget(ih->handle, "*title_label");
+ if (title_label)
+ {
+ if (!value) value = "";
+ iupmotSetString(title_label, XmNlabelString, value);
+ return 1;
+ }
+ return 0;
+}
+
+static void* motFrameGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child)
+{
+ (void)child;
+ return XtNameToWidget(ih->handle, "*child_manager");
+}
+
+static int motFrameMapMethod(Ihandle* ih)
+{
+ char *title;
+ int num_args = 0;
+ Arg args[20];
+ Widget child_manager;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ title = iupAttribGet(ih, "TITLE");
+
+ if (title)
+ iupAttribSetStr(ih, "_IUPFRAME_HAS_TITLE", "1");
+ else
+ {
+ char* value = iupAttribGetStr(ih, "SUNKEN");
+ if (iupStrBoolean(value))
+ iupmotSetArg(args, num_args, XmNshadowType, XmSHADOW_IN);
+ else
+ iupmotSetArg(args, num_args, XmNshadowType, XmSHADOW_ETCHED_IN);
+ }
+
+ /* 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 */
+ /* Manager */
+ iupmotSetArg(args, num_args, XmNshadowThickness, 2);
+ /* Frame */
+ iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* no shadow margins */
+ iupmotSetArg(args, num_args, XmNmarginWidth, 0); /* no shadow margins */
+
+ ih->handle = XtCreateManagedWidget(
+ iupDialogGetChildIdStr(ih), /* child identifier */
+ xmFrameWidgetClass, /* widget class */
+ iupChildTreeGetNativeParentHandle(ih), /* widget parent */
+ args, num_args);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupDialogGetChildId(ih); /* must be after using the string */
+
+ if (title)
+ {
+ 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);
+ /* Frame Constraint */
+ iupmotSetArg(args, num_args, XmNchildType, XmFRAME_TITLE_CHILD);
+ title_label = XtCreateManagedWidget("title_label", xmLabelWidgetClass, ih->handle, args, num_args);
+ iupmotSetString(title_label, XmNlabelString, title);
+ }
+
+ child_manager = XtVaCreateManagedWidget(
+ "child_manager",
+ xmBulletinBoardWidgetClass,
+ ih->handle,
+ /* Core */
+ XmNborderWidth, 0,
+ /* Manager */
+ XmNshadowThickness, 0,
+ XmNnavigationType, XmTAB_GROUP,
+ /* BulletinBoard */
+ XmNmarginWidth, 0,
+ XmNmarginHeight, 0,
+ XmNresizePolicy, XmRESIZE_NONE, /* no automatic resize of children */
+ /* Frame Constraint */
+ XmNchildType, XmFRAME_WORKAREA_CHILD,
+ NULL);
+
+ /* initialize the widget */
+ XtRealizeWidget(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFrameInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motFrameMapMethod;
+ ic->GetInnerNativeContainerHandle = motFrameGetInnerNativeContainerHandleMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, motFrameSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motFrameSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motFrameSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motFrameSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, motFrameSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/mot/iupmot_globalattrib.c b/iup/src/mot/iupmot_globalattrib.c
new file mode 100755
index 0000000..9567cf5
--- /dev/null
+++ b/iup/src/mot/iupmot_globalattrib.c
@@ -0,0 +1,155 @@
+/** \file
+ * \brief Motif Driver implementation of iupdrvSetGlobal
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_strmessage.h"
+
+#include "iupmot_drv.h"
+
+
+static void motGlobalSendKey(int key, int press)
+{
+ Window focus;
+ int revert_to;
+ XKeyEvent evt;
+ memset(&evt, 0, sizeof(XKeyEvent));
+ evt.display = iupmot_display;
+ evt.send_event = True;
+ evt.root = DefaultRootWindow(iupmot_display);
+
+ XGetInputFocus(iupmot_display, &focus, &revert_to);
+ evt.window = focus;
+
+ iupmotKeyEncode(key, &evt.keycode, &evt.state);
+ if (!evt.keycode)
+ return;
+
+ if (press & 0x01)
+ {
+ evt.type = KeyPress;
+ XSendEvent(iupmot_display, (Window)InputFocus, False, KeyPressMask, (XEvent*)&evt);
+ }
+
+ if (press & 0x02)
+ {
+ evt.type = KeyRelease;
+ XSendEvent(iupmot_display, (Window)InputFocus, False, KeyReleaseMask, (XEvent*)&evt);
+ }
+}
+
+int iupdrvSetGlobal(const char *name, const char *value)
+{
+ if (iupStrEqual(name, "LANGUAGE"))
+ {
+ iupStrMessageUpdateLanguage(value);
+ return 1;
+ }
+ if (iupStrEqual(name, "AUTOREPEAT"))
+ {
+ XKeyboardControl values;
+ if (iupStrBoolean(value))
+ values.auto_repeat_mode = 1;
+ else
+ values.auto_repeat_mode = 0;
+ XChangeKeyboardControl(iupmot_display, KBAutoRepeatMode, &values);
+ return 0;
+ }
+ if (iupStrEqual(name, "CURSORPOS"))
+ {
+ int x, y;
+ if (iupStrToIntInt(value, &x, &y, 'x') == 2)
+ XWarpPointer(iupmot_display,None,RootWindow(iupmot_display, iupmot_screen),0,0,0,0,x,y);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEYPRESS"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ motGlobalSendKey(key, 0x01);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEYRELEASE"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ motGlobalSendKey(key, 0x02);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEY"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ motGlobalSendKey(key, 0x03);
+ return 0;
+ }
+ return 1;
+}
+
+char* iupdrvGetGlobal(const char *name)
+{
+ if (iupStrEqual(name, "CURSORPOS"))
+ {
+ int x, y;
+ char* str = iupStrGetMemory(50);
+ iupdrvGetCursorPos(&x, &y);
+ sprintf(str, "%dx%d", x, y);
+ return str;
+ }
+ if (iupStrEqual(name, "SHIFTKEY"))
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[0] == 'S')
+ return "ON";
+ return "OFF";
+ }
+ if (iupStrEqual(name, "CONTROLKEY"))
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[1] == 'C')
+ return "ON";
+ return "OFF";
+ }
+ if (iupStrEqual(name, "MODKEYSTATE"))
+ {
+ char *str = iupStrGetMemory(5);
+ iupdrvGetKeyState(str);
+ return str;
+ }
+ if (iupStrEqual(name, "SCREENSIZE"))
+ {
+ char *str = iupStrGetMemory(50);
+ int w, h;
+ iupdrvGetScreenSize(&w, &h);
+ sprintf(str, "%dx%d", w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "FULLSIZE"))
+ {
+ char *str = iupStrGetMemory(50);
+ int w, h;
+ iupdrvGetFullSize(&w, &h);
+ sprintf(str, "%dx%d", w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "SCREENDEPTH"))
+ {
+ char *str = iupStrGetMemory(50);
+ int bpp = iupdrvGetScreenDepth();
+ sprintf(str, "%d", bpp);
+ return str;
+ }
+ return NULL;
+}
diff --git a/iup/src/mot/iupmot_image.c b/iup/src/mot/iupmot_image.c
new file mode 100755
index 0000000..b0078d5
--- /dev/null
+++ b/iup/src/mot/iupmot_image.c
@@ -0,0 +1,397 @@
+/** \file
+ * \brief Image Resource.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_drvinfo.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+void iupdrvImageGetRawData(void* handle, unsigned char* imgdata)
+{
+ Pixmap pixmap = (Pixmap)handle;
+ int w, h, y, x, bpp;
+ XImage *xi;
+
+ if (!iupdrvImageGetInfo(handle, &w, &h, &bpp))
+ return;
+
+ if (bpp==8)
+ return;
+
+ xi = XGetImage(iupmot_display, pixmap, 0, 0, w, h, ULONG_MAX, ZPixmap);
+ if (xi)
+ {
+ /* planes are separated in imgdata */
+ int planesize = w*h;
+ unsigned char *r = imgdata,
+ *g = imgdata+planesize,
+ *b = imgdata+2*planesize;
+ for (y=0; y<h; y++)
+ {
+ int lineoffset = (h-1 - y)*w; /* imgdata is bottom up */
+ for (x=0; x<w; x++)
+ {
+ iupmotColorGetRGB(XGetPixel(xi, x, y), r + lineoffset+x, g + lineoffset+x, b + lineoffset+x);
+ }
+ }
+
+ XDestroyImage(xi);
+ }
+}
+
+void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata)
+{
+ int y, x;
+ Pixmap pixmap;
+ GC gc;
+
+ pixmap = XCreatePixmap(iupmot_display,
+ RootWindow(iupmot_display,iupmot_screen),
+ width, height, iupdrvGetScreenDepth());
+ if (!pixmap)
+ return NULL;
+
+ gc = XCreateGC(iupmot_display,pixmap,0,NULL);
+
+ /* Pixmap is top-bottom */
+ /* imgdata is bottom up */
+
+ if (bpp == 8)
+ {
+ Pixel color2pixel[256];
+ int i;
+ for (i=0;i<colors_count;i++)
+ color2pixel[i] = iupmotColorGetPixel(colors[i].r, colors[i].g, colors[i].b);
+
+ for (y=0;y<height;y++)
+ {
+ int lineoffset = (height-1 - y)*width; /* imgdata is bottom up */
+ for(x=0;x<width;x++)
+ {
+ unsigned long p = color2pixel[imgdata[lineoffset+x]];
+ XSetForeground(iupmot_display,gc,p);
+ XDrawPoint(iupmot_display,pixmap,gc,x,y);
+ }
+ }
+ }
+ else
+ {
+ /* planes are separated in imgdata */
+ int planesize = width*height;
+ unsigned char *r = imgdata,
+ *g = imgdata+planesize,
+ *b = imgdata+2*planesize;
+ for (y=0;y<height;y++)
+ {
+ int lineoffset = (height-1 - y)*width; /* imgdata is bottom up */
+ for(x=0;x<width;x++)
+ {
+ unsigned long p = iupmotColorGetPixel(r[lineoffset+x], g[lineoffset+x], b[lineoffset+x]);
+ XSetForeground(iupmot_display,gc,p);
+ XDrawPoint(iupmot_display,pixmap,gc,x,y);
+ }
+ }
+ }
+
+ XFreeGC(iupmot_display,gc);
+
+ return (void*)pixmap;
+}
+
+void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive)
+{
+ int y, x, bpp, bgcolor_depend = 0,
+ width = ih->currentwidth,
+ height = ih->currentheight;
+ unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+ Pixmap pixmap;
+ unsigned char bg_r=0, bg_g=0, bg_b=0;
+ GC gc;
+ Pixel color2pixel[256];
+
+ bpp = iupAttribGetInt(ih, "BPP");
+
+ iupStrToRGB(bgcolor, &bg_r, &bg_g, &bg_b);
+
+ if (bpp == 8)
+ {
+ int i, colors_count = 0;
+ iupColor colors[256];
+
+ iupImageInitColorTable(ih, colors, &colors_count);
+
+ for (i=0;i<colors_count;i++)
+ {
+ if (colors[i].a == 0)
+ {
+ colors[i].r = bg_r;
+ colors[i].g = bg_g;
+ colors[i].b = bg_b;
+ colors[i].a = 255;
+ bgcolor_depend = 1;
+ }
+
+ if (make_inactive)
+ iupImageColorMakeInactive(&(colors[i].r), &(colors[i].g), &(colors[i].b),
+ bg_r, bg_g, bg_b);
+
+ color2pixel[i] = iupmotColorGetPixel(colors[i].r, colors[i].g, colors[i].b);
+ }
+ }
+
+ pixmap = XCreatePixmap(iupmot_display,
+ RootWindow(iupmot_display,iupmot_screen),
+ width, height, iupdrvGetScreenDepth());
+ if (!pixmap)
+ return NULL;
+
+ gc = XCreateGC(iupmot_display,pixmap,0,NULL);
+ for (y=0;y<height;y++)
+ {
+ for(x=0;x<width;x++)
+ {
+ unsigned long p;
+ if (bpp == 8)
+ p = color2pixel[imgdata[y*width+x]];
+ else
+ {
+ int channels = (bpp==24)? 3: 4;
+ unsigned char *pixel_data = imgdata + y*width*channels + x*channels;
+ unsigned char r = *(pixel_data),
+ g = *(pixel_data+1),
+ b = *(pixel_data+2);
+
+ if (bpp == 32)
+ {
+ unsigned char a = *(pixel_data+3);
+ if (a != 255)
+ {
+ r = iupALPHABLEND(r, bg_r, a);
+ g = iupALPHABLEND(g, bg_g, a);
+ b = iupALPHABLEND(b, bg_b, a);
+ bgcolor_depend = 1;
+ }
+ }
+
+ if (make_inactive)
+ iupImageColorMakeInactive(&r, &g, &b, bg_r, bg_g, bg_b);
+
+ p = iupmotColorGetPixel(r, g, b);
+ }
+
+ XSetForeground(iupmot_display,gc,p);
+ XDrawPoint(iupmot_display,pixmap,gc,x,y);
+ }
+ }
+ XFreeGC(iupmot_display,gc);
+
+ if (bgcolor_depend || make_inactive)
+ iupAttribSetStr(ih, "_IUP_BGCOLOR_DEPEND", "1");
+
+ return (void*)pixmap;
+}
+
+void* iupdrvImageCreateIcon(Ihandle *ih)
+{
+ return iupdrvImageCreateImage(ih, NULL, 0);
+}
+
+void* iupdrvImageCreateCursor(Ihandle *ih)
+{
+ int bpp,y,x,hx,hy,
+ width = ih->currentwidth,
+ height = ih->currentheight,
+ line_size = (width+7)/8,
+ size_bytes = line_size*height;
+ unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+ char *sbits, *mbits, *sb, *mb;
+ Pixmap source, mask;
+ XColor fg, bg;
+ unsigned char r, g, b;
+ Cursor cursor;
+
+ bpp = iupAttribGetInt(ih, "BPP");
+ if (bpp > 8)
+ return NULL;
+
+ sbits = (char*)malloc(2*size_bytes);
+ if (!sbits) return NULL;
+ memset(sbits, 0, 2*size_bytes);
+ mbits = sbits + size_bytes;
+
+ sb = sbits;
+ mb = mbits;
+ for (y=0; y<height; y++)
+ {
+ for (x=0; x<width; x++)
+ {
+ int byte = x/8;
+ int bit = x%8;
+ int index = (int)imgdata[y*width+x];
+ /* index==0 is transparent */
+ if (index == 1)
+ sb[byte] = (char)(sb[byte] | (1<<bit));
+ if (index != 0)
+ mb[byte] = (char)(mb[byte] | (1<<bit));
+ }
+
+ sb += line_size;
+ mb += line_size;
+ }
+
+ r = 255; g = 255; b = 255;
+ iupStrToRGB(iupAttribGet(ih, "1"), &r, &g, &b );
+ fg.red = iupCOLOR8TO16(r);
+ fg.green = iupCOLOR8TO16(g);
+ fg.blue = iupCOLOR8TO16(b);
+ fg.flags = DoRed | DoGreen | DoBlue;
+
+ r = 0; g = 0; b = 0;
+ iupStrToRGB(iupAttribGet(ih, "2"), &r, &g, &b );
+ bg.red = iupCOLOR8TO16(r);
+ bg.green = iupCOLOR8TO16(g);
+ bg.blue = iupCOLOR8TO16(b);
+ bg.flags = DoRed | DoGreen | DoBlue;
+
+ hx=0; hy=0;
+ iupStrToIntInt(iupAttribGet(ih, "HOTSPOT"), &hx, &hy, ':');
+
+ source = XCreateBitmapFromData(iupmot_display,
+ RootWindow(iupmot_display,iupmot_screen),
+ sbits, width, height);
+ mask = XCreateBitmapFromData(iupmot_display,
+ RootWindow(iupmot_display,iupmot_screen),
+ mbits, width, height);
+
+ cursor = XCreatePixmapCursor(iupmot_display, source, mask, &fg, &bg, hx, hy);
+
+ free(sbits);
+ return (void*)cursor;
+}
+
+void* iupdrvImageCreateMask(Ihandle *ih)
+{
+ int bpp,y,x,
+ width = ih->currentwidth,
+ height = ih->currentheight,
+ line_size = (width+7)/8,
+ size_bytes = line_size*height;
+ unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+ char *bits, *sb;
+ Pixmap mask;
+ unsigned char colors[256];
+
+ bpp = iupAttribGetInt(ih, "BPP");
+ if (bpp > 8)
+ return NULL;
+
+ bits = (char*)malloc(size_bytes);
+ if (!bits) return NULL;
+ memset(bits, 0, size_bytes);
+
+ iupImageInitNonBgColors(ih, colors);
+
+ sb = bits;
+ for (y=0; y<height; y++)
+ {
+ for (x=0; x<width; x++)
+ {
+ int byte = x/8;
+ int bit = x%8;
+ int index = (int)imgdata[y*width+x];
+ if (colors[index])
+ sb[byte] = (char)(sb[byte] | (1<<bit));
+ }
+
+ sb += line_size;
+ }
+
+ mask = XCreateBitmapFromData(iupmot_display,
+ RootWindow(iupmot_display,iupmot_screen),
+ bits, width, height);
+
+ free(bits);
+ return (void*)mask;
+}
+
+void* iupdrvImageLoad(const char* name, int type)
+{
+ if (type == IUPIMAGE_CURSOR)
+ {
+ Cursor cursor = 0;
+ int id;
+ if (iupStrToInt(name, &id))
+ cursor = XCreateFontCursor(iupmot_display, id);
+ return (void*)cursor;
+ }
+ else /* IUPIMAGE_IMAGE or IUPIMAGE_ICON */
+ {
+ Screen* screen = ScreenOfDisplay(iupmot_display, iupmot_screen);
+ Pixmap pixmap = XmGetPixmap(screen, (char*)name, BlackPixelOfScreen(screen), WhitePixelOfScreen(screen));
+ if (pixmap == XmUNSPECIFIED_PIXMAP)
+ {
+ unsigned int width, height;
+ int hotx, hoty;
+ pixmap = 0;
+ XReadBitmapFile(iupmot_display, RootWindow(iupmot_display,iupmot_screen), name, &width, &height, &pixmap, &hotx, &hoty);
+ }
+ return (void*)pixmap;
+ }
+}
+
+int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp)
+{
+ Pixmap pixmap = (Pixmap)handle;
+ Window root;
+ int x, y;
+ unsigned int width, height, b, depth;
+ if (!XGetGeometry(iupmot_display, pixmap, &root, &x, &y, &width, &height, &b, &depth))
+ {
+ if (w) *w = 0;
+ if (h) *h = 0;
+ if (bpp) *bpp = 0;
+ return 0;
+ }
+ if (w) *w = width;
+ if (h) *h = height;
+ if (bpp) *bpp = iupImageNormBpp(depth);
+ return 1;
+}
+
+int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count)
+{
+ /* How to get the pallete? */
+ (void)colors;
+ (void)colors_count;
+ return iupdrvImageGetInfo(handle, w, h, bpp);
+}
+
+void iupdrvImageDestroy(void* handle, int type)
+{
+ if (type == IUPIMAGE_CURSOR)
+ XFreeCursor(iupmot_display, (Cursor)handle);
+ else
+ {
+ Screen* screen = ScreenOfDisplay(iupmot_display, iupmot_screen);
+ if (!XmDestroyPixmap(screen, (Pixmap)handle))
+ XFreePixmap(iupmot_display, (Pixmap)handle);
+ }
+}
+
diff --git a/iup/src/mot/iupmot_key.c b/iup/src/mot/iupmot_key.c
new file mode 100755
index 0000000..835b5d7
--- /dev/null
+++ b/iup/src/mot/iupmot_key.c
@@ -0,0 +1,425 @@
+/** \file
+ * \brief Motif Driver keyboard mapping
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <X11/keysym.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+#include "iupkey.h"
+
+#include "iup_object.h"
+#include "iup_key.h"
+#include "iup_str.h"
+
+#include "iupmot_drv.h"
+
+typedef struct Imot2iupkey
+{
+ KeySym motcode;
+ int iupcode;
+ int s_iupcode;
+ int c_iupcode;
+ int m_iupcode;
+ int y_iupcode;
+} Imot2iupkey;
+
+static Imot2iupkey motkey_map[] = {
+
+{ XK_Escape, K_ESC, K_sESC, K_cESC, K_mESC ,K_yESC },
+{ XK_Pause, K_PAUSE, K_sPAUSE, K_cPAUSE, K_mPAUSE ,K_yPAUSE },
+{ XK_Print, K_Print, K_sPrint, K_cPrint, K_mPrint ,K_yPrint },
+{ XK_Menu, K_Menu, K_sMenu, K_cMenu, K_mMenu ,K_yMenu },
+
+{ XK_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME ,K_yHOME },
+{ XK_Up, K_UP, K_sUP, K_cUP, K_mUP ,K_yUP },
+{ XK_Prior, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP ,K_yPGUP },
+{ XK_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT ,K_yLEFT },
+{ XK_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE},
+{ XK_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT ,K_yRIGHT },
+{ XK_End, K_END, K_sEND, K_cEND, K_mEND ,K_yEND },
+{ XK_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN ,K_yDOWN },
+{ XK_Next, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN ,K_yPGDN },
+{ XK_Insert, K_INS, K_sINS, K_cINS, K_mINS ,K_yINS },
+{ XK_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL ,K_yDEL },
+{ XK_space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP },
+{ XK_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB },
+{ XK_Return, K_CR, K_sCR, K_cCR, K_mCR ,K_yCR },
+{ XK_BackSpace, K_BS, K_sBS, K_cBS, K_mBS ,K_yBS },
+
+{ XK_1, K_1, K_exclam, K_c1, K_m1, K_y1 },
+{ XK_2, K_2, K_at, K_c2, K_m2, K_y2 },
+{ XK_3, K_3, K_numbersign, K_c3, K_m3, K_y3 },
+{ XK_4, K_4, K_dollar, K_c4, K_m4, K_y4 },
+{ XK_5, K_5, K_percent, K_c5, K_m5, K_y5 },
+{ XK_6, K_6, K_circum, K_c6, K_m6, K_y6 },
+{ XK_7, K_7, K_ampersand, K_c7, K_m7, K_y7 },
+{ XK_8, K_8, K_asterisk, K_c8, K_m8, K_y8 },
+{ XK_9, K_9, K_parentleft, K_c9, K_m9, K_y9 },
+{ XK_0, K_0, K_parentright, K_c0, K_m0, K_y0 },
+
+{ XK_a, K_a, K_A, K_cA, K_mA, K_yA },
+{ XK_b, K_b, K_B, K_cB, K_mB, K_yB },
+{ XK_c, K_c, K_C, K_cC, K_mC, K_yC },
+{ XK_d, K_d, K_D, K_cD, K_mD, K_yD },
+{ XK_e, K_e, K_E, K_cE, K_mE, K_yE },
+{ XK_f, K_f, K_F, K_cF, K_mF, K_yF },
+{ XK_g, K_g, K_G, K_cG, K_mG, K_yG },
+{ XK_h, K_h, K_H, K_cH, K_mH, K_yH },
+{ XK_i, K_i, K_I, K_cI, K_mI, K_yI },
+{ XK_j, K_j, K_J, K_cJ, K_mJ, K_yJ },
+{ XK_k, K_k, K_K, K_cK, K_mK, K_yK },
+{ XK_l, K_l, K_L, K_cL, K_mL, K_yL },
+{ XK_m, K_m, K_M, K_cM, K_mM, K_yM },
+{ XK_n, K_n, K_N, K_cN, K_mN, K_yN },
+{ XK_o, K_o, K_O, K_cO, K_mO, K_yO },
+{ XK_p, K_p, K_P, K_cP, K_mP, K_yP },
+{ XK_q, K_q, K_Q, K_cQ, K_mQ, K_yQ },
+{ XK_r, K_r, K_R, K_cR, K_mR, K_yR },
+{ XK_s, K_s, K_S, K_cS, K_mS, K_yS },
+{ XK_t, K_t, K_T, K_cT, K_mT, K_yT },
+{ XK_u, K_u, K_U, K_cU, K_mU, K_yU },
+{ XK_v, K_v, K_V, K_cV, K_mV, K_yV },
+{ XK_w, K_w, K_W, K_cW, K_mW, K_yW },
+{ XK_x, K_x, K_X, K_cX, K_mX, K_yX },
+{ XK_y, K_y, K_Y, K_cY, K_mY, K_yY },
+{ XK_z, K_z, K_Z, K_cZ, K_mZ, K_yZ },
+
+{ XK_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 },
+{ XK_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 },
+{ XK_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 },
+{ XK_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 },
+{ XK_F5, K_F5, K_sF5, K_cF5, K_mF5, K_yF5 },
+{ XK_F6, K_F6, K_sF6, K_cF6, K_mF6, K_yF6 },
+{ XK_F7, K_F7, K_sF7, K_cF7, K_mF7, K_yF7 },
+{ XK_F8, K_F8, K_sF8, K_cF8, K_mF8, K_yF8 },
+{ XK_F9, K_F9, K_sF9, K_cF9, K_mF9, K_yF9 },
+{ XK_F10, K_F10, K_sF10, K_cF10, K_mF10, K_yF10 },
+{ XK_F11, K_F11, K_sF11, K_cF11, K_mF11, K_yF11 },
+{ XK_F12, K_F12, K_sF12, K_cF12, K_mF12, K_yF12 },
+
+{ XK_semicolon, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon },
+{ XK_equal, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual },
+{ XK_comma, K_comma, K_less, K_cComma, K_mComma, K_yComma },
+{ XK_minus, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus },
+{ XK_period, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod },
+{ XK_slash, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash },
+{ XK_grave, K_grave, K_tilde, 0, 0, 0 },
+{ XK_bracketleft, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft },
+{ XK_backslash, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash },
+{ XK_bracketright,K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright },
+{ XK_apostrophe, K_apostrophe, K_quotedbl, 0, 0, 0 },
+
+{ XK_KP_0, K_0, K_0, K_c0, K_m0, K_y0 },
+{ XK_KP_1, K_1, K_1, K_c1, K_m1, K_y1 },
+{ XK_KP_2, K_2, K_2, K_c2, K_m2, K_y2 },
+{ XK_KP_3, K_3, K_3, K_c3, K_m3, K_y3 },
+{ XK_KP_4, K_4, K_4, K_c4, K_m4, K_y4 },
+{ XK_KP_5, K_5, K_5, K_c5, K_m5, K_y5 },
+{ XK_KP_6, K_6, K_6, K_c6, K_m6, K_y6 },
+{ XK_KP_7, K_7, K_7, K_c7, K_m7, K_y7 },
+{ XK_KP_8, K_8, K_8, K_c8, K_m8, K_y8 },
+{ XK_KP_9, K_9, K_9, K_c9, K_m9, K_y9 },
+{ XK_KP_Multiply, K_asterisk, K_sAsterisk, K_cAsterisk, K_mAsterisk, K_yAsterisk },
+{ XK_KP_Add, K_plus, K_sPlus, K_cPlus, K_mPlus, K_yPlus },
+{ XK_KP_Subtract, K_minus, K_sMinus, K_cMinus, K_mMinus, K_yMinus },
+{ XK_KP_Decimal, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod },
+{ XK_KP_Divide, K_slash, K_sSlash, K_cSlash, K_mSlash, K_ySlash },
+{ XK_KP_Separator, K_comma, K_sComma, K_cComma, K_mComma, K_yComma },
+
+{ XK_ccedilla, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla },
+
+{ XK_dead_tilde, K_tilde, K_circum, 0, 0, 0 },
+{ XK_dead_acute, K_acute, K_grave, 0, 0, 0 },
+{ XK_dead_grave, K_grave, K_tilde, 0, 0, 0 },
+
+{ XK_KP_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 },
+{ XK_KP_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 },
+{ XK_KP_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 },
+{ XK_KP_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 },
+{ XK_KP_Space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP },
+{ XK_KP_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB },
+{ XK_KP_Equal, K_equal, 0, K_cEqual, K_mEqual, K_yEqual },
+
+{ XK_KP_Enter, K_CR, K_sCR, K_cCR, K_mCR, K_yCR },
+{ XK_KP_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME, K_yHOME },
+{ XK_KP_Up, K_UP, K_sUP, K_cUP, K_mUP, K_yUP },
+{ XK_KP_Page_Up, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP, K_yPGUP },
+{ XK_KP_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT, K_yLEFT },
+{ XK_KP_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE},
+{ XK_KP_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT, K_yRIGHT },
+{ XK_KP_End, K_END, K_sEND, K_cEND, K_mEND, K_yEND },
+{ XK_KP_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN, K_yDOWN },
+{ XK_KP_Page_Down, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN, K_yPGDN },
+{ XK_KP_Insert, K_INS, K_sINS, K_cINS, K_mINS, K_yINS },
+{ XK_KP_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL, K_yDEL }
+
+};
+
+void iupmotKeyEncode(int key, unsigned int *keyval, unsigned int *state)
+{
+ int i, iupcode = key & 0xFF; /* 0-255 interval */
+ int count = sizeof(motkey_map)/sizeof(motkey_map[0]);
+ for (i = 0; i < count; i++)
+ {
+ Imot2iupkey* key_map = &(motkey_map[i]);
+ if (key_map->iupcode == iupcode)
+ {
+ *keyval = XKeysymToKeycode(iupmot_display, key_map->motcode);
+ *state = 0;
+
+ if (iupcode != key)
+ {
+ if (key_map->c_iupcode == key)
+ *state = ControlMask;
+ else if (key_map->m_iupcode == key)
+ *state = Mod1Mask;
+ else if (key_map->y_iupcode == key)
+ *state = Mod4Mask;
+ else if (key_map->s_iupcode == key)
+ *state = ShiftMask;
+ }
+ return;
+ }
+ else if (key_map->s_iupcode == key) /* There are Shift keys bellow 256 */
+ {
+ *keyval = XKeysymToKeycode(iupmot_display, key_map->motcode);
+ *state = ShiftMask;
+ return;
+ }
+ }
+}
+
+static int motKeyMap2Iup(unsigned int state, int i)
+{
+ int code = 0;
+ if (state & ControlMask) /* Ctrl */
+ code = motkey_map[i].c_iupcode;
+ else if (state & Mod1Mask ||
+ state & Mod5Mask) /* Alt */
+ code = motkey_map[i].m_iupcode;
+ else if (state & Mod4Mask) /* Apple/Win */
+ code = motkey_map[i].y_iupcode;
+ else if (state & LockMask) /* CapsLock */
+ {
+ if ((state & ShiftMask) || !iupKeyCanCaps(motkey_map[i].iupcode))
+ return motkey_map[i].iupcode;
+ else
+ code = motkey_map[i].s_iupcode;
+ }
+ else if (state & ShiftMask) /* Shift */
+ code = motkey_map[i].s_iupcode;
+ else
+ return motkey_map[i].iupcode;
+
+ if (!code)
+ code = motkey_map[i].iupcode;
+
+ return code;
+}
+
+static int motKeyDecode(XKeyEvent *evt)
+{
+ int i;
+ KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0);
+ int count = sizeof(motkey_map)/sizeof(motkey_map[0]);
+
+ if ((evt->state & Mod2Mask) && /* NumLock */
+ (motcode >= XK_KP_Home) &&
+ (motcode <= XK_KP_Delete))
+ {
+ /* remap to numeric keys */
+ KeySym remap_numkey[] = {XK_KP_7, XK_KP_4, XK_KP_8, XK_KP_6, XK_KP_2, XK_KP_9, XK_KP_3, XK_KP_1, XK_KP_5, XK_KP_0, XK_KP_Decimal};
+ motcode = remap_numkey[motcode-XK_KP_Home];
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (motkey_map[i].motcode == motcode)
+ return motKeyMap2Iup(evt->state, i);
+ }
+
+ return 0;
+}
+
+KeySym iupmotKeyCharToKeySym(char c)
+{
+ int i;
+ int count = sizeof(motkey_map)/sizeof(motkey_map[0]);
+
+ for (i = 0; i < count; i++)
+ {
+ if (motkey_map[i].iupcode == c)
+ return motkey_map[i].motcode;
+ if (motkey_map[i].s_iupcode == c)
+ {
+ if (motkey_map[i].motcode >= XK_a &&
+ motkey_map[i].motcode <= XK_z)
+ return motkey_map[i].motcode - (XK_a-XK_A);
+ }
+ }
+
+ return 0;
+}
+
+/* Discards keyrepeat by removing the keypress event from the queue.
+ * The pair keyrelease/keypress is always put together in the queue,
+ * by removing the keypress, we only worry about keyrelease. In case
+ * of a keyrelease, we ignore it if the next event is a keypress (which
+ * means repetition. Otherwise it is a real keyrelease.
+ *
+ * Returns 1 if the keypress is found in the queue and 0 otherwise.
+ */
+static int motKeyDiscardKeypressRepeat(XEvent *evt)
+{
+ XEvent ahead;
+ if (XEventsQueued(iupmot_display, QueuedAfterReading))
+ {
+ XPeekEvent(iupmot_display, &ahead);
+ if (ahead.type == KeyPress && ahead.xkey.window == evt->xkey.window
+ && ahead.xkey.keycode == evt->xkey.keycode && ahead.xkey.time == evt->xkey.time)
+ {
+ /* Pop off the repeated KeyPress and ignore */
+ XNextEvent(iupmot_display, evt);
+ /* Ignore the auto repeated KeyRelease/KeyPress pair */
+ return 1;
+ }
+ }
+ /* No KeyPress found */
+ return 0;
+}
+
+/* this is called only for canvas */
+void iupmotCanvasKeyReleaseEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont)
+{
+ if (motKeyDiscardKeypressRepeat(evt))
+ {
+ /* call key_press because it was removed from the queue */
+ iupmotKeyPressEvent(w, ih, evt, cont);
+ }
+ else
+ {
+ int result;
+ int code = motKeyDecode((XKeyEvent*)evt);
+ if (code == 0)
+ return;
+ result = iupKeyCallKeyPressCb(ih, code, 0);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return;
+ }
+ if (result == IUP_IGNORE)
+ {
+ *cont = False;
+ return;
+ }
+ }
+}
+
+void iupmotKeyPressEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont)
+{
+ int result;
+ int code = motKeyDecode((XKeyEvent*)evt);
+ if (code == 0)
+ return;
+
+ if ((((XKeyEvent*)evt)->state & Mod1Mask || ((XKeyEvent*)evt)->state & Mod5Mask)) /* Alt */
+ {
+ KeySym motcode = XKeycodeToKeysym(iupmot_display, ((XKeyEvent*)evt)->keycode, 0);
+ if (motcode < 128)
+ {
+ IFni cb;
+ Ihandle* dialog = IupGetDialog(ih);
+ char attrib[22] = "_IUPMOT_MNEMONIC_ _CB";
+ attrib[17] = (char)toupper(motcode);
+ cb = (IFni)IupGetCallback(dialog, attrib);
+ if (cb)
+ {
+ cb(dialog, attrib[17]);
+ return;
+ }
+ }
+ }
+
+ result = iupKeyCallKeyCb(ih, code);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return;
+ }
+ if (result == IUP_IGNORE)
+ {
+ *cont = False;
+ return;
+ }
+
+ /* in the previous callback the dialog could be destroyed */
+ if (iupObjectCheck(ih))
+ {
+ /* this is called only for canvas */
+ if (ih->iclass->nativetype==IUP_TYPECANVAS)
+ {
+ result = iupKeyCallKeyPressCb(ih, code, 1);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return;
+ }
+ if (result == IUP_IGNORE)
+ {
+ *cont = False;
+ return;
+ }
+ }
+
+ if (!iupKeyProcessNavigation(ih, code, ((XKeyEvent*)evt)->state & ShiftMask))
+ {
+ *cont = False;
+ return;
+ }
+ }
+
+ (void)w;
+}
+
+void iupmotButtonKeySetStatus(unsigned int state, unsigned int but, char* status, int doubleclick)
+{
+ if (state & ShiftMask)
+ iupKEYSETSHIFT(status);
+
+ if (state & ControlMask)
+ iupKEYSETCONTROL(status);
+
+ if ((state & Button1Mask) || but==Button1)
+ iupKEYSETBUTTON1(status);
+
+ if ((state & Button2Mask) || but==Button2)
+ iupKEYSETBUTTON2(status);
+
+ if ((state & Button3Mask) || but==Button3)
+ iupKEYSETBUTTON3(status);
+
+ if ((state & Button4Mask) || but==Button4)
+ iupKEYSETBUTTON4(status);
+
+ if ((state & Button5Mask) || but==Button5)
+ iupKEYSETBUTTON5(status);
+
+ if (state & Mod1Mask || state & Mod5Mask) /* Alt */
+ iupKEYSETALT(status);
+
+ if (state & Mod4Mask) /* Apple/Win */
+ iupKEYSETSYS(status);
+
+ if (doubleclick)
+ iupKEYSETDOUBLE(status);
+}
+
diff --git a/iup/src/mot/iupmot_label.c b/iup/src/mot/iupmot_label.c
new file mode 100755
index 0000000..52dfc9a
--- /dev/null
+++ b/iup/src/mot/iupmot_label.c
@@ -0,0 +1,256 @@
+/** \file
+ * \brief Label Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <Xm/Label.h>
+#include <Xm/Separator.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_label.h"
+#include "iup_drv.h"
+#include "iup_image.h"
+
+#include "iupmot_drv.h"
+
+
+static int motLabelSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ {
+ iupmotSetMnemonicTitle(ih, value);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int motLabelSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ /* ignore given value, must use only from parent */
+ value = iupBaseNativeParentGetBgColor(ih);
+
+ if (iupdrvBaseSetBgColorAttrib(ih, value))
+ return 1;
+ return 0;
+}
+
+static int motLabelSetBackgroundAttrib(Ihandle* ih, const char* value)
+{
+ /* ignore given value, must use only from parent */
+ value = iupAttribGetInheritNativeParent(ih, "BACKGROUND");
+
+ if (iupdrvBaseSetBgColorAttrib(ih, value))
+ return 1;
+ else
+ {
+ Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0);
+ if (pixmap)
+ {
+ XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int motLabelSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ unsigned char align;
+ char value1[30]="", value2[30]="";
+
+ iupStrToStrStr(value, value1, value2, ':'); /* value2 is ignored, NOT supported in Motif */
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ align = XmALIGNMENT_END;
+ else if (iupStrEqualNoCase(value1, "ACENTER"))
+ align = XmALIGNMENT_CENTER;
+ else /* "ALEFT" */
+ align = XmALIGNMENT_BEGINNING;
+
+ XtVaSetValues(ih->handle, XmNalignment, align, NULL);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int motLabelSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_IMAGE)
+ {
+ iupmotSetPixmap(ih, value, XmNlabelPixmap, 0);
+
+ if (!iupdrvIsActive(ih))
+ {
+ if (!iupAttribGet(ih, "IMINACTIVE"))
+ {
+ /* if not active and IMINACTIVE is not defined
+ then automaticaly create one based on IMAGE */
+ iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 1); /* make_inactive */
+ }
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int motLabelSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_IMAGE)
+ {
+ iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 0);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int motLabelSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ /* update the inactive image if necessary */
+ if (ih->data->type == IUP_LABEL_IMAGE && !iupStrBoolean(value))
+ {
+ if (!iupAttribGet(ih, "IMINACTIVE"))
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ char* name = iupAttribGet(ih, "IMAGE");
+ iupmotSetPixmap(ih, name, XmNlabelInsensitivePixmap, 1); /* make_inactive */
+ }
+ }
+
+ return iupBaseSetActiveAttrib(ih, value);
+}
+
+static int motLabelSetPaddingAttrib(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)
+ {
+ XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding,
+ XmNmarginWidth, ih->data->horiz_padding, NULL);
+ }
+ return 0;
+}
+
+static int motLabelMapMethod(Ihandle* ih)
+{
+ char* value;
+ int num_args = 0;
+ Arg args[20];
+ WidgetClass widget_class;
+
+ value = iupAttribGet(ih, "SEPARATOR");
+ if (value)
+ {
+ widget_class = xmSeparatorWidgetClass;
+ if (iupStrEqualNoCase(value, "HORIZONTAL"))
+ {
+ ih->data->type = IUP_LABEL_SEP_HORIZ;
+ iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL);
+ }
+ else /* "VERTICAL" */
+ {
+ ih->data->type = IUP_LABEL_SEP_VERT;
+ iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL);
+ }
+ }
+ else
+ {
+ value = iupAttribGet(ih, "IMAGE");
+ widget_class = xmLabelWidgetClass;
+ if (value)
+ {
+ ih->data->type = IUP_LABEL_IMAGE;
+ iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP);
+ }
+ else
+ {
+ ih->data->type = IUP_LABEL_TEXT;
+ iupmotSetArg(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 */
+ /* Primitive */
+ iupmotSetArg(args, num_args, XmNtraversalOn, False);
+ iupmotSetArg(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);
+
+ ih->handle = XtCreateManagedWidget(
+ iupDialogGetChildIdStr(ih), /* child identifier */
+ widget_class, /* widget class */
+ iupChildTreeGetNativeParentHandle(ih), /* widget parent */
+ args, num_args);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupDialogGetChildId(ih); /* must be after using the string */
+
+ /* Drag Source is enabled by default in label */
+ iupmotDisableDragSource(ih->handle);
+
+ /* initialize the widget */
+ XtRealizeWidget(ih->handle);
+
+ if (ih->data->type == IUP_LABEL_TEXT)
+ iupmotSetString(ih->handle, XmNlabelString, "");
+
+ return IUP_NOERROR;
+}
+
+void iupdrvLabelInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motLabelMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, motLabelSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", iupmotGetBgColorAttrib, motLabelSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motLabelSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, motLabelSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupLabel only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, motLabelSetAlignmentAttrib, "ALEFT:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, motLabelSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PADDING", iupLabelGetPaddingAttrib, motLabelSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+
+ /* IupLabel GTK and Motif only */
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, motLabelSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/mot/iupmot_list.c b/iup/src/mot/iupmot_list.c
new file mode 100755
index 0000000..f8e73ed
--- /dev/null
+++ b/iup/src/mot/iupmot_list.c
@@ -0,0 +1,1404 @@
+/** \file
+ * \brief List Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <Xm/List.h>
+#include <Xm/ComboBox.h>
+#include <Xm/ScrolledW.h>
+#include <Xm/TextF.h>
+#include <X11/keysym.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <time.h>
+#include <limits.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_mask.h"
+#include "iup_key.h"
+#include "iup_list.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+static void motListComboBoxSelectionCallback(Widget w, Ihandle* ih, XmComboBoxCallbackStruct* call_data);
+
+
+void iupdrvListAddItemSpace(Ihandle* ih, int *h)
+{
+ if (ih->data->has_editbox)
+ *h += 1;
+ else
+ *h += 3;
+}
+
+void iupdrvListAddBorders(Ihandle* ih, int *x, int *y)
+{
+ int border_size = 2*4;
+ (*x) += border_size;
+ (*y) += border_size;
+
+ if (ih->data->is_dropdown)
+ {
+ if (ih->data->has_editbox)
+ {
+ /* extra border for the editbox */
+ int internal_border_size = 2*2;
+ (*x) += internal_border_size;
+ (*y) += internal_border_size;
+ }
+ }
+ else
+ {
+ if (ih->data->has_editbox)
+ (*y) += 2*2; /* internal border between editbox and list */
+ else
+ (*x) += 2; /* extra border for the simple list */
+ }
+}
+
+static int motListConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ (void)x;
+ if (ih->data->has_editbox)
+ {
+ Widget cblist;
+ XtVaGetValues(ih->handle, XmNlist, &cblist, NULL);
+ return XmListYToPos(cblist, (Position)y); /* XmListYToPos returns start at 1 */
+ }
+ else
+ return XmListYToPos(ih->handle, (Position)y);
+}
+
+int iupdrvListGetCount(Ihandle* ih)
+{
+ int count;
+ XtVaGetValues(ih->handle, XmNitemCount, &count, NULL);
+ return count;
+}
+
+static void motListAddItem(Ihandle* ih, int pos, const char* value)
+{
+ XmString str = XmStringCreateLocalized((String)value);
+ /* The utility functions use 0=last 1=first */
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ XmComboBoxAddItem(ih->handle, str, pos+1, False);
+ else
+ XmListAddItem(ih->handle, str, pos+1);
+ XmStringFree(str);
+}
+
+static void motListAddSortedItem(Ihandle* ih, const char *value)
+{
+ char *text;
+ XmString *strlist;
+ int u_bound, l_bound = 0;
+
+ XtVaGetValues(ih->handle, XmNitemCount, &u_bound, XmNitems, &strlist, NULL);
+
+ u_bound--;
+ /* perform binary search */
+ while (u_bound >= l_bound)
+ {
+ int i = l_bound + (u_bound - l_bound)/2;
+ text = (char*)XmStringUnparse(strlist[i], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
+ if (!text)
+ break;
+ if (strcmp (text, value) > 0)
+ u_bound = i-1; /* newtext comes before item */
+ else
+ l_bound = i+1; /* newtext comes after item */
+ XtFree(text);
+ }
+
+ motListAddItem(ih, l_bound, value);
+}
+
+void iupdrvListAppendItem(Ihandle* ih, const char* value)
+{
+ if (iupAttribGetBoolean(ih, "SORT"))
+ motListAddSortedItem(ih, value);
+ else
+ motListAddItem(ih, -1, value);
+}
+
+void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value)
+{
+ if (iupAttribGetBoolean(ih, "SORT"))
+ motListAddSortedItem(ih, value);
+ else
+ motListAddItem(ih, pos, value);
+}
+
+void iupdrvListRemoveItem(Ihandle* ih, int pos)
+{
+ /* The utility functions use 0=last 1=first */
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ XmComboBoxDeletePos(ih->handle, pos+1);
+ else
+ XmListDeletePos(ih->handle, pos+1);
+}
+
+void iupdrvListRemoveAllItems(Ihandle* ih)
+{
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ {
+ Widget cblist;
+ XtVaGetValues(ih->handle, XmNlist, &cblist, NULL);
+ XmListDeleteAllItems(cblist);
+ XmComboBoxUpdate(ih->handle);
+ }
+ else
+ XmListDeleteAllItems(ih->handle);
+}
+
+
+/*********************************************************************************/
+
+
+static char* motListGetIdValueAttrib(Ihandle* ih, const char* name_id)
+{
+ int pos = iupListGetPos(ih, name_id);
+ if (pos != -1)
+ {
+ XmString* items;
+ XtVaGetValues(ih->handle, XmNitems, &items, NULL);
+ return iupmotConvertString(items[pos]);
+ }
+ return NULL;
+}
+
+static int motListSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (sb_win)
+ {
+ Pixel color;
+
+ /* ignore given value for the scrollbars, must use only from parent */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ color = iupmotColorGetPixelStr(parent_value);
+ if (color != (Pixel)-1)
+ {
+ Widget sb = NULL;
+
+ iupmotSetBgColor(sb_win, color);
+
+ XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL);
+ if (sb) iupmotSetBgColor(sb, color);
+
+ XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL);
+ if (sb) iupmotSetBgColor(sb, color);
+ }
+
+ return iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */
+ }
+ else
+ {
+ char* parent_value;
+
+ /* use given value for Edit and List also */
+ Pixel color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ {
+ Widget cbedit, cblist, sb;
+
+ iupmotSetBgColor(ih->handle, color);
+
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ if (cbedit) iupmotSetBgColor(cbedit, color);
+
+ XtVaGetValues(ih->handle, XmNlist, &cblist, NULL);
+ if (cblist) iupmotSetBgColor(cblist, color);
+
+ XtVaGetValues(cblist, XmNverticalScrollBar, &sb, NULL);
+ if (sb) iupmotSetBgColor(sb, color);
+
+ XtVaGetValues(cblist, XmNhorizontalScrollBar, &sb, NULL);
+ if (sb) iupmotSetBgColor(sb, color);
+ }
+
+ /* but reset just the background, so the combobox will look like a button */
+ parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ color = iupmotColorGetPixelStr(parent_value);
+ if (color != (Pixel)-1)
+ XtVaSetValues(ih->handle, XmNbackground, color, NULL);
+
+ return 1;
+ }
+}
+
+static int motListSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ {
+ XtVaSetValues(ih->handle, XmNforeground, color, NULL);
+
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ {
+ Widget w;
+ XtVaGetValues(ih->handle, XmNtextField, &w, NULL);
+ XtVaSetValues(w, XmNforeground, color, NULL);
+
+ XtVaGetValues(ih->handle, XmNlist, &w, NULL);
+ XtVaSetValues(w, XmNforeground, color, NULL);
+ }
+ }
+
+ return 1;
+}
+
+static char* motListGetValueAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char *str, *xstr;
+ Widget cbedit;
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ xstr = XmTextFieldGetString(cbedit);
+ str = iupStrGetMemoryCopy(xstr);
+ XtFree(xstr);
+ return str;
+ }
+ else
+ {
+ if (ih->data->is_dropdown)
+ {
+ char* str;
+ int pos;
+ XtVaGetValues(ih->handle, XmNselectedPosition, &pos, NULL);
+ str = iupStrGetMemory(50);
+ sprintf(str, "%d", pos+1); /* IUP starts at 1 */
+ return str;
+ }
+ else
+ {
+ int *pos, sel_count;
+ if (XmListGetSelectedPos(ih->handle, &pos, &sel_count)) /* XmListGetSelectedPos starts at 1 */
+ {
+ if (!ih->data->is_multiple)
+ {
+ char* str = iupStrGetMemory(50);
+ sprintf(str, "%d", pos[0]);
+ XtFree((char*)pos);
+ return str;
+ }
+ else
+ {
+ int i, count;
+ char* str;
+ XtVaGetValues(ih->handle, XmNitemCount, &count, NULL);
+ str = iupStrGetMemory(count+1);
+ memset(str, '-', count);
+ str[count]=0;
+ for (i=0; i<sel_count; i++)
+ str[pos[i]-1] = '+';
+ XtFree((char*)pos);
+ return str;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int motListSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->has_editbox)
+ {
+ Widget cbedit;
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ if (!value) value = "";
+
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */
+
+ XmTextFieldSetString(cbedit, (char*)value);
+
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+ else
+ {
+ if (ih->data->is_dropdown)
+ {
+ int pos;
+ if (iupStrToInt(value, &pos)==1)
+ {
+ XtRemoveCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih);
+
+ XtVaSetValues(ih->handle, XmNselectedPosition, pos-1, NULL); /* IUP starts at 1 */
+ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos);
+
+ XtAddCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih);
+ }
+ }
+ else
+ {
+ if (!ih->data->is_multiple)
+ {
+ int pos;
+ if (iupStrToInt(value, &pos)==1)
+ {
+ XmListSelectPos(ih->handle, pos, FALSE); /* XmListSelectPos starts at 1 */
+ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos);
+ }
+ else
+ {
+ XmListDeselectAllItems(ih->handle);
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ }
+ }
+ else
+ {
+ /* User has changed a multiple selection on a simple list. */
+ int i, count, len;
+
+ /* Clear all selections */
+ XmListDeselectAllItems(ih->handle);
+
+ if (!value)
+ {
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ return 0;
+ }
+
+ XtVaGetValues(ih->handle, XmNitemCount, &count, NULL);
+ len = strlen(value);
+ if (len < count)
+ count = len;
+
+ XtVaSetValues(ih->handle, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
+
+ /* update selection list */
+ for (i = 0; i<count; i++)
+ {
+ if (value[i]=='+')
+ XmListSelectPos(ih->handle, i+1, False); /* XmListSelectPos starts at 1 */
+ }
+
+ XtVaSetValues(ih->handle, XmNselectionPolicy, XmEXTENDED_SELECT,
+ XmNselectionMode, XmNORMAL_MODE, NULL); /* must also restore this */
+ iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int motListSetVisibleItemsAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_dropdown)
+ {
+ int count;
+ if (iupStrToInt(value, &count)==1)
+ XtVaSetValues(ih->handle, XmNvisibleItemCount, count, NULL);
+ }
+ return 1;
+}
+
+static int motListSetShowDropdownAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_dropdown)
+ {
+ if (iupStrBoolean(value))
+ {
+ XButtonEvent ev;
+ memset(&ev, 0, sizeof(XButtonEvent));
+ ev.type = ButtonPress;
+ ev.display = XtDisplay(ih->handle);
+ ev.send_event = True;
+ ev.root = RootWindow(iupmot_display, iupmot_screen);
+ ev.time = clock()*CLOCKS_PER_SEC;
+ ev.window = XtWindow(ih->handle);
+ ev.state = Button1Mask;
+ ev.button = Button1;
+ ev.same_screen = True;
+ XtCallActionProc(ih->handle, "CBDropDownList", (XEvent*)&ev, 0, 0 );
+ }
+ else
+ XtCallActionProc(ih->handle, "CBDisarm", 0, 0, 0 );
+ }
+ return 0;
+}
+
+static int motListSetTopItemAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->is_dropdown)
+ {
+ int pos = 1;
+ if (iupStrToInt(value, &pos))
+ {
+ if (ih->data->has_editbox)
+ {
+ Widget cblist;
+ XtVaGetValues(ih->handle, XmNlist, &cblist, NULL);
+ XtVaSetValues(cblist, XmNtopItemPosition, pos, NULL);
+ }
+ else
+ XtVaSetValues(ih->handle, XmNtopItemPosition, pos, NULL);
+ }
+ }
+ return 0;
+}
+
+static int motListSetSpacingAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_dropdown)
+ return 0;
+
+ if (!iupStrToInt(value, &ih->data->spacing))
+ ih->data->spacing = 0;
+
+ if (ih->handle)
+ {
+ if (ih->data->has_editbox)
+ {
+ Widget cblist;
+ XtVaGetValues(ih->handle, XmNlist, &cblist, NULL);
+ XtVaSetValues(cblist, XmNlistSpacing, ih->data->spacing*2,
+ XmNlistMarginWidth, ih->data->spacing,
+ XmNlistMarginHeight, ih->data->spacing,
+ NULL);
+ }
+ else
+ XtVaSetValues(ih->handle, XmNlistSpacing, ih->data->spacing*2,
+ XmNlistMarginWidth, ih->data->spacing,
+ XmNlistMarginHeight, ih->data->spacing,
+ NULL);
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int motListSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle)
+ {
+ Widget cbedit;
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XtVaSetValues(cbedit, XmNmarginHeight, ih->data->vert_padding,
+ XmNmarginWidth, ih->data->horiz_padding, NULL);
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int motListSetReadOnlyAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->has_editbox)
+ {
+ Widget cbedit;
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XtVaSetValues(cbedit, XmNeditable, iupStrBoolean(value)? False: True, NULL);
+ }
+ return 0;
+}
+
+static char* motListGetReadOnlyAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ Boolean editable;
+ Widget cbedit;
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XtVaGetValues(cbedit, XmNeditable, &editable, NULL);
+ if (editable)
+ return "YES";
+ else
+ return "NO";
+ }
+ else
+ return NULL;
+}
+
+static int motListSetInsertAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ return 0;
+
+ if (ih->data->has_editbox)
+ {
+ Widget cbedit;
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */
+ XmTextFieldRemove(cbedit);
+ XmTextFieldInsert(cbedit, XmTextFieldGetInsertionPosition(cbedit), (char*)value);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+
+ return 0;
+}
+
+static int motListSetSelectedTextAttrib(Ihandle* ih, const char* value)
+{
+ XmTextPosition start, end;
+ Widget cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ if (XmTextFieldGetSelectionPosition(cbedit, &start, &end) && start!=end)
+ {
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */
+ XmTextFieldReplace(cbedit, start, end, (char*)value);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+
+ return 0;
+}
+
+static char* motListGetSelectedTextAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char* selectedtext, *str;
+ Widget cbedit;
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ selectedtext = XmTextFieldGetSelection(cbedit);
+ str = iupStrGetMemoryCopy(selectedtext);
+ XtFree(selectedtext);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int motListSetAppendAttrib(Ihandle* ih, const char* value)
+{
+ if (value && ih->data->has_editbox)
+ {
+ XmTextPosition pos;
+ Widget cbedit;
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ pos = XmTextFieldGetLastPosition(cbedit);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */
+ XmTextFieldInsert(cbedit, pos+1, (char*)value);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+ return 0;
+}
+
+static int motListSetSelectionAttrib(Ihandle* ih, const char* value)
+{
+ int start=1, end=1;
+ Widget cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XmTextFieldClearSelection(cbedit, CurrentTime);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XmTextFieldSetSelection(cbedit, (XmTextPosition)0, (XmTextPosition)XmTextFieldGetLastPosition(cbedit), CurrentTime);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<1 || end<1)
+ return 0;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ /* end is inside the selection, in IUP is outside */
+ end--;
+
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XmTextFieldSetSelection(cbedit, (XmTextPosition)start, (XmTextPosition)end, CurrentTime);
+
+ return 0;
+}
+
+static char* motListGetSelectionAttrib(Ihandle* ih)
+{
+ XmTextPosition start = 0, end = 0;
+ char* str;
+ Widget cbedit;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ if (!XmTextFieldGetSelectionPosition(cbedit, &start, &end) || start==end)
+ return NULL;
+
+ str = iupStrGetMemory(100);
+
+ /* end is inside the selection, in IUP is outside */
+ end++;
+
+ start++; /* IUP starts at 1 */
+ end++;
+ sprintf(str, "%d:%d", (int)start, (int)end);
+
+ return str;
+}
+
+static int motListSetSelectionPosAttrib(Ihandle* ih, const char* value)
+{
+ int start=0, end=0;
+ Widget cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XmTextFieldClearSelection(cbedit, CurrentTime);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XmTextFieldSetSelection(cbedit, (XmTextPosition)0, (XmTextPosition)XmTextFieldGetLastPosition(cbedit), CurrentTime);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<0 || end<0)
+ return 0;
+
+ /* end is inside the selection, in IUP is outside */
+ end--;
+
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XmTextFieldSetSelection(cbedit, (XmTextPosition)start, (XmTextPosition)end, CurrentTime);
+
+ return 0;
+}
+
+static char* motListGetSelectionPosAttrib(Ihandle* ih)
+{
+ XmTextPosition start = 0, end = 0;
+ char* str;
+ Widget cbedit;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ if (!XmTextFieldGetSelectionPosition(cbedit, &start, &end) || start==end)
+ return NULL;
+
+ str = iupStrGetMemory(100);
+
+ /* end is inside the selection, in IUP is outside */
+ end++;
+
+ sprintf(str, "%d:%d", (int)start, (int)end);
+
+ return str;
+}
+
+static int motListSetCaretAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+ Widget cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ pos--; /* IUP starts at 1 */
+
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XmTextFieldSetInsertionPosition(cbedit, (XmTextPosition)pos);
+ XmTextFieldShowPosition(cbedit, (XmTextPosition)pos);
+
+ return 0;
+}
+
+static char* motListGetCaretAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ XmTextPosition pos;
+ Widget cbedit;
+ char* str = iupStrGetMemory(50);
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ pos = XmTextFieldGetInsertionPosition(cbedit);
+ pos++; /* IUP starts at 1 */
+ sprintf(str, "%d", (int)pos);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int motListSetCaretPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+ Widget cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XmTextFieldSetInsertionPosition(cbedit, (XmTextPosition)pos);
+ XmTextFieldShowPosition(cbedit, (XmTextPosition)pos);
+
+ return 0;
+}
+
+static char* motListGetCaretPosAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ XmTextPosition pos;
+ Widget cbedit;
+ char* str = iupStrGetMemory(50);
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ pos = XmTextFieldGetInsertionPosition(cbedit);
+ sprintf(str, "%d", (int)pos);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int motListSetScrollToAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+ Widget cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+ pos--; /* return to Motif referece */
+
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XmTextFieldShowPosition(cbedit, (XmTextPosition)pos);
+
+ return 0;
+}
+
+static int motListSetScrollToPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+ Widget cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XmTextFieldShowPosition(cbedit, (XmTextPosition)pos);
+
+ return 0;
+}
+
+static int motListSetNCAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!iupStrToInt(value, &ih->data->nc))
+ ih->data->nc = INT_MAX;
+
+ if (ih->handle)
+ {
+ Widget cbedit;
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XtVaSetValues(cbedit, XmNmaxLength, ih->data->nc, NULL);
+ }
+ return 0;
+}
+
+static int motListSetClipboardAttrib(Ihandle *ih, const char *value)
+{
+ Widget cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+
+ if (iupStrEqualNoCase(value, "COPY"))
+ {
+ char *str = XmTextFieldGetSelection(cbedit);
+
+ XmTextFieldCopy(cbedit, CurrentTime);
+
+ /* do it also for the X clipboard */
+ XStoreBytes(iupmot_display, str, strlen(str)+1);
+ XtFree(str);
+ }
+ else if (iupStrEqualNoCase(value, "CUT"))
+ {
+ char *str = XmTextFieldGetSelection(cbedit);
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+
+ XmTextFieldCut(cbedit, CurrentTime);
+
+ /* do it also for the X clipboard */
+ XStoreBytes(iupmot_display, str, strlen(str)+1);
+ XtFree(str);
+ XmTextFieldRemove(cbedit);
+
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+ else if (iupStrEqualNoCase(value, "PASTE"))
+ {
+ int size;
+ char* str = XFetchBytes(iupmot_display, &size);
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+
+ XmTextFieldPaste(cbedit); /* TODO: this could force 2 pastes, check in CDE */
+
+ /* do it also for the X clipboard */
+ XmTextFieldRemove(cbedit);
+ XmTextFieldInsert(cbedit, XmTextFieldGetInsertionPosition(cbedit), str);
+ XFree(str);
+
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+ else if (iupStrEqualNoCase(value, "CLEAR"))
+ {
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+ XmTextFieldRemove(cbedit);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+ return 0;
+}
+
+
+/*********************************************************************************/
+
+
+static void motListEditModifyVerifyCallback(Widget cbedit, Ihandle *ih, XmTextVerifyPtr text)
+{
+ int start, end, key = 0;
+ char *value, *new_value, *insert_value;
+ KeySym motcode = 0;
+ IFnis cb;
+
+ if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB"))
+ return;
+
+ cb = (IFnis)IupGetCallback(ih, "EDIT_CB");
+ if (!cb && !ih->data->mask)
+ return;
+
+ if (text->event && text->event->type == KeyPress)
+ {
+ unsigned int state = ((XKeyEvent*)text->event)->state;
+ if (state & ControlMask || /* Ctrl */
+ state & Mod1Mask ||
+ state & Mod5Mask || /* Alt */
+ state & Mod4Mask) /* Apple/Win */
+ return;
+
+ motcode = XKeycodeToKeysym(iupmot_display, ((XKeyEvent*)text->event)->keycode, 0);
+ }
+
+ value = XmTextFieldGetString(cbedit);
+ start = text->startPos;
+ end = text->endPos;
+ insert_value = text->text->ptr;
+
+ if (motcode == XK_Delete)
+ {
+ new_value = value;
+ iupStrRemove(value, start, end, 1);
+ }
+ else if (motcode == XK_BackSpace)
+ {
+ new_value = value;
+ iupStrRemove(value, start, end, -1);
+ }
+ else
+ {
+ if (!value)
+ new_value = iupStrDup(insert_value);
+ else if (insert_value)
+ new_value = iupStrInsert(value, insert_value, start, end);
+ else
+ new_value = value;
+ }
+
+ if (insert_value && insert_value[0]!=0 && insert_value[1]==0)
+ key = insert_value[0];
+
+ if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0)
+ {
+ if (new_value != value) free(new_value);
+ XtFree(value);
+ text->doit = False; /* abort processing */
+ return;
+ }
+
+ if (cb)
+ {
+ int cb_ret = cb(ih, key, (char*)new_value);
+ if (cb_ret==IUP_IGNORE)
+ text->doit = False; /* abort processing */
+ else if (cb_ret==IUP_CLOSE)
+ {
+ IupExitLoop();
+ text->doit = False; /* abort processing */
+ }
+ else if (cb_ret!=0 && key!=0 &&
+ cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE)
+ {
+ insert_value[0] = (char)cb_ret; /* replace key */
+ }
+ }
+
+ if (new_value != value) free(new_value);
+ XtFree(value);
+}
+
+static void motListEditMotionVerifyCallback(Widget w, Ihandle* ih, XmTextVerifyCallbackStruct* textverify)
+{
+ int pos;
+
+ IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB");
+ if (!cb) return;
+
+ pos = textverify->newInsert;
+
+ if (pos != ih->data->last_caret_pos)
+ {
+ ih->data->last_caret_pos = pos;
+ cb(ih, 1, pos+1, pos);
+ }
+
+ (void)w;
+}
+
+static void motListEditKeyPressEvent(Widget cbedit, Ihandle *ih, XKeyEvent *evt, Boolean *cont)
+{
+ *cont = True;
+ iupmotKeyPressEvent(cbedit, ih, (XEvent*)evt, cont);
+ if (*cont == False)
+ return;
+
+ if (evt->state & ControlMask) /* Ctrl */
+ {
+ KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0);
+ if (motcode == XK_c)
+ {
+ motListSetClipboardAttrib(ih, "COPY");
+ *cont = False;
+ return;
+ }
+ else if (motcode == XK_x)
+ {
+ motListSetClipboardAttrib(ih, "CUT");
+ *cont = False;
+ return;
+ }
+ else if (motcode == XK_v)
+ {
+ motListSetClipboardAttrib(ih, "PASTE");
+ *cont = False;
+ return;
+ }
+ else if (motcode == XK_a)
+ {
+ XmTextFieldSetSelection(cbedit, 0, XmTextFieldGetLastPosition(cbedit), CurrentTime);
+ *cont = False;
+ return;
+ }
+ }
+}
+
+static void motListEditValueChangedCallback(Widget w, Ihandle* ih, XmAnyCallbackStruct* valuechanged)
+{
+ if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB"))
+ return;
+
+ iupBaseCallValueChangedCb(ih);
+
+ (void)valuechanged;
+ (void)w;
+}
+
+static void motListDropDownPopupCallback(Widget w, Ihandle* ih, XtPointer call_data)
+{
+ IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB");
+ if (cb)
+ cb(ih, 1);
+ (void)w;
+ (void)call_data;
+}
+
+static void motListDropDownPopdownCallback(Widget w, Ihandle* ih, XtPointer call_data)
+{
+ IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB");
+ if (cb)
+ cb(ih, 0);
+ (void)w;
+ (void)call_data;
+}
+
+static void motListDefaultActionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* call_data)
+{
+ if (call_data->event->type == ButtonPress || call_data->event->type == ButtonRelease)
+ {
+ IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB");
+ if (cb)
+ {
+ int pos = call_data->item_position; /* Here Motif already starts at 1 */
+ iupListSingleCallDblClickCallback(ih, cb, pos);
+ }
+ }
+
+ (void)w;
+}
+
+static void motListComboBoxSelectionCallback(Widget w, Ihandle* ih, XmComboBoxCallbackStruct* call_data)
+{
+ IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ int pos = call_data->item_position;
+ if (pos==0)
+ {
+ /* must check if it is really checked or it is for the edit box */
+ XmString* items;
+ XtVaGetValues(ih->handle, XmNitems, &items, NULL);
+ if (!XmStringCompare(call_data->item_or_text, items[0]))
+ return;
+ }
+ pos++; /* IUP starts at 1 */
+ iupListSingleCallActionCallback(ih, cb, pos);
+ }
+
+ if (!ih->data->has_editbox)
+ iupBaseCallValueChangedCb(ih);
+
+ (void)w;
+}
+
+static void motListBrowseSelectionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* call_data)
+{
+ IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ int pos = call_data->item_position; /* Here Motif already starts at 1 */
+ iupListSingleCallActionCallback(ih, cb, pos);
+ }
+
+ if (!ih->data->has_editbox)
+ iupBaseCallValueChangedCb(ih);
+
+ (void)w;
+}
+
+static void motListExtendedSelectionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* call_data)
+{
+ IFns multi_cb = (IFns)IupGetCallback(ih, "MULTISELECT_CB");
+ IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION");
+ if (multi_cb || cb)
+ {
+ int* pos = call_data->selected_item_positions;
+ int sel_count = call_data->selected_item_count;
+ int i;
+
+ /* In Motif, the position of item is "plus one".
+ "iupListMultipleCallActionCallback" works with the list of selected items from the zero position.
+ So, "minus one" here. */
+ for (i = 0; i < sel_count; i++)
+ pos[i] -= 1;
+
+ iupListMultipleCallActionCallback(ih, cb, multi_cb, pos, sel_count);
+ }
+
+ if (!ih->data->has_editbox)
+ iupBaseCallValueChangedCb(ih);
+
+ (void)w;
+}
+
+
+/*********************************************************************************/
+
+
+static int motListMapMethod(Ihandle* ih)
+{
+ int num_args = 0;
+ Arg args[30];
+ Widget parent = iupChildTreeGetNativeParentHandle(ih);
+ char* child_id = iupDialogGetChildIdStr(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);
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ iupmotSetArg(args, num_args, XmNtraversalOn, True);
+ else
+ iupmotSetArg(args, num_args, XmNtraversalOn, False);
+
+ iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP);
+ iupmotSetArg(args, num_args, XmNhighlightThickness, 2);
+ iupmotSetArg(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 */
+ else
+ iupmotSetArg(args, num_args, XmNcomboBoxType, XmCOMBO_BOX); /* visible-list+edit */
+ }
+ else
+ iupmotSetArg(args, num_args, XmNcomboBoxType, XmDROP_DOWN_LIST); /* hidden-list */
+
+ ih->handle = XtCreateManagedWidget(
+ child_id, /* child identifier */
+ xmComboBoxWidgetClass, /* widget class */
+ parent, /* widget parent */
+ args, num_args);
+ }
+ else
+ {
+ Widget sb_win;
+
+ /* 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);
+
+ sb_win = XtCreateManagedWidget(
+ child_id, /* child identifier */
+ xmScrolledWindowWidgetClass, /* widget class */
+ parent, /* widget parent */
+ args, num_args);
+
+ if (!sb_win)
+ return IUP_ERROR;
+
+ parent = sb_win;
+ child_id = "list";
+
+ /* 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 */
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ iupmotSetArg(args, num_args, XmNtraversalOn, True);
+ else
+ iupmotSetArg(args, num_args, XmNtraversalOn, False);
+
+ iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP);
+ iupmotSetArg(args, num_args, XmNhighlightThickness, 2);
+ iupmotSetArg(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 */
+
+ if (ih->data->is_multiple)
+ iupmotSetArg(args, num_args, XmNselectionPolicy, XmEXTENDED_SELECT);
+ else
+ iupmotSetArg(args, num_args, XmNselectionPolicy, XmBROWSE_SELECT);
+
+ if (iupAttribGetBoolean(ih, "AUTOHIDE"))
+ iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED);
+ else
+ iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC);
+
+ ih->handle = XtCreateManagedWidget(
+ child_id, /* child identifier */
+ xmListWidgetClass, /* widget class */
+ parent, /* widget parent */
+ args, num_args);
+ }
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupDialogGetChildId(ih); /* must be after using the string */
+
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ {
+ Widget cbedit, cblist;
+ XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL);
+ XtVaGetValues(ih->handle, XmNlist, &cblist, NULL);
+
+ XtAddEventHandler(cbedit, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih);
+ XtAddEventHandler(cbedit, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(cbedit, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddCallback(cbedit, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih);
+
+ XtAddCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih);
+
+ if (ih->data->has_editbox)
+ {
+ XtAddEventHandler(cbedit, KeyPressMask, False, (XtEventHandler)motListEditKeyPressEvent, (XtPointer)ih);
+ XtAddCallback(cbedit, XmNmodifyVerifyCallback, (XtCallbackProc)motListEditModifyVerifyCallback, (XtPointer)ih);
+ XtAddCallback(cbedit, XmNmotionVerifyCallback, (XtCallbackProc)motListEditMotionVerifyCallback, (XtPointer)ih);
+ XtAddCallback(cbedit, XmNvalueChangedCallback, (XtCallbackProc)motListEditValueChangedCallback, (XtPointer)ih);
+
+ /* Disable Drag Source */
+ iupmotDisableDragSource(cbedit);
+ }
+ else
+ XtAddEventHandler(cbedit, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih);
+
+ if (ih->data->is_dropdown)
+ {
+ XtVaSetValues(ih->handle, XmNvisibleItemCount, 5, NULL);
+ XtAddCallback(XtParent(XtParent(cblist)), XmNpopupCallback, (XtCallbackProc)motListDropDownPopupCallback, (XtPointer)ih);
+ XtAddCallback(XtParent(XtParent(cblist)), XmNpopdownCallback, (XtCallbackProc)motListDropDownPopdownCallback, (XtPointer)ih);
+ }
+ else
+ {
+ XtAddCallback(cblist, XmNdefaultActionCallback, (XtCallbackProc)motListDefaultActionCallback, (XtPointer)ih);
+ XtAddEventHandler(cblist, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih);
+ XtAddEventHandler(cblist, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih);
+
+ /* Disable Drag Source */
+ iupmotDisableDragSource(cblist);
+ }
+ }
+ else
+ {
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent);
+ XtVaSetValues(parent, XmNworkWindow, ih->handle, NULL);
+
+ XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih);
+
+ XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih);
+ XtAddCallback (ih->handle, XmNbrowseSelectionCallback, (XtCallbackProc)motListBrowseSelectionCallback, (XtPointer)ih);
+ XtAddCallback (ih->handle, XmNextendedSelectionCallback, (XtCallbackProc)motListExtendedSelectionCallback, (XtPointer)ih);
+ XtAddCallback (ih->handle, XmNdefaultActionCallback, (XtCallbackProc)motListDefaultActionCallback, (XtPointer)ih);
+ }
+
+ /* Disable Drag Source */
+ iupmotDisableDragSource(ih->handle);
+
+ /* initialize the widget */
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ XtRealizeWidget(ih->handle);
+ else
+ XtRealizeWidget(parent);
+
+ if (IupGetGlobal("_IUP_RESET_TXTCOLORS"))
+ {
+ iupmotSetGlobalColorAttrib(ih->handle, XmNbackground, "TXTBGCOLOR");
+ iupmotSetGlobalColorAttrib(ih->handle, XmNforeground, "TXTFGCOLOR");
+ IupSetGlobal("_IUP_RESET_TXTCOLORS", NULL);
+ }
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)motListConvertXYToPos);
+
+ iupListSetInitialItems(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvListInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motListMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motListSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motListSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT);
+
+ /* IupList only */
+ iupClassRegisterAttributeId(ic, "IDVALUE", motListGetIdValueAttrib, iupListSetIdValueAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE", motListGetValueAttrib, motListSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VISIBLE_ITEMS", NULL, motListSetVisibleItemsAttrib, IUPAF_SAMEASSYSTEM, "5", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TOPITEM", NULL, motListSetTopItemAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWDROPDOWN", NULL, motListSetShowDropdownAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPACING", iupListGetSpacingAttrib, motListSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupListGetPaddingAttrib, motListSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "SELECTEDTEXT", motListGetSelectedTextAttrib, motListSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTION", motListGetSelectionAttrib, motListSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTIONPOS", motListGetSelectionPosAttrib, motListSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARET", motListGetCaretAttrib, motListSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARETPOS", motListGetCaretPosAttrib, motListSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INSERT", NULL, motListSetInsertAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPEND", NULL, motListSetAppendAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "READONLY", motListGetReadOnlyAttrib, motListSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "NC", iupListGetNCAttrib, motListSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, motListSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTO", NULL, motListSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, motListSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/mot/iupmot_loop.c b/iup/src/mot/iupmot_loop.c
new file mode 100755
index 0000000..828ddcd
--- /dev/null
+++ b/iup/src/mot/iupmot_loop.c
@@ -0,0 +1,108 @@
+/** \file
+ * \brief Motif Message Loop
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+
+#include <Xm/Xm.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iupmot_drv.h"
+
+
+/* local variables */
+static int mot_mainloop = 0;
+static int mot_exitmainloop = 0;
+static IFidle mot_idle_cb = NULL;
+static XtWorkProcId mot_idle_id;
+
+
+static Boolean motIdlecbWorkProc(XtPointer client_data)
+{
+ (void)client_data;
+ if (mot_idle_cb)
+ {
+ int ret = mot_idle_cb();
+ if (ret == IUP_CLOSE)
+ {
+ mot_idle_cb = NULL;
+ IupExitLoop();
+ return True; /* removes the working procedure */
+ }
+ if (ret == IUP_IGNORE)
+ {
+ mot_idle_cb = NULL;
+ return True; /* removes the working procedure */
+ }
+
+ return False; /* keeps the working procedure */
+ }
+
+ return True; /* removes the working procedure */
+}
+
+void iupdrvSetIdleFunction(Icallback f)
+{
+ if (mot_idle_cb)
+ XtRemoveWorkProc(mot_idle_id);
+
+ mot_idle_cb = (IFidle)f;
+
+ if (mot_idle_cb)
+ mot_idle_id = XtAppAddWorkProc(iupmot_appcontext, motIdlecbWorkProc, NULL);
+}
+
+static int motLoopStep(void)
+{
+ XtAppProcessEvent(iupmot_appcontext, XtIMAll);
+ return (mot_exitmainloop)? IUP_CLOSE : IUP_DEFAULT;
+}
+
+void IupExitLoop(void)
+{
+ mot_exitmainloop = 1;
+}
+
+int IupMainLoopLevel(void)
+{
+ return mot_mainloop;
+}
+
+int IupMainLoop(void)
+{
+ mot_mainloop++;
+ mot_exitmainloop = 0;
+
+ while (!mot_exitmainloop)
+ {
+ if (motLoopStep() == IUP_CLOSE)
+ break;
+ }
+
+ mot_exitmainloop = 0;
+ mot_mainloop--;
+ return IUP_NOERROR;
+}
+
+int IupLoopStep(void)
+{
+ if (!XtAppPending(iupmot_appcontext))
+ return IUP_DEFAULT;
+
+ return motLoopStep();
+}
+
+void IupFlush(void)
+{
+ while (XPending(iupmot_display) != 0)
+ {
+ if (motLoopStep() == IUP_CLOSE)
+ break;
+ }
+
+ XFlush(iupmot_display);
+}
diff --git a/iup/src/mot/iupmot_menu.c b/iup/src/mot/iupmot_menu.c
new file mode 100755
index 0000000..be9b953
--- /dev/null
+++ b/iup/src/mot/iupmot_menu.c
@@ -0,0 +1,457 @@
+/** \file
+ * \brief Menu Resources
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Separator.h>
+#include <Xm/CascadeB.h>
+#include <Xm/ToggleB.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_label.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+#include "iup_menu.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+static int mot_menu_exitloop = 0;
+
+int iupdrvMenuPopup(Ihandle* ih, int x, int y)
+{
+ XButtonEvent ev;
+ ev.x_root = x;
+ ev.y_root = y;
+ XmMenuPosition(ih->handle, &ev);
+
+ XtManageChild(ih->handle);
+
+ mot_menu_exitloop = 0;
+ while (!mot_menu_exitloop)
+ XtAppProcessEvent(iupmot_appcontext, XtIMAll);
+ mot_menu_exitloop = 0;
+
+ return IUP_NOERROR;
+}
+
+int iupdrvMenuGetMenuBarSize(Ihandle* ih)
+{
+ int ch;
+ iupdrvFontGetCharSize(ih, NULL, &ch);
+ return 5 + ch + 5;
+}
+
+
+/*******************************************************************************************/
+
+
+static void motItemActivateCallback(Widget w, Ihandle* ih, XtPointer call_data)
+{
+ Icallback cb;
+
+ if (XmIsToggleButton(ih->handle) && !iupAttribGetBoolean(ih, "AUTOTOGGLE") && !iupAttribGetBoolean(ih->parent, "RADIO"))
+ {
+ /* Motif by default will do autotoggle */
+ XmToggleButtonSetState(ih->handle, !XmToggleButtonGetState(ih->handle),0);
+ }
+
+ cb = IupGetCallback(ih, "ACTION");
+ if (cb && cb(ih)==IUP_CLOSE)
+ IupExitLoop();
+
+ (void)w;
+ (void)call_data;
+}
+
+static void motItemArmCallback(Widget w, Ihandle* ih, XtPointer call_data)
+{
+ Icallback cb = IupGetCallback(ih, "HIGHLIGHT_CB");
+ if (cb)
+ cb(ih);
+
+ (void)w;
+ (void)call_data;
+}
+
+static void motMenuMapCallback(Widget w, Ihandle* ih, XtPointer call_data)
+{
+ Icallback cb = IupGetCallback(ih, "OPEN_CB");
+ if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "OPEN_CB"); /* check also in the Submenu */
+ if (cb) cb(ih);
+
+ (void)w;
+ (void)call_data;
+}
+
+static void motMenuUnmapCallback(Widget w, Ihandle* ih, XtPointer call_data)
+{
+ Icallback cb = IupGetCallback(ih, "MENUCLOSE_CB");
+ if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "MENUCLOSE_CB"); /* check also in the Submenu */
+ if (cb) cb(ih);
+
+ (void)w;
+ (void)call_data;
+}
+
+static void motPopupMenuUnmapCallback(Widget w, Ihandle* ih, XtPointer call_data)
+{
+ motMenuUnmapCallback(w, ih, call_data);
+ mot_menu_exitloop = 1;
+}
+
+
+/*******************************************************************************************/
+
+
+static void motMenuUnMapMethod(Ihandle* ih)
+{
+ if (iupMenuIsMenuBar(ih))
+ XtDestroyWidget(ih->handle);
+ else
+ XtDestroyWidget(XtParent(ih->handle)); /* in this case the RowColumn widget is a child of a MenuShell. */
+}
+
+static int motMenuMapMethod(Ihandle* ih)
+{
+ int num_args = 0;
+ Arg args[30];
+
+ if (iupMenuIsMenuBar(ih))
+ {
+ /* top level menu used for MENU attribute in IupDialog (a menu bar) */
+
+ ih->handle = XtVaCreateManagedWidget(
+ iupMenuGetChildIdStr(ih),
+ xmRowColumnWidgetClass,
+ iupChildTreeGetNativeParentHandle(ih),
+ XmNrowColumnType, XmMENU_BAR,
+ XmNmarginHeight, 0,
+ XmNmarginWidth, 0,
+ XmNresizeWidth, False,
+ NULL);
+ if (!ih->handle)
+ return IUP_ERROR;
+ }
+ else
+ {
+ /* all XmCreate* functions here, also create RowColumn Widgets. */
+
+ if (ih->parent)
+ {
+ /* parent is a submenu */
+
+ if (iupAttribGetBoolean(ih, "RADIO"))
+ {
+ iupmotSetArg(args, num_args, XmNpacking, XmPACK_COLUMN);
+ iupmotSetArg(args, num_args, XmNradioBehavior, TRUE);
+ }
+
+ ih->handle = XmCreatePulldownMenu(
+ ih->parent->handle,
+ iupMenuGetChildIdStr(ih),
+ args,
+ num_args);
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* update the CascadeButton */
+ XtVaSetValues(ih->parent->handle, XmNsubMenuId, ih->handle, NULL);
+
+ XtAddCallback(ih->handle, XmNmapCallback, (XtCallbackProc)motMenuMapCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNunmapCallback, (XtCallbackProc)motMenuUnmapCallback, (XtPointer)ih);
+ }
+ else
+ {
+ /* top level menu used for IupPopup */
+
+ iupmotSetArg(args, num_args, XmNpopupEnabled, XmPOPUP_AUTOMATIC);
+
+ ih->handle = XmCreatePopupMenu(
+ iupmot_appshell,
+ iupMenuGetChildIdStr(ih),
+ args,
+ num_args);
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ XtAddCallback(ih->handle, XmNmapCallback, (XtCallbackProc)motMenuMapCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNunmapCallback, (XtCallbackProc)motPopupMenuUnmapCallback, (XtPointer)ih);
+ }
+ }
+
+ ih->serial = iupMenuGetChildId(ih); /* must be after using the string */
+
+ return IUP_NOERROR;
+}
+
+void iupdrvMenuInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motMenuMapMethod;
+ ic->UnMap = motMenuUnMapMethod;
+
+ /* Used by iupdrvMenuGetMenuBarSize */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, NULL, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_DEFAULT); /* use inheritance to retrieve standard fonts */
+
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+}
+
+
+/*******************************************************************************************/
+
+
+static int motItemSetTitleImageAttrib(Ihandle* ih, const char* value)
+{
+ iupmotSetPixmap(ih, value, XmNlabelPixmap, 0);
+ return 1;
+}
+
+static int motItemSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ char *str;
+
+ if (!value)
+ {
+ str = " ";
+ value = str;
+ }
+ else
+ str = iupMenuProcessTitle(ih, value);
+
+ if (XmIsToggleButton(ih->handle))
+ {
+ char *p = strchr(str, '\t');
+ if (p)
+ {
+ int offset = (p-str);
+ char* new_value = iupStrDup(str);
+ char* acc_value = new_value + offset + 1;
+ new_value[offset] = 0;
+ iupmotSetMnemonicTitle(ih, new_value);
+ iupmotSetString(ih->handle, XmNacceleratorText, acc_value);
+ free(new_value);
+
+ if (str != value) free(str);
+ return 1;
+ }
+ }
+
+ iupmotSetMnemonicTitle(ih, str);
+
+ if (str != value) free(str);
+ return 1;
+}
+
+static int motItemSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (XmIsToggleButton(ih->handle))
+ {
+ if (iupAttribGetBoolean(ih->parent, "RADIO"))
+ value = "ON";
+
+ XmToggleButtonSetState(ih->handle, iupStrBoolean(value),0);
+ }
+ return 0;
+}
+
+static char* motItemGetValueAttrib(Ihandle* ih)
+{
+ if (XmIsToggleButton(ih->handle) && XmToggleButtonGetState(ih->handle))
+ return "ON";
+ else
+ return "OFF";
+}
+
+static int motItemMapMethod(Ihandle* ih)
+{
+ int pos;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ /* Menu bar can contain only CascadeButtons */
+ if (iupMenuIsMenuBar(ih->parent))
+ {
+ ih->handle = XtVaCreateManagedWidget(
+ iupMenuGetChildIdStr(ih),
+ xmCascadeButtonWidgetClass,
+ ih->parent->handle,
+ NULL);
+
+ XtAddCallback(ih->handle, XmNactivateCallback, (XtCallbackProc)motItemActivateCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNcascadingCallback, (XtCallbackProc)motItemArmCallback, (XtPointer)ih);
+ }
+ else
+ {
+ int num_args = 0;
+ Arg args[10];
+
+ 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));
+ }
+ else
+ {
+ if (iupAttribGetBoolean(ih, "HIDEMARK"))
+ iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_NONE);
+ else
+ iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK);
+ iupmotSetArg(args, num_args, XmNlabelType, iupAttribGet(ih, "TITLEIMAGE")? XmPIXMAP: XmSTRING);
+ }
+
+ ih->handle = XtCreateManagedWidget(
+ iupMenuGetChildIdStr(ih),
+ xmToggleButtonWidgetClass,
+ ih->parent->handle,
+ args,
+ num_args);
+
+ XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motItemActivateCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNarmCallback, (XtCallbackProc)motItemArmCallback, (XtPointer)ih);
+ }
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupMenuGetChildId(ih); /* must be after using the string */
+
+ XtAddCallback (ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih);
+
+ pos = IupGetChildPos(ih->parent, ih);
+ XtVaSetValues(ih->handle, XmNpositionIndex, pos, NULL); /* RowColumn Constraint */
+
+ iupUpdateStandardFontAttrib(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvItemInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motItemMapMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* IupItem only */
+ iupClassRegisterAttribute(ic, "VALUE", motItemGetValueAttrib, motItemSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, motItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TITLEIMAGE", NULL, motItemSetTitleImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupItem Gtk and Motif only */
+ iupClassRegisterAttribute(ic, "HIDEMARK", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED);
+}
+
+
+/*******************************************************************************************/
+
+
+static int motSubmenuMapMethod(Ihandle* ih)
+{
+ int pos;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ ih->handle = XtVaCreateManagedWidget(
+ iupMenuGetChildIdStr(ih),
+ xmCascadeButtonWidgetClass,
+ ih->parent->handle,
+ NULL);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupMenuGetChildId(ih); /* must be after using the string */
+
+ pos = IupGetChildPos(ih->parent, ih);
+ XtVaSetValues(ih->handle, XmNpositionIndex, pos, NULL); /* RowColumn Constraint */
+
+ XtAddCallback(ih->handle, XmNcascadingCallback, (XtCallbackProc)motItemArmCallback, (XtPointer)ih);
+
+ iupUpdateStandardFontAttrib(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvSubmenuInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motSubmenuMapMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* IupSubmenu only */
+ iupClassRegisterAttribute(ic, "TITLE", NULL, motItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+}
+
+
+/*******************************************************************************************/
+
+
+static int motSeparatorMapMethod(Ihandle* ih)
+{
+ int pos;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ ih->handle = XtVaCreateManagedWidget(
+ iupMenuGetChildIdStr(ih),
+ xmSeparatorWidgetClass,
+ ih->parent->handle,
+ NULL);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupMenuGetChildId(ih); /* must be after using the string */
+
+ pos = IupGetChildPos(ih->parent, ih);
+ XtVaSetValues(ih->handle, XmNpositionIndex, pos, NULL); /* RowColumn Constraint */
+
+ return IUP_NOERROR;
+}
+
+void iupdrvSeparatorInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motSeparatorMapMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+}
diff --git a/iup/src/mot/iupmot_messagedlg.c b/iup/src/mot/iupmot_messagedlg.c
new file mode 100755
index 0000000..6660503
--- /dev/null
+++ b/iup/src/mot/iupmot_messagedlg.c
@@ -0,0 +1,191 @@
+/** \file
+ * \brief Motif IupMessageDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <Xm/Xm.h>
+#include <Xm/MwmUtil.h>
+#include <Xm/MessageB.h>
+#include <Xm/Protocols.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drvinfo.h"
+#include "iup_dialog.h"
+#include "iup_strmessage.h"
+
+#include "iupmot_drv.h"
+
+
+static void motMessageDlgDeleteWindowCallback(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Ihandle *ih = (Ihandle*)client_data;
+ if (!ih) return;
+ (void)call_data;
+ (void)w;
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "BUTTONS"), "OK"))
+ iupAttribSetStr(ih, "BUTTONRESPONSE", "1");
+ else
+ iupAttribSetStr(ih, "BUTTONRESPONSE", "2");
+ iupAttribSetStr(ih, "_IUP_WM_DELETE", "1");
+}
+
+static void motMessageDlgCallback(Widget w, Ihandle* ih, XmAnyCallbackStruct* call_data)
+{
+ (void)w;
+ if (call_data->reason == XmCR_OK)
+ iupAttribSetStr(ih, "BUTTONRESPONSE", "1");
+ else if (call_data->reason == XmCR_CANCEL)
+ iupAttribSetStr(ih, "BUTTONRESPONSE", "2");
+}
+
+static void motMessageDlgHelpCallback(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Ihandle *ih = (Ihandle*)client_data;
+ Icallback cb = (Icallback)IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ {
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "BUTTONS"), "OK"))
+ iupAttribSetStr(ih, "BUTTONRESPONSE", "1");
+ else
+ iupAttribSetStr(ih, "BUTTONRESPONSE", "2");
+ }
+
+ (void)call_data;
+ (void)w;
+}
+
+static int motMessageDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ Widget msgbox, dialog;
+ int style = XmDIALOG_FULL_APPLICATION_MODAL;
+ int type = XmDIALOG_MESSAGE;
+ int num_but = 2;
+ char *value;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ if (parent)
+ {
+ msgbox = XmCreateMessageDialog(parent, "messagedialog", NULL, 0);
+ dialog = XtParent(msgbox);
+ }
+ else
+ {
+ dialog = XtAppCreateShell(NULL, "messagedialog", topLevelShellWidgetClass, iupmot_display, NULL, 0);
+ msgbox = XmCreateMessageBox(dialog, "messagebox", NULL, 0);
+ style = XmDIALOG_MODELESS;
+ XtVaSetValues(dialog,
+ XmNmwmInputMode, MWM_INPUT_FULL_APPLICATION_MODAL,
+ XmNmappedWhenManaged, False,
+ XmNsaveUnder, True,
+ NULL);
+ }
+ if (!msgbox)
+ return IUP_NOERROR;
+
+ value = iupAttribGetStr(ih, "DIALOGTYPE");
+ if (iupStrEqualNoCase(value, "ERROR"))
+ type = XmDIALOG_ERROR;
+ else if (iupStrEqualNoCase(value, "WARNING"))
+ type = XmDIALOG_WARNING;
+ else if (iupStrEqualNoCase(value, "INFORMATION"))
+ type = XmDIALOG_INFORMATION;
+ else if (iupStrEqualNoCase(value, "QUESTION"))
+ type = XmDIALOG_QUESTION;
+
+
+ value = iupAttribGet(ih, "TITLE");
+ if (value)
+ iupmotSetString(msgbox, XmNdialogTitle, value);
+ else
+ {
+ if (parent)
+ {
+ XmString title;
+ XtVaGetValues(parent, XmNdialogTitle, &title, NULL);
+ XtVaSetValues(msgbox, XmNdialogTitle, title, NULL);
+ }
+ }
+
+ value = iupAttribGet(ih, "VALUE");
+ if (value)
+ iupmotSetString(msgbox, XmNmessageString, value);
+
+ XtVaSetValues(msgbox,
+ XmNdialogType, type,
+ XmNdialogStyle, style,
+ XmNautoUnmanage, False,
+ XmNnoResize, True,
+ NULL);
+
+ value = iupAttribGetStr(ih, "BUTTONS");
+ if (iupStrEqualNoCase(value, "OK"))
+ {
+ XtUnmanageChild(XmMessageBoxGetChild(msgbox, XmDIALOG_CANCEL_BUTTON));
+ num_but = 1;
+ }
+ else if (iupStrEqualNoCase(value, "YESNO"))
+ {
+ iupmotSetString(msgbox, XmNokLabelString, iupStrMessageGet("IUP_YES"));
+ iupmotSetString(msgbox, XmNcancelLabelString, iupStrMessageGet("IUP_NO"));
+ }
+
+ if (!IupGetCallback(ih, "HELP_CB"))
+ XtUnmanageChild(XmMessageBoxGetChild(msgbox, XmDIALOG_HELP_BUTTON));
+
+ if (num_but == 2 && iupAttribGetInt(ih, "BUTTONDEFAULT") == 2)
+ XtVaSetValues(msgbox, XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON, NULL);
+ else
+ XtVaSetValues(msgbox, XmNdefaultButtonType, XmDIALOG_OK_BUTTON, NULL);
+
+ XtAddCallback(msgbox, XmNokCallback, (XtCallbackProc)motMessageDlgCallback, (XtPointer)ih);
+ XtAddCallback(msgbox, XmNcancelCallback, (XtCallbackProc)motMessageDlgCallback, (XtPointer)ih);
+ XtAddCallback(msgbox, XmNhelpCallback, (XtCallbackProc)motMessageDlgHelpCallback, (XtPointer)ih);
+
+ XmAddWMProtocolCallback(dialog, iupmot_wm_deletewindow, motMessageDlgDeleteWindowCallback, (XtPointer)ih);
+ XtManageChild(msgbox);
+
+ XtRealizeWidget(dialog);
+ ih->handle = dialog;
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+
+ if (style == XmDIALOG_MODELESS)
+ XtPopup(dialog, XtGrabExclusive);
+
+ /* while the user hasn't provided an answer, simulate main loop.
+ ** The answer changes as soon as the user selects one of the
+ ** buttons and the callback routine changes its value. */
+ iupAttribSetStr(ih, "BUTTONRESPONSE", NULL);
+ while (iupAttribGet(ih, "BUTTONRESPONSE") == NULL)
+ XtAppProcessEvent(iupmot_appcontext, XtIMAll);
+
+ if (!iupAttribGet(ih, "_IUP_WM_DELETE"))
+ {
+ XtUnmanageChild(msgbox);
+
+ if (style == XmDIALOG_MODELESS)
+ {
+ XtPopdown(dialog);
+ XtDestroyWidget(dialog);
+ }
+ }
+
+ return IUP_NOERROR;
+}
+
+void iupdrvMessageDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = motMessageDlgPopup;
+}
diff --git a/iup/src/mot/iupmot_open.c b/iup/src/mot/iupmot_open.c
new file mode 100755
index 0000000..a59dbff
--- /dev/null
+++ b/iup/src/mot/iupmot_open.c
@@ -0,0 +1,141 @@
+/** \file
+ * \brief Motif Open/Close
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <locale.h>
+#include <string.h>
+
+#include <Xm/Xm.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_globalattrib.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+/* global variables */
+Widget iupmot_appshell = 0;
+Display* iupmot_display = 0;
+int iupmot_screen = 0;
+Visual* iupmot_visual = 0;
+XtAppContext iupmot_appcontext = 0;
+
+void* iupdrvGetDisplay(void)
+{
+ return iupmot_display;
+}
+
+void iupmotSetGlobalColorAttrib(Widget w, const char* xmname, const char* name)
+{
+ unsigned char r, g, b;
+ Pixel color;
+
+ XtVaGetValues(w, xmname, &color, NULL);
+ iupmotColorGetRGB(color, &r, &g, &b);
+
+ iupGlobalSetDefaultColorAttrib(name, r, g, b);
+}
+
+int iupdrvOpen(int *argc, char ***argv)
+{
+ IupSetGlobal("DRIVER", "Motif");
+
+ /* XtSetLanguageProc(NULL, NULL, NULL);
+ Removed to avoid invalid locale in modern Linux that set LANG=en_US.UTF-8 */
+
+ /* We do NOT use XtVaOpenApplication because it crashes when using internal dummy argc and argv.
+ iupmot_appshell = XtVaOpenApplication(&iupmot_appcontext, "Iup", NULL, 0, argc, *argv, NULL,
+ sessionShellWidgetClass, NULL); */
+
+ XtToolkitInitialize();
+
+ iupmot_appcontext = XtCreateApplicationContext();
+
+ iupmot_display = XtOpenDisplay(iupmot_appcontext, NULL, NULL, "Iup", NULL, 0, argc, *argv);
+ if (!iupmot_display)
+ {
+ fprintf (stderr, "IUP error: cannot open display.\n");
+ return IUP_ERROR;
+ }
+
+ iupmot_appshell = XtAppCreateShell(NULL, "Iup", sessionShellWidgetClass, iupmot_display, NULL, 0);
+ if (!iupmot_appshell)
+ {
+ fprintf(stderr, "IUP error: cannot create shell.\n");
+ return IUP_ERROR;
+ }
+ IupSetGlobal("APPSHELL", (char*)iupmot_appshell);
+
+ IupStoreGlobal("SYSTEMLANGUAGE", setlocale(LC_ALL, NULL));
+
+ iupmot_screen = XDefaultScreen(iupmot_display);
+
+ IupSetGlobal("XDISPLAY", (char*)iupmot_display);
+ IupSetGlobal("XSCREEN", (char*)iupmot_screen);
+
+ /* screen depth can be 8bpp, but canvas can be 24bpp */
+ {
+ XVisualInfo vinfo;
+ if (XMatchVisualInfo(iupmot_display, iupmot_screen, 24, TrueColor, &vinfo) ||
+ XMatchVisualInfo(iupmot_display, iupmot_screen, 16, TrueColor, &vinfo))
+ {
+ iupmot_visual = vinfo.visual;
+ IupSetGlobal("TRUECOLORCANVAS", "YES");
+ }
+ else
+ {
+ iupmot_visual = DefaultVisual(iupmot_display, iupmot_screen);
+ IupSetGlobal("TRUECOLORCANVAS", "NO");
+ }
+ }
+
+ /* driver system version */
+ {
+ int major = xmUseVersion/1000;
+ int minor = xmUseVersion - major * 1000;
+ IupSetfAttribute(NULL, "MOTIFVERSION", "%d.%d", major, minor);
+ IupSetfAttribute(NULL, "MOTIFNUMBER", "%d", (XmVERSION * 1000 + XmREVISION * 100 + XmUPDATE_LEVEL));
+
+ IupSetGlobal("XSERVERVENDOR", ServerVendor(iupmot_display));
+ IupSetfAttribute(NULL, "XVENDORRELEASE", "%d", VendorRelease(iupmot_display));
+ }
+
+ iupmotColorInit();
+
+ /* dialog background color */
+ {
+ iupmotSetGlobalColorAttrib(iupmot_appshell, XmNbackground, "DLGBGCOLOR");
+ iupGlobalSetDefaultColorAttrib("DLGFGCOLOR", 0, 0, 0);
+ IupSetGlobal("_IUP_RESET_DLGBGCOLOR", "YES"); /* will update the DLGFGCOLOR when the first dialog is mapped */
+
+ iupGlobalSetDefaultColorAttrib("TXTBGCOLOR", 255, 255, 255);
+ iupGlobalSetDefaultColorAttrib("TXTFGCOLOR", 0, 0, 0);
+ IupSetGlobal("_IUP_RESET_TXTCOLORS", "YES"); /* will update the TXTCOLORS when the first text or list is mapped */
+ }
+
+ if (getenv("IUP_DEBUG"))
+ XSynchronize(iupmot_display, 1);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvClose(void)
+{
+ iupmotColorFinish();
+ iupmotTipsFinish();
+
+ if (iupmot_appshell)
+ XtDestroyWidget(iupmot_appshell);
+
+ if (iupmot_appcontext)
+ XtDestroyApplicationContext(iupmot_appcontext);
+}
diff --git a/iup/src/mot/iupmot_progressbar.c b/iup/src/mot/iupmot_progressbar.c
new file mode 100755
index 0000000..7266d38
--- /dev/null
+++ b/iup/src/mot/iupmot_progressbar.c
@@ -0,0 +1,165 @@
+/** \file
+* \brief Progress bar Control
+*
+* See Copyright Notice in "iup.h"
+*/
+
+#include <Xm/Xm.h>
+#include <Xm/Scale.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_progressbar.h"
+#include "iup_drv.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+static int motProgressBarSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ ih->data->value = 0;
+ else
+ ih->data->value = atof(value);
+ iProgressBarCropValue(ih);
+
+ XtVaSetValues(ih->handle, XmNvalue, (int)(SHRT_MAX * (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin)), NULL);
+
+ return 0;
+}
+
+static int motProgressBarSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ if (!iupAttribGetStr(ih, "FGCOLOR"))
+ {
+ Pixel color;
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ r = (r*8)/10;
+ g = (g*8)/10;
+ b = (b*8)/10;
+
+ color = iupmotColorGetPixel(r, g, b);
+ if (color != (Pixel)-1)
+ {
+ Widget w = XtNameToWidget(ih->handle, "*Scrollbar");
+ XtVaSetValues(w, XmNtroughColor, color, NULL);
+ }
+ }
+
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+}
+
+
+static int motProgressBarSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ {
+ Widget w = XtNameToWidget(ih->handle, "*Scrollbar");
+ XtVaSetValues(w, XmNtroughColor, color, NULL);
+ }
+
+ return 1;
+}
+
+static void motProgressBarLayoutUpdateMethod(Ihandle *ih)
+{
+ unsigned char orientation;
+ XtVaGetValues(ih->handle, XmNorientation, &orientation, NULL);
+
+ if (orientation == XmVERTICAL)
+ XtVaSetValues(ih->handle, XmNscaleWidth, ih->currentwidth, NULL);
+ else
+ XtVaSetValues(ih->handle, XmNscaleHeight, ih->currentheight, NULL);
+
+ iupdrvBaseLayoutUpdateMethod(ih);
+}
+
+static int motProgressBarMapMethod(Ihandle* ih)
+{
+ int num_args = 0;
+ 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 */
+ /* Primitive */
+ iupmotSetArg(args, num_args, XmNtraversalOn, False);
+ iupmotSetArg(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);
+
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL"))
+ {
+ iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL);
+
+ if (ih->currentheight < ih->currentwidth)
+ {
+ int tmp = ih->currentheight;
+ ih->currentheight = ih->currentwidth;
+ ih->currentwidth = tmp;
+ }
+ }
+ else
+ iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL);
+
+ ih->handle = XtCreateManagedWidget(
+ iupDialogGetChildIdStr(ih), /* child identifier */
+ xmScaleWidgetClass, /* widget class */
+ iupChildTreeGetNativeParentHandle(ih), /* widget parent */
+ args, num_args);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupDialogGetChildId(ih); /* must be after using the string */
+
+ /* initialize the widget */
+ XtRealizeWidget(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvProgressBarInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motProgressBarMapMethod;
+ ic->LayoutUpdate = motProgressBarLayoutUpdateMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motProgressBarSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motProgressBarSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+
+ /* IupProgressBar only */
+ iupClassRegisterAttribute(ic, "VALUE", iProgressBarGetValueAttrib, motProgressBarSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, "HORIZONTAL", NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/mot/iupmot_tabs.c b/iup/src/mot/iupmot_tabs.c
new file mode 100755
index 0000000..7c8a6b5
--- /dev/null
+++ b/iup/src/mot/iupmot_tabs.c
@@ -0,0 +1,593 @@
+/** \file
+* \brief Tabs Control
+*
+* See Copyright Notice in "iup.h"
+*/
+
+#include <Xm/Xm.h>
+#include <Xm/Notebook.h>
+#include <Xm/BulletinB.h>
+#include <Xm/PushB.h>
+#include <Xm/Label.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_tabs.h"
+#include "iup_image.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+int iupdrvTabsExtraDecor(Ihandle* ih)
+{
+ (void)ih;
+ return 1;
+}
+
+int iupdrvTabsGetLineCountAttrib(Ihandle* ih)
+{
+ (void)ih;
+ return 1;
+}
+
+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");
+
+ XtVaSetValues(ih->handle, XmNcurrentPageNumber, pos, NULL);
+}
+
+int iupdrvTabsGetCurrentTab(Ihandle* ih)
+{
+ int pos;
+ XtVaGetValues(ih->handle, XmNcurrentPageNumber, &pos, NULL);
+ return pos;
+}
+
+static void motTabsUpdatePageNumber(Ihandle* ih)
+{
+ int pos, old_pos;
+ Ihandle* child;
+ for (pos = 0, child = ih->firstchild; child; child = child->brother, pos++)
+ {
+ Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ if (child_manager)
+ {
+ old_pos = iupAttribGetInt(child, "_IUPMOT_TABNUMBER"); /* did not work when using XtVaGetValues(child_manager, XmNpageNumber) */
+ if (pos != old_pos)
+ {
+ Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON");
+ XtVaSetValues(child_manager, XmNpageNumber, pos, NULL);
+ XtVaSetValues(tab_button, XmNpageNumber, pos, NULL);
+ iupAttribSetInt(child, "_IUPMOT_TABNUMBER", pos);
+ }
+ }
+ }
+}
+
+static void motTabsUpdatePageBgPixmap(Ihandle* ih, Pixmap pixmap)
+{
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ if (child_manager)
+ XtVaSetValues(child_manager, XmNbackgroundPixmap, pixmap, NULL);
+ }
+}
+
+static void motTabsUpdatePageBgColor(Ihandle* ih, Pixel color)
+{
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ if (child_manager)
+ iupmotSetBgColor(child_manager, color);
+ }
+}
+
+static void motTabsUpdateButtonsFgColor(Ihandle* ih, Pixel color)
+{
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON");
+ if (tab_button)
+ XtVaSetValues(tab_button, XmNforeground, color, NULL);
+ }
+}
+
+static void motTabsUpdateButtonsBgColor(Ihandle* ih, Pixel color)
+{
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON");
+ if (tab_button)
+ iupmotSetBgColor(tab_button, color);
+ }
+}
+
+static void motTabsUpdateButtonsPadding(Ihandle* ih)
+{
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON");
+ if (tab_button)
+ XtVaSetValues(tab_button, XmNmarginHeight, ih->data->vert_padding,
+ XmNmarginWidth, ih->data->horiz_padding, NULL);
+ }
+}
+
+static void motTabsUpdatePageFont(Ihandle* ih)
+{
+ Ihandle* child;
+ XmFontList fontlist = (XmFontList)iupmotGetFontListAttrib(ih);
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON");
+ if (tab_button)
+ XtVaSetValues(tab_button, XmNrenderTable, fontlist, NULL);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* motTabs - Sets and Gets accessors */
+/* ------------------------------------------------------------------------- */
+
+static int motTabsSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+
+ if (ih->handle)
+ motTabsUpdateButtonsPadding(ih);
+ return 0;
+}
+
+static void motTabsUpdateTabType(Ihandle* ih)
+{
+ if (ih->data->type == ITABS_LEFT)
+ XtVaSetValues(ih->handle, XmNbackPagePlacement, XmBOTTOM_LEFT,
+ XmNorientation, XmHORIZONTAL,
+ NULL);
+ else if(ih->data->type == ITABS_RIGHT)
+ XtVaSetValues(ih->handle, XmNbackPagePlacement, XmBOTTOM_RIGHT,
+ XmNorientation, XmHORIZONTAL,
+ NULL);
+ else if(ih->data->type == ITABS_BOTTOM)
+ XtVaSetValues(ih->handle, XmNbackPagePlacement, XmBOTTOM_RIGHT,
+ XmNorientation, XmVERTICAL,
+ NULL);
+ else /* "TOP" */
+ XtVaSetValues(ih->handle, XmNbackPagePlacement, XmTOP_RIGHT,
+ XmNorientation, XmVERTICAL,
+ NULL);
+}
+
+static int motTabsSetTabTypeAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrEqualNoCase(value, "LEFT"))
+ ih->data->type = ITABS_LEFT;
+ else if(iupStrEqualNoCase(value, "RIGHT"))
+ ih->data->type = ITABS_RIGHT;
+ else if(iupStrEqualNoCase(value, "BOTTOM"))
+ ih->data->type = ITABS_BOTTOM;
+ else /* "TOP" */
+ ih->data->type = ITABS_TOP;
+
+ if (ih->handle)
+ motTabsUpdateTabType(ih);
+
+ return 0;
+}
+
+static int motTabsSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color;
+
+ /* given value is used only for child, to the Tabs must use only from parent */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ color = iupmotColorGetPixelStr(parent_value);
+ if (color != (Pixel)-1)
+ {
+ iupmotSetBgColor(ih->handle, color);
+ motTabsUpdatePageBgColor(ih, color);
+ }
+
+ color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ motTabsUpdateButtonsBgColor(ih, color);
+
+ return 1;
+}
+
+static int motTabsSetBackgroundAttrib(Ihandle* ih, const char* value)
+{
+ /* given value is used only for child, to the Tabs must use only from parent */
+ char* parent_value = iupAttribGetInheritNativeParent(ih, "BACKGROUND");
+
+ Pixel color = iupmotColorGetPixelStr(parent_value);
+ if (color != (Pixel)-1)
+ {
+ iupmotSetBgColor(ih->handle, color);
+ motTabsUpdatePageBgColor(ih, color);
+ }
+ else
+ {
+ Pixmap pixmap = (Pixmap)iupImageGetImage(parent_value, ih, 0);
+ if (pixmap)
+ {
+ XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL);
+ motTabsUpdatePageBgPixmap(ih, pixmap);
+ }
+ }
+
+ (void)value;
+ return 1;
+}
+
+static int motTabsSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ {
+ XtVaSetValues(ih->handle, XmNforeground, color, NULL);
+ motTabsUpdateButtonsFgColor(ih, color);
+ return 1;
+ }
+ return 0;
+}
+
+static int motTabsSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+ if (ih->handle)
+ motTabsUpdatePageFont(ih);
+ return 1;
+}
+
+static int motTabsSetTabTitleAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int pos;
+ if (value && iupStrToInt(name_id, &pos)==1)
+ {
+ Ihandle* child = IupGetChild(ih, pos);
+ Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON");
+ if (tab_button)
+ iupmotSetString(tab_button, XmNlabelString, value);
+ }
+ return 1;
+}
+
+static int motTabsSetTabImageAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int pos;
+ if (value && iupStrToInt(name_id, &pos)==1)
+ {
+ Ihandle* child = IupGetChild(ih, pos);
+ Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON");
+ if (tab_button)
+ {
+ Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0);
+ if (pixmap)
+ XtVaSetValues(tab_button, XmNlabelPixmap, pixmap, NULL);
+ }
+ }
+ return 1;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* motTabs - Callback */
+/* ------------------------------------------------------------------------- */
+
+void motTabsPageChangedCallback(Widget w, Ihandle* ih, XmNotebookCallbackStruct *nptr)
+{
+ if (nptr->reason == XmCR_MAJOR_TAB)
+ {
+ 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");
+
+ cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB");
+ if (cb)
+ cb(ih, child, prev_child);
+ }
+ (void)w;
+}
+
+static void motTabsConfigureNotify(Widget w, XEvent *evt, String* s, Cardinal *card)
+{
+ /* Motif does not process the changed of position and/or size of children outside the parent's client area.
+ Since Notebook pages are not resized until they are moved into the visible area,
+ we must update the children position and size when a tab page is resize.
+ Since tab pages are not hidden, they are moved outside the visible area,
+ a resize occours every time a tab is activated.
+ */
+ Ihandle *child;
+ (void)s;
+ (void)card;
+ (void)evt;
+
+ XtVaGetValues(w, XmNuserData, &child, NULL);
+ if (!child) return;
+
+ iupLayoutUpdate(child);
+}
+
+/* ------------------------------------------------------------------------- */
+/* motTabs - Methods and Init Class */
+/* ------------------------------------------------------------------------- */
+
+static void motTabsChildAddedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (IupGetName(child) == NULL)
+ iupAttribSetHandleName(child);
+
+ if (ih->handle)
+ {
+ Widget child_manager;
+ Widget tab_button;
+ int num_args = 0, pos;
+ Arg args[30];
+ char *tabtitle, *tabimage, *background;
+ Pixel color;
+
+ /* open space for new tab number */
+ motTabsUpdatePageNumber(ih);
+
+ pos = IupGetChildPos(ih, child);
+
+ /* Create pages */
+ child_manager = XtVaCreateManagedWidget(
+ "child_manager",
+ xmBulletinBoardWidgetClass,
+ ih->handle,
+ /* Core */
+ XmNborderWidth, 0,
+ /* Manager */
+ XmNshadowThickness, 0,
+ XmNnavigationType, XmTAB_GROUP,
+ XmNuserData, child, /* used only in motTabsConfigureNotify */
+ /* BulletinBoard */
+ XmNmarginWidth, 0,
+ XmNmarginHeight, 0,
+ XmNresizePolicy, XmRESIZE_NONE, /* no automatic resize of children */
+ /* Notebook Constraint */
+ XmNnotebookChildType, XmPAGE,
+ XmNpageNumber, pos,
+ XmNresizable, True,
+ NULL);
+
+ XtOverrideTranslations(child_manager, XtParseTranslationTable("<Configure>: iupTabsConfigure()"));
+
+ tabtitle = iupAttribGet(child, "TABTITLE");
+ if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos);
+ tabimage = iupAttribGet(child, "TABIMAGE");
+ if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos);
+ if (!tabtitle && !tabimage)
+ tabtitle = " ";
+
+ /* Create tabs */
+ /* Label */
+ iupmotSetArg(args, num_args, XmNlabelType, tabtitle? XmSTRING: XmPIXMAP);
+ iupmotSetArg(args, num_args, XmNmarginHeight, 0);
+ iupmotSetArg(args, num_args, XmNmarginWidth, 0);
+ /* Notebook Constraint */
+ iupmotSetArg(args, num_args, XmNnotebookChildType, XmMAJOR_TAB);
+ iupmotSetArg(args, num_args, XmNpageNumber, pos);
+ tab_button = XtCreateManagedWidget("tab_button", xmPushButtonWidgetClass, ih->handle, args, num_args);
+
+ /* Disable Drag Source */
+ iupmotDisableDragSource(tab_button);
+
+ XtAddEventHandler(tab_button, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(tab_button, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(tab_button, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih);
+ XtAddEventHandler(tab_button, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih);
+
+ if (tabtitle)
+ iupmotSetString(tab_button, XmNlabelString, tabtitle);
+ else
+ {
+ Pixmap pixmap = (Pixmap)iupImageGetImage(tabimage, ih, 0);
+ if (pixmap)
+ XtVaSetValues(tab_button, XmNlabelPixmap, pixmap, NULL);
+ }
+
+ background = iupBaseNativeParentGetBgColorAttrib(ih);
+ color = iupmotColorGetPixelStr(background);
+ if (color != -1)
+ iupmotSetBgColor(child_manager, color);
+ else
+ {
+ Pixmap pixmap = (Pixmap)iupImageGetImage(background, ih, 0);
+ if (pixmap)
+ {
+ XtVaSetValues(child_manager, XmNbackgroundPixmap, pixmap, NULL);
+ }
+ }
+
+ background = iupAttribGetStr(ih, "BGCOLOR");
+ color = iupmotColorGetPixelStr(background);
+ if (color != -1)
+ iupmotSetBgColor(tab_button, color);
+
+ color = iupmotColorGetPixelStr(IupGetAttribute(ih, "FGCOLOR"));
+ XtVaSetValues(tab_button, XmNforeground, color, NULL);
+
+ XtRealizeWidget(child_manager);
+ XtRealizeWidget(tab_button);
+
+ iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)child_manager);
+ 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");
+ }
+}
+
+static void motTabsChildRemovedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (ih->handle)
+ {
+ Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ if (child_manager)
+ {
+ int cur_pos, 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);
+ }
+
+ XtDestroyWidget(tab_button);
+ XtDestroyWidget(child_manager);
+
+ /* compact the tab number usage */
+ motTabsUpdatePageNumber(ih);
+
+ iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL);
+ iupAttribSetStr(child, "_IUPMOT_TABBUTTON", NULL);
+ iupAttribSetStr(child, "_IUPMOT_TABNUMBER", NULL);
+ }
+ }
+}
+
+static int motTabsMapMethod(Ihandle* ih)
+{
+ int num_args = 0;
+ Arg args[30];
+
+ if (!ih->parent)
+ 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 */
+ /* Manager */
+ iupmotSetArg(args, num_args, XmNshadowThickness, 0);
+ iupmotSetArg(args, num_args, XmNtraversalOn, True);
+ iupmotSetArg(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);
+
+ ih->handle = XtCreateManagedWidget(
+ iupDialogGetChildIdStr(ih), /* child identifier */
+ xmNotebookWidgetClass, /* widget class */
+ iupChildTreeGetNativeParentHandle(ih), /* widget parent */
+ args, num_args);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupDialogGetChildId(ih); /* must be after using the string */
+
+ /* Disable page scroller */
+ {
+ Widget scroller;
+ scroller = XtNameToWidget(ih->handle, "*PageScroller");
+ XtUnmanageChild(scroller);
+ }
+
+ /* Callbacks */
+ XtAddCallback(ih->handle, XmNpageChangedCallback, (XtCallbackProc)motTabsPageChangedCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih);
+
+ /* update Tab position */
+ motTabsUpdateTabType(ih);
+
+ /* current value is now given by the native system */
+ iupAttribSetStr(ih, "_IUPTABS_VALUE_HANDLE", NULL);
+
+ /* initialize the widget */
+ XtRealizeWidget(ih->handle);
+
+ /* Create pages and tabs */
+ if (ih->firstchild)
+ {
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ motTabsChildAddedMethod(ih, child);
+ }
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTabsInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motTabsMapMethod;
+ ic->ChildAdded = motTabsChildAddedMethod;
+ ic->ChildRemoved = motTabsChildRemovedMethod;
+
+ {
+ /* Set up a translation table that captures "Resize" events
+ (also called ConfigureNotify or Configure events). */
+ XtActionsRec rec = {"iupTabsConfigure", motTabsConfigureNotify};
+ XtAppAddActions(iupmot_appcontext, &rec, 1);
+ }
+
+ /* Driver Dependent Attribute functions */
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, motTabsSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motTabsSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motTabsSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motTabsSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* IupTabs only */
+ iupClassRegisterAttribute(ic, "TABTYPE", iupTabsGetTabTypeAttrib, motTabsSetTabTypeAttrib, IUPAF_SAMEASSYSTEM, "TOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ 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);
+}
diff --git a/iup/src/mot/iupmot_text.c b/iup/src/mot/iupmot_text.c
new file mode 100755
index 0000000..4a8f936
--- /dev/null
+++ b/iup/src/mot/iupmot_text.c
@@ -0,0 +1,1165 @@
+/** \file
+ * \brief Text Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <Xm/TextF.h>
+#include <Xm/Text.h>
+#include <Xm/ScrolledW.h>
+#include <Xm/SpinB.h>
+#include <X11/keysym.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_mask.h"
+#include "iup_drv.h"
+#include "iup_array.h"
+#include "iup_text.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+#ifndef XmIsSpinBox
+#define XmIsSpinBox(w) XtIsSubclass(w, xmSpinBoxWidgetClass)
+#endif
+
+#ifndef XmNwrap
+#define XmNwrap "Nwrap"
+#endif
+
+void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag)
+{
+ (void)ih;
+ (void)formattag;
+}
+
+void iupdrvTextAddSpin(int *w, int h)
+{
+ *w += h/2;
+}
+
+void iupdrvTextAddBorders(int *w, int *h)
+{
+ int border_size = 2*5;
+ (*w) += border_size;
+ (*h) += border_size;
+}
+
+static void motTextGetLinColFromPosition(const char *str, int pos, int *lin, int *col )
+{
+ int i;
+
+ *lin = 0;
+ *col = 0;
+
+ for (i=0; i<pos; i++)
+ {
+ if (*str == '\n')
+ {
+ (*lin)++;
+ *col = 0;
+ }
+ else
+ (*col)++;
+
+ str++;
+ }
+
+ (*lin)++; /* IUP starts at 1 */
+ (*col)++;
+}
+
+static int motTextSetLinColToPosition(const char *str, int lin, int col)
+{
+ int pos=0, cur_lin=0, cur_col=0;
+
+ lin--; /* IUP starts at 1 */
+ col--;
+
+ while (*str)
+ {
+ if (lin<=cur_lin && col<=cur_col)
+ break;
+
+ if (*str == '\n')
+ {
+ cur_lin++;
+ cur_col = 0;
+ }
+ else
+ cur_col++;
+
+ str++;
+ pos++;
+ }
+
+ return pos;
+}
+
+void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos)
+{
+ char* str = XmTextGetString(ih->handle);
+ *pos = motTextSetLinColToPosition(str, lin, col);
+ XtFree(str);
+}
+
+void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col)
+{
+ char *str = XmTextGetString(ih->handle);
+ motTextGetLinColFromPosition(str, pos, lin, col);
+ XtFree(str);
+}
+
+static int motTextConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ return XmTextXYToPos(ih->handle, x, y);
+}
+
+
+/*******************************************************************************************/
+
+
+static int motTextSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle)
+ {
+ XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding,
+ XmNmarginWidth, ih->data->horiz_padding, NULL);
+ }
+ return 0;
+}
+
+static int motTextSetReadOnlyAttrib(Ihandle* ih, const char* value)
+{
+ XtVaSetValues(ih->handle, XmNeditable, iupStrBoolean(value)? False: True, NULL);
+ return 0;
+}
+
+static char* motTextGetReadOnlyAttrib(Ihandle* ih)
+{
+ Boolean editable;
+ XtVaGetValues(ih->handle, XmNeditable, &editable, NULL);
+ if (editable)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int motTextSetInsertAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (!value)
+ return 0;
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+ XmTextRemove(ih->handle);
+ XmTextInsert(ih->handle, XmTextGetInsertionPosition(ih->handle), (char*)value);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+
+ return 0;
+}
+
+static int motTextSetSelectedTextAttrib(Ihandle* ih, const char* value)
+{
+ XmTextPosition start, end;
+
+ if (!value)
+ return 0;
+
+ if (XmTextGetSelectionPosition(ih->handle, &start, &end) && start!=end)
+ {
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+ XmTextReplace(ih->handle, start, end, (char*)value);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+
+ return 0;
+}
+
+static char* motTextGetSelectedTextAttrib(Ihandle* ih)
+{
+ char* selectedtext = XmTextGetSelection(ih->handle);
+ char* str = iupStrGetMemoryCopy(selectedtext);
+ XtFree(selectedtext);
+ return str;
+}
+
+static int motTextSetAppendAttrib(Ihandle* ih, const char* value)
+{
+ XmTextPosition pos;
+ if (!ih->handle) /* do not store 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)
+ XmTextInsert(ih->handle, pos, "\n");
+ if (value)
+ XmTextInsert(ih->handle, pos+1, (char*)value);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ return 0;
+}
+
+static int motTextSetSelectionAttrib(Ihandle* ih, const char* value)
+{
+ int start=1, end=1;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ XmTextClearSelection(ih->handle, CurrentTime);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ XmTextSetSelection(ih->handle, (XmTextPosition)0, (XmTextPosition)XmTextGetLastPosition(ih->handle), CurrentTime);
+ return 0;
+ }
+
+ if (ih->data->is_multiline)
+ {
+ int lin_start=1, col_start=1, lin_end=1, col_end=1;
+ char *str;
+
+ if (sscanf(value, "%d,%d:%d,%d", &lin_start, &col_start, &lin_end, &col_end)!=4) return 0;
+ if (lin_start<1 || col_start<1 || lin_end<1 || col_end<1) return 0;
+
+ str = XmTextGetString(ih->handle);
+ start = motTextSetLinColToPosition(str, lin_start, col_start);
+ end = motTextSetLinColToPosition(str, lin_end, col_end);
+ XtFree(str);
+ }
+ else
+ {
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<1 || end<1)
+ return 0;
+
+ start--; /* IUP starts at 1 */
+ end--;
+ }
+
+ /* end is inside the selection, in IUP is outside */
+ end--;
+
+ XmTextSetSelection(ih->handle, (XmTextPosition)start, (XmTextPosition)end, CurrentTime);
+
+ return 0;
+}
+
+static char* motTextGetSelectionAttrib(Ihandle* ih)
+{
+ XmTextPosition start = 0, end = 0;
+ char* str;
+
+ if (!XmTextGetSelectionPosition(ih->handle, &start, &end) || start==end)
+ return NULL;
+
+ str = iupStrGetMemory(100);
+
+ /* end is inside the selection, in IUP is outside */
+ end++;
+
+ if (ih->data->is_multiline)
+ {
+ int start_col, start_lin, end_col, end_lin;
+
+ char *value = XmTextGetString(ih->handle);
+ motTextGetLinColFromPosition(value, start, &start_lin, &start_col);
+ motTextGetLinColFromPosition(value, end, &end_lin, &end_col);
+ XtFree(value);
+
+ sprintf(str,"%d,%d:%d,%d", start_lin, start_col, end_lin, end_col);
+ }
+ else
+ {
+ start++; /* IUP starts at 1 */
+ end++;
+ sprintf(str, "%d:%d", (int)start, (int)end);
+ }
+
+ return str;
+}
+
+static int motTextSetSelectionPosAttrib(Ihandle* ih, const char* value)
+{
+ int start=0, end=0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ XmTextClearSelection(ih->handle, CurrentTime);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ XmTextSetSelection(ih->handle, (XmTextPosition)0, (XmTextPosition)XmTextGetLastPosition(ih->handle), CurrentTime);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<0 || end<0)
+ return 0;
+
+ /* end is inside the selection, in IUP is outside */
+ end--;
+
+ XmTextSetSelection(ih->handle, (XmTextPosition)start, (XmTextPosition)end, CurrentTime);
+
+ return 0;
+}
+
+static char* motTextGetSelectionPosAttrib(Ihandle* ih)
+{
+ XmTextPosition start = 0, end = 0;
+ char* str;
+
+ if (!XmTextGetSelectionPosition(ih->handle, &start, &end) || start==end)
+ return NULL;
+
+ str = iupStrGetMemory(100);
+
+ /* end is inside the selection, in IUP is outside */
+ end++;
+
+ sprintf(str, "%d:%d", (int)start, (int)end);
+
+ return str;
+}
+
+static int motTextSetCaretAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ int lin = 1, col = 1;
+ char *str;
+
+ iupStrToIntInt(value, &lin, &col, ',');
+
+ str = XmTextGetString(ih->handle);
+ pos = motTextSetLinColToPosition(str, lin, col);
+ XtFree(str);
+ }
+ else
+ {
+ sscanf(value,"%i",&pos);
+ pos--; /* IUP starts at 1 */
+ }
+
+ XmTextSetInsertionPosition(ih->handle, (XmTextPosition)pos);
+ XmTextShowPosition(ih->handle, (XmTextPosition)pos);
+
+ return 0;
+}
+
+static char* motTextGetCaretAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(50);
+
+ XmTextPosition pos = XmTextGetInsertionPosition(ih->handle);
+
+ if (ih->data->is_multiline)
+ {
+ int col, lin;
+
+ char *value = XmTextGetString(ih->handle);
+ motTextGetLinColFromPosition(value, pos, &lin, &col);
+ XtFree(value);
+
+ sprintf(str, "%d,%d", lin, col);
+ }
+ else
+ {
+ pos++; /* IUP starts at 1 */
+ sprintf(str, "%d", (int)pos);
+ }
+
+ return str;
+}
+
+static int motTextSetCaretPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ XmTextSetInsertionPosition(ih->handle, (XmTextPosition)pos);
+ XmTextShowPosition(ih->handle, (XmTextPosition)pos);
+
+ return 0;
+}
+
+static char* motTextGetCaretPosAttrib(Ihandle* ih)
+{
+ XmTextPosition pos = XmTextGetInsertionPosition(ih->handle);
+ char* str = iupStrGetMemory(50);
+ sprintf(str, "%d", (int)pos);
+ return str;
+}
+
+static int motTextSetScrollToAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ int lin = 1, col = 1, pos;
+ char* str;
+
+ iupStrToIntInt(value, &lin, &col, ',');
+ if (lin < 1) lin = 1;
+ if (col < 1) col = 1;
+
+ str = XmTextGetString(ih->handle);
+ pos = motTextSetLinColToPosition(str, lin, col);
+ XtFree(str);
+ }
+ else
+ {
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+ pos--; /* return to Motif referece */
+ }
+
+ XmTextShowPosition(ih->handle, (XmTextPosition)pos);
+
+ return 0;
+}
+
+static int motTextSetScrollToPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ XmTextShowPosition(ih->handle, (XmTextPosition)pos);
+
+ return 0;
+}
+
+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;
+}
+
+static int motTextSetClipboardAttrib(Ihandle *ih, const char *value)
+{
+ if (iupStrEqualNoCase(value, "COPY"))
+ {
+ char *str = XmTextGetSelection(ih->handle);
+ if (!str) return 0;
+
+ XmTextCopy(ih->handle, CurrentTime);
+
+ /* do it also for the X clipboard */
+ XStoreBytes(iupmot_display, str, strlen(str)+1);
+ XtFree(str);
+ }
+ else if (iupStrEqualNoCase(value, "CUT"))
+ {
+ char *str = XmTextGetSelection(ih->handle);
+ if (!str) return 0;
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+
+ XmTextCut(ih->handle, CurrentTime);
+
+ /* do it also for the X clipboard */
+ XStoreBytes(iupmot_display, str, strlen(str)+1);
+ XtFree(str);
+ XmTextRemove(ih->handle);
+
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+ else if (iupStrEqualNoCase(value, "PASTE"))
+ {
+ int size;
+ char* str = XFetchBytes(iupmot_display, &size);
+ if (!str) return 0;
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+
+ XmTextPaste(ih->handle); /* TODO: this could force 2 pastes, check in CDE */
+
+ /* do it also for the X clipboard */
+ XmTextRemove(ih->handle);
+ XmTextInsert(ih->handle, XmTextGetInsertionPosition(ih->handle), str);
+ XFree(str);
+
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+ else if (iupStrEqualNoCase(value, "CLEAR"))
+ {
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+ XmTextRemove(ih->handle);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+ return 0;
+}
+
+static int motTextSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (sb_win)
+ {
+ Pixel color;
+
+ /* ignore given value for the scrollbars, must use only from parent */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ color = iupmotColorGetPixelStr(parent_value);
+ if (color != (Pixel)-1)
+ {
+ Widget sb = NULL;
+
+ iupmotSetBgColor(sb_win, color);
+
+ XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL);
+ if (sb) iupmotSetBgColor(sb, color);
+
+ XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL);
+ if (sb) iupmotSetBgColor(sb, color);
+ }
+ }
+
+ return iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */
+}
+
+static int motTextSetSpinMinAttrib(Ihandle* ih, const char* value)
+{
+ Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (spinbox && XmIsSpinBox(spinbox))
+ {
+ int min;
+ if (iupStrToInt(value, &min))
+ {
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+ XtVaSetValues(ih->handle, XmNminimumValue, min, NULL);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+ }
+ return 1;
+}
+
+static int motTextSetSpinMaxAttrib(Ihandle* ih, const char* value)
+{
+ Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (spinbox && XmIsSpinBox(spinbox))
+ {
+ int max;
+ if (iupStrToInt(value, &max))
+ {
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+ XtVaSetValues(ih->handle, XmNmaximumValue, max, NULL);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+ }
+ return 1;
+}
+
+static int motTextSetSpinIncAttrib(Ihandle* ih, const char* value)
+{
+ Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (spinbox && XmIsSpinBox(spinbox))
+ {
+ int inc;
+ if (iupStrToInt(value, &inc))
+ {
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+ XtVaSetValues(ih->handle, XmNincrementValue, inc, NULL);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ }
+ }
+ return 1;
+}
+
+static int motTextSetSpinValueAttrib(Ihandle* ih, const char* value)
+{
+ Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (spinbox && XmIsSpinBox(spinbox))
+ {
+ int pos;
+ if (iupStrToInt(value, &pos))
+ {
+ char* value = NULL;
+ int min, max;
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+ XtVaGetValues(ih->handle, XmNminimumValue, &min,
+ XmNmaximumValue, &max, NULL);
+ if (pos < min) pos = min;
+ if (pos > max) pos = max;
+ if (iupAttribGet(ih, "_IUPMOT_SPIN_NOAUTO"))
+ value = XmTextGetString(ih->handle);
+
+ XtVaSetValues(ih->handle, XmNposition, pos, NULL);
+
+ if (value)
+ {
+ XmTextSetString(ih->handle, (char*)value);
+ XtFree(value);
+ }
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static char* motTextGetSpinValueAttrib(Ihandle* ih)
+{
+ Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (spinbox && XmIsSpinBox(spinbox))
+ {
+ int pos;
+ char *str = iupStrGetMemory(50);
+ XtVaGetValues(ih->handle, XmNposition, &pos, NULL);
+ sprintf(str, "%d", pos);
+ return str;
+ }
+ return NULL;
+}
+
+static int motTextSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (!value) value = "";
+ motTextSetSpinValueAttrib(ih, value);
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+ XmTextSetString(ih->handle, (char*)value);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ return 0;
+}
+
+static char* motTextGetValueAttrib(Ihandle* ih)
+{
+ char* value = XmTextGetString(ih->handle);
+ char* str = iupStrGetMemoryCopy(value);
+ XtFree(value);
+ return str;
+}
+
+
+/******************************************************************************/
+
+
+static void motTextSpinModifyVerifyCallback(Widget w, Ihandle* ih, XmSpinBoxCallbackStruct *cbs)
+{
+ IFni cb = (IFni) IupGetCallback(ih, "SPIN_CB");
+ if (cb)
+ {
+ int ret = cb(ih, cbs->position);
+ if (ret == IUP_IGNORE)
+ {
+ cbs->doit = 1;
+ return;
+ }
+ }
+ (void)w;
+
+ iupAttribSetStr(ih, "_IUPMOT_SPIN_DISABLE_TEXT_CB", "1");
+}
+
+static void motTextModifyVerifyCallback(Widget w, Ihandle *ih, XmTextVerifyPtr text)
+{
+ int start, end, key = 0;
+ char *value, *new_value, *insert_value;
+ KeySym motcode = 0;
+ IFnis cb;
+
+ if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB"))
+ return;
+
+ if (iupAttribGet(ih, "_IUPMOT_SPIN_DISABLE_TEXT_CB"))
+ {
+ if (iupAttribGet(ih, "_IUPMOT_SPIN_NOAUTO"))
+ text->doit = False;
+
+ iupAttribSetStr(ih, "_IUPMOT_SPIN_DISABLE_TEXT_CB", NULL);
+ return;
+ }
+
+ cb = (IFnis)IupGetCallback(ih, "ACTION");
+ if (!cb && !ih->data->mask)
+ return;
+
+ if (text->event && text->event->type == KeyPress)
+ {
+ unsigned int state = ((XKeyEvent*)text->event)->state;
+ if (state & ControlMask || /* Ctrl */
+ state & Mod1Mask ||
+ state & Mod5Mask || /* Alt */
+ state & Mod4Mask) /* Apple/Win */
+ return;
+
+ motcode = XKeycodeToKeysym(iupmot_display, ((XKeyEvent*)text->event)->keycode, 0);
+ }
+
+ value = XmTextGetString(ih->handle);
+ start = text->startPos;
+ end = text->endPos;
+ insert_value = text->text->ptr;
+
+ if (motcode == XK_Delete)
+ {
+ new_value = value;
+ iupStrRemove(value, start, end, 1);
+ }
+ else if (motcode == XK_BackSpace)
+ {
+ new_value = value;
+ iupStrRemove(value, start, end, -1);
+ }
+ else
+ {
+ if (!value)
+ new_value = iupStrDup(insert_value);
+ else if (insert_value)
+ new_value = iupStrInsert(value, insert_value, start, end);
+ else
+ new_value = value;
+ }
+
+ if (insert_value && insert_value[0]!=0 && insert_value[1]==0)
+ key = insert_value[0];
+
+ if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0)
+ {
+ if (new_value != value) free(new_value);
+ XtFree(value);
+ text->doit = False; /* abort processing */
+ return;
+ }
+
+ if (cb)
+ {
+ int cb_ret = cb(ih, key, (char*)new_value);
+ if (cb_ret==IUP_IGNORE)
+ text->doit = False; /* abort processing */
+ else if (cb_ret==IUP_CLOSE)
+ {
+ IupExitLoop();
+ text->doit = False; /* abort processing */
+ }
+ else if (cb_ret!=0 && key!=0 &&
+ cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE)
+ {
+ insert_value[0] = (char)cb_ret; /* replace key */
+ }
+ }
+
+ if (text->doit)
+ {
+ /* Spin is not automatically updated when you directly edit the text */
+ Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (spinbox && XmIsSpinBox(spinbox) && !iupAttribGet(ih, "_IUPMOT_SPIN_NOAUTO"))
+ {
+ int pos;
+ if (iupStrToInt(new_value, &pos))
+ {
+ XmTextPosition caret_pos = text->currInsert;
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1");
+ XtVaSetValues(ih->handle, XmNposition, pos, NULL);
+ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL);
+ /* do not handle all situations, but handle the basic ones */
+ if (text->startPos == text->endPos) /* insert */
+ caret_pos++;
+ else if (text->startPos < text->endPos && text->startPos < text->currInsert) /* backspace */
+ caret_pos--;
+ XmTextSetInsertionPosition(ih->handle, caret_pos);
+ text->doit = False;
+ }
+ }
+ }
+
+ if (new_value != value) free(new_value);
+ XtFree(value);
+ (void)w;
+}
+
+static void motTextMotionVerifyCallback(Widget w, Ihandle* ih, XmTextVerifyCallbackStruct* textverify)
+{
+ int col, lin, pos;
+
+ IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB");
+ if (!cb) return;
+
+ pos = textverify->newInsert;
+
+ if (ih->data->is_multiline)
+ {
+ char *value = XmTextGetString(ih->handle);
+ motTextGetLinColFromPosition(value, pos, &lin, &col);
+ XtFree(value);
+ }
+ else
+ {
+ col = pos;
+ col++; /* IUP starts at 1 */
+ lin = 1;
+ }
+
+ if (pos != ih->data->last_caret_pos)
+ {
+ ih->data->last_caret_pos = pos;
+ cb(ih, lin, col, pos);
+ }
+
+ (void)w;
+}
+
+static void motTextValueChangedCallback(Widget w, Ihandle* ih, XmAnyCallbackStruct* valuechanged)
+{
+ if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB"))
+ return;
+
+ iupBaseCallValueChangedCb(ih);
+
+ (void)valuechanged;
+ (void)w;
+}
+
+static void motTextKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont)
+{
+ Widget spinbox;
+
+ *cont = True;
+ iupmotKeyPressEvent(w, ih, (XEvent*)evt, cont);
+ if (*cont == False)
+ return;
+
+ if (evt->state & ControlMask) /* Ctrl */
+ {
+ KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0);
+ if (motcode == XK_c)
+ motTextSetClipboardAttrib(ih, "COPY");
+ else if (motcode == XK_x)
+ motTextSetClipboardAttrib(ih, "CUT");
+ else if (motcode == XK_v)
+ motTextSetClipboardAttrib(ih, "PASTE");
+ else if (motcode == XK_a)
+ XmTextSetSelection(ih->handle, 0, XmTextGetLastPosition(ih->handle), CurrentTime);
+ }
+
+ spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (spinbox && XmIsSpinBox(spinbox))
+ {
+ KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0);
+ if (motcode == XK_Left || motcode == XK_Right)
+ {
+ /* avoid spin increment using Left/Right arrows,
+ but must manually handle the new cursor position */
+ XmTextPosition caret_pos = XmTextGetInsertionPosition(ih->handle);
+ XmTextSetInsertionPosition(ih->handle, (motcode == XK_Left)? caret_pos-1: caret_pos+1);
+ *cont = False;
+ }
+ }
+}
+
+
+/******************************************************************************/
+
+
+static void motTextLayoutUpdateMethod(Ihandle* ih)
+{
+ Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (spinbox && XmIsSpinBox(spinbox))
+ {
+ XtVaSetValues(ih->handle,
+ XmNwidth, (XtArgVal)ih->currentwidth-ih->currentheight/2,
+ XmNheight, (XtArgVal)ih->currentheight,
+ NULL);
+
+ XtVaSetValues(spinbox,
+ XmNx, (XtArgVal)ih->x,
+ XmNy, (XtArgVal)ih->y,
+ XmNwidth, (XtArgVal)ih->currentwidth,
+ XmNheight, (XtArgVal)ih->currentheight,
+ XmNarrowSize, ih->currentheight/2,
+ NULL);
+ }
+ else
+ iupdrvBaseLayoutUpdateMethod(ih);
+}
+
+static int motTextMapMethod(Ihandle* ih)
+{
+ int num_args = 0;
+ Arg args[30];
+ Widget parent = iupChildTreeGetNativeParentHandle(ih);
+ char* child_id = iupDialogGetChildIdStr(ih);
+ int spin = 0;
+ WidgetClass widget_class = xmTextWidgetClass;
+
+ if (ih->data->is_multiline)
+ {
+ Widget sb_win;
+ int wordwrap = 0;
+
+ if (iupAttribGetBoolean(ih, "WORDWRAP"))
+ {
+ wordwrap = 1;
+ ih->data->sb &= ~IUP_SB_HORIZ; /* must remove the horizontal scroolbar */
+ }
+
+ /******************************/
+ /* 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);
+
+ sb_win = XtCreateManagedWidget(
+ child_id, /* child identifier */
+ xmScrolledWindowWidgetClass, /* widget class */
+ parent, /* widget parent */
+ args, num_args);
+
+ if (!sb_win)
+ return IUP_ERROR;
+
+ parent = sb_win;
+ child_id = "text";
+
+ num_args = 0;
+ iupmotSetArg(args, num_args, XmNeditMode, XmMULTI_LINE_EDIT);
+ if (wordwrap)
+ iupmotSetArg(args, num_args, XmNwordWrap, True);
+ }
+ else
+ {
+ widget_class = xmTextFieldWidgetClass;
+
+ if (iupAttribGetBoolean(ih, "SPIN"))
+ {
+ 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);
+
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT"))
+ iupmotSetArg(args, num_args, XmNarrowLayout, XmARROWS_BEGINNING);
+ else
+ iupmotSetArg(args, num_args, XmNarrowLayout, XmARROWS_END);
+
+ spinbox = XtCreateManagedWidget(
+ child_id, /* child identifier */
+ xmSpinBoxWidgetClass, /* widget class */
+ parent, /* widget parent */
+ args, num_args);
+
+ if (!spinbox)
+ return IUP_ERROR;
+
+ XtAddCallback(spinbox, XmNmodifyVerifyCallback, (XtCallbackProc)motTextSpinModifyVerifyCallback, (XtPointer)ih);
+
+ parent = spinbox;
+ child_id = "text";
+ spin = 1;
+
+ if (!iupAttribGetBoolean(ih, "SPINAUTO"))
+ iupAttribSetStr(ih, "_IUPMOT_SPIN_NOAUTO", "1");
+ }
+
+ num_args = 0;
+ iupmotSetArg(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);
+
+ if (iupAttribGetBoolean(ih, "SPINWRAP"))
+ iupmotSetArg(args, num_args, XmNwrap, TRUE);
+ else
+ iupmotSetArg(args, num_args, XmNwrap, FALSE);
+ }
+ else
+ {
+ 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 */
+
+ iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */
+ iupmotSetArg(args, num_args, XmNmarginWidth, 0);
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ iupmotSetArg(args, num_args, XmNtraversalOn, True);
+ else
+ iupmotSetArg(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);
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ iupmotSetArg(args, num_args, XmNshadowThickness, 2);
+ else
+ iupmotSetArg(args, num_args, XmNshadowThickness, 0);
+
+ if (ih->data->is_multiline)
+ {
+ if (ih->data->sb & IUP_SB_HORIZ)
+ iupmotSetArg(args, num_args, XmNscrollHorizontal, True);
+ else
+ iupmotSetArg(args, num_args, XmNscrollHorizontal, False);
+
+ if (ih->data->sb & IUP_SB_VERT)
+ iupmotSetArg(args, num_args, XmNscrollVertical, True);
+ else
+ iupmotSetArg(args, num_args, XmNscrollVertical, False);
+ }
+
+ ih->handle = XtCreateManagedWidget(
+ child_id, /* child identifier */
+ widget_class, /* widget class */
+ parent, /* widget parent */
+ args, num_args);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupDialogGetChildId(ih); /* must be after using the string */
+
+ if (ih->data->is_multiline)
+ {
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent);
+ XtVaSetValues(parent, XmNworkWindow, ih->handle, NULL);
+ }
+ else if (spin)
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent);
+
+ XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)motTextKeyPressEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih);
+
+ XtAddCallback(ih->handle, XmNmodifyVerifyCallback, (XtCallbackProc)motTextModifyVerifyCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNmotionVerifyCallback, (XtCallbackProc)motTextMotionVerifyCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motTextValueChangedCallback, (XtPointer)ih);
+
+ /* Disable Drag Source */
+ iupmotDisableDragSource(ih->handle);
+
+ /* initialize the widget */
+ if (ih->data->is_multiline || spin)
+ XtRealizeWidget(parent);
+ else
+ XtRealizeWidget(ih->handle);
+
+ if (IupGetGlobal("_IUP_RESET_TXTCOLORS"))
+ {
+ iupmotSetGlobalColorAttrib(ih->handle, XmNbackground, "TXTBGCOLOR");
+ iupmotSetGlobalColorAttrib(ih->handle, XmNforeground, "TXTFGCOLOR");
+ IupSetGlobal("_IUP_RESET_TXTCOLORS", NULL);
+ }
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)motTextConvertXYToPos);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTextInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motTextMapMethod;
+ ic->LayoutUpdate = motTextLayoutUpdateMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT);
+
+ /* IupText only */
+ iupClassRegisterAttribute(ic, "PADDING", iupTextGetPaddingAttrib, motTextSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "VALUE", motTextGetValueAttrib, motTextSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTEDTEXT", motTextGetSelectedTextAttrib, motTextSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTION", motTextGetSelectionAttrib, motTextSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTIONPOS", motTextGetSelectionPosAttrib, motTextSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARET", motTextGetCaretAttrib, motTextSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARETPOS", motTextGetCaretPosAttrib, motTextSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INSERT", NULL, motTextSetInsertAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPEND", NULL, motTextSetAppendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "READONLY", motTextGetReadOnlyAttrib, motTextSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "NC", iupTextGetNCAttrib, motTextSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, motTextSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FORMATTING", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* formatting not supported in Motif */
+ iupClassRegisterAttribute(ic, "SCROLLTO", NULL, motTextSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, motTextSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINMIN", NULL, motTextSetSpinMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINMAX", NULL, motTextSetSpinMaxAttrib, IUPAF_SAMEASSYSTEM, "100", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPININC", NULL, motTextSetSpinIncAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINVALUE", motTextGetSpinValueAttrib, motTextSetSpinValueAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/mot/iupmot_timer.c b/iup/src/mot/iupmot_timer.c
new file mode 100755
index 0000000..d23867e
--- /dev/null
+++ b/iup/src/mot/iupmot_timer.c
@@ -0,0 +1,70 @@
+/** \file
+ * \brief Timer for the Motif Driver.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <Xm/Xm.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_assert.h"
+#include "iup_timer.h"
+
+#include "iupmot_drv.h"
+
+
+static void motTimerProc(XtPointer client_data, XtIntervalId *id)
+{
+ Ihandle *ih = (Ihandle*)client_data;
+ Icallback cb;
+ (void)id;
+
+ if (!iupObjectCheck(ih)) /* control could be destroyed before timer callback */
+ return;
+
+ ih->serial = -1;
+ /* we have to restart the timer everytime */
+ iupdrvTimerRun(ih);
+
+ cb = IupGetCallback(ih, "ACTION_CB");
+ if (cb)
+ {
+ if (cb(ih)==IUP_CLOSE)
+ IupExitLoop();
+ }
+}
+
+void iupdrvTimerRun(Ihandle *ih)
+{
+ unsigned int time_ms;
+
+ if (ih->serial > 0) /* timer already started */
+ return;
+
+ time_ms = iupAttribGetInt(ih, "TIME");
+ if (time_ms > 0)
+ ih->serial = XtAppAddTimeOut(iupmot_appcontext, time_ms, motTimerProc, (XtPointer)ih);
+}
+
+void iupdrvTimerStop(Ihandle* ih)
+{
+ if (ih->serial > 0)
+ {
+ XtRemoveTimeOut(ih->serial);
+ ih->serial = -1;
+ }
+}
+
+void iupdrvTimerInitClass(Iclass* ic)
+{
+ (void)ic;
+}
diff --git a/iup/src/mot/iupmot_tips.c b/iup/src/mot/iupmot_tips.c
new file mode 100755
index 0000000..25bdbea
--- /dev/null
+++ b/iup/src/mot/iupmot_tips.c
@@ -0,0 +1,226 @@
+/** \file
+ * \brief Motif Driver TIPS Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <Xm/Label.h>
+
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+/* Default offset from cursor */
+#define TIP_X_OFFSET 12
+#define TIP_Y_OFFSET 12
+
+typedef struct _Imottips
+{
+ Widget Dialog;
+ Widget Label;
+ XtIntervalId ShowTimerId; /* Timer: from enterwin to show tip */
+ XtIntervalId HideTimerId; /* Timer: from visible to hide tip */
+ unsigned long ShowInterval; /* Time for tipPopupTimerId */
+ unsigned long HideInterval; /* Time for tipActiveTimerId */
+ int Visible;
+ Ihandle* ih;
+} Imottips;
+
+static Imottips mot_tips = {0, 0, 0, 0, 0, 0};
+
+static void motTipsShow(void)
+{
+ Window root, child;
+ int cx, cy, x, y;
+ unsigned int keys;
+ char* value;
+
+ XQueryPointer(iupmot_display, RootWindow(iupmot_display, iupmot_screen),
+ &root, &child, &x, &y, &cx, &cy, &keys);
+
+ value = iupAttribGet(mot_tips.ih, "TIPRECT");
+ if (value)
+ {
+ int x1, x2, y1, y2, wx = x, wy = y;
+ sscanf(value, "%d %d %d %d", &x1, &y1, &x2, &y2);
+ iupdrvScreenToClient(mot_tips.ih, &wx, &wy);
+ if (wx < x1 || wx > x2 || wy < y1 || wy > y2)
+ {
+ iupmotTipLeaveNotify();
+ return;
+ }
+ }
+
+ XtVaSetValues(mot_tips.Dialog,
+ XmNx, (XtArgVal)(x+TIP_X_OFFSET),
+ XmNy, (XtArgVal)(y+TIP_Y_OFFSET),
+ NULL);
+
+ if (mot_tips.Visible)
+ XRaiseWindow(iupmot_display, XtWindow(mot_tips.Dialog));
+ else
+ XtMapWidget(mot_tips.Dialog);
+
+ mot_tips.ShowTimerId = (XtIntervalId) NULL;
+ mot_tips.Visible = TRUE;
+}
+
+static void motTipsHide(void)
+{
+ mot_tips.HideTimerId = (XtIntervalId) NULL;
+ iupmotTipLeaveNotify();
+}
+
+static int motTipsSet(Ihandle *ih)
+{
+ char* tipText = iupAttribGet(ih, "TIP");
+ if (!tipText)
+ return FALSE;
+
+ if (!mot_tips.Dialog)
+ {
+ mot_tips.Dialog = XtVaAppCreateShell(" ", "tip",
+ overrideShellWidgetClass, iupmot_display,
+ XmNmappedWhenManaged, False,
+ NULL);
+
+ mot_tips.Label = XtVaCreateManagedWidget("label tip",
+ xmLabelWidgetClass, mot_tips.Dialog, /* must use IupGetAttribute to use inheritance */
+ XmNforeground, iupmotColorGetPixelStr(IupGetAttribute(ih, "TIPFGCOLOR")),
+ XmNbackground, iupmotColorGetPixelStr(IupGetAttribute(ih, "TIPBGCOLOR")),
+ NULL);
+
+ XtRealizeWidget(mot_tips.Dialog);
+ }
+
+ /* set label font */
+ {
+ XmFontList fontlist = (XmFontList)iupmotGetFontListAttrib(ih);
+ char* value = iupAttribGetStr(ih, "TIPFONT");
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "SYSTEM"))
+ fontlist = NULL;
+ else
+ fontlist = iupmotGetFontList(iupAttribGet(ih, "TIPFOUNDRY"), value);
+ }
+
+ if (fontlist)
+ XtVaSetValues(mot_tips.Label, XmNfontList, fontlist, NULL);
+ }
+
+ /* set label contents */
+ iupmotSetString(mot_tips.Label, XmNlabelString, tipText);
+
+ /* set label size */
+ {
+ int lw = 0, lh = 0;
+ iupdrvFontGetMultiLineStringSize(ih, tipText, &lw, &lh);
+
+ /* add room for margin */
+ lw += 2*(2);
+ lh += 2*(2);
+
+ XtVaSetValues(mot_tips.Label,
+ XmNwidth, (XtArgVal)lw,
+ XmNheight, (XtArgVal)lh,
+ NULL);
+ XtVaSetValues(mot_tips.Dialog,
+ XmNwidth, (XtArgVal)lw,
+ XmNheight, (XtArgVal)lh,
+ NULL);
+ }
+
+ mot_tips.ShowTimerId = (XtIntervalId) NULL;
+ mot_tips.HideTimerId = (XtIntervalId) NULL;
+ mot_tips.Visible = FALSE;
+ mot_tips.ShowInterval = 500; /* 1/2 second to show */
+
+ {
+ int delay = IupGetInt(ih, "TIPDELAY"); /* must use IupGetInt to use inheritance */
+ mot_tips.HideInterval = delay + mot_tips.ShowInterval;
+ }
+
+ return TRUE;
+}
+
+int iupdrvBaseSetTipVisibleAttrib(Ihandle* ih, const char* value)
+{
+ /* must use IupGetAttribute to use inheritance */
+ if (!IupGetAttribute(ih, "TIP"))
+ return 0;
+
+ if (iupStrBoolean(value))
+ iupmotTipEnterNotify(ih);
+ else
+ iupmotTipLeaveNotify();
+
+ return 0;
+}
+
+void iupmotTipEnterNotify(Ihandle *ih)
+{
+ iupmotTipLeaveNotify();
+
+ if (motTipsSet(ih) == FALSE)
+ return;
+
+ mot_tips.ih = ih;
+
+ mot_tips.ShowTimerId = XtAppAddTimeOut( /* EnterWin to Show */
+ iupmot_appcontext,
+ mot_tips.ShowInterval,
+ (XtTimerCallbackProc)motTipsShow,
+ NULL);
+ mot_tips.HideTimerId = XtAppAddTimeOut( /* Visible to Hide */
+ iupmot_appcontext,
+ mot_tips.HideInterval,
+ (XtTimerCallbackProc)motTipsHide,
+ NULL);
+}
+
+void iupmotTipLeaveNotify(void)
+{
+ if (mot_tips.ShowTimerId)
+ {
+ XtRemoveTimeOut(mot_tips.ShowTimerId);
+ mot_tips.ShowTimerId = (XtIntervalId) NULL;
+ }
+ if (mot_tips.HideTimerId)
+ {
+ XtRemoveTimeOut(mot_tips.HideTimerId);
+ mot_tips.HideTimerId = (XtIntervalId) NULL;
+ }
+ if (mot_tips.Visible)
+ {
+ XtUnmapWidget(mot_tips.Dialog);
+ mot_tips.Visible = FALSE;
+ }
+}
+
+void iupmotTipsFinish(void)
+{
+ if (mot_tips.Dialog)
+ {
+ XtDestroyWidget(mot_tips.Dialog);
+ memset(&mot_tips, 0, sizeof(Imottips));
+ }
+}
+
+int iupdrvBaseSetTipAttrib(Ihandle* ih, const char* value)
+{
+ /* implement this stub here because of the other drivers. */
+ (void)ih;
+ (void)value;
+ return 1;
+}
diff --git a/iup/src/mot/iupmot_toggle.c b/iup/src/mot/iupmot_toggle.c
new file mode 100755
index 0000000..b18f24d
--- /dev/null
+++ b/iup/src/mot/iupmot_toggle.c
@@ -0,0 +1,469 @@
+/** \file
+ * \brief Toggle Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <Xm/ToggleB.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_toggle.h"
+#include "iup_drv.h"
+#include "iup_image.h"
+#include "iup_key.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+void iupdrvToggleAddCheckBox(int *x, int *y)
+{
+ (*x) += 15+6+3;
+ if ((*y) < 15+6) (*y) = 12+6; /* minimum height */
+ (*y) += 6;
+}
+
+
+/*********************************************************************************/
+
+
+static int motToggleSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ {
+ char* parent_value = iupAttribGetInheritNativeParent(ih, "BGCOLOR");
+ if (!parent_value)
+ {
+ /* if not defined at a native parent,
+ then change the toggle button color to the given color instead using the default */
+ if (iupdrvBaseSetBgColorAttrib(ih, value)) /* let XmChangeColor do its job */
+ {
+ parent_value = IupGetGlobal("DLGBGCOLOR");
+ XtVaSetValues(ih->handle, XmNbackground, iupmotColorGetPixelStr(parent_value), NULL); /* reset just the background */
+
+ if (ih->data->radio)
+ XtVaSetValues(ih->handle, XmNselectColor, iupmotColorGetPixel(0, 0, 0), NULL);
+ XtVaSetValues(ih->handle, XmNunselectColor, iupmotColorGetPixelStr(value), NULL);
+ return 1;
+ }
+ }
+ else
+ {
+ /* ignore given value, must use only from parent */
+ if (iupdrvBaseSetBgColorAttrib(ih, parent_value))
+ {
+ if (ih->data->radio)
+ XtVaSetValues(ih->handle, XmNselectColor, iupmotColorGetPixel(0, 0, 0), NULL);
+ XtVaSetValues(ih->handle, XmNunselectColor, iupmotColorGetPixelStr(parent_value), NULL);
+ return 1;
+ }
+ }
+ return 0;
+ }
+ else
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+}
+
+static int motToggleSetBackgroundAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ {
+ Pixel color;
+
+ /* ignore given value, must use only from parent */
+ value = iupAttribGetInheritNativeParent(ih, "BACKGROUND");
+
+ color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ {
+ XtVaSetValues(ih->handle, XmNbackground, color, NULL);
+ return 1;
+ }
+ else
+ {
+ Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0);
+ if (pixmap)
+ {
+ XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int motToggleSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ {
+ iupmotSetMnemonicTitle(ih, value);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int motToggleSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char align;
+ char value1[30]="", value2[30]="";
+
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ return 0;
+
+ iupStrToStrStr(value, value1, value2, ':'); /* value2 is ignored, NOT supported in Motif */
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ align = XmALIGNMENT_END;
+ else if (iupStrEqualNoCase(value1, "ACENTER"))
+ align = XmALIGNMENT_CENTER;
+ else /* "ALEFT" */
+ align = XmALIGNMENT_BEGINNING;
+
+ XtVaSetValues (ih->handle, XmNalignment, align, NULL);
+ return 1;
+}
+
+static int motToggleSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ iupmotSetPixmap(ih, value, XmNlabelPixmap, 0);
+
+ if (!iupAttribGet(ih, "IMINACTIVE"))
+ {
+ /* if not active and IMINACTIVE is not defined
+ then automaticaly create one based on IMAGE */
+ iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 1); /* make_inactive */
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int motToggleSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 0);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int motToggleSetImPressAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ iupmotSetPixmap(ih, value, XmNselectPixmap, 0);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int motToggleSetValueAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle *radio;
+ unsigned char check;
+
+ if (iupStrEqualNoCase(value,"NOTDEF"))
+ check = XmINDETERMINATE;
+ else if (iupStrBoolean(value))
+ check = XmSET;
+ else
+ check = XmUNSET;
+
+ /* This is necessary because Motif toggle does not have support for radio.
+ It is implemented using an external RadioBox that we do not use. */
+ radio = iupRadioFindToggleParent(ih);
+ if (radio)
+ {
+ Ihandle* last_tg;
+ unsigned char oldcheck;
+
+ XtVaGetValues(ih->handle, XmNset, &oldcheck, NULL);
+
+ last_tg = (Ihandle*)iupAttribGet(radio, "_IUPMOT_LASTTOGGLE");
+ if (check)
+ {
+ if (iupObjectCheck(last_tg) && last_tg != ih)
+ XtVaSetValues(last_tg->handle, XmNset, XmUNSET, NULL);
+ iupAttribSetStr(radio, "_IUPMOT_LASTTOGGLE", (char*)ih);
+ }
+
+ if (last_tg != ih && oldcheck != check)
+ XtVaSetValues(ih->handle, XmNset, check, NULL);
+ }
+ else
+ XtVaSetValues(ih->handle, XmNset, check, NULL);
+
+ return 0;
+}
+
+static char* motToggleGetValueAttrib(Ihandle* ih)
+{
+ unsigned char check = 0;
+ XtVaGetValues (ih->handle, XmNset, &check, NULL);
+ if (check == XmINDETERMINATE)
+ return "NOTDEF";
+ else if (check == XmSET)
+ return "ON";
+ else
+ return "OFF";
+}
+
+static int motToggleSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle && ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding,
+ XmNmarginWidth, ih->data->horiz_padding, NULL);
+ }
+ return 0;
+}
+
+static char* motToggleGetSelectColorAttrib(Ihandle* ih)
+{
+ unsigned char r, g, b;
+ Pixel color;
+ char* str = iupStrGetMemory(20);
+ XtVaGetValues(ih->handle, XmNselectColor, &color, NULL);
+ iupmotColorGetRGB(color, &r, &g, &b);
+ sprintf(str, "%d %d %d", (int)r, (int)g, (int)b);
+ return str;
+}
+
+static int motToggleSetSelectColorAttrib(Ihandle* ih, const char *value)
+{
+ Pixel color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ XtVaSetValues(ih->handle, XmNselectColor, color, NULL);
+ return 1;
+}
+
+static void motToggleValueChangedCallback(Widget w, Ihandle* ih, XmToggleButtonCallbackStruct* call_data)
+{
+ Ihandle *radio;
+ IFni cb;
+ int check = call_data->set;
+
+ /* Must manually hide the tip if the toggle is pressed. */
+ iupmotTipLeaveNotify();
+
+ /* This is necessary because Motif toggle does not have support for radio.
+ It is implemented using an external RadioBox that we do not use. */
+ radio = iupRadioFindToggleParent(ih);
+ if (radio)
+ {
+ if (check)
+ {
+ Ihandle* last_tg = (Ihandle*)iupAttribGet(radio, "_IUPMOT_LASTTOGGLE");
+ if (iupObjectCheck(last_tg) && last_tg != ih)
+ {
+ /* uncheck last toggle */
+ XtVaSetValues(last_tg->handle, XmNset, XmUNSET, NULL);
+
+ cb = (IFni) IupGetCallback(last_tg, "ACTION");
+ if (cb && cb(last_tg, 0) == IUP_CLOSE)
+ IupExitLoop();
+
+ iupBaseCallValueChangedCb(last_tg);
+ }
+ iupAttribSetStr(radio, "_IUPMOT_LASTTOGGLE", (char*)ih);
+
+ if (last_tg != ih)
+ {
+ cb = (IFni)IupGetCallback(ih, "ACTION");
+ if (cb && cb (ih, 1) == IUP_CLOSE)
+ IupExitLoop();
+
+ iupBaseCallValueChangedCb(ih);
+ }
+ }
+ else
+ {
+ /* Force stay checked */
+ XtVaSetValues(ih->handle, XmNset, XmSET, NULL);
+ }
+ }
+ else
+ {
+ if (check == XmINDETERMINATE)
+ check = -1;
+
+ cb = (IFni)IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ if (cb(ih, check) == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ iupBaseCallValueChangedCb(ih);
+ }
+
+ (void)w;
+}
+
+static int motToggleMapMethod(Ihandle* ih)
+{
+ Ihandle* radio = iupRadioFindToggleParent(ih);
+ char* value;
+ int num_args = 0;
+ Arg args[40];
+
+ if (radio)
+ ih->data->radio = 1;
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ {
+ ih->data->type = IUP_TOGGLE_IMAGE;
+ iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP);
+ }
+ else
+ {
+ ih->data->type = IUP_TOGGLE_TEXT;
+ iupmotSetArg(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 */
+ /* Primitive */
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ iupmotSetArg(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);
+ /* 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);
+
+ if (radio)
+ {
+ iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN);
+ iupmotSetArg(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND);
+
+ if (!iupAttribGet(radio, "_IUPMOT_LASTTOGGLE"))
+ {
+ /* this is the first toggle in the radio, and the last toggle with VALUE=ON */
+ iupAttribSetStr(ih, "VALUE","ON");
+ }
+ }
+ else
+ {
+ if (ih->data->type == IUP_TOGGLE_TEXT && iupAttribGetBoolean(ih, "3STATE"))
+ iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_INDETERMINATE);
+ else
+ iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN);
+ iupmotSetArg(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);
+ }
+ else
+ {
+ iupmotSetArg(args, num_args, XmNspacing, 3);
+ iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX);
+ iupmotSetArg(args, num_args, XmNalignment, XmALIGNMENT_BEGINNING);
+ if (radio)
+ {
+ iupmotSetArg(args, num_args, XmNindicatorSize, 13);
+ iupmotSetArg(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0));
+ }
+ else
+ iupmotSetArg(args, num_args, XmNindicatorSize, 15);
+
+ iupmotSetArg(args, num_args, XmNshadowThickness, 0);
+ iupmotSetArg(args, num_args, XmNdetailShadowThickness, 2);
+ }
+
+ ih->handle = XtCreateManagedWidget(
+ iupDialogGetChildIdStr(ih), /* child identifier */
+ xmToggleButtonWidgetClass, /* widget class */
+ iupChildTreeGetNativeParentHandle(ih), /* widget parent */
+ args, num_args);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupDialogGetChildId(ih); /* must be after using the string */
+
+ XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih);
+
+ XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+
+ XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih);
+
+ XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motToggleValueChangedCallback, (XtPointer)ih);
+
+ /* Disable Drag Source */
+ iupmotDisableDragSource(ih->handle);
+
+ /* initialize the widget */
+ XtRealizeWidget(ih->handle);
+
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ iupmotSetString(ih->handle, XmNlabelString, "");
+
+ return IUP_NOERROR;
+}
+
+void iupdrvToggleInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motToggleMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", iupmotGetBgColorAttrib, motToggleSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motToggleSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, motToggleSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupToggle only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, motToggleSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ACENTER:ACENTER", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, motToggleSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, motToggleSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, motToggleSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE", motToggleGetValueAttrib, motToggleSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTCOLOR", motToggleGetSelectColorAttrib, motToggleSetSelectColorAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupToggleGetPaddingAttrib, motToggleSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+}
diff --git a/iup/src/mot/iupmot_tree.c b/iup/src/mot/iupmot_tree.c
new file mode 100755
index 0000000..eb230af
--- /dev/null
+++ b/iup/src/mot/iupmot_tree.c
@@ -0,0 +1,2848 @@
+#include <Xm/Xm.h>
+#include <Xm/Form.h>
+#include <Xm/Container.h>
+#include <Xm/IconG.h>
+#include <Xm/ScrolledW.h>
+#include <Xm/XmosP.h>
+#include <Xm/Text.h>
+#include <Xm/Transfer.h>
+#include <Xm/DragDrop.h>
+#include <X11/keysym.h>
+
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <time.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_dialog.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_key.h"
+#include "iup_image.h"
+#include "iup_array.h"
+#include "iup_tree.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+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);
+
+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; i<numChild; i++)
+ {
+ /* Recursively traverse child items */
+ if (!motTreeForEach(ih, wItemChildList[i], func, userdata))
+ {
+ XtFree((char*)wItemChildList);
+ return 0;
+ }
+ }
+ if (wItemChildList) XtFree((char*)wItemChildList);
+
+ return 1;
+}
+
+/*****************************************************************************/
+/* COPYING ITEMS (Branches and its children) */
+/*****************************************************************************/
+/* Insert the copied item in a new location. Returns the new item. */
+static Widget motTreeCopyItem(Ihandle* ih, Widget wItem, Widget wParent, int pos, int full_copy)
+{
+ Widget wNewItem;
+ XmString title;
+ motTreeItemData *itemData;
+ Pixel fgcolor, bgcolor;
+ int num_args = 0;
+ Arg args[30];
+ Pixmap image = XmUNSPECIFIED_PIXMAP, mask = XmUNSPECIFIED_PIXMAP;
+ unsigned char state;
+
+ iupmotSetArg(args, num_args, XmNentryParent, wParent);
+ 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);
+
+ /* Get values to copy */
+ XtVaGetValues(wItem, XmNlabelString, &title,
+ XmNuserData, &itemData,
+ XmNforeground, &fgcolor,
+ XmNsmallIconPixmap, &image,
+ XmNsmallIconMask, &mask,
+ XmNoutlineState, &state,
+ NULL);
+
+ if (full_copy) /* during a full copy the userdata reference is not copied */
+ {
+ /* 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);
+
+ iupmotSetArg(args, num_args, XmNentryParent, wParent);
+ iupmotSetArg(args, num_args, XmNpositionIndex, pos);
+
+ XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL);
+ iupmotSetArg(args, num_args, XmNbackground, bgcolor);
+
+ wNewItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args);
+
+ /* Root always expanded */
+ XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL);
+
+ XtRealizeWidget(wNewItem);
+
+ return wNewItem;
+}
+
+static void motTreeCopyChildren(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int full_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 */
+
+ /* Recursively transfer all the items */
+ motTreeCopyChildren(ih, wItemChildList[i], wNewItem, full_copy);
+
+ /* Go to next sibling item */
+ i++;
+ }
+
+ if (wItemChildList) XtFree((char*)wItemChildList);
+}
+
+/* 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)
+{
+ Widget wNewItem, wParent;
+ motTreeItemData *itemDataDst;
+ unsigned char stateDst;
+ int pos;
+
+ XtVaGetValues(wItemDst, XmNoutlineState, &stateDst,
+ XmNuserData, &itemDataDst,
+ NULL);
+
+ if (itemDataDst->kind == ITREE_BRANCH && stateDst == XmEXPANDED)
+ {
+ /* copy as first child of expanded branch */
+ wParent = wItemDst;
+ pos = 0;
+ }
+ else
+ {
+ /* 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);
+
+ motTreeCopyChildren(ih, wItemSrc, wNewItem, full_copy);
+
+ return wNewItem;
+}
+
+static void motTreeContainerDeselectAll(Ihandle *ih)
+{
+ XKeyEvent ev;
+
+ memset(&ev, 0, sizeof(XKeyEvent));
+ ev.type = KeyPress;
+ ev.display = XtDisplay(ih->handle);
+ ev.send_event = True;
+ ev.root = RootWindow(iupmot_display, iupmot_screen);
+ ev.time = clock()*CLOCKS_PER_SEC;
+ ev.window = XtWindow(ih->handle);
+ ev.state = ControlMask;
+ ev.keycode = XK_backslash;
+ ev.same_screen = True;
+
+ XtCallActionProc(ih->handle, "ContainerDeselectAll", (XEvent*)&ev, 0, 0);
+}
+
+static void motTreeContainerSelectAll(Ihandle *ih)
+{
+ XKeyEvent ev;
+
+ memset(&ev, 0, sizeof(XKeyEvent));
+ ev.type = KeyPress;
+ ev.display = XtDisplay(ih->handle);
+ ev.send_event = True;
+ ev.root = RootWindow(iupmot_display, iupmot_screen);
+ ev.time = clock()*CLOCKS_PER_SEC;
+ ev.window = XtWindow(ih->handle);
+ ev.state = ControlMask;
+ ev.keycode = XK_slash;
+ ev.same_screen = True;
+
+ XtCallActionProc(ih->handle, "ContainerSelectAll", (XEvent*)&ev, 0, 0);
+}
+
+static Widget motTreeGetLastVisibleNode(Ihandle* ih, Widget wItem)
+{
+ unsigned char itemState;
+
+ XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL);
+
+ if (itemState == XmEXPANDED)
+ {
+ WidgetList wChildrenTree = NULL;
+ int numChildren = XmContainerGetItemChildren(ih->handle, wItem, &wChildrenTree);
+ if(numChildren)
+ wItem = motTreeGetLastVisibleNode(ih, wChildrenTree[numChildren - 1]);
+ if (wChildrenTree) XtFree((char*)wChildrenTree);
+ }
+
+ return wItem;
+}
+
+static Widget motTreeFindVisibleNodeId(Ihandle* ih, WidgetList itemList, int numItems, Widget itemNode)
+{
+ Widget itemChild;
+ WidgetList itemChildList;
+ int i = 0;
+ int numChild;
+ unsigned char itemState;
+
+ while(i != numItems)
+ {
+ /* 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++;
+ }
+
+ return NULL;
+}
+
+static Widget motTreeFindVisibleNodeFromId(Ihandle* ih, WidgetList itemList, int numItems)
+{
+ Widget itemChild;
+ WidgetList itemChildList;
+ int i = 0;
+ int numChild;
+ unsigned char itemState;
+
+ while(i != numItems)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control--; /* not the real id since it counts only the visible ones */
+
+ /* 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);
+ 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 = motTreeFindVisibleNodeFromId(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++;
+ }
+
+ return NULL;
+}
+
+static Widget motTreeGetNextVisibleNode(Ihandle* ih, Widget wRoot, Widget wItem)
+{
+ Widget wNext;
+
+ ih->data->id_control = -1;
+ motTreeFindVisibleNodeId(ih, &wRoot, 1, wItem);
+ ih->data->id_control++; /* more 1 visible node */
+
+ wNext = motTreeFindVisibleNodeFromId(ih, &wRoot, 1);
+
+ if (ih->data->id_control >= 0)
+ wNext = motTreeGetLastVisibleNode(ih, wRoot);
+
+ return wNext;
+}
+
+static Widget motTreeGetPreviousVisibleNode(Ihandle* ih, Widget wRoot, 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);
+}
+
+static void motTreeUpdateBgColor(Ihandle* ih, WidgetList itemList, int numItems, Pixel bgcolor)
+{
+ WidgetList itemChildList;
+ int i = 0;
+ int numChild;
+
+ while(i != numItems)
+ {
+ 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++;
+ }
+}
+
+static void motTreeUpdateImages(Ihandle* ih, WidgetList itemList, int numItems, int mode)
+{
+ motTreeItemData *itemData;
+ int i = 0;
+
+ /* called when one of the default images is changed */
+
+ while(i != numItems)
+ {
+ /* Get node attributes */
+ XtVaGetValues(itemList[i], XmNuserData, &itemData, NULL);
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ unsigned char itemState;
+ XtVaGetValues(itemList[i], 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);
+ }
+ }
+ 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);
+ }
+ }
+
+ /* 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);
+ }
+ }
+
+ /* Go to next sibling node */
+ i++;
+ }
+}
+
+static int motTreeSelectFunc(Ihandle* ih, Widget wItem, 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 */
+ }
+
+ if (do_select)
+ XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL);
+ else
+ XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL);
+
+ (void)ih;
+ return 1;
+}
+
+static void motTreeInvertAllNodeMarking(Ihandle* ih)
+{
+ int select = -1;
+ motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSelectFunc, &select);
+}
+
+typedef struct _motTreeRange{
+ Widget wItem1, wItem2;
+ char inside, clear;
+}motTreeRange;
+
+static int motTreeSelectRangeFunc(Ihandle* ih, Widget wItem, motTreeRange* range)
+{
+ 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 */
+ {
+ if (range->wItem1 == wItem) end_range=1;
+ else if (range->wItem2 == wItem) end_range=1;
+ }
+
+ 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)
+ {
+ /* Check whether we have child items */
+ itemChildList = NULL;
+ numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList);
+
+ if(numChild)
+ {
+ XtVaSetValues(itemList[i], XmNoutlineState, itemState, NULL);
+ motTreeExpandCollapseAllNodes(ih, itemChildList, numChild, itemState);
+ }
+
+ if (itemChildList) XtFree((char*)itemChildList);
+ /* Go to next sibling item */
+ i++;
+ }
+}
+
+static void motTreeDestroyItemData(Ihandle* ih, Widget wItem)
+{
+ motTreeItemData *itemData = NULL;
+ XtVaGetValues(wItem, XmNuserData, &itemData, NULL);
+ if (itemData)
+ {
+ 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;
+
+ while(i != numItems)
+ {
+ /* 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++;
+ }
+}
+
+static void motTreeRemoveNode(Ihandle* ih, Widget wItem, int del_userdata)
+{
+ 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)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control++;
+
+ /* 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)
+ {
+ /* 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;
+ }
+ }
+
+ if (itemChildList) XtFree((char*)itemChildList);
+ /* Go to next sibling item */
+ i++;
+ }
+
+ return NULL;
+}
+
+static Widget motTreeFindNodeFromID(Ihandle* ih, WidgetList itemList, int numItems)
+{
+ Widget itemChild;
+ WidgetList itemChildList;
+ int i = 0;
+ int numChild;
+
+ while(i != numItems)
+ {
+ /* 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++;
+ }
+
+ return NULL;
+}
+
+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;
+}
+
+static Widget motTreeFindUserDataID(Ihandle* ih, WidgetList itemList, int numItems, void* userdata)
+{
+ 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];
+
+ /* 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;
+ }
+ }
+
+ 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;
+}
+
+static void motTreeSetFocusNode(Ihandle* ih, Widget wItem)
+{
+ iupAttribSetStr(ih, "_IUPTREE_LAST_FOCUS", (char*)wItem);
+ XmProcessTraversal(wItem, XmTRAVERSE_CURRENT);
+}
+
+static Widget motTreeGetFocusNode(Ihandle* ih)
+{
+ Widget wItem = XmGetFocusWidget(ih->handle); /* returns the focus in the dialog */
+ if (wItem && XtParent(wItem) == ih->handle) /* is a node */
+ return wItem;
+
+ 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"))
+ return;
+
+ /* usually when one Gadget is selected different than the previous one,
+ leave/enter events are generated. But we could not find the exact condition,
+ so this is a workaround. Some leave events will be lost. */
+ if (evt->type == EnterNotify)
+ {
+ if (iupAttribGet(ih, "_IUPTREE_IGNORE_ENTERLEAVE"))
+ {
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_ENTERLEAVE", NULL);
+ return;
+ }
+ }
+ else if (evt->type == LeaveNotify)
+ {
+ if (iupAttribGet(ih, "_IUPTREE_IGNORE_ENTERLEAVE"))
+ return;
+ }
+
+ iupmotEnterLeaveWindowEvent(w, ih, evt, cont);
+}
+
+static void motTreeFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont)
+{
+ unsigned char selpol;
+ Widget wItem = XmGetFocusWidget(w); /* returns the focus in the dialog */
+ Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM");
+
+ if (XtParent(wItem) == w) /* is a node */
+ iupAttribSetStr(ih, "_IUPTREE_LAST_FOCUS", (char*)wItem);
+
+ if (wItem == NULL || wItem == wRoot)
+ {
+ iupmotFocusChangeEvent(w, ih, evt, cont);
+ return;
+ }
+
+ XtVaGetValues(w, XmNselectionPolicy, &selpol, NULL);
+ if (selpol != XmSINGLE_SELECT)
+ return;
+
+ if (evt->type == FocusIn && !iupStrBoolean(IupGetGlobal("CONTROLKEY")))
+ {
+ XtVaSetValues(w, XmNselectedObjects, NULL, NULL);
+ XtVaSetValues(w, XmNselectedObjectCount, 0, NULL);
+ XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL);
+ }
+}
+
+void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add)
+{
+ Widget wItemPrev = motTreeFindNodeFromString(ih, name_id);
+ Widget wNewItem;
+ XmString itemTitle;
+ motTreeItemData *itemData, *itemDataPrev;
+ Pixel bgcolor, fgcolor;
+ int kindPrev, num_args = 0;
+ Arg args[30];
+
+ if (!wItemPrev)
+ return;
+
+ 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 = (unsigned char)kind;
+
+ itemTitle = XmStringCreateLocalized((String)title);
+
+ /* Get default colors */
+ 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)
+ {
+ /* 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;
+
+ XtVaGetValues(wItemPrev, XmNentryParent, &wItemParent, NULL);
+ XtVaGetValues(wItemPrev, XmNpositionIndex, &pos, NULL);
+
+ iupmotSetArg(args, num_args, XmNentryParent, wItemParent);
+ iupmotSetArg(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);
+
+ 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);
+ }
+ else
+ {
+ iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_collapsed);
+ iupmotSetArg(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);
+ }
+
+
+ wNewItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args);
+
+ if (kind == ITREE_BRANCH)
+ {
+ if (ih->data->add_expanded)
+ {
+ iupAttribSetStr(ih, "_IUP_IGNORE_BRANCHOPEN", "1");
+ XtVaSetValues(wNewItem, XmNoutlineState, XmEXPANDED, NULL);
+ }
+ else
+ XtVaSetValues(wNewItem, XmNoutlineState, XmCOLLAPSED, NULL);
+ }
+
+ /* Root always expanded */
+ XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL);
+
+ XtRealizeWidget(wNewItem);
+ 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);
+ if (!wItem)
+ return 0;
+
+ XtVaGetValues(wItem, XmNuserData, &itemData, NULL);
+ XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL);
+ itemData->image_expanded = (Pixmap)iupImageGetImage(value, ih, 0);
+ if (!itemData->image_expanded)
+ {
+ itemData->image_expanded = XmUNSPECIFIED_PIXMAP;
+ itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP;
+ }
+ else
+ {
+ itemData->image_expanded_mask = (Pixmap)iupImageGetMask(value);
+ if (!itemData->image_expanded_mask) itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP;
+ }
+
+ if (itemData->kind == ITREE_BRANCH && itemState == XmEXPANDED)
+ {
+ if (itemData->image_expanded == XmUNSPECIFIED_PIXMAP)
+ XtVaSetValues(wItem, XmNsmallIconPixmap, (Pixmap)ih->data->def_image_expanded,
+ XmNsmallIconMask, (Pixmap)ih->data->def_image_expanded_mask,
+ NULL);
+ else
+ XtVaSetValues(wItem, XmNsmallIconPixmap, itemData->image_expanded,
+ XmNsmallIconMask, itemData->image_expanded_mask,
+ NULL);
+ }
+
+ return 1;
+}
+
+static int motTreeSetImageAttrib(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->image = (Pixmap)iupImageGetImage(value, ih, 0);
+ if (!itemData->image)
+ {
+ itemData->image = XmUNSPECIFIED_PIXMAP;
+ itemData->image_mask = XmUNSPECIFIED_PIXMAP;
+ }
+ else
+ {
+ itemData->image_mask = (Pixmap)iupImageGetMask(value);
+ if (!itemData->image_mask) itemData->image_mask = XmUNSPECIFIED_PIXMAP;
+ }
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ unsigned char itemState;
+ XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL);
+ if (itemState == XmCOLLAPSED)
+ {
+ if (itemData->image == XmUNSPECIFIED_PIXMAP)
+ XtVaSetValues(wItem, XmNsmallIconPixmap, (Pixmap)ih->data->def_image_collapsed,
+ XmNsmallIconMask, (Pixmap)ih->data->def_image_collapsed_mask,
+ NULL);
+ else
+ XtVaSetValues(wItem, XmNsmallIconPixmap, itemData->image,
+ XmNsmallIconMask, itemData->image_mask,
+ NULL);
+ }
+ }
+ else
+ {
+ if (itemData->image == XmUNSPECIFIED_PIXMAP)
+ XtVaSetValues(wItem, XmNsmallIconPixmap, (Pixmap)ih->data->def_image_leaf,
+ XmNsmallIconMask, (Pixmap)ih->data->def_image_leaf_mask,
+ NULL);
+ else
+ XtVaSetValues(wItem, XmNsmallIconPixmap, itemData->image,
+ XmNsmallIconMask, itemData->image_mask,
+ NULL);
+ }
+
+ return 1;
+}
+
+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)
+ {
+ ih->data->def_image_expanded = (void*)XmUNSPECIFIED_PIXMAP;
+ ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+ else
+ {
+ ih->data->def_image_expanded_mask = iupImageGetMask(value);
+ if (!ih->data->def_image_expanded_mask) ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+
+ /* Update all images, starting at root node */
+ motTreeUpdateImages(ih, &wRoot, 1, 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)
+ {
+ ih->data->def_image_collapsed = (void*)XmUNSPECIFIED_PIXMAP;
+ ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+ else
+ {
+ ih->data->def_image_collapsed_mask = iupImageGetMask(value);
+ if (!ih->data->def_image_collapsed_mask) ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+
+ /* Update all images, starting at root node */
+ motTreeUpdateImages(ih, &wRoot, 1, 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)
+ {
+ ih->data->def_image_leaf = (void*)XmUNSPECIFIED_PIXMAP;
+ ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+ else
+ {
+ ih->data->def_image_leaf_mask = iupImageGetMask(value);
+ if (!ih->data->def_image_leaf_mask) ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+
+ /* Update all images, starting at root node */
+ motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_LEAF);
+
+ return 1;
+}
+
+static char* motTreeGetStateAttrib(Ihandle* ih, const char* name_id)
+{
+ int hasChildren;
+ unsigned char itemState;
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return 0;
+
+ XtVaGetValues(wItem, XmNnumChildren, &hasChildren, NULL);
+ XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL);
+
+ if (hasChildren)
+ {
+ if(itemState == XmEXPANDED)
+ return "EXPANDED";
+ else
+ return "COLLAPSED";
+ }
+
+ return NULL;
+}
+
+static int motTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return 0;
+
+ if (iupStrEqualNoCase(value, "EXPANDED"))
+ XtVaSetValues(wItem, XmNoutlineState, XmEXPANDED, NULL);
+ else
+ XtVaSetValues(wItem, XmNoutlineState, XmCOLLAPSED, NULL);
+
+ return 0;
+}
+
+static char* motTreeGetColorAttrib(Ihandle* ih, const char* name_id)
+{
+ unsigned char r, g, b;
+ Pixel color;
+ char* str;
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return NULL;
+
+ XtVaGetValues(wItem, XmNforeground, &color, NULL);
+ iupmotColorGetRGB(color, &r, &g, &b);
+
+ str = iupStrGetMemory(20);
+ sprintf(str, "%d %d %d", (int)r, (int)g, (int)b);
+ return str;
+}
+
+static int motTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ Pixel color;
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return 0;
+
+ color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ XtVaSetValues(wItem, XmNforeground, color, NULL);
+ return 0;
+}
+
+static char* motTreeGetDepthAttrib(Ihandle* ih, const char* name_id)
+{
+ Widget wRoot;
+ int dep = 0;
+ char* depth;
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return NULL;
+
+ wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM");
+
+ while((wRoot != wItem) && (wItem != NULL))
+ {
+ XtVaGetValues(wItem, XmNentryParent, &wItem, NULL);
+ dep++;
+ }
+
+ depth = iupStrGetMemory(10);
+ sprintf(depth, "%d", dep);
+ return depth;
+}
+
+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 */
+ return 0;
+ wItemSrc = motTreeFindNodeFromString(ih, name_id);
+ if (!wItemSrc)
+ return 0;
+ wItemDst = motTreeFindNodeFromString(ih, value);
+ if (!wItemDst)
+ return 0;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ wParent = wItemDst;
+ while(wParent)
+ {
+ XtVaGetValues(wParent, XmNentryParent, &wParent, NULL);
+ if (wParent == wItemSrc)
+ 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 */
+
+ return 0;
+}
+
+static int motTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ Widget wItemDst, wParent, wItemSrc;
+
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ wItemSrc = motTreeFindNodeFromString(ih, name_id);
+ if (!wItemSrc)
+ return 0;
+ wItemDst = motTreeFindNodeFromString(ih, value);
+ if (!wItemDst)
+ return 0;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ wParent = wItemDst;
+ while(wParent)
+ {
+ XtVaGetValues(wParent, XmNentryParent, &wParent, NULL);
+ if (wParent == wItemSrc)
+ return 0;
+ }
+
+ /* Copying the node and its children to the new position */
+ motTreeCopyNode(ih, wItemSrc, wItemDst, 1);
+
+ return 0;
+}
+
+static char* motTreeGetParentAttrib(Ihandle* ih, const char* name_id)
+{
+ Widget wItemParent;
+ char* str;
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return NULL;
+
+ /* get the parent item */
+ XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL);
+ if (!wItemParent)
+ return NULL;
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", motTreeGetNodeId(ih, wItemParent));
+ return str;
+}
+
+static char* motTreeGetChildCountAttrib(Ihandle* ih, const char* name_id)
+{
+ char* str;
+ WidgetList wList = NULL;
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return NULL;
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", XmContainerGetItemChildren(ih->handle, wItem, &wList));
+ if (wList) XtFree((char*)wList);
+ 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; i<childCount; i++)
+ count += motTreeCount(ih, wList[i]);
+ if (wList) XtFree((char*)wList);
+ return count;
+}
+
+static char* motTreeGetCountAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(10);
+ Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM");
+ sprintf(str, "%d", motTreeCount(ih, wRoot));
+ return str;
+}
+
+static char* motTreeGetKindAttrib(Ihandle* ih, const char* name_id)
+{
+ motTreeItemData *itemData;
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return NULL;
+
+ XtVaGetValues(wItem, XmNuserData, &itemData, NULL);
+
+ if(itemData->kind == ITREE_BRANCH)
+ return "BRANCH";
+ else
+ return "LEAF";
+}
+
+static char* motTreeGetValueAttrib(Ihandle* ih)
+{
+ char* str;
+ Widget wItem = motTreeGetFocusNode(ih);
+ if (!wItem)
+ return "0"; /* default VALUE is root */
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", motTreeGetNodeId(ih, wItem));
+ return str;
+}
+
+static int motTreeSetMarkAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->mark_mode==ITREE_MARK_SINGLE)
+ return 0;
+
+ if(iupStrEqualNoCase(value, "CLEARALL"))
+ motTreeContainerDeselectAll(ih);
+ else if(iupStrEqualNoCase(value, "MARKALL"))
+ motTreeContainerSelectAll(ih);
+ else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */
+ motTreeInvertAllNodeMarking(ih);
+ else if(iupStrEqualPartial(value, "INVERT"))
+ {
+ unsigned char isSelected;
+ Widget wItem = motTreeFindNodeFromString(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);
+ }
+ else if(iupStrEqualNoCase(value, "BLOCK"))
+ {
+ Widget wItem = (Widget)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE");
+ Widget wFocusItem = motTreeGetFocusNode(ih);
+ if(!wFocusItem || !wItem)
+ return 0;
+ motTreeSelectRange(ih, wFocusItem, wItem, 0);
+ }
+ else
+ {
+ Widget wItem1, wItem2;
+ char str1[50], str2[50];
+ if (iupStrToStrStr(value, str1, str2, '-')!=2)
+ return 0;
+
+ wItem1 = motTreeFindNodeFromString(ih, str1);
+ if (!wItem1)
+ return 0;
+ wItem2 = motTreeFindNodeFromString(ih, str2);
+ if (!wItem2)
+ return 0;
+
+ motTreeSelectRange(ih, wItem1, wItem2, 0);
+ }
+
+ return 1;
+}
+
+static int motTreeSetValueAttrib(Ihandle* ih, const char* value)
+{
+ Widget wRoot, wItem;
+
+ if (motTreeSetMarkAttrib(ih, value))
+ return 0;
+
+ wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM");
+
+ if (iupStrEqualNoCase(value, "ROOT"))
+ wItem = wRoot;
+ else if(iupStrEqualNoCase(value, "LAST"))
+ wItem = motTreeGetLastVisibleNode(ih, wRoot);
+ else if(iupStrEqualNoCase(value, "PGUP"))
+ {
+ Widget wItemFocus = motTreeGetFocusNode(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);
+ }
+ else if(iupStrEqualNoCase(value, "PGDN"))
+ {
+ Widget wNext, wItemFocus;
+
+ wItemFocus = motTreeGetFocusNode(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;
+ }
+ else if(iupStrEqualNoCase(value, "NEXT"))
+ {
+ Widget wItemFocus = motTreeGetFocusNode(ih);
+ if (!wItemFocus)
+ return 0;
+
+ wItem = motTreeGetNextVisibleNode(ih, wRoot, wItemFocus);
+ }
+ else if(iupStrEqualNoCase(value, "PREVIOUS"))
+ {
+ Widget wItemFocus = motTreeGetFocusNode(ih);
+ if(!wItemFocus)
+ return 0;
+
+ wItem = motTreeGetPreviousVisibleNode(ih, wRoot, wItemFocus);
+ }
+ else
+ wItem = motTreeFindNodeFromString(ih, value);
+
+ if (!wItem)
+ return 0;
+
+ /* select */
+ if (ih->data->mark_mode==ITREE_MARK_SINGLE)
+ {
+ /* clear previous selection */
+ XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL);
+ XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL);
+
+ XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL);
+ }
+
+ /* set focus (will scroll to visible) */
+ motTreeSetFocusNode(ih, wItem);
+
+ iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", motTreeGetNodeId(ih, wItem));
+
+ return 0;
+}
+
+static int motTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id)
+{
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return 0;
+
+ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)wItem);
+
+ return 1;
+}
+
+static char* motTreeGetMarkedAttrib(Ihandle* ih, const char* name_id)
+{
+ unsigned char isSelected;
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return NULL;
+
+ XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL);
+
+ if(isSelected == XmSELECTED)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int motTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return 0;
+
+ if (iupStrBoolean(value))
+ XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL);
+ else
+ XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL);
+
+ return 0;
+}
+
+static char* motTreeGetTitle(Widget wItem)
+{
+ char *title;
+ XmString itemTitle;
+ XtVaGetValues(wItem, XmNlabelString, &itemTitle, NULL);
+ title = iupmotConvertString(itemTitle);
+ XmStringFree(itemTitle);
+ return title;
+}
+
+static char* motTreeGetTitleAttrib(Ihandle* ih, const char* name_id)
+{
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return NULL;
+ return motTreeGetTitle(wItem);
+}
+
+static int motTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return 0;
+
+ iupmotSetString(wItem, XmNlabelString, value);
+
+ return 0;
+}
+
+static int motTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ XmFontList fontlist = NULL;
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return 0;
+
+ if (value)
+ {
+ char attr[20];
+ sprintf(attr, "TITLEFOUNDRY%s", name_id);
+ fontlist = iupmotGetFontList(iupAttribGet(ih, attr), value);
+ }
+ XtVaSetValues(wItem, XmNrenderTable, fontlist, NULL);
+
+ return 0;
+}
+
+static char* motTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id)
+{
+ XmFontList fontlist;
+ Widget wItem = motTreeFindNodeFromString(ih, name_id);
+ if (!wItem)
+ return NULL;
+
+ XtVaGetValues(wItem, XmNrenderTable, &fontlist, NULL);
+ 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));
+ 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 int motTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */
+ {
+ 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 */
+ return 0;
+
+ /* deleting the specified node (and it's children) */
+ motTreeRemoveNode(ih, wItem, 1);
+ }
+ else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */
+ {
+ Widget wItem = motTreeFindNodeFromString(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);
+ }
+ }
+ 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 ok = XmIsIconGadget(wSelectedItemList[i]);
+ if ((wSelectedItemList[i] != wRoot) && ok) /* the root node can't be deleted */
+ motTreeRemoveNode(ih, wSelectedItemList[i], 1);
+ }
+ }
+
+ return 0;
+}
+
+static char* motTreeGetIndentationAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(255);
+ Dimension indent;
+ XtVaGetValues(ih->handle, XmNoutlineIndentation, &indent, NULL);
+ sprintf(str, "%d", (int)indent);
+ return str;
+}
+
+static int motTreeSetIndentationAttrib(Ihandle* ih, const char* value)
+{
+ int indent;
+ if (iupStrToInt(value, &indent))
+ XtVaSetValues(ih->handle, XmNoutlineIndentation, (Dimension)indent, NULL);
+ return 0;
+}
+
+static int motTreeSetTopItemAttrib(Ihandle* ih, const char* value)
+{
+ Widget wItem = motTreeFindNodeFromString(ih, value);
+ Widget sb_win;
+ Widget wItemParent;
+
+ if (!wItem)
+ return 0;
+
+ /* expand all parents */
+ XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL);
+ while(wItemParent)
+ {
+ XtVaSetValues(wItemParent, XmNoutlineState, XmEXPANDED, NULL);
+ XtVaGetValues(wItemParent, XmNentryParent, &wItemParent, NULL);
+ }
+
+ sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ XmScrollVisible(sb_win, wItem, 0, 0);
+
+ return 0;
+}
+
+static int motTreeSpacingFunc(Ihandle* ih, Widget wItem, void *data)
+{
+ XtVaSetValues(wItem, XmNmarginHeight, ih->data->spacing, NULL);
+ (void)data;
+ return 1;
+}
+
+static int motTreeSetSpacingAttrib(Ihandle* ih, const char* value)
+{
+ if (!iupStrToInt(value, &ih->data->spacing))
+ ih->data->spacing = 1;
+
+ if (ih->data->spacing < 1)
+ ih->data->spacing = 1;
+
+ if (ih->handle)
+ {
+ motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSpacingFunc, 0);
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int motTreeSetExpandAllAttrib(Ihandle* ih, const char* value)
+{
+ Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM");
+
+ if (iupStrBoolean(value))
+ motTreeExpandCollapseAllNodes(ih, &wRoot, 1, XmEXPANDED);
+ else
+ {
+ motTreeExpandCollapseAllNodes(ih, &wRoot, 1, XmCOLLAPSED);
+
+ /* The root node is always expanded */
+ XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL);
+ }
+
+ return 0;
+}
+
+static int motTreeSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ Pixel color;
+
+ /* ignore given value for the scrollbars, must use only from parent */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ color = iupmotColorGetPixelStr(parent_value);
+ if (color != (Pixel)-1)
+ {
+ Widget sb = NULL;
+
+ iupmotSetBgColor(sb_win, color);
+
+ XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL);
+ if (sb) iupmotSetBgColor(sb, color);
+
+ XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL);
+ if (sb) iupmotSetBgColor(sb, color);
+ }
+
+ 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);
+ }
+
+ iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */
+
+ /* update internal image cache */
+ iupTreeUpdateImages(ih);
+
+ return 1;
+}
+
+static int motTreeSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ XtVaSetValues(ih->handle, XmNforeground, color, NULL);
+
+ return 1;
+}
+
+void iupdrvTreeUpdateMarkMode(Ihandle *ih)
+{
+ XtVaSetValues(ih->handle, XmNselectionPolicy, (ih->data->mark_mode==ITREE_MARK_SINGLE)? XmSINGLE_SELECT: XmEXTENDED_SELECT, NULL);
+}
+
+/************************************************************************************************/
+
+
+static void motTreeSetRenameCaretPos(Widget cbEdit, const char* value)
+{
+ int pos = 1;
+
+ if (iupStrToInt(value, &pos))
+ {
+ if (pos < 1) pos = 1;
+ pos--; /* IUP starts at 1 */
+
+ XtVaSetValues(cbEdit, XmNcursorPosition, pos, NULL);
+ }
+}
+
+static void motTreeSetRenameSelectionPos(Widget cbEdit, const char* value)
+{
+ int start = 1, end = 1;
+
+ if (iupStrToIntInt(value, &start, &end, ':') != 2)
+ return;
+
+ if(start < 1 || end < 1)
+ return;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ XmTextSetSelection(cbEdit, start, end, CurrentTime);
+}
+
+/*****************************************************************************/
+
+static int motTreeCallBranchCloseCb(Ihandle* ih, Widget wItem)
+{
+ IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB");
+
+ if(cbBranchClose)
+ return cbBranchClose(ih, motTreeGetNodeId(ih, wItem));
+
+ return IUP_DEFAULT;
+}
+
+static int motTreeCallBranchOpenCb(Ihandle* ih, Widget wItem)
+{
+ IFni cbBranchOpen;
+
+ if (iupAttribGet(ih, "_IUP_IGNORE_BRANCHOPEN"))
+ {
+ iupAttribSetStr(ih, "_IUP_IGNORE_BRANCHOPEN", NULL);
+ return IUP_DEFAULT;
+ }
+
+ cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB");
+ if (cbBranchOpen)
+ return cbBranchOpen(ih, motTreeGetNodeId(ih, wItem));
+
+ return IUP_DEFAULT;
+}
+
+static void motTreeCallMultiSelectionCb(Ihandle* ih)
+{
+ IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB");
+ IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB");
+ WidgetList wSelectedItemList = NULL;
+ Widget wRoot;
+ int countItems;
+
+ wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM");
+
+ XtVaGetValues(ih->handle, XmNselectedObjects, &wSelectedItemList,
+ XmNselectedObjectCount, &countItems, NULL);
+ if (countItems == 0)
+ return;
+
+ if (cbMulti || cbSelec)
+ {
+ int* id_rowItem = malloc(sizeof(int) * countItems);
+ int i = 0;
+
+ for(i = 0; i < countItems; i++)
+ id_rowItem[i] = motTreeGetNodeId(ih, wSelectedItemList[i]);
+
+ if (cbMulti)
+ cbMulti(ih, id_rowItem, countItems);
+ else
+ {
+ for (i=0; i<countItems; i++)
+ cbSelec(ih, id_rowItem[i], 1);
+ }
+
+ free(id_rowItem);
+ }
+}
+
+static int motTreeConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ Widget wItem = XmObjectAtPoint(ih->handle, (Position)x, (Position)y);
+ if (wItem)
+ return motTreeGetNodeId(ih, wItem);
+ return -1;
+}
+
+static void motTreeCallRightClickCb(Ihandle* ih, int x, int y)
+{
+ IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB");
+ if (cbRightClick)
+ {
+ int id = motTreeConvertXYToPos(ih, x, y);
+ if (id != -1)
+ cbRightClick(ih, id);
+ }
+}
+
+static void motTreeCallRenameCb(Ihandle* ih)
+{
+ IFnis cbRename;
+ Widget wItem, wEdit;
+ int ignore = 0;
+ String title = NULL;
+
+ wItem = (Widget)iupAttribGet(ih, "_IUPTREE_SELECTED");
+ wEdit = (Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD");
+
+ XtVaGetValues((Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD"), XmNvalue, &title, NULL);
+
+ cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB");
+ if (cbRename)
+ {
+ if (cbRename(ih, motTreeGetNodeId(ih, wItem), title) == IUP_IGNORE)
+ ignore = 1;
+ }
+
+ if (!ignore)
+ iupmotSetString(wItem, XmNlabelString, title);
+
+ XtDestroyWidget(wEdit);
+
+ iupAttribSetStr(ih, "_IUPTREE_EDITFIELD", NULL);
+ iupAttribSetStr(ih, "_IUPTREE_SELECTED", NULL);
+}
+
+static int motTreeCallDragDropCb(Ihandle* ih, Widget wItemDrag, Widget wItemDrop, int *is_ctrl)
+{
+ IFniiii cbDragDrop = (IFniiii)IupGetCallback(ih, "DRAGDROP_CB");
+ int is_shift = 0;
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[0] == 'S')
+ is_shift = 1;
+ if (key[1] == 'C')
+ *is_ctrl = 1;
+ else
+ *is_ctrl = 0;
+
+ if (cbDragDrop)
+ {
+ int drag_id = motTreeGetNodeId(ih, wItemDrag);
+ int drop_id = motTreeGetNodeId(ih, wItemDrop);
+ return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl);
+ }
+
+ return IUP_CONTINUE; /* allow to move by default if callback not defined */
+}
+
+static void motTreeEditFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont)
+{
+ if (evt->type == FocusOut)
+ motTreeCallRenameCb(ih);
+
+ (void)cont;
+ (void)w;
+}
+
+static void motTreeEditKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont)
+{
+ KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0);
+ if (motcode == XK_Return)
+ {
+ Widget wItem = (Widget)iupAttribGet(ih, "_IUPTREE_SELECTED");
+ motTreeCallRenameCb(ih);
+ motTreeSetFocusNode(ih, wItem);
+ }
+ else if (motcode == XK_Escape)
+ {
+ Widget wEdit = (Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD");
+ Widget wItem = (Widget)iupAttribGet(ih, "_IUPTREE_SELECTED");
+
+ XtDestroyWidget(wEdit);
+ motTreeSetFocusNode(ih, wItem);
+
+ iupAttribSetStr(ih, "_IUPTREE_EDITFIELD", NULL);
+ iupAttribSetStr(ih, "_IUPTREE_SELECTED", NULL);
+ }
+
+ (void)cont;
+ (void)w;
+}
+
+static void motTreeScrollbarOffset(Widget sb_win, Position *x, Position *y)
+{
+ Widget sb_horiz, sb_vert;
+ XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb_horiz, NULL);
+ if (sb_horiz)
+ {
+ int pos;
+ XtVaGetValues(sb_horiz, XmNvalue, &pos, NULL);
+ *x = *x - (Position)pos;
+ }
+ XtVaGetValues(sb_win, XmNverticalScrollBar, &sb_vert, NULL);
+ if (sb_vert)
+ {
+ int pos;
+ XtVaGetValues(sb_vert, XmNvalue, &pos, NULL);
+ *y = *y - (Position)pos;
+ }
+}
+
+static void motTreeShowEditField(Ihandle* ih, Widget wItem)
+{
+ int num_args = 0, w_img = 0;
+ Arg args[30];
+ Position x, y;
+ Dimension w, h;
+ char* child_id = iupDialogGetChildIdStr(ih);
+ Widget cbEdit;
+ XmString title;
+ char* value;
+ Pixel color;
+ Pixmap image = XmUNSPECIFIED_PIXMAP;
+ XmFontList fontlist;
+ Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+
+ XtVaGetValues(wItem, XmNx, &x,
+ XmNy, &y,
+ XmNwidth, &w,
+ XmNheight, &h,
+ XmNlabelString, &title,
+ XmNsmallIconPixmap, &image,
+ XmNforeground, &color,
+ XmNrenderTable, &fontlist,
+ NULL);
+
+ motTreeScrollbarOffset(sb_win, &x, &y);
+ 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);
+
+ cbEdit = XtCreateManagedWidget(
+ child_id, /* child identifier */
+ xmTextWidgetClass, /* widget class */
+ sb_win,
+ args, num_args);
+
+ /* Disable Drag Source */
+ iupmotDisableDragSource(cbEdit);
+
+ XtAddEventHandler(cbEdit, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(cbEdit, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(cbEdit, FocusChangeMask, False, (XtEventHandler)motTreeEditFocusChangeEvent, (XtPointer)ih);
+ XtAddEventHandler(cbEdit, KeyPressMask, False, (XtEventHandler)motTreeEditKeyPressEvent, (XtPointer)ih);
+
+ iupAttribSetStr(ih, "_IUPTREE_SELECTED", (char*)wItem);
+ iupAttribSetStr(ih, "_IUPTREE_EDITFIELD", (char*)cbEdit);
+
+ XmProcessTraversal(cbEdit, XmTRAVERSE_CURRENT);
+
+ XmTextSetSelection(cbEdit, (XmTextPosition)0, (XmTextPosition)XmTextGetLastPosition(cbEdit), CurrentTime);
+
+ value = iupAttribGetStr(ih, "RENAMECARET");
+ if (value)
+ motTreeSetRenameCaretPos(cbEdit, value);
+
+ value = iupAttribGetStr(ih, "RENAMESELECTION");
+ if (value)
+ motTreeSetRenameSelectionPos(cbEdit, value);
+
+ /* the parents callbacks can be called while editing
+ so we must avoid their processing if _IUPTREE_EDITFIELD is defined. */
+}
+
+static void motTreeSelectionCallback(Widget w, Ihandle* ih, XmContainerSelectCallbackStruct *nptr)
+{
+ IFnii cbSelec;
+ int is_ctrl = 0;
+ (void)w;
+ (void)nptr;
+
+printf("SelectionCallback(%d)\n", nptr->selected_item_count);
+
+ if (ih->data->mark_mode == ITREE_MARK_MULTIPLE)
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[0] == 'S')
+ return;
+ else if (key[1] == 'C')
+ is_ctrl = 1;
+
+ if (nptr->selected_item_count>1 && !is_ctrl)
+ {
+ if (IupGetCallback(ih, "MULTISELECTION_CB"))
+ {
+ if (nptr->auto_selection_type==XmAUTO_NO_CHANGE)
+ motTreeCallMultiSelectionCb(ih);
+ }
+ else
+ {
+ if (nptr->auto_selection_type==XmAUTO_MOTION)
+ motTreeCallMultiSelectionCb(ih);
+ }
+ return;
+ }
+ }
+
+ cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB");
+ if (cbSelec)
+ {
+ Widget wItemFocus = motTreeGetFocusNode(ih);
+ int curpos = motTreeGetNodeId(ih, wItemFocus);
+ if (is_ctrl)
+ {
+ unsigned char isSelected;
+ XtVaGetValues(wItemFocus, XmNvisualEmphasis, &isSelected, NULL);
+ cbSelec(ih, curpos, isSelected == XmSELECTED? 1: 0);
+ }
+ else
+ {
+ int oldpos = iupAttribGetInt(ih, "_IUPTREE_OLDVALUE");
+ if (oldpos != curpos)
+ {
+ cbSelec(ih, oldpos, 0); /* unselected */
+ cbSelec(ih, curpos, 1); /* selected */
+
+ iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", curpos);
+ }
+ }
+ }
+}
+
+static void motTreeDefaultActionCallback(Widget w, Ihandle* ih, XmContainerSelectCallbackStruct *nptr)
+{
+ unsigned char itemState;
+ WidgetList wSelectedItemList = NULL;
+ int countItems;
+ motTreeItemData *itemData;
+ Widget wItem;
+ (void)w;
+
+ wSelectedItemList = nptr->selected_items;
+ countItems = nptr->selected_item_count;
+
+ if (!countItems || (Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD"))
+ return;
+
+ /* this works also when using multiple selection */
+ wItem = wSelectedItemList[0];
+
+ XtVaGetValues(wItem, XmNoutlineState, &itemState,
+ XmNuserData, &itemData, NULL);
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ if (itemState == XmEXPANDED)
+ XtVaSetValues(wItem, XmNoutlineState, XmCOLLAPSED, NULL);
+ else
+ XtVaSetValues(wItem, XmNoutlineState, XmEXPANDED, NULL);
+ }
+ else
+ {
+ IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB");
+ if (cbExecuteLeaf)
+ cbExecuteLeaf(ih, motTreeGetNodeId(ih, wItem));
+ }
+}
+
+static void motTreeOutlineChangedCallback(Widget w, Ihandle* ih, XmContainerOutlineCallbackStruct *nptr)
+{
+ motTreeItemData *itemData;
+ XtVaGetValues(nptr->item, XmNuserData, &itemData, NULL);
+
+ if (nptr->reason == XmCR_EXPANDED)
+ {
+ if (motTreeCallBranchOpenCb(ih, nptr->item) == IUP_IGNORE)
+ nptr->new_outline_state = XmCOLLAPSED; /* prevent the change */
+ else
+ {
+ XtVaSetValues(nptr->item, XmNsmallIconPixmap, (itemData->image_expanded!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded: (Pixmap)ih->data->def_image_expanded, NULL);
+ XtVaSetValues(nptr->item, XmNsmallIconMask, (itemData->image_expanded_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded_mask: (Pixmap)ih->data->def_image_expanded_mask, NULL);
+ }
+ }
+ else if (nptr->reason == XmCR_COLLAPSED)
+ {
+ if (motTreeCallBranchCloseCb(ih, nptr->item) == IUP_IGNORE)
+ nptr->new_outline_state = XmEXPANDED; /* prevent the change */
+ else
+ {
+ XtVaSetValues(nptr->item, XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_collapsed, NULL);
+ XtVaSetValues(nptr->item, XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_collapsed_mask, NULL);
+ }
+ }
+
+ (void)w;
+}
+
+static void motTreeTraverseObscuredCallback(Widget widget, Ihandle* ih, XmTraverseObscuredCallbackStruct *cbs)
+{
+ (void)ih;
+ /* allow to do automatic scroll when navigating in the tree */
+ XmScrollVisible(widget, cbs->traversal_destination, 10, 10);
+}
+
+static void motTreeKeyReleaseEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont)
+{
+ KeySym motcode;
+
+ if (iupAttribGet(ih, "_IUPTREE_EDITFIELD"))
+ return;
+
+ motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0);
+ if (motcode == XK_Down || motcode == XK_U || motcode == XK_Home || motcode == XK_End)
+ {
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & ShiftMask))
+ motTreeCallMultiSelectionCb(ih);
+ }
+
+ (void)w;
+ (void)cont;
+}
+
+static void motTreeKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont)
+{
+ KeySym motcode;
+
+ if (iupAttribGet(ih, "_IUPTREE_EDITFIELD"))
+ return;
+
+ *cont = True;
+ iupmotKeyPressEvent(w, ih, (XEvent*)evt, cont);
+ if (*cont == False)
+ return;
+
+ motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0);
+ if (motcode == XK_F2)
+ motTreeSetRenameAttrib(ih, NULL);
+ else if (motcode == XK_F1)
+ 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);
+
+ /* Ctrl+Arrows move only focus */
+ if (motcode == XK_Down)
+ wItem = motTreeGetNextVisibleNode(ih, wRoot, wItemFocus);
+ else
+ wItem = motTreeGetPreviousVisibleNode(ih, wRoot, wItemFocus);
+
+ motTreeSetFocusNode(ih, wItem);
+ *cont = False;
+ }
+ else if(motcode == XK_Home || motcode == XK_End)
+ {
+ Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM");
+ Widget wItem;
+
+ /* Not processed by Motif */
+
+ if (motcode == XK_Home)
+ wItem = wRoot;
+ else
+ wItem = motTreeGetLastVisibleNode(ih, wRoot);
+
+ /* Ctrl+Arrows move only focus */
+ if (!(evt->state & ControlMask))
+ {
+ /* Shift+Arrows select block */
+ if (evt->state & ShiftMask)
+ {
+ Widget wItemFocus = motTreeGetFocusNode(ih);
+ if (!wItemFocus)
+ return;
+ motTreeSelectRange(ih, wItemFocus, wItem, 1);
+ }
+ else
+ {
+ /* clear previous selection */
+ XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL);
+ XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL);
+
+ XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL);
+ }
+ }
+
+ motTreeSetFocusNode(ih, wItem);
+ *cont = False;
+ }
+ else if(motcode == XK_space && (evt->state & ControlMask))
+ {
+ Widget wItemFocus = motTreeGetFocusNode(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);
+ }
+ }
+}
+
+static void motTreeButtonEvent(Widget w, Ihandle* ih, XButtonEvent* evt, Boolean* cont)
+{
+ (void)w;
+ (void)cont;
+
+ if (iupAttribGet(ih, "_IUPTREE_EDITFIELD"))
+ return;
+
+ *cont = True;
+ iupmotButtonPressReleaseEvent(w, ih, (XEvent*)evt, cont);
+ if (*cont == False)
+ return;
+
+ if (evt->type==ButtonPress)
+ {
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_ENTERLEAVE", "1");
+
+ if (evt->button==Button1)
+ {
+ Widget wItemFocus = motTreeGetFocusNode(ih);
+ static Widget wLastItem = NULL;
+ static Time last = 0;
+ int clicktwice = 0, doubleclicktime = XtGetMultiClickTime(iupmot_display);
+ int elapsed = (int)(evt->time - last);
+ last = evt->time;
+
+ /* stay away from double click and leave some room for clicks */
+ if (elapsed > (3*doubleclicktime)/2 && elapsed <= 3*doubleclicktime)
+ clicktwice = 1;
+
+ if (clicktwice && wLastItem && wLastItem==wItemFocus)
+ {
+ motTreeSetRenameAttrib(ih, NULL);
+ *cont = False;
+ }
+ wLastItem = wItemFocus;
+ }
+ else if (evt->button==Button3)
+ motTreeCallRightClickCb(ih, evt->x, evt->y);
+ }
+ else if (evt->type==ButtonRelease)
+ {
+ if (evt->button==Button1)
+ {
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & ShiftMask))
+ motTreeCallMultiSelectionCb(ih);
+ }
+ }
+}
+
+static void motTreeTransferProc(Widget drop_context, XtPointer client_data, Atom *seltype, Atom *type, XtPointer value, unsigned long *length, int format)
+{
+ Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False);
+ Widget wItemDrop = (Widget)client_data;
+ Widget wItemDrag = (Widget)value;
+
+ if (*type == atomTreeItem)
+ {
+ Widget wParent;
+ Ihandle* ih = NULL;
+ int is_ctrl;
+
+ if (!wItemDrop || wItemDrag == wItemDrop)
+ return;
+
+ wParent = wItemDrop;
+ while(wParent)
+ {
+ XtVaGetValues(wParent, XmNentryParent, &wParent, NULL);
+ if (wParent == wItemDrag)
+ return;
+ }
+
+ XtVaGetValues(XtParent(wItemDrag), XmNuserData, &ih, NULL);
+
+ 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);
+
+ if (!is_ctrl)
+ {
+ /* 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);
+
+ motTreeSetFocusNode(ih, wNewItem);
+ }
+ }
+
+ (void)drop_context;
+ (void)seltype;
+ (void)format;
+ (void)length;
+}
+
+static void motTreeDropProc(Widget w, XtPointer client_data, XmDropProcCallbackStruct* drop_data)
+{
+ Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False);
+ XmDropTransferEntryRec transferList[2];
+ Arg args[10];
+ int i, num_args = 0;
+ Widget wItemDrop, drop_context;
+ Cardinal numExportTargets;
+ Atom *exportTargets;
+ Boolean found = False;
+ (void)client_data;
+
+ drop_context = drop_data->dragContext;
+
+ /* retrieve the data targets */
+ iupmotSetArg(args, num_args, XmNexportTargets, &exportTargets);
+ iupmotSetArg(args, num_args, XmNnumExportTargets, &numExportTargets);
+ XtGetValues(drop_context, args, num_args);
+
+ for (i = 0; i < (int)numExportTargets; i++)
+ {
+ if (exportTargets[i] == atomTreeItem)
+ {
+ found = True;
+ break;
+ }
+ }
+
+ wItemDrop = XmObjectAtPoint(w, drop_data->x, drop_data->y);
+ if (!wItemDrop)
+ found = False;
+
+ 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);
+ }
+ 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);
+ }
+
+ XmDropTransferStart(drop_context, args, num_args);
+}
+
+static void motTreeDragDropFinishCallback(Widget drop_context, XtPointer client_data, XtPointer call_data)
+{
+ Widget source_icon = NULL;
+ XtVaGetValues(drop_context, XmNsourceCursorIcon, &source_icon, NULL);
+ if (source_icon)
+ XtDestroyWidget(source_icon);
+ (void)call_data;
+ (void)client_data;
+}
+
+static void motTreeDragMotionCallback(Widget drop_context, Widget wItemDrag, XmDragMotionCallbackStruct* drag_motion)
+{
+ Ihandle* ih = NULL;
+ XtVaGetValues(XtParent(wItemDrag), XmNuserData, &ih, NULL);
+ if (!iupAttribGet(ih, "NODRAGFEEDBACK"))
+ {
+ Widget wItem;
+ int x = drag_motion->x;
+ int y = drag_motion->y;
+ iupdrvScreenToClient(ih, &x, &y);
+ wItem = XmObjectAtPoint(ih->handle, (Position)x, (Position)y);
+ if (wItem)
+ {
+ XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL);
+ XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL);
+ XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL);
+ }
+ }
+ (void)drop_context;
+}
+
+static Boolean motTreeConvertProc(Widget drop_context, Atom *selection, Atom *target, Atom *type_return,
+ XtPointer *value_return, unsigned long *length_return, int *format_return)
+{
+ Atom atomMotifDrop = XInternAtom(iupmot_display, "_MOTIF_DROP", False);
+ Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False);
+ Widget wItemDrag = NULL;
+
+ /* check if we are dealing with a drop */
+ if (*selection != atomMotifDrop || *target != atomTreeItem)
+ return False;
+
+ XtVaGetValues(drop_context, XmNclientData, &wItemDrag, NULL);
+ if (!wItemDrag)
+ return False;
+
+ /* format the value for transfer */
+ *type_return = atomTreeItem;
+ *value_return = (XtPointer)wItemDrag;
+ *length_return = 1;
+ *format_return = 32;
+ return True;
+}
+
+static void motTreeStartDrag(Widget w, XButtonEvent* evt, String* params, Cardinal* num_params)
+{
+ Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False);
+ Atom exportList[1];
+ Widget drag_icon, drop_context;
+ Pixmap pixmap = 0, mask = 0;
+ int num_args = 0;
+ Arg args[40];
+ Pixel fg, bg;
+ Widget wItemDrag = XmObjectAtPoint(w, (Position)evt->x, (Position)evt->y);
+ if (!wItemDrag)
+ return;
+
+ XtVaGetValues(wItemDrag, XmNsmallIconPixmap, &pixmap,
+ XmNsmallIconMask, &mask,
+ XmNbackground, &bg,
+ XmNforeground, &fg,
+ NULL);
+
+ iupmotSetArg(args, num_args, XmNpixmap, pixmap);
+ iupmotSetArg(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);
+
+ /* start the drag and register a callback to clean up when done */
+ drop_context = XmDragStart(w, (XEvent*)evt, args, num_args);
+ XtAddCallback(drop_context, XmNdragDropFinishCallback, (XtCallbackProc)motTreeDragDropFinishCallback, NULL);
+ XtAddCallback(drop_context, XmNdragMotionCallback, (XtCallbackProc)motTreeDragMotionCallback, (XtPointer)wItemDrag);
+
+ (void)params;
+ (void)num_params;
+}
+
+static void motTreeEnableDragDrop(Widget w)
+{
+ Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False);
+ Atom importList[1];
+ Arg args[40];
+ int num_args = 0;
+ char dragTranslations[] = "#override <Btn2Down>: StartDrag()";
+ static int do_rec = 0;
+ if (!do_rec)
+ {
+ XtActionsRec rec = {"StartDrag", (XtActionProc)motTreeStartDrag};
+ XtAppAddActions(iupmot_appcontext, &rec, 1);
+ do_rec = 1;
+ }
+ 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);
+ XmDropSiteUpdate(w, args, num_args);
+
+ XtVaSetValues(XmGetXmDisplay(iupmot_display), XmNenableDragIcon, True, NULL);
+}
+
+static int motTreeMapMethod(Ihandle* ih)
+{
+ int num_args = 0;
+ Arg args[40];
+ Widget parent = iupChildTreeGetNativeParentHandle(ih);
+ char* child_id = iupDialogGetChildIdStr(ih);
+ Widget sb_win;
+
+ /******************************/
+ /* 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);
+
+ sb_win = XtCreateManagedWidget(
+ child_id, /* child identifier */
+ xmScrolledWindowWidgetClass, /* widget class */
+ parent, /* widget parent */
+ args, num_args);
+
+ if (!sb_win)
+ return IUP_ERROR;
+
+ XtAddCallback (sb_win, XmNtraverseObscuredCallback, (XtCallbackProc)motTreeTraverseObscuredCallback, (XtPointer)ih);
+
+ parent = sb_win;
+ child_id = "container";
+
+ 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 */
+
+ iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */
+ iupmotSetArg(args, num_args, XmNmarginWidth, 0);
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ iupmotSetArg(args, num_args, XmNtraversalOn, True);
+ else
+ iupmotSetArg(args, num_args, XmNtraversalOn, False);
+
+ iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP);
+ iupmotSetArg(args, num_args, XmNhighlightThickness, 2);
+ iupmotSetArg(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);
+
+ if (iupAttribGetBoolean(ih, "HIDELINES"))
+ iupmotSetArg(args, num_args, XmNoutlineLineStyle, XmNO_LINE);
+ else
+ iupmotSetArg(args, num_args, XmNoutlineLineStyle, XmSINGLE);
+
+ if (iupAttribGetBoolean(ih, "HIDEBUTTONS"))
+ iupmotSetArg(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_ABSENT);
+ else
+ iupmotSetArg(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_PRESENT);
+
+ ih->handle = XtCreateManagedWidget(
+ child_id, /* child identifier */
+ xmContainerWidgetClass, /* widget class */
+ parent, /* widget parent */
+ args, num_args);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupDialogGetChildId(ih); /* must be after using the string */
+
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent);
+
+ XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)motTreeEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)motTreeEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)motTreeFocusChangeEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)motTreeKeyPressEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, KeyReleaseMask, False, (XtEventHandler)motTreeKeyReleaseEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)motTreeButtonEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih);
+
+ /* Callbacks */
+ /* XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); NOT WORKING */
+ XtAddCallback(ih->handle, XmNoutlineChangedCallback, (XtCallbackProc)motTreeOutlineChangedCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNdefaultActionCallback, (XtCallbackProc)motTreeDefaultActionCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motTreeSelectionCallback, (XtPointer)ih);
+
+ XtRealizeWidget(parent);
+
+ if (ih->data->show_dragdrop)
+ {
+ motTreeEnableDragDrop(ih->handle);
+ XtVaSetValues(ih->handle, XmNuserData, ih, NULL); /* to be used in motTreeTransferProc */
+ }
+ else
+ iupmotDisableDragSource(ih->handle);
+
+ /* Force background update before setting the images */
+ {
+ char* value = iupAttribGet(ih, "BGCOLOR");
+ if (value)
+ {
+ motTreeSetBgColorAttrib(ih, value);
+ iupAttribSetStr(ih, "BGCOLOR", NULL);
+ }
+ }
+
+ /* Initialize the default images */
+ ih->data->def_image_leaf = iupImageGetImage("IMGLEAF", ih, 0);
+ if (!ih->data->def_image_leaf)
+ {
+ ih->data->def_image_leaf = (void*)XmUNSPECIFIED_PIXMAP;
+ ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+ else
+ {
+ ih->data->def_image_leaf_mask = iupImageGetMask("IMGLEAF");
+ if (!ih->data->def_image_leaf_mask) ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+
+ ih->data->def_image_collapsed = iupImageGetImage("IMGCOLLAPSED", ih, 0);
+ if (!ih->data->def_image_collapsed)
+ {
+ ih->data->def_image_collapsed = (void*)XmUNSPECIFIED_PIXMAP;
+ ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+ else
+ {
+ ih->data->def_image_collapsed_mask = iupImageGetMask("IMGCOLLAPSED");
+ if (!ih->data->def_image_collapsed_mask) ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+
+ ih->data->def_image_expanded = iupImageGetImage("IMGEXPANDED", ih, 0);
+ if (!ih->data->def_image_expanded)
+ {
+ ih->data->def_image_expanded = (void*)XmUNSPECIFIED_PIXMAP;
+ ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+ else
+ {
+ ih->data->def_image_expanded_mask = iupImageGetMask("IMGEXPANDED");
+ if (!ih->data->def_image_expanded_mask) ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP;
+ }
+
+ motTreeAddRootNode(ih);
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)motTreeConvertXYToPos);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTreeInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motTreeMapMethod;
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motTreeSetBgColorAttrib, "TXTBGCOLOR", NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motTreeSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT);
+
+ /* 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);
+
+ /* IupTree Attributes - IMAGES */
+ iupClassRegisterAttributeId(ic, "IMAGE", NULL, motTreeSetImageAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "IMAGEEXPANDED", NULL, motTreeSetImageExpandedAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "IMAGELEAF", NULL, motTreeSetImageLeafAttrib, IUPAF_SAMEASSYSTEM, "IMGLEAF", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEBRANCHCOLLAPSED", NULL, motTreeSetImageBranchCollapsedAttrib, IUPAF_SAMEASSYSTEM, "IMGCOLLAPSED", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEBRANCHEXPANDED", NULL, motTreeSetImageBranchExpandedAttrib, IUPAF_SAMEASSYSTEM, "IMGEXPANDED", IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - NODES */
+ iupClassRegisterAttributeId(ic, "STATE", motTreeGetStateAttrib, motTreeSetStateAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "DEPTH", motTreeGetDepthAttrib, NULL, IUPAF_READONLY|IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "KIND", motTreeGetKindAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "PARENT", motTreeGetParentAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ 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);
+
+ /* IupTree Attributes - MARKS */
+ iupClassRegisterAttributeId(ic, "MARKED", motTreeGetMarkedAttrib, motTreeSetMarkedAttrib, IUPAF_NO_INHERIT);
+ 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, "VALUE", motTreeGetValueAttrib, motTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - ACTION */
+ iupClassRegisterAttributeId(ic, "DELNODE", NULL, motTreeSetDelNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ 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
new file mode 100755
index 0000000..200d2b4
--- /dev/null
+++ b/iup/src/mot/iupmot_val.c
@@ -0,0 +1,488 @@
+/** \file
+ * \brief Valuator Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <Xm/Xm.h>
+#include <Xm/Scale.h>
+#include <Xm/SeparatoG.h>
+#include <X11/keysym.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_val.h"
+#include "iup_image.h"
+#include "iup_drv.h"
+
+#include "iupmot_drv.h"
+#include "iupmot_color.h"
+
+
+void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h)
+{
+ int ticks_size = 0;
+ if (iupAttribGetInt(ih, "SHOWTICKS"))
+ ticks_size = 8;
+
+ if (ih->data->type == IVAL_HORIZONTAL)
+ {
+ *w = 30;
+ *h = 20+ticks_size;
+ }
+ else
+ {
+ *w = 20+ticks_size;
+ *h = 30;
+ }
+}
+
+static void motValRemoveOldTicks(Widget scale)
+{
+ WidgetList children = (WidgetList)0;
+ Cardinal num_children = (Cardinal)0;
+ Cardinal i;
+ String name;
+
+ XtVaGetValues(scale, XmNchildren, &children,
+ XmNnumChildren, &num_children,
+ NULL);
+
+ for (i = 0; i < num_children; i++)
+ {
+ if (XmIsSeparatorGadget(children[i]))
+ {
+ if ((name = XtName(children[i])) != (String)0)
+ {
+ if ((strcmp(name, "BigTic") == 0) ||
+ (strcmp(name, "MedTic") == 0) ||
+ (strcmp(name, "SmallTic") == 0))
+ {
+ XtDestroyWidget(children[i]);
+ }
+ }
+ }
+ }
+}
+
+static int motValSetShowTicksAttrib(Ihandle* ih, const char* value)
+{
+ int tick_freq, show_ticks;
+
+ if (!ih->data->show_ticks) /* can only set if already not zero */
+ return 0;
+
+ show_ticks = atoi(value);
+ if (show_ticks<2) show_ticks=2;
+ ih->data->show_ticks = show_ticks;
+
+ motValRemoveOldTicks(ih->handle);
+
+ /* Defines the interval frequency for tick marks */
+ tick_freq = SHRT_MAX/(show_ticks-1);
+ XmScaleSetTicks(ih->handle, tick_freq, 0, 0, 8, 0, 0);
+ return 0;
+}
+
+static int motValSetPageStepAttrib(Ihandle* ih, const char* value)
+{
+ int pagesize;
+ ih->data->pagestep = atof(value);
+ pagesize = (int)(ih->data->pagestep*SHRT_MAX);
+ XtVaSetValues(ih->handle, XmNscaleMultiple, pagesize, NULL);
+ return 0; /* do not store value in hash table */
+}
+
+static int motValSetStepAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->step = atof(value);
+ return 0; /* do not store value in hash table */
+}
+
+static int motValSetValueAttrib(Ihandle* ih, const char* value)
+{
+ int ival;
+
+ ih->data->val = atof(value);
+ iupValCropValue(ih);
+
+ ival = (int)(((ih->data->val-ih->data->vmin)/(ih->data->vmax - ih->data->vmin))*SHRT_MAX);
+ XtVaSetValues(ih->handle, XmNvalue, ival, NULL);
+
+ return 0; /* do not store value in hash table */
+}
+
+static int motValSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color;
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ r = (r*8)/10;
+ g = (g*8)/10;
+ b = (b*8)/10;
+
+ color = iupmotColorGetPixel(r, g, b);
+ if (color != (Pixel)-1)
+ {
+ Widget w = XtNameToWidget(ih->handle, "*Scrollbar");
+ XtVaSetValues(w, XmNtroughColor, color, NULL);
+ }
+
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+}
+
+static int motValSetBackgroundAttrib(Ihandle* ih, const char* value)
+{
+ Pixel color;
+
+ /* ignore given value, must use only from parent */
+ value = iupAttribGetInheritNativeParent(ih, "BACKGROUND");
+
+ color = iupmotColorGetPixelStr(value);
+ if (color != (Pixel)-1)
+ {
+ XtVaSetValues(ih->handle, XmNbackground, color, NULL);
+ return 1;
+ }
+ else
+ {
+ Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0);
+ if (pixmap)
+ {
+ XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/*********************************************************************************************/
+
+
+static void motValCallAction(Ihandle* ih, int ival, int cb_state)
+{
+ double old_val = ih->data->val;
+ IFn cb;
+
+ ih->data->val = (((double)ival/(double)SHRT_MAX)*(ih->data->vmax - ih->data->vmin)) + ih->data->vmin;
+ iupValCropValue(ih);
+
+ cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB");
+ if (cb)
+ {
+ if (ih->data->val == old_val)
+ return;
+
+ cb(ih);
+ }
+ else
+ {
+ IFnd cb_old;
+ if (cb_state == 0)
+ cb_old = (IFnd) IupGetCallback(ih, "MOUSEMOVE_CB");
+ else if (cb_state == -1)
+ cb_old = (IFnd) IupGetCallback(ih, "BUTTON_RELEASE_CB");
+ else
+ cb_old = (IFnd) IupGetCallback(ih, "BUTTON_PRESS_CB");
+
+ if (cb_old)
+ cb_old(ih, ih->data->val);
+ }
+}
+
+static void motValIncPageValue(Ihandle *ih, int dir)
+{
+ int pagesize, ival;
+ pagesize = (int)(ih->data->pagestep*SHRT_MAX);
+
+ if (ih->data->inverted)
+ dir *= -1;
+
+ XtVaGetValues(ih->handle, XmNvalue, &ival, NULL);
+ ival += dir*pagesize;
+ if (ival < 0) ival = 0;
+ if (ival > SHRT_MAX) ival = SHRT_MAX;
+ XtVaSetValues(ih->handle, XmNvalue, ival, NULL);
+
+ motValCallAction(ih, ival, 1);
+}
+
+static void motValIncLineValue(Ihandle *ih, int dir)
+{
+ int linesize, ival;
+ linesize = (int)(ih->data->step*SHRT_MAX);
+
+ if (ih->data->inverted)
+ dir *= -1;
+
+ XtVaGetValues(ih->handle, XmNvalue, &ival, NULL);
+ ival += dir*linesize;
+ if (ival < 0) ival = 0;
+ if (ival > SHRT_MAX) ival = SHRT_MAX;
+ XtVaSetValues(ih->handle, XmNvalue, ival, NULL);
+
+ motValCallAction(ih, ival, 1);
+}
+
+static void motValKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont)
+{
+ KeySym motcode;
+
+ *cont = True;
+ iupmotKeyPressEvent(w, ih, (XEvent*)evt, cont);
+ if (*cont == False)
+ return;
+
+ motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0);
+
+ /* add missing support for numeric keyboard */
+ /* add missing support for left/right in vertical
+ and up/down in horizontal */
+ if (motcode == XK_Left || motcode == XK_KP_Left ||
+ motcode == XK_Up || motcode == XK_KP_Up)
+ {
+ motValIncLineValue(ih, -1);
+ *cont = False;
+ return;
+ }
+ if (motcode == XK_Right || motcode == XK_KP_Right ||
+ motcode == XK_Down || motcode == XK_KP_Down)
+ {
+ motValIncLineValue(ih, 1);
+ *cont = False;
+ return;
+ }
+ if (motcode == XK_Prior || motcode == XK_KP_Page_Up)
+ {
+ motValIncPageValue(ih, -1);
+ *cont = False;
+ return;
+ }
+ if (motcode == XK_Next || motcode == XK_KP_Page_Down)
+ {
+ motValIncPageValue(ih, 1);
+ *cont = False;
+ return;
+ }
+
+ /* change Home and End default behaviour */
+ if (ih->data->inverted)
+ {
+ if (motcode==XK_Home || motcode==XK_KP_Home)
+ {
+ int ival = SHRT_MAX; /* set to maximum */
+ XtVaSetValues(ih->handle, XmNvalue, ival, NULL);
+ motValCallAction(ih, ival, 1);
+ *cont = False;
+ return;
+ }
+ if (motcode==XK_End || motcode==XK_KP_End)
+ {
+ int ival = 0; /* set to minimum */
+ XtVaSetValues(ih->handle, XmNvalue, ival, NULL);
+ motValCallAction(ih, ival, 1);
+ *cont = False;
+ return;
+ }
+ }
+ else
+ {
+ /* add missing support for numeric keyboard */
+ if (motcode==XK_KP_Home)
+ {
+ int ival = 0; /* set to minimum */
+ XtVaSetValues(ih->handle, XmNvalue, ival, NULL);
+ motValCallAction(ih, ival, 1);
+ *cont = False;
+ return;
+ }
+ if (motcode==XK_KP_End)
+ {
+ int ival = SHRT_MAX; /* set to maximum */
+ XtVaSetValues(ih->handle, XmNvalue, ival, NULL);
+ motValCallAction(ih, ival, 1);
+ *cont = False;
+ return;
+ }
+ }
+}
+
+static void motValValueChangedCallback(Widget w, Ihandle* ih, XmScaleCallbackStruct *cbs)
+{
+ int cb_state = 1;
+
+ if(cbs->reason == XmCR_DRAG)
+ cb_state = 0;
+ else if (cbs->event && (cbs->event->type==ButtonRelease || cbs->event->type==KeyRelease))
+ cb_state = -1;
+
+ motValCallAction(ih, cbs->value, cb_state);
+
+ (void)w;
+}
+
+static void motValButtonPressReleaseEvent(Widget w, Ihandle* ih, XButtonEvent* evt, Boolean* cont)
+{
+ (void)w;
+ (void)cont;
+
+ /* When Button1 is pressed, the Scrollbar loses its focus to the scale,
+ So we avoid calling GETFOCUS/KILLFOCUS.
+ */
+
+ if (evt->type==ButtonPress && evt->button==Button1)
+ {
+ iupAttribSetStr(ih, "_IUPVAL_IGNOREFOCUS", "1");
+ }
+ if (evt->type==ButtonRelease && evt->button==Button1)
+ {
+ iupAttribSetStr(ih, "_IUPVAL_IGNOREFOCUS", NULL);
+ iupAttribSetStr(ih, "_IUPVAL_IGNOREKILLFOCUS", "1");
+ }
+}
+
+static void motValFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont)
+{
+ if (iupAttribGet(ih, "_IUPVAL_IGNOREFOCUS"))
+ return;
+
+ if (evt->type == FocusOut && iupAttribGet(ih, "_IUPVAL_IGNOREKILLFOCUS"))
+ {
+ iupAttribSetStr(ih, "_IUPVAL_IGNOREKILLFOCUS", NULL);
+ return;
+ }
+
+ iupmotFocusChangeEvent(w, ih, evt, cont);
+}
+
+
+/*********************************************************************************************/
+
+
+static int motValMapMethod(Ihandle* ih)
+{
+ int num_args = 0;
+ Arg args[30];
+ 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 */
+ /* Primitive */
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ iupmotSetArg(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);
+ /* 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);
+
+ if (ih->data->type == IVAL_HORIZONTAL)
+ {
+ iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL);
+ if (ih->data->inverted)
+ iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_LEFT);
+ else
+ iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_RIGHT);
+ }
+ else
+ {
+ iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL);
+ if (ih->data->inverted)
+ iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_TOP);
+ else
+ iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_BOTTOM);
+ }
+
+ ih->handle = XtCreateManagedWidget(
+ iupDialogGetChildIdStr(ih), /* child identifier */
+ xmScaleWidgetClass, /* widget class */
+ iupChildTreeGetNativeParentHandle(ih), /* widget parent */
+ args, num_args);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* callbacks */
+ XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+ XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih);
+
+ /* XmScale changes the default behavior of these, must set directly into the scrollbar */
+ /* XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); */
+ /* XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); */
+
+ XtAddCallback(ih->handle, XmNdragCallback, (XtCallbackProc)motValValueChangedCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motValValueChangedCallback, (XtPointer)ih);
+ XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih);
+
+ {
+ Widget sb = XtNameToWidget(ih->handle, "Scrollbar"); /* TODO: Test this in other Motifs */
+ if (sb)
+ {
+ XtAddEventHandler(sb, FocusChangeMask, False, (XtEventHandler)motValFocusChangeEvent, (XtPointer)ih);
+ XtAddEventHandler(sb, KeyPressMask, False, (XtEventHandler)motValKeyPressEvent, (XtPointer)ih);
+ XtAddEventHandler(sb, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)motValButtonPressReleaseEvent, (XtPointer)ih);
+ }
+ }
+
+ /* Ticks can only be created before XtRealizeWidget */
+ show_ticks = iupAttribGetInt(ih, "SHOWTICKS");
+ if (show_ticks)
+ {
+ if (show_ticks<2) show_ticks=2;
+ ih->data->show_ticks = show_ticks; /* non zero value, can be changed later, but not to zero */
+ }
+
+ ih->serial = iupDialogGetChildId(ih); /* must be after using the string */
+
+ /* initialize the widget */
+ XtRealizeWidget(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvValInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motValMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motValSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motValSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+
+ /* IupVal only */
+ iupClassRegisterAttribute(ic, "VALUE", iupValGetValueAttrib, motValSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PAGESTEP", iupValGetPageStepAttrib, motValSetPageStepAttrib, IUPAF_SAMEASSYSTEM, "0.1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWTICKS", iupValGetShowTicksAttrib, motValSetShowTicksAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "STEP", iupValGetStepAttrib, motValSetStepAttrib, IUPAF_SAMEASSYSTEM, "0.01", IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/mot/iupunix_help.c b/iup/src/mot/iupunix_help.c
new file mode 100755
index 0000000..02be1da
--- /dev/null
+++ b/iup/src/mot/iupunix_help.c
@@ -0,0 +1,44 @@
+/** \file
+ * \brief Motif Driver IupHelp
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+
+int IupHelp(const char *url)
+{
+ char *cmd;
+ int ret;
+ char *browser = getenv("IUP_HELPAPP");
+ if (!browser)
+ browser = IupGetGlobal("HELPAPP");
+
+ if (!browser)
+ {
+ char* system = IupGetGlobal("SYSTEM");
+ if (iupStrEqualNoCase(system, "Linux") ||
+ iupStrEqualNoCase(system, "FreeBSD"))
+ browser = "firefox";
+ else if (iupStrEqualNoCase(system, "Darwin"))
+ browser = "safari";
+ else if (iupStrEqualPartial(system, "CYGWIN"))
+ browser = "iexplore";
+ else
+ browser = "netscape";
+ }
+
+ cmd = (char*)malloc(sizeof(char)*(strlen(url)+strlen(browser)+3));
+ sprintf(cmd, "%s %s &", browser, url);
+ ret = system(cmd);
+ free(cmd);
+ if (ret == -1)
+ return -1;
+ return 1;
+}
diff --git a/iup/src/mot/iupunix_info.c b/iup/src/mot/iupunix_info.c
new file mode 100755
index 0000000..b522638
--- /dev/null
+++ b/iup/src/mot/iupunix_info.c
@@ -0,0 +1,305 @@
+/** \file
+ * \brief UNIX System Information
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/stat.h>
+
+/* This module should depend only on IUP core headers
+ and UNIX system headers. NO Motif headers allowed. */
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "iup_str.h"
+#include "iup_drvinfo.h"
+
+
+int iupdrvMakeDirectory(const char* name)
+{
+ mode_t oldmask = umask((mode_t)0);
+ int fail = mkdir(name, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
+ S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ umask (oldmask);
+ if (fail)
+ return 0;
+ return 1;
+}
+
+int iupdrvIsFile(const char* name)
+{
+ struct stat status;
+ if (stat(name, &status) != 0)
+ return 0;
+ if (S_ISDIR(status.st_mode))
+ return 0;
+ return 1;
+}
+
+int iupdrvIsDirectory(const char* name)
+{
+ struct stat status;
+ if (stat(name, &status) != 0)
+ return 0;
+ if (S_ISDIR(status.st_mode))
+ return 1;
+ return 0;
+}
+
+char* iupdrvGetCurrentDirectory(void)
+{
+ size_t size = 256;
+ char *buffer = (char *)malloc(size);
+
+ for (;;)
+ {
+ if (getcwd(buffer, size) != NULL)
+ return buffer;
+
+ if (errno != ERANGE)
+ {
+ free(buffer);
+ return NULL;
+ }
+
+ size += size;
+ buffer = (char *)realloc(buffer, size);
+ }
+
+ return NULL;
+}
+
+int iupdrvSetCurrentDirectory(const char* dir)
+{
+ return chdir(dir) == 0? 1: 0;
+}
+
+int iupdrvGetWindowDecor(void* wnd, int *border, int *caption)
+{
+ XWindowAttributes wa;
+ wa.x = 0; wa.y = 0;
+ XGetWindowAttributes((Display*)iupdrvGetDisplay(), (Window)wnd, &wa);
+ if (wa.x > 0 && wa.y > 0 && wa.y >= wa.x)
+ {
+ *border = wa.x;
+ *caption = wa.y - *border;
+ return 1;
+ }
+
+ *border = 0;
+ *caption = 0;
+
+ return 0;
+}
+
+static int xGetWorkAreaSize(Display* display, int screen, int *width, int *height)
+{
+ /* _NET_WORKAREA, x, y, width, height CARDINAL[][4]/32 */
+ static Atom workarea = 0;
+ Atom type;
+ long *data;
+ int format;
+ unsigned long after, ndata;
+
+ if (!workarea)
+ workarea = XInternAtom(display, "_NET_WORKAREA", False);
+
+ XGetWindowProperty(display, RootWindow(display, screen),
+ workarea, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &ndata,
+ &after, (unsigned char **)&data);
+ if (type != XA_CARDINAL || data == NULL)
+ {
+ if (data) XFree(data);
+ return 0;
+ }
+
+ *width = data[2]; /* get only for the first desktop */
+ *height = data[3];
+
+ XFree(data);
+ return 1;
+}
+
+void iupdrvGetScreenSize(int *width, int *height)
+{
+ Display* display = (Display*)iupdrvGetDisplay();
+ int screen = XDefaultScreen(display);
+ if (!xGetWorkAreaSize(display, screen, width, height))
+ {
+ *width = DisplayWidth(display, screen);
+ *height = DisplayHeight(display, screen);
+ }
+}
+
+void iupdrvGetFullSize(int *width, int *height)
+{
+ Display* display = (Display*)iupdrvGetDisplay();
+ int screen = XDefaultScreen(display);
+ Window root = RootWindow(display, screen);
+ XWindowAttributes wa;
+ XGetWindowAttributes(display, root, &wa);
+ *width = wa.width;
+ *height = wa.height;
+}
+
+static int xCheckVisualInfo(Display* drv_display, int bpp)
+{
+ int nitems;
+ XVisualInfo info, *ret_info;
+
+ info.depth = bpp;
+ ret_info = XGetVisualInfo(drv_display, VisualDepthMask, &info, &nitems);
+ if (ret_info != NULL)
+ {
+ XFree(ret_info);
+ return 1;
+ }
+ return 0;
+}
+
+int iupdrvGetScreenDepth(void)
+{
+ static int first = 1;
+ static int bpp;
+
+ if (first)
+ {
+ Display* drv_display = (Display*)iupdrvGetDisplay();
+
+ if (xCheckVisualInfo(drv_display, 24))
+ {
+ bpp = 24;
+ return bpp;
+ }
+
+ if (xCheckVisualInfo(drv_display, 16))
+ {
+ bpp = 16;
+ return bpp;
+ }
+
+ if (xCheckVisualInfo(drv_display, 8))
+ {
+ bpp = 8;
+ return bpp;
+ }
+
+ if (xCheckVisualInfo(drv_display, 4))
+ {
+ bpp = 4;
+ return bpp;
+ }
+
+ bpp = 2;
+
+ first = 0;
+ }
+
+ return bpp;
+}
+
+void iupdrvGetCursorPos(int *x, int *y)
+{
+ Window root, child;
+ int cx, cy;
+ unsigned int keys;
+ Display* display = (Display*)iupdrvGetDisplay();
+ int screen = XDefaultScreen(display);
+
+ XQueryPointer(display, RootWindow(display, screen),
+ &root, &child, x, y, &cx, &cy, &keys);
+}
+
+static int xCheckModifier(KeyCode* modifiermap, int max_keypermod, int index, const char* keys)
+{
+ int i;
+ for (i = 0; i < max_keypermod; i++)
+ {
+ KeyCode key = modifiermap[max_keypermod * index + i];
+ if (key)
+ {
+ int KeyIndex = key / 8;
+ int KeyMask = 1 << (key % 8);
+ if (keys[KeyIndex] & KeyMask)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void iupdrvGetKeyState(char* key)
+{
+ char keys[32];
+ Display* display = (Display*)iupdrvGetDisplay();
+ XModifierKeymap *modMap = XGetModifierMapping(display);
+ XQueryKeymap(display, keys);
+
+ if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, ShiftMapIndex, keys))
+ key[0] = 'S';
+ else
+ key[0] = ' ';
+ if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, ControlMapIndex, keys))
+ key[1] = 'C';
+ else
+ key[1] = ' ';
+ if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, Mod1MapIndex, keys) ||
+ xCheckModifier(modMap->modifiermap, modMap->max_keypermod, Mod5MapIndex, keys))
+ key[2] = 'A';
+ else
+ key[2] = ' ';
+ if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, Mod4MapIndex, keys))
+ key[3] = 'Y';
+ else
+ key[3] = ' ';
+
+ key[4] = 0;
+
+ XFreeModifiermap(modMap);
+}
+
+char *iupdrvGetSystemName(void)
+{
+ struct utsname un;
+ char *str = iupStrGetMemory(50);
+
+ uname(&un);
+ strcpy(str, un.sysname);
+
+ return str;
+}
+
+char *iupdrvGetSystemVersion(void)
+{
+ struct utsname un;
+ char *str = iupStrGetMemory(60);
+
+ uname(&un);
+ strcpy(str, un.release);
+ strcat(str, ".");
+ strcat(str, un.version);
+
+ return str;
+}
+
+char *iupdrvGetComputerName(void)
+{
+ char* str = iupStrGetMemory(50);
+ gethostname(str, 50);
+ return str;
+}
+
+char *iupdrvGetUserName(void)
+{
+ return (char*)getlogin();
+}
diff --git a/iup/src/win/iupwin_brush.c b/iup/src/win/iupwin_brush.c
new file mode 100755
index 0000000..228e6d4
--- /dev/null
+++ b/iup/src/win/iupwin_brush.c
@@ -0,0 +1,62 @@
+/** \file
+ * \brief Windows Brush Cache
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <windows.h>
+
+#include "iup.h"
+#include "iup_array.h"
+
+#include "iupwin_brush.h"
+
+
+typedef struct _IwinBrush
+{
+ HBRUSH hbrush;
+ COLORREF color;
+} IwinBrush;
+
+static Iarray* win_brushes = NULL;
+
+HBRUSH iupwinBrushGet(COLORREF color)
+{
+ int i, count = iupArrayCount(win_brushes);
+
+ /* If a brush with the desired color already exists... */
+ IwinBrush* brushes = (IwinBrush*)iupArrayGetData(win_brushes);
+ for (i = 0; i < count; i++)
+ {
+ if (brushes[i].color == color)
+ return brushes[i].hbrush;
+ }
+
+ /* If it doesn't exist, it should be created... */
+ brushes = (IwinBrush*)iupArrayInc(win_brushes);
+
+ brushes[i].color = color;
+ brushes[i].hbrush = CreateSolidBrush(color);
+
+ return brushes[i].hbrush;
+}
+
+void iupwinBrushInit(void)
+{
+ win_brushes = iupArrayCreate(50, sizeof(IwinBrush));
+}
+
+void iupwinBrushFinish(void)
+{
+ int i, count = iupArrayCount(win_brushes);
+ IwinBrush* brushes = (IwinBrush*)iupArrayGetData(win_brushes);
+ for (i = 0; i < count; i++)
+ {
+ DeleteObject(brushes[i].hbrush);
+ brushes[i].hbrush = NULL;
+ }
+ iupArrayDestroy(win_brushes);
+}
diff --git a/iup/src/win/iupwin_brush.h b/iup/src/win/iupwin_brush.h
new file mode 100755
index 0000000..463f323
--- /dev/null
+++ b/iup/src/win/iupwin_brush.h
@@ -0,0 +1,26 @@
+/** \file
+ * \brief Windows Brush Cache
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPWIN_BRUSH_H
+#define __IUPWIN_BRUSH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* returns a brush from the brush cache. */
+HBRUSH iupwinBrushGet(COLORREF c);
+
+/* initializes the brush cache */
+void iupwinBrushInit(void);
+void iupwinBrushFinish(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/win/iupwin_button.c b/iup/src/win/iupwin_button.c
new file mode 100755
index 0000000..7f780e3
--- /dev/null
+++ b/iup/src/win/iupwin_button.c
@@ -0,0 +1,715 @@
+/** \file
+ * \brief Button Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_button.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+
+
+#ifndef CDIS_SHOWKEYBOARDCUES
+#define CDIS_SHOWKEYBOARDCUES 0x0200 /* it is defined only when _WIN32_WINNT >= 0x0501 */
+#endif
+
+
+static int winButtonGetBorder(void)
+{
+ return 4;
+}
+
+void iupdrvButtonAddBorders(int *x, int *y)
+{
+ int border_size = winButtonGetBorder()*2;
+ (*x) += border_size;
+ (*y) += border_size;
+}
+
+/****************************************************************/
+
+static int winButtonCalcAlignPosX(int horiz_alignment, int rect_width, int width, int xpad, int shift)
+{
+ int x;
+
+ if (horiz_alignment == IUP_ALIGN_ARIGHT)
+ x = rect_width - (width + 2*xpad);
+ else if (horiz_alignment == IUP_ALIGN_ACENTER)
+ x = (rect_width - (width + 2*xpad))/2;
+ else /* ALEFT */
+ x = 0;
+
+ x += xpad;
+
+ if (shift)
+ x++;
+
+ return x;
+}
+
+static int winButtonCalcAlignPosY(int vert_alignment, int rect_height, int height, int ypad, int shift)
+{
+ int y;
+
+ if (vert_alignment == IUP_ALIGN_ABOTTOM)
+ y = rect_height - (height + 2*ypad);
+ else if (vert_alignment == IUP_ALIGN_ATOP)
+ y = 0;
+ else /* ACENTER */
+ y = (rect_height - (height + 2*ypad))/2;
+
+ y += ypad;
+
+ if (shift)
+ y++;
+
+ return y;
+}
+
+static HBITMAP winButtonGetBitmap(Ihandle* ih, UINT itemState, int *shift, int *w, int *h, int *bpp, HBITMAP *hMask)
+{
+ char *name;
+ int make_inactive = 0;
+ HBITMAP hBitmap;
+ *hMask = NULL;
+
+ if (itemState & ODS_DISABLED)
+ {
+ name = iupAttribGet(ih, "IMINACTIVE");
+ if (!name)
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ make_inactive = 1;
+ }
+ }
+ else
+ {
+ name = iupAttribGet(ih, "IMPRESS");
+ if (itemState & ODS_SELECTED && name)
+ {
+ if (shift && !iupAttribGetStr(ih, "IMPRESSBORDER"))
+ *shift = 0;
+ }
+ else
+ name = iupAttribGet(ih, "IMAGE");
+ }
+
+ hBitmap = iupImageGetImage(name, ih, make_inactive);
+
+ /* must use this info, since image can be a driver image loaded from resources */
+ iupdrvImageGetInfo(hBitmap, w, h, bpp);
+
+ if (*bpp == 8)
+ *hMask = iupdrvImageCreateMask(IupGetHandle(name));
+
+ return hBitmap;
+}
+
+static void winButtonDrawImageText(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState)
+{
+ int xpad = ih->data->horiz_padding + border,
+ ypad = ih->data->vert_padding + border;
+ int x, y, width, height,
+ txt_x, txt_y, txt_width, txt_height,
+ img_x, img_y, img_width, img_height,
+ bpp, shift = 0;
+ HFONT hFont = (HFONT)iupwinGetHFontAttrib(ih);
+ HBITMAP hBitmap, hMask;
+ COLORREF fgcolor;
+
+ char* title = iupdrvBaseGetTitleAttrib(ih);
+ char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */
+ iupdrvFontGetMultiLineStringSize(ih, str, &txt_width, &txt_height);
+ if (str && str!=title) free(str);
+
+ if (itemState & ODS_DISABLED)
+ fgcolor = GetSysColor(COLOR_GRAYTEXT);
+ else
+ fgcolor = ih->data->fgcolor;
+
+ hBitmap = winButtonGetBitmap(ih, itemState, NULL, &img_width, &img_height, &bpp, &hMask);
+ if (!hBitmap)
+ return;
+
+ if (ih->data->img_position == IUP_IMGPOS_RIGHT ||
+ ih->data->img_position == IUP_IMGPOS_LEFT)
+ {
+ width = img_width + txt_width + ih->data->spacing;
+ height = iupMAX(img_height, txt_height);
+ }
+ else
+ {
+ width = iupMAX(img_width, txt_width);
+ height = img_height + txt_height + ih->data->spacing;
+ }
+
+ if (itemState & ODS_SELECTED && !iupwin_comctl32ver6)
+ shift = 1;
+
+ x = winButtonCalcAlignPosX(ih->data->horiz_alignment, rect_width, width, xpad, shift);
+ y = winButtonCalcAlignPosY(ih->data->vert_alignment, rect_height, height, ypad, shift);
+
+ switch(ih->data->img_position)
+ {
+ case IUP_IMGPOS_TOP:
+ img_y = y;
+ txt_y = y + img_height + ih->data->spacing;
+ if (img_width > txt_width)
+ {
+ img_x = x;
+ txt_x = x + (img_width-txt_width)/2;
+ }
+ else
+ {
+ img_x = x + (txt_width-img_width)/2;
+ txt_x = x;
+ }
+ break;
+ case IUP_IMGPOS_BOTTOM:
+ img_y = y + txt_height + ih->data->spacing;
+ txt_y = y;
+ if (img_width > txt_width)
+ {
+ img_x = x;
+ txt_x = x + (img_width-txt_width)/2;
+ }
+ else
+ {
+ img_x = x + (txt_width-img_width)/2;
+ txt_x = x;
+ }
+ break;
+ case IUP_IMGPOS_RIGHT:
+ img_x = x + txt_width + ih->data->spacing;
+ txt_x = x;
+ if (img_height > txt_height)
+ {
+ img_y = y;
+ txt_y = y + (img_height-txt_height)/2;
+ }
+ else
+ {
+ img_y = y + (txt_height-img_height)/2;
+ txt_y = y;
+ }
+ break;
+ default: /* IUP_IMGPOS_LEFT */
+ img_x = x;
+ txt_x = x + img_width + ih->data->spacing;
+ if (img_height > txt_height)
+ {
+ img_y = y;
+ txt_y = y + (img_height-txt_height)/2;
+ }
+ else
+ {
+ img_y = y + (txt_height-img_height)/2;
+ txt_y = y;
+ }
+ break;
+ }
+
+ iupwinDrawBitmap(hDC, hBitmap, hMask, img_x, img_y, img_width, img_height, bpp);
+ iupwinDrawText(hDC, title, txt_x, txt_y, txt_width, txt_height, hFont, fgcolor, 0);
+
+ if (hMask)
+ DeleteObject(hMask);
+}
+
+static void winButtonDrawImage(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState)
+{
+ int xpad = ih->data->horiz_padding + border,
+ ypad = ih->data->vert_padding + border;
+ int x, y, width, height, bpp, shift = 0;
+ HBITMAP hBitmap, hMask;
+
+ if (itemState & ODS_SELECTED && !iupwin_comctl32ver6)
+ shift = 1;
+
+ hBitmap = winButtonGetBitmap(ih, itemState, &shift, &width, &height, &bpp, &hMask);
+ if (!hBitmap)
+ return;
+
+ x = winButtonCalcAlignPosX(ih->data->horiz_alignment, rect_width, width, xpad, shift);
+ y = winButtonCalcAlignPosY(ih->data->vert_alignment, rect_height, height, ypad, shift);
+
+ iupwinDrawBitmap(hDC, hBitmap, hMask, x, y, width, height, bpp);
+
+ if (hMask)
+ DeleteObject(hMask);
+}
+
+static void winButtonDrawText(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState)
+{
+ int xpad = ih->data->horiz_padding + border,
+ ypad = ih->data->vert_padding + border;
+ int x, y, width, height, shift = 0;
+ COLORREF fgcolor;
+
+ char* title = iupdrvBaseGetTitleAttrib(ih);
+ if (title)
+ {
+ HFONT hFont = (HFONT)iupwinGetHFontAttrib(ih);
+ char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */
+ iupdrvFontGetMultiLineStringSize(ih, str, &width, &height);
+ if (str && str!=title) free(str);
+
+ if (itemState & ODS_DISABLED)
+ fgcolor = GetSysColor(COLOR_GRAYTEXT);
+ else
+ fgcolor = ih->data->fgcolor;
+
+ if (itemState & ODS_SELECTED && !iupwin_comctl32ver6)
+ shift = 1;
+
+ x = winButtonCalcAlignPosX(ih->data->horiz_alignment, rect_width, width, xpad, shift);
+ y = winButtonCalcAlignPosY(ih->data->vert_alignment, rect_height, height, ypad, shift);
+
+ iupwinDrawText(hDC, title, x, y, width, height, hFont, fgcolor, 0);
+ }
+ else
+ {
+ /* fill with the background color if defined at the element */
+ char* bgcolor = iupAttribGet(ih, "BGCOLOR");
+ if (bgcolor)
+ {
+ RECT rect;
+ unsigned char r=0, g=0, b=0;
+ iupStrToRGB(bgcolor, &r, &g, &b);
+ SetDCBrushColor(hDC, RGB(r,g,b));
+ rect.left = xpad;
+ rect.top = ypad;
+ rect.right = rect_width - xpad;
+ rect.bottom = rect_height - ypad;
+ FillRect(hDC, &rect, (HBRUSH)GetStockObject(DC_BRUSH));
+ }
+ }
+}
+
+static void winButtonDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem)
+{
+ 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);
+
+ iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem);
+
+ if ((drawitem->itemState & ODS_FOCUS) && !(drawitem->itemState & ODS_HOTLIGHT))
+ drawitem->itemState |= ODS_DEFAULT;
+
+ border = winButtonGetBorder();
+
+ if (ih->data->type & IUP_BUTTON_IMAGE && iupAttribGet(ih, "IMPRESS") && !iupAttribGetStr(ih, "IMPRESSBORDER"))
+ draw_border = 0;
+ else
+ {
+ if (iupAttribGetBoolean(ih, "FLAT"))
+ {
+ if (drawitem->itemState & ODS_HOTLIGHT || iupAttribGet(ih, "_IUPWINBUT_ENTERWIN"))
+ draw_border = 1;
+ else
+ draw_border = 0;
+ }
+ else
+ draw_border = 1;
+ }
+
+ if (draw_border)
+ iupwinDrawButtonBorder(ih->handle, hDC, &drawitem->rcItem, drawitem->itemState);
+
+ if (ih->data->type == IUP_BUTTON_IMAGE)
+ winButtonDrawImage(ih, hDC, width, height, border, drawitem->itemState);
+ else if (ih->data->type == IUP_BUTTON_TEXT)
+ winButtonDrawText(ih, hDC, width, height, border, drawitem->itemState);
+ else /* both */
+ winButtonDrawImageText(ih, hDC, width, height, border, drawitem->itemState);
+
+ if (drawitem->itemState & ODS_FOCUS)
+ {
+ border--;
+ iupdrvDrawFocusRect(ih, hDC, border, border, width-2*border, height-2*border);
+ }
+
+ iupwinDrawDestroyBitmapDC(&bmpDC);
+}
+
+
+/***********************************************************************************************/
+
+
+static int winButtonSetImageAttrib(Ihandle* ih, const char* value)
+{
+ (void)value;
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ {
+ iupdrvDisplayUpdate(ih);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winButtonSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ (void)value;
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ {
+ iupdrvDisplayUpdate(ih);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winButtonSetImPressAttrib(Ihandle* ih, const char* value)
+{
+ (void)value;
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ {
+ iupdrvDisplayUpdate(ih);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winButtonSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ /* redraw IMINACTIVE image if any */
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ iupdrvDisplayUpdate(ih);
+
+ return iupBaseSetActiveAttrib(ih, value);
+}
+
+static int winButtonSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ char value1[30]="", value2[30]="";
+
+ iupStrToStrStr(value, value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ ih->data->horiz_alignment = IUP_ALIGN_ARIGHT;
+ else if (iupStrEqualNoCase(value1, "ALEFT"))
+ ih->data->horiz_alignment = IUP_ALIGN_ALEFT;
+ else /* "ACENTER" */
+ ih->data->horiz_alignment = IUP_ALIGN_ACENTER;
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ ih->data->vert_alignment = IUP_ALIGN_ABOTTOM;
+ else if (iupStrEqualNoCase(value2, "ATOP"))
+ ih->data->vert_alignment = IUP_ALIGN_ATOP;
+ else /* "ACENTER" */
+ ih->data->vert_alignment = IUP_ALIGN_ACENTER;
+
+ iupdrvDisplayRedraw(ih);
+
+ return 1;
+}
+
+static char* winButtonGetAlignmentAttrib(Ihandle *ih)
+{
+ char* horiz_align2str[3] = {"ALEFT", "ACENTER", "ARIGHT"};
+ char* vert_align2str[3] = {"ATOP", "ACENTER", "ABOTTOM"};
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%s:%s", horiz_align2str[ih->data->horiz_alignment], vert_align2str[ih->data->vert_alignment]);
+ return str;
+}
+
+static int winButtonSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle)
+ iupdrvDisplayRedraw(ih);
+ return 0;
+}
+
+static int winButtonSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ /* update internal image cache for controls that have the IMAGE attribute */
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ {
+ iupAttribSetStr(ih, "BGCOLOR", value);
+ iupImageUpdateParent(ih);
+ iupdrvDisplayRedraw(ih);
+ }
+ return 1;
+}
+
+static char* winButtonGetBgColorAttrib(Ihandle* ih)
+{
+ /* the most important use of this is to provide
+ the correct background for images */
+ if (iupwin_comctl32ver6 && !iupAttribGet(ih, "IMPRESS"))
+ {
+ COLORREF cr;
+ if (iupwinDrawGetThemeButtonBgColor(ih->handle, &cr))
+ {
+ char* str = iupStrGetMemory(20);
+ sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr));
+ return str;
+ }
+ }
+
+ if (iupAttribGet(ih, "IMPRESS"))
+ return iupBaseNativeParentGetBgColorAttrib(ih);
+ else
+ return NULL;
+}
+
+static int winButtonSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ ih->data->fgcolor = RGB(r,g,b);
+ iupdrvDisplayRedraw(ih);
+ }
+ return 1;
+}
+
+/****************************************************************************************/
+
+static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ {
+ /* redraw IMPRESS image if any */
+ if ((msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) && iupAttribGet(ih, "IMPRESS"))
+ iupdrvDisplayRedraw(ih);
+ }
+
+ switch (msg)
+ {
+ case WM_XBUTTONDBLCLK:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_XBUTTONDOWN:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ {
+ iupwinButtonDown(ih, msg, wp, lp);
+ break;
+ }
+ case WM_XBUTTONUP:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ {
+ iupwinButtonUp(ih, msg, wp, lp);
+
+ /* BN_CLICKED will NOT be notified when not receiving the focus */
+ if (msg==WM_LBUTTONUP && !iupAttribGetBoolean(ih, "FOCUSONCLICK"))
+ {
+ Icallback cb = IupGetCallback(ih, "ACTION");
+ if (cb && cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ break;
+ }
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ if (wp==VK_RETURN)
+ {
+ /* enter activates the button */
+ iupdrvActivate(ih);
+
+ *result = 0;
+ return 1; /* abort default processing, or the default button will be activated,
+ in this case even if there is a default button, this button must be activated instead. */
+ }
+ break;
+ case WM_MOUSELEAVE:
+ if (!iupwin_comctl32ver6)
+ {
+ iupAttribSetStr(ih, "_IUPWINBUT_ENTERWIN", NULL);
+ iupdrvDisplayRedraw(ih);
+ }
+ break;
+ case WM_MOUSEMOVE:
+ if (!iupwin_comctl32ver6)
+ {
+ if (!iupAttribGet(ih, "_IUPWINBUT_ENTERWIN"))
+ {
+ iupAttribSetStr(ih, "_IUPWINBUT_ENTERWIN", "1");
+ iupdrvDisplayRedraw(ih);
+ }
+ }
+ break;
+ case WM_SETFOCUS:
+ {
+ HWND previous = (HWND)wp;
+ if (!iupAttribGetBoolean(ih, "FOCUSONCLICK") && wp && iupAttribGet(ih, "_IUPWIN_ENTERWIN"))
+ {
+ SetFocus(previous);
+ *result = 0;
+ return 1;
+ }
+ }
+ break;
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+static int winButtonWmNotify(Ihandle* ih, NMHDR* msg_info, int *result)
+{
+ if (msg_info->code == NM_CUSTOMDRAW)
+ {
+ NMCUSTOMDRAW *customdraw = (NMCUSTOMDRAW*)msg_info;
+
+ if (customdraw->dwDrawStage==CDDS_PREERASE)
+ {
+ DRAWITEMSTRUCT drawitem;
+ drawitem.itemState = 0;
+
+ if (customdraw->uItemState & CDIS_DISABLED)
+ drawitem.itemState |= ODS_DISABLED;
+ else if (customdraw->uItemState & CDIS_SELECTED)
+ drawitem.itemState |= ODS_SELECTED;
+ else if (customdraw->uItemState & CDIS_HOT)
+ drawitem.itemState |= ODS_HOTLIGHT;
+ else if (customdraw->uItemState & CDIS_DEFAULT)
+ drawitem.itemState |= ODS_DEFAULT;
+
+ if (customdraw->uItemState & CDIS_FOCUS && (customdraw->uItemState & CDIS_SHOWKEYBOARDCUES))
+ drawitem.itemState |= ODS_FOCUS;
+
+ drawitem.hDC = customdraw->hdc;
+ drawitem.rcItem = customdraw->rc;
+
+ winButtonDrawItem(ih, (void*)&drawitem); /* Simulate a WM_DRAWITEM */
+
+ *result = CDRF_SKIPDEFAULT;
+ return 1;
+ }
+ }
+
+ return 0; /* result not used */
+}
+
+static int winButtonWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp)
+{
+ int cmd = HIWORD(wp);
+ switch (cmd)
+ {
+ case BN_DOUBLECLICKED:
+ case BN_CLICKED:
+ {
+ Icallback cb = IupGetCallback(ih, "ACTION");
+ if (cb && cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+ }
+ }
+
+ (void)lp;
+ return 0; /* not used */
+}
+
+static int winButtonMapMethod(Ihandle* ih)
+{
+ char* value;
+ DWORD dwStyle = WS_CHILD |
+ BS_NOTIFY; /* necessary because of the base messages */
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ /* Buttons with the BS_PUSHBUTTON style do NOT use the returned brush in WM_CTLCOLORBTN.
+ Buttons with these styles are always drawn with the default system colors.
+ So FGCOLOR and BGCOLOR do NOT work.
+ The BS_FLAT style does NOT completely remove the borders. With XP styles is ignored. So FLAT do NOT work.
+ BCM_SETTEXTMARGIN is not working.
+ Buttons with images and with XP styles do NOT draw the focus feedback.
+ Can NOT remove the borders when using IMPRESS.
+ So IUP will draw its own button,
+ but uses the Windows functions to draw text and images in native format. */
+ if (iupwin_comctl32ver6)
+ dwStyle |= BS_PUSHBUTTON; /* it will be an ownerdraw because we use NM_CUSTOMDRAW */
+ else
+ dwStyle |= BS_OWNERDRAW;
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ {
+ ih->data->type = IUP_BUTTON_IMAGE;
+
+ value = iupAttribGet(ih, "TITLE");
+ if (value)
+ ih->data->type |= IUP_BUTTON_TEXT;
+ }
+ else
+ ih->data->type = IUP_BUTTON_TEXT;
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ if (!iupwinCreateWindowEx(ih, "BUTTON", 0, dwStyle))
+ return IUP_ERROR;
+
+ /* Process WM_COMMAND */
+ IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winButtonWmCommand);
+
+ /* Process BUTTON_CB */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winButtonProc);
+
+ if (iupwin_comctl32ver6)
+ IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winButtonWmNotify); /* Process WM_NOTIFY */
+ else
+ IupSetCallback(ih, "_IUPWIN_DRAWITEM_CB", (Icallback)winButtonDrawItem); /* Process WM_DRAWITEM */
+
+ return IUP_NOERROR;
+}
+
+void iupdrvButtonInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winButtonMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, winButtonSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", winButtonGetBgColorAttrib, winButtonSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winButtonSetFgColorAttrib, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force the new default value */
+ iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupButton only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", winButtonGetAlignmentAttrib, winButtonSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, winButtonSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, winButtonSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, winButtonSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FOCUSONCLICK", NULL, NULL, "YES", NULL, IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupButtonGetPaddingAttrib, winButtonSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+}
diff --git a/iup/src/win/iupwin_canvas.c b/iup/src/win/iupwin_canvas.c
new file mode 100755
index 0000000..bb88b8a
--- /dev/null
+++ b/iup/src/win/iupwin_canvas.c
@@ -0,0 +1,724 @@
+/** \file
+ * \brief Canvas Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <limits.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_canvas.h"
+#include "iup_key.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_brush.h"
+
+
+static void winCanvasSetScrollInfo(HWND hWnd, int imin, int imax, int ipos, int ipage, int flag)
+{
+ SCROLLINFO scrollinfo;
+ scrollinfo.cbSize = sizeof(SCROLLINFO);
+ scrollinfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ scrollinfo.nPage = ipage;
+ scrollinfo.nPos = ipos;
+ scrollinfo.nMax = imax;
+ scrollinfo.nMin = imin;
+ SetScrollInfo(hWnd, flag, &scrollinfo, TRUE);
+}
+
+static int winCanvasSetBgColorAttrib(Ihandle *ih, const char *value)
+{
+ (void)value;
+ iupdrvDisplayUpdate(ih);
+ return 1;
+}
+
+static int winCanvasSetDXAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ double posx, xmin, xmax;
+ float dx;
+ int iposx, ipagex;
+
+ if (!iupStrToFloat(value, &dx))
+ return 1;
+
+ xmin = iupAttribGetFloat(ih, "XMIN");
+ xmax = iupAttribGetFloat(ih, "XMAX");
+ posx = ih->data->posx;
+
+ iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx);
+
+ if (dx >= (xmax-xmin))
+ {
+ if (iupAttribGetBoolean(ih, "XAUTOHIDE"))
+ ShowScrollBar(ih->handle, SB_HORZ, FALSE);
+ else
+ EnableScrollBar(ih->handle, SB_HORZ, ESB_DISABLE_BOTH);
+ return 1;
+ }
+ else
+ {
+ ShowScrollBar(ih->handle, SB_HORZ, TRUE);
+ EnableScrollBar(ih->handle, SB_HORZ, ESB_ENABLE_BOTH);
+ }
+
+ winCanvasSetScrollInfo(ih->handle, IUP_SB_MIN, IUP_SB_MAX, iposx, ipagex, SB_HORZ);
+
+ /* update position because it could be corrected */
+ iupCanvasCalcScrollRealPos(xmin, xmax, &posx,
+ IUP_SB_MIN, IUP_SB_MAX, ipagex, &iposx);
+
+ ih->data->posx = (float)posx;
+ }
+ return 1;
+}
+
+static int winCanvasSetPosXAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ double xmin, xmax, dx;
+ float posx;
+ int iposx, ipagex;
+
+ if (!iupStrToFloat(value, &posx))
+ return 1;
+
+ xmin = iupAttribGetFloat(ih, "XMIN");
+ xmax = iupAttribGetFloat(ih, "XMAX");
+ dx = iupAttribGetFloat(ih, "DX");
+
+ if (posx < xmin) posx = (float)xmin;
+ if (posx > (xmax - dx)) posx = (float)(xmax - dx);
+ ih->data->posx = posx;
+
+ iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx);
+
+ SetScrollPos(ih->handle,SB_HORZ,iposx,TRUE);
+ }
+ return 1;
+}
+
+static int winCanvasSetDYAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ double posy, ymin, ymax;
+ float dy;
+ int iposy, ipagey;
+
+ if (!iupStrToFloat(value, &dy))
+ return 1;
+
+ ymin = iupAttribGetFloat(ih, "YMIN");
+ ymax = iupAttribGetFloat(ih, "YMAX");
+ posy = ih->data->posy;
+
+ iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy);
+
+ if (dy >= (ymax-ymin))
+ {
+ if (iupAttribGetBoolean(ih, "YAUTOHIDE"))
+ ShowScrollBar(ih->handle, SB_VERT, FALSE);
+ else
+ EnableScrollBar(ih->handle, SB_VERT, ESB_DISABLE_BOTH);
+ return 1;
+ }
+ else
+ {
+ ShowScrollBar(ih->handle, SB_VERT, TRUE);
+ EnableScrollBar(ih->handle, SB_VERT, ESB_ENABLE_BOTH);
+ }
+
+ winCanvasSetScrollInfo(ih->handle, IUP_SB_MIN, IUP_SB_MAX, iposy, ipagey, SB_VERT);
+
+ /* update position because it could be corrected */
+ iupCanvasCalcScrollRealPos(ymin, ymax, &posy,
+ IUP_SB_MIN, IUP_SB_MAX, ipagey, &iposy);
+
+ ih->data->posy = (float)posy;
+ }
+ return 1;
+}
+
+static int winCanvasSetPosYAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ double ymin, ymax, dy;
+ float posy;
+ int iposy, ipagey;
+
+ if (!iupStrToFloat(value, &posy))
+ return 1;
+
+ ymin = iupAttribGetFloat(ih, "YMIN");
+ ymax = iupAttribGetFloat(ih, "YMAX");
+ dy = iupAttribGetFloat(ih, "DY");
+
+ if (posy < ymin) posy = (float)ymin;
+ if (posy > (ymax - dy)) posy = (float)(ymax - dy);
+ ih->data->posy = posy;
+
+ iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy);
+
+ SetScrollPos(ih->handle,SB_VERT,iposy,TRUE);
+ }
+ return 1;
+}
+
+static void winCanvasGetScrollInfo(HWND hWnd, int *ipos, int *ipage, int flag, int track)
+{
+ SCROLLINFO scrollinfo;
+ scrollinfo.cbSize = sizeof(SCROLLINFO);
+ if (track)
+ scrollinfo.fMask = SIF_PAGE | SIF_TRACKPOS;
+ else
+ scrollinfo.fMask = SIF_PAGE | SIF_POS;
+ GetScrollInfo(hWnd, flag, &scrollinfo);
+ *ipage = scrollinfo.nPage;
+ if (track)
+ *ipos = scrollinfo.nTrackPos;
+ else
+ *ipos = scrollinfo.nPos;
+}
+
+static void winCanvasUpdateHorScroll(Ihandle* ih, WORD winop)
+{
+ IFniff cb;
+ double xmin, xmax, posx, linex;
+ int ipagex, iposx, ilinex, op;
+
+ /* unused */
+ if (winop == SB_TOP ||
+ winop == SB_BOTTOM ||
+ winop == SB_ENDSCROLL)
+ return;
+
+ xmax = iupAttribGetFloat(ih,"XMAX");
+ xmin = iupAttribGetFloat(ih,"XMIN");
+
+ winCanvasGetScrollInfo(ih->handle, &iposx, &ipagex, SB_HORZ, winop==SB_THUMBTRACK? 1: 0);
+
+ if (!iupAttribGet(ih,"LINEX"))
+ {
+ ilinex = ipagex/10;
+ if (!ilinex)
+ ilinex = 1;
+ }
+ else
+ {
+ /* line and page convertions are the same */
+ linex = iupAttribGetFloat(ih,"LINEX");
+ iupCanvasCalcScrollIntPos(xmin, xmax, linex, 0,
+ IUP_SB_MIN, IUP_SB_MAX, &ilinex, NULL);
+ }
+
+ switch (winop)
+ {
+ case SB_LINEDOWN:
+ iposx = iposx + ilinex;
+ op = IUP_SBRIGHT;
+ break;
+ case SB_LINEUP:
+ iposx = iposx - ilinex;
+ op = IUP_SBLEFT;
+ break;
+ case SB_PAGEDOWN:
+ iposx = iposx + ipagex;
+ op = IUP_SBPGRIGHT;
+ break;
+ case SB_PAGEUP:
+ iposx = iposx - ipagex;
+ op = IUP_SBPGLEFT;
+ break;
+ case SB_THUMBTRACK:
+ op = IUP_SBDRAGH;
+ break;
+ case SB_THUMBPOSITION:
+ op = IUP_SBPOSH;
+ break;
+ default:
+ return;
+ }
+
+ iupCanvasCalcScrollRealPos(xmin, xmax, &posx,
+ IUP_SB_MIN, IUP_SB_MAX, ipagex, &iposx);
+
+ SetScrollPos(ih->handle,SB_HORZ,iposx,TRUE);
+ ih->data->posx = (float)posx;
+
+ cb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ if (cb)
+ cb(ih,op,(float)posx,ih->data->posy);
+ else
+ {
+ IFnff cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ cb (ih, (float)posx, ih->data->posy);
+ }
+}
+
+static void winCanvasUpdateVerScroll(Ihandle* ih, WORD winop)
+{
+ IFniff cb;
+ double ymin, ymax, posy, liney;
+ int ipagey, iposy, iliney, op;
+
+ /* unused */
+ if (winop == SB_TOP ||
+ winop == SB_BOTTOM ||
+ winop == SB_ENDSCROLL)
+ return;
+
+ ymax = iupAttribGetFloat(ih,"YMAX");
+ ymin = iupAttribGetFloat(ih,"YMIN");
+
+ winCanvasGetScrollInfo(ih->handle, &iposy, &ipagey, SB_VERT, winop==SB_THUMBTRACK? 1: 0);
+
+ if (!iupAttribGet(ih, "LINEY"))
+ {
+ iliney = ipagey/10;
+ if (!iliney)
+ iliney = 1;
+ }
+ else
+ {
+ /* line and page convertions are the same */
+ liney = iupAttribGetFloat(ih,"LINEY");
+ iupCanvasCalcScrollIntPos(ymin, ymax, liney, 0,
+ IUP_SB_MIN, IUP_SB_MAX, &iliney, NULL);
+ }
+
+ switch (winop)
+ {
+ case SB_LINEDOWN:
+ iposy = iposy + iliney;
+ op = IUP_SBDN;
+ break;
+ case SB_LINEUP:
+ iposy = iposy - iliney;
+ op = IUP_SBUP;
+ break;
+ case SB_PAGEDOWN:
+ iposy = iposy + ipagey;
+ op = IUP_SBPGDN;
+ break;
+ case SB_PAGEUP:
+ iposy = iposy - ipagey;
+ op = IUP_SBPGUP;
+ break;
+ case SB_THUMBTRACK:
+ op = IUP_SBDRAGV;
+ break;
+ case SB_THUMBPOSITION:
+ op = IUP_SBPOSV;
+ break;
+ default:
+ return;
+ }
+
+ iupCanvasCalcScrollRealPos(ymin, ymax, &posy,
+ IUP_SB_MIN, IUP_SB_MAX, ipagey, &iposy);
+
+ SetScrollPos(ih->handle,SB_VERT,iposy,TRUE);
+ ih->data->posy = (float)posy;
+
+ cb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ if (cb)
+ cb(ih, op, ih->data->posx,(float)posy);
+ else
+ {
+ IFnff cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ cb (ih, ih->data->posx, (float)posy);
+ }
+}
+
+static int winCanvasProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch (msg)
+ {
+ case WM_ERASEBKGND:
+ /* only paint background if ACTION is not defined */
+ if (!IupGetCallback(ih, "ACTION"))
+ {
+ RECT rect;
+ HDC hdc = (HDC)wp;
+ COLORREF color;
+ iupwinGetColorRef(ih, "BGCOLOR", &color);
+ GetClientRect(ih->handle, &rect);
+ FillRect(hdc, &rect, iupwinBrushGet(color));
+ }
+ /* always return non zero value */
+ *result = 1;
+ return 1;
+ case WM_PAINT:
+ {
+ IFnff cb = (IFnff)IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(ih->handle, &ps);
+ 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);
+
+ iupAttribSetStr(ih, "CLIPRECT", NULL);
+ iupAttribSetStr(ih, "HDC_WMPAINT", NULL);
+ EndPaint(ih->handle, &ps);
+ }
+ break;
+ }
+ case WM_SIZE:
+ {
+ IFnii cb = (IFnii)IupGetCallback(ih, "RESIZE_CB");
+ if (cb)
+ {
+ RECT rect;
+ GetClientRect(ih->handle, &rect);
+ cb(ih, rect.right-rect.left, rect.bottom-rect.top);
+ /* w=LOWORD (lp), h=HIWORD(lp) can not be used because and invalid size
+ at the first time of WM_SIZE with scroolbars. */
+ }
+ *result = 0;
+ return 1;
+ }
+ case WM_GETDLGCODE:
+ /* avoid beeps when keys are pressed */
+ *result = DLGC_WANTCHARS|DLGC_WANTARROWS;
+ return 1;
+ case WM_MOUSEWHEEL:
+ {
+ IFnfiis cb = (IFnfiis)IupGetCallback(ih, "WHEEL_CB");
+ short delta = (short)HIWORD(wp);
+ if (cb)
+ {
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ POINT p;
+ p.x = LOWORD(lp); p.y = HIWORD(lp);
+ ScreenToClient(ih->handle, &p);
+
+ iupwinButtonKeySetStatus(LOWORD(wp), status, 0);
+
+ cb(ih, (float)delta/120.0f, p.x, p.y, status);
+ }
+ else
+ {
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ int i, winop = delta>0? SB_LINEUP: SB_LINEDOWN;
+ delta = (short)abs(delta/120);
+ for (i=0; i < delta; i++)
+ SendMessage(ih->handle, WM_VSCROLL, MAKELONG(winop, 0), 0);
+ }
+ }
+
+ *result = 0;
+ return 1;
+ }
+ case WM_XBUTTONDBLCLK:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_XBUTTONDOWN:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ {
+ /* Force focus on canvas click */
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ SetFocus(ih->handle);
+
+ SetCapture(ih->handle);
+
+ if (iupwinButtonDown(ih, msg, wp, lp))
+ {
+ /* refresh the cursor, it could have been changed in BUTTON_CB */
+ SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE));
+ }
+
+ if (msg==WM_XBUTTONDOWN || msg==WM_XBUTTONDBLCLK)
+ *result = 1;
+ else
+ *result = 0;
+ return 1;
+ }
+ case WM_MOUSEMOVE:
+ {
+ if (iupwinMouseMove(ih, msg, wp, lp))
+ {
+ /* refresh the cursor, it could have been changed in MOTION_CB */
+ SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE));
+ }
+
+ break; /* let iupwinBaseProc process enter/leavewin */
+ }
+ case WM_XBUTTONUP:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ {
+ ReleaseCapture();
+
+ if (iupwinButtonUp(ih, msg, wp, lp))
+ {
+ /* refresh the cursor, it could have been changed in BUTTON_CB */
+ SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE));
+ }
+
+ *result = 0;
+ if (msg==WM_XBUTTONUP)
+ *result = 1;
+ return 1;
+ }
+ case WM_KILLFOCUS:
+ {
+ if (GetCapture() == ih->handle)
+ ReleaseCapture();
+ break;
+ }
+ case WM_SETCURSOR:
+ {
+ if (ih->handle == (HWND)wp && LOWORD(lp)==HTCLIENT)
+ {
+ HCURSOR hCur = (HCURSOR)iupAttribGet(ih, "_IUPWIN_HCURSOR");
+ if (hCur)
+ {
+ SetCursor(hCur);
+ *result = 1;
+ return 1;
+ }
+ else if (iupAttribGet(ih, "CURSOR"))
+ {
+ SetCursor(NULL);
+ *result = 1;
+ return 1;
+ }
+ }
+ break;
+ }
+ case WM_INITMENU:
+ /* abort capture if a menu is opened */
+ ReleaseCapture();
+ break;
+ case WM_VSCROLL:
+ winCanvasUpdateVerScroll(ih, LOWORD(wp));
+ *result = 0;
+ return 1;
+ case WM_HSCROLL:
+ winCanvasUpdateHorScroll(ih, LOWORD(wp));
+ *result = 0;
+ return 1;
+ }
+
+ /* can be a container */
+ if (ih->firstchild)
+ return iupwinBaseContainerProc(ih, msg, wp, lp, result);
+ else
+ 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;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (ih->iclass->is_interactive)
+ {
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+ }
+
+ if (ih->firstchild) /* can be a container */
+ {
+ dwStyle |= WS_CLIPSIBLINGS;
+
+ if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED"))
+ dwExStyle |= WS_EX_COMPOSITED;
+ else
+ dwStyle |= WS_CLIPCHILDREN;
+ }
+
+ if (iupAttribGetBoolean(ih, "MDICLIENT"))
+ {
+ /* creating a MDI Client that will be inside the MDI Frame,
+ it will work as parent of all MDI children */
+ Ihandle *winmenu = IupGetAttributeHandle(ih, "MDIMENU");
+
+ classname = "mdiclient";
+
+ iupAttribSetStr(ih, "BORDER", "NO");
+
+ iupAttribSetStr(IupGetDialog(ih), "MDICLIENT_HANDLE", (char*)ih);
+
+ clientdata = &clientstruct;
+ clientstruct.hWindowMenu = winmenu? winmenu->handle: NULL;
+
+ /* The system increments the identifier
+ for each additional MDI child window the application creates,
+ and reassigns identifiers when the application
+ destroys a window to keep the range of identifiers contiguous. */
+ clientstruct.idFirstChild = IUP_MDICHILD_START;
+ }
+ else
+ classname = "IupCanvas";
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ dwStyle |= WS_BORDER;
+
+ ih->data->sb = iupBaseGetScrollbar(ih);
+ if (ih->data->sb & IUP_SB_HORIZ)
+ dwStyle |= WS_HSCROLL;
+ if (ih->data->sb & IUP_SB_VERT)
+ dwStyle |= WS_VSCROLL;
+
+ ih->serial = iupDialogGetChildId(ih);
+
+ ih->handle = CreateWindowEx(dwExStyle,/* extended style */
+ classname, /* window class */
+ NULL, /* title */
+ dwStyle, /* window style */
+ 0, /* x-position */
+ 0, /* y-position */
+ 10, /* default width to avoid 0 */
+ 10, /* default height to avoid 0 */
+ iupChildTreeGetNativeParentHandle(ih), /* window parent */
+ (HMENU)ih->serial, /* child identifier */
+ iupwin_hinstance, /* instance of app. */
+ clientdata);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* associate HWND with Ihandle*, all Win32 controls must call this. */
+ iupwinHandleSet(ih);
+
+ IupSetCallback(ih, "_IUPWIN_OLDPROC_CB", (Icallback)DefWindowProc);
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winCanvasProc);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ return IUP_NOERROR;
+}
+
+static void winCanvasMDICloseChildren(Ihandle* client)
+{
+ HWND hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+
+ /* As long as the MDI client has a child, close it */
+ while (hWndChild)
+ {
+ Ihandle* child = iupwinHandleGet(hWndChild);
+ if (iupObjectCheck(child) && iupAttribGetBoolean(child, "MDICHILD"))
+ IupDestroy(child);
+
+ hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+ }
+}
+
+static void winCanvasUnMapMethod(Ihandle* ih)
+{
+ if (iupAttribGetBoolean(ih, "MDICLIENT"))
+ {
+ /* hide the MDI client window to avoid multiple re-paints */
+ ShowWindow(ih->handle, SW_HIDE);
+
+ /* must destroy all MDI Children */
+ winCanvasMDICloseChildren(ih);
+
+ DestroyWindow(ih->handle);
+
+ /* mdiclient class is not a IUP class, must return here */
+ return;
+ }
+
+ /* remove the association before destroying */
+ iupwinHandleRemove(ih);
+
+ /* remove from parent and destroys window */
+ SetParent(ih->handle, NULL);
+ DestroyWindow(ih->handle);
+}
+
+static void winCanvasReleaseMethod(Iclass* ic)
+{
+ (void)ic;
+ if (iupwinClassExist("IupCanvas"))
+ UnregisterClass("IupCanvas", iupwin_hinstance);
+}
+
+void iupdrvCanvasInitClass(Iclass* ic)
+{
+ if (!iupwinClassExist("IupCanvas"))
+ winCanvasRegisterClass();
+
+ /* Driver Dependent Class functions */
+ ic->Map = winCanvasMapMethod;
+ ic->UnMap = winCanvasUnMapMethod;
+ ic->Release = winCanvasReleaseMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winCanvasSetBgColorAttrib, "255 255 255", NULL, IUPAF_DEFAULT); /* force new default value */
+
+ /* IupCanvas only */
+ iupClassRegisterAttribute(ic, "DRAWSIZE", iupdrvBaseGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "DX", NULL, winCanvasSetDXAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "DY", NULL, winCanvasSetDYAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "POSX", iupCanvasGetPosXAttrib, winCanvasSetPosXAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "POSY", iupCanvasGetPosYAttrib, winCanvasSetPosYAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "XAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "YAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED);
+
+ /* IupCanvas Windows only */
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "HWND", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_clipboard.c b/iup/src/win/iupwin_clipboard.c
new file mode 100755
index 0000000..1e0fab4
--- /dev/null
+++ b/iup/src/win/iupwin_clipboard.c
@@ -0,0 +1,190 @@
+/** \file
+ * \brief Clipboard for the Windows Driver.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+
+
+static int winClipboardSetTextAttrib(Ihandle *ih, const char *value)
+{
+ HANDLE hHandle;
+ void* clip_str;
+ int size = strlen(value)+1;
+ (void)ih;
+
+ if (!OpenClipboard(NULL))
+ return 0;
+
+ hHandle = GlobalAlloc(GMEM_MOVEABLE, size);
+ if (!hHandle)
+ return 0;
+
+ clip_str = GlobalLock(hHandle);
+ CopyMemory(clip_str, value, size);
+ GlobalUnlock(hHandle);
+
+ EmptyClipboard();
+ SetClipboardData(CF_TEXT, hHandle);
+ CloseClipboard();
+
+ return 0;
+}
+
+static char* winClipboardGetTextAttrib(Ihandle *ih)
+{
+ HANDLE hHandle;
+ char* str;
+ (void)ih;
+
+ if (!OpenClipboard(NULL))
+ return NULL;
+
+ hHandle = GetClipboardData(CF_TEXT);
+ if (!hHandle)
+ {
+ CloseClipboard();
+ return NULL;
+ }
+
+ str = iupStrGetMemoryCopy((char*)GlobalLock(hHandle));
+
+ GlobalUnlock(hHandle);
+ CloseClipboard();
+ return str;
+}
+
+static int winClipboardSetImageAttrib(Ihandle *ih, const char *value)
+{
+ HBITMAP hBitmap;
+
+ if (!OpenClipboard(NULL))
+ return 0;
+
+ hBitmap = (HBITMAP)iupImageGetImage(value, ih, 0);
+ iupImageClearCache(ih, hBitmap);
+
+ EmptyClipboard();
+ SetClipboardData(CF_BITMAP, (HANDLE)hBitmap);
+ CloseClipboard();
+
+ return 0;
+}
+
+static int winClipboardSetNativeImageAttrib(Ihandle *ih, const char *value)
+{
+ if (!OpenClipboard(NULL))
+ return 0;
+
+ EmptyClipboard();
+ SetClipboardData(CF_DIB, (HANDLE)value);
+ CloseClipboard();
+
+ (void)ih;
+ return 0;
+}
+
+static HANDLE winCopyHandle(HANDLE hHandle)
+{
+ void *src_data, *dst_data;
+ SIZE_T size = GlobalSize(hHandle);
+ HANDLE hNewHandle = GlobalAlloc(GMEM_MOVEABLE, size);
+ if (!hNewHandle)
+ return NULL;
+
+ src_data = GlobalLock(hHandle);
+ dst_data = GlobalLock(hNewHandle);
+ CopyMemory(dst_data, src_data, size);
+ GlobalUnlock(hHandle);
+ GlobalUnlock(hNewHandle);
+
+ return hNewHandle;
+}
+
+static char* winClipboardGetNativeImageAttrib(Ihandle *ih)
+{
+ HANDLE hHandle;
+
+ if (!OpenClipboard(NULL))
+ return 0;
+
+ hHandle = GetClipboardData(CF_DIB);
+ if (!hHandle)
+ {
+ CloseClipboard();
+ return NULL;
+ }
+
+ hHandle = winCopyHandle(hHandle); /* must duplicate because CloseClipboard will invalidate the handle */
+ CloseClipboard();
+
+ (void)ih;
+ return (char*)hHandle;
+}
+
+static char* winClipboardGetTextAvailableAttrib(Ihandle *ih)
+{
+ int check;
+ (void)ih;
+ OpenClipboard(NULL);
+ check = IsClipboardFormatAvailable(CF_TEXT);
+ CloseClipboard();
+ if (check)
+ return "YES";
+ else
+ return "NO";
+}
+
+static char* winClipboardGetImageAvailableAttrib(Ihandle *ih)
+{
+ int check;
+ (void)ih;
+ OpenClipboard(NULL);
+ check = IsClipboardFormatAvailable(CF_DIB);
+ CloseClipboard();
+ if (check)
+ return "YES";
+ else
+ return "NO";
+}
+
+/******************************************************************************/
+
+Ihandle* IupClipboard(void)
+{
+ return IupCreate("clipboard");
+}
+
+Iclass* iupClipboardGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "clipboard";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Attribute functions */
+ iupClassRegisterAttribute(ic, "TEXT", winClipboardGetTextAttrib, winClipboardSetTextAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "NATIVEIMAGE", winClipboardGetNativeImageAttrib, winClipboardSetNativeImageAttrib, NULL, NULL, IUPAF_NO_STRING|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, winClipboardSetImageAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TEXTAVAILABLE", winClipboardGetTextAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEAVAILABLE", winClipboardGetImageAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
diff --git a/iup/src/win/iupwin_colordlg.c b/iup/src/win/iupwin_colordlg.c
new file mode 100755
index 0000000..f0baa79
--- /dev/null
+++ b/iup/src/win/iupwin_colordlg.c
@@ -0,0 +1,133 @@
+/** \file
+ * \brief IupColorDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+
+
+#define IUP_COLOR_RED 706
+
+static UINT_PTR winColorDlgHookProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+ (void)wParam;
+ if (uiMsg == WM_INITDIALOG)
+ {
+ HWND hWndItem;
+ CHOOSECOLOR* choosecolor = (CHOOSECOLOR*)lParam;
+ Ihandle* ih = (Ihandle*)choosecolor->lCustData;
+
+ char* value = iupAttribGet(ih, "TITLE");
+ if (value)
+ SetWindowText(hWnd, value);
+
+ ih->handle = hWnd;
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+ iupAttribSetStr(ih, "HWND", (char*)hWnd); /* used by HELP_CB in winDialogBaseProc */
+
+ hWndItem = GetDlgItem(hWnd, IUP_COLOR_RED);
+ SetFocus(hWndItem);
+ }
+ return 0;
+}
+
+static char* winColorDlgColorsToString(COLORREF* lpCustColors)
+{
+ int i, inc, off = 0;
+ char iup_str[20];
+ char* str = iupStrGetMemory(300);
+ for (i=0; i < 16; i++)
+ {
+ inc = sprintf(iup_str, "%d %d %d;", (int)GetRValue(*lpCustColors), (int)GetGValue(*lpCustColors), (int)GetBValue(*lpCustColors));
+ memcpy(str+off, iup_str, inc);
+ off += inc;
+ lpCustColors++;
+ }
+ str[off-1] = 0; /* remove last separator */
+ return str;
+}
+
+static void winColorDlgStringToColors(char* str, COLORREF* lpCustColors)
+{
+ int i = 0;
+ unsigned char r, g, b;
+
+ while (str && *str && i < 16)
+ {
+ if (iupStrToRGB(str, &r, &g, &b))
+ *lpCustColors = RGB(r,g,b);
+
+ str = strchr(str, ';');
+ if (str) str++;
+ i++;
+ lpCustColors++;
+ }
+}
+
+static int winColorDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ CHOOSECOLOR choosecolor;
+ unsigned char r, g, b;
+ COLORREF lpCustColors[16];
+ char* value;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ iupStrToRGB(iupAttribGet(ih, "VALUE"), &r, &g, &b);
+
+ ZeroMemory(lpCustColors, 16*sizeof(COLORREF));
+
+ value = iupAttribGetStr(ih, "COLORTABLE");
+ if (value)
+ winColorDlgStringToColors(value, lpCustColors);
+
+ ZeroMemory(&choosecolor, sizeof(CHOOSECOLOR));
+ choosecolor.lStructSize = sizeof(CHOOSECOLOR);
+ choosecolor.hwndOwner = parent;
+ choosecolor.rgbResult = RGB(r, g, b);
+ choosecolor.lpCustColors = lpCustColors;
+ choosecolor.lCustData = (LPARAM)ih;
+
+ choosecolor.Flags = CC_RGBINIT|CC_FULLOPEN;
+ if (IupGetCallback(ih, "HELP_CB"))
+ choosecolor.Flags |= CC_SHOWHELP;
+
+ choosecolor.Flags |= CC_ENABLEHOOK;
+ choosecolor.lpfnHook = (LPCCHOOKPROC)winColorDlgHookProc;
+
+ if (!ChooseColor(&choosecolor))
+ {
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "COLORTABLE", NULL);
+ iupAttribSetStr(ih, "STATUS", NULL);
+ return IUP_NOERROR;
+ }
+
+ iupAttribSetStrf(ih, "VALUE", "%d %d %d", GetRValue(choosecolor.rgbResult),
+ GetGValue(choosecolor.rgbResult),
+ GetBValue(choosecolor.rgbResult));
+ iupAttribSetStr(ih, "COLORTABLE", winColorDlgColorsToString(lpCustColors));
+ iupAttribSetStr(ih, "STATUS", "1");
+
+ return IUP_NOERROR;
+}
+
+void iupdrvColorDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = winColorDlgPopup;
+}
diff --git a/iup/src/win/iupwin_common.c b/iup/src/win/iupwin_common.c
new file mode 100755
index 0000000..a1a7c0f
--- /dev/null
+++ b/iup/src/win/iupwin_common.c
@@ -0,0 +1,865 @@
+/** \file
+ * \brief Windows Base Procedure
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_key.h"
+#include "iup_str.h"
+#include "iup_class.h"
+#include "iup_attrib.h"
+#include "iup_focus.h"
+#include "iup_image.h"
+#include "iup_dialog.h"
+#include "iup_drvinfo.h"
+#include "iup_drv.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_brush.h"
+
+
+#ifndef XBUTTON1
+#define XBUTTON1 0x0001 /* not defined in MingW3 */
+#endif
+
+int iupwinClassExist(const char* name)
+{
+ WNDCLASS WndClass;
+ if (GetClassInfo(iupwin_hinstance, name, &WndClass))
+ return 1;
+ return 0;
+}
+
+int iupwinGetScreenRes(void)
+{
+ int res;
+ HDC ScreenDC = GetDC(NULL);
+ res = GetDeviceCaps(ScreenDC, LOGPIXELSY);
+ ReleaseDC(NULL, ScreenDC);
+ return res;
+}
+
+void iupdrvActivate(Ihandle* ih)
+{
+ /* do not use BM_CLICK because it changes the focus
+ and does not animates the button press */
+ SendMessage(ih->handle, BM_SETSTATE, TRUE, 0);
+ IupFlush();
+ Sleep(150);
+ SendMessage(GetParent(ih->handle), WM_COMMAND, MAKEWPARAM(0, BN_CLICKED), (LPARAM)ih->handle);
+ SendMessage(ih->handle, BM_SETSTATE, FALSE, 0);
+}
+
+WCHAR* iupwinStrChar2Wide(const char* str)
+{
+ if (str)
+ {
+ int len = strlen(str)+1;
+ WCHAR* wstr = malloc(len * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, len);
+ return wstr;
+ }
+
+ return NULL;
+}
+
+int iupdrvGetScrollbarSize(void)
+{
+ int xv = GetSystemMetrics(SM_CXVSCROLL);
+ int yh = GetSystemMetrics(SM_CYHSCROLL);
+ return xv > yh ? xv : yh;
+}
+
+void iupdrvReparent(Ihandle* ih)
+{
+ SetParent(ih->handle, iupChildTreeGetNativeParentHandle(ih));
+}
+
+void iupdrvBaseLayoutUpdateMethod(Ihandle *ih)
+{
+ SetWindowPos(ih->handle, NULL, ih->x, ih->y, ih->currentwidth, ih->currentheight,
+ SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
+}
+
+void iupdrvDisplayRedraw(Ihandle *ih)
+{
+ /* REDRAW Now */
+ RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_NOCHILDREN|RDW_UPDATENOW);
+}
+
+void iupdrvDisplayUpdate(Ihandle *ih)
+{
+ /* Post a REDRAW */
+ RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_NOCHILDREN);
+}
+
+void iupdrvScreenToClient(Ihandle* ih, int *x, int *y)
+{
+ POINT p;
+ p.x = *x;
+ p.y = *y;
+ ScreenToClient(ih->handle, &p);
+ *x = p.x;
+ *y = p.y;
+}
+
+static void winTrackMouse(HWND hwnd, int enter)
+{
+ TRACKMOUSEEVENT mouse;
+ mouse.cbSize = sizeof(TRACKMOUSEEVENT);
+
+ if (enter)
+ mouse.dwFlags = TME_HOVER;
+ else
+ mouse.dwFlags = TME_LEAVE;
+
+ mouse.hwndTrack = hwnd;
+ mouse.dwHoverTime = 1;
+ TrackMouseEvent(&mouse);
+}
+
+static void winCallEnterLeaveWindow(Ihandle *ih, int enter)
+{
+ Icallback cb = NULL;
+
+ if (!ih->iclass->is_interactive)
+ return;
+
+ if (enter)
+ {
+ winTrackMouse(ih->handle, 0);
+
+ if (!iupAttribGetInt(ih, "_IUPWIN_ENTERWIN"))
+ {
+ cb = IupGetCallback(ih,"ENTERWINDOW_CB");
+ iupAttribSetStr(ih, "_IUPWIN_ENTERWIN", "1");
+ }
+ }
+ else
+ {
+ cb = IupGetCallback(ih,"LEAVEWINDOW_CB");
+ iupAttribSetStr(ih, "_IUPWIN_ENTERWIN", NULL);
+ }
+
+ if (cb)
+ cb(ih);
+}
+
+void iupwinMergeStyle(Ihandle* ih, DWORD old_mask, DWORD value)
+{
+ DWORD dwStyle = GetWindowLong(ih->handle, GWL_STYLE);
+ dwStyle &= ~(old_mask); /* clear old bits */
+ dwStyle |= value;
+ SetWindowLong(ih->handle, GWL_STYLE, dwStyle);
+}
+
+void iupwinSetStyle(Ihandle* ih, DWORD value, int set)
+{
+ DWORD dwStyle = GetWindowLong(ih->handle, GWL_STYLE);
+ if (set)
+ dwStyle |= value;
+ else
+ dwStyle &= ~(value);
+ SetWindowLong(ih->handle, GWL_STYLE, dwStyle);
+}
+
+int iupwinBaseProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ (void)lp;
+
+ switch (msg)
+ {
+ case WM_GETDLGCODE:
+ {
+ *result = DLGC_WANTALLKEYS;
+ return 1;
+ }
+ case WM_NOTIFY: /* usually sent only to parent,
+ but TIPs are configured to be handled here */
+ {
+ NMHDR* msg_info = (NMHDR*)lp;
+ if (msg_info->code == TTN_GETDISPINFO)
+ iupwinTipsGetDispInfo(lp);
+ break;
+ }
+ case WM_DROPFILES:
+ iupwinDropFiles((HDROP)wp, ih);
+ break;
+ case WM_HELP:
+ {
+ Ihandle* child;
+ HELPINFO* help_info = (HELPINFO*)lp;
+
+ if (help_info->iContextType == HELPINFO_MENUITEM)
+ child = iupwinMenuGetItemHandle((HMENU)help_info->hItemHandle, (int)help_info->iCtrlId);
+ else
+ child = iupwinHandleGet(help_info->hItemHandle);
+
+ if (child)
+ {
+ Icallback cb = (Icallback) IupGetCallback(child, "HELP_CB");
+ if (cb)
+ {
+ if (cb(child) == IUP_CLOSE)
+ IupExitLoop();
+
+ *result = 0;
+ return 1; /* abort default processing */
+ }
+ }
+ break;
+ }
+ case WM_MOUSELEAVE:
+ winCallEnterLeaveWindow(ih, 0);
+ break;
+ case WM_MOUSEMOVE:
+ winCallEnterLeaveWindow(ih, 1);
+ break;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ if (!iupwinKeyEvent(ih, (int)wp, 1))
+ {
+ *result = 0;
+ return 1; /* abort default processing */
+ }
+ break;
+ case WM_SYSKEYUP:
+ case WM_KEYUP:
+ {
+ int ret;
+ if (wp == VK_SNAPSHOT) /* called only on key up */
+ {
+ ret = iupwinKeyEvent(ih, (int)wp, 1);
+ if (ret && iupObjectCheck(ih))
+ ret = iupwinKeyEvent(ih, (int)wp, 0);
+ }
+ else
+ ret = iupwinKeyEvent(ih, (int)wp, 0);
+
+ if (!ret)
+ {
+ *result = 0;
+ return 1; /* abort default processing */
+ }
+
+ break;
+ }
+ case WM_SETFOCUS:
+ iupwinWmSetFocus(ih);
+ break;
+ case WM_KILLFOCUS:
+ iupCallKillFocusCb(ih);
+ break;
+ case WOM_CLOSE:
+ case WOM_DONE:
+ case WOM_OPEN:
+ {
+ IFni cb = (IFni)IupGetCallback(ih, "WOM_CB");
+ if (cb)
+ {
+ int v = -2; /* Error */
+ switch(msg)
+ {
+ case WOM_OPEN: v = 1; break;
+ case WOM_DONE: v = 0; break;
+ case WOM_CLOSE: v = -1; break;
+ }
+ cb(ih, v);
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+LRESULT CALLBACK iupwinBaseWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ int ret = 0;
+ LRESULT result = 0;
+ IwinProc winProc;
+ WNDPROC oldProc;
+ Ihandle *ih;
+
+ ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */
+
+ /* retrieve the control previous procedure for subclassing */
+ oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB");
+
+ /* check if the element defines a custom procedure */
+ winProc = (IwinProc)IupGetCallback(ih, "_IUPWIN_CTRLPROC_CB");
+ if (winProc)
+ ret = winProc(ih, msg, wp, lp, &result);
+ else
+ ret = iupwinBaseProc(ih, msg, wp, lp, &result);
+
+ if (ret)
+ return result;
+ else
+ return CallWindowProc(oldProc, hwnd, msg, wp, lp);
+}
+
+static Ihandle* winContainerWmCommandGetIhandle(Ihandle *ih, WPARAM wp, LPARAM lp)
+{
+ /* WPARAM - if HIWORD is 0 if the message is from a menu.
+ or HIWORD is 1 if the message is from an accelerator.
+ or HIWORD is the notification code if the message is from a control.
+ LOWORD is the identifier.
+ LPARAM - the control sending the message or 0. */
+
+ Ihandle *child = NULL;
+
+ if (HIWORD(wp)==0 && lp==0 && LOWORD(wp)>10)
+ {
+ Ihandle* dlg_menu = IupGetAttributeHandle(ih, "MENU");
+ if (dlg_menu)
+ child = iupwinMenuGetItemHandle((HMENU)dlg_menu->handle, LOWORD(wp)); /* menu */
+ }
+ else
+ {
+ if (lp==0)
+ child = ih; /* native parent */
+ else
+ {
+ child = iupwinHandleGet((void*)lp); /* control */
+ if (!child)
+ child = iupwinHandleGet((void*)GetParent((HWND)lp)); /* control */
+ }
+ }
+
+ return child;
+}
+
+int iupwinBaseContainerProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ /* All messages here are sent to the parent Window,
+ but they are usefull for child controls. */
+
+ switch (msg)
+ {
+ case WM_COMMAND:
+ {
+ Ihandle* child = winContainerWmCommandGetIhandle(ih, wp, lp);
+ if (child)
+ {
+ IFnii cb = (IFnii)IupGetCallback(child, "_IUPWIN_COMMAND_CB");
+ if (cb)
+ cb(child, wp, lp);
+ }
+
+ break;
+ }
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORSTATIC:
+ {
+ Ihandle* child = iupwinHandleGet((void*)lp);
+ if (child)
+ {
+ IFctlColor cb = (IFctlColor)IupGetCallback(child, "_IUPWIN_CTLCOLOR_CB");
+ if (cb)
+ return cb(child, (HDC)wp, result);
+ }
+ break;
+ }
+ case WM_DRAWITEM: /* for OWNERDRAW controls */
+ {
+ Ihandle *child = NULL;
+ DRAWITEMSTRUCT *drawitem = (LPDRAWITEMSTRUCT)lp;
+ if (!drawitem)
+ break;
+
+ if (wp == 0) /* a menu */
+ child = iupwinMenuGetItemHandle((HMENU)drawitem->hwndItem, drawitem->itemID);
+ else
+ child = iupwinHandleGet(drawitem->hwndItem);
+
+ if (child)
+ {
+ IFdrawItem cb = (IFdrawItem)IupGetCallback(child, "_IUPWIN_DRAWITEM_CB");
+ if (cb)
+ {
+ cb(child, (void*)drawitem);
+ *result = TRUE;
+ return 1;
+ }
+ }
+ break;
+ }
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ {
+ Ihandle *child = iupwinHandleGet((void*)lp);
+ if (child)
+ {
+ IFni cb = (IFni)IupGetCallback(child, "_IUPWIN_CUSTOMSCROLL_CB");
+ if (cb)
+ cb(child, LOWORD(wp));
+ }
+ break;
+ }
+ case WM_NOTIFY: /* Currently, the following controls support custom draw functionality:
+ Header, List-view, Rebar, Toolbar, ToolTip, Trackbar, Tree-view.
+ And for Button if using Windows XP Style. */
+ {
+ Ihandle *child;
+ NMHDR* msg_info = (NMHDR*)lp;
+ if (!msg_info)
+ break;
+
+ child = iupwinHandleGet(msg_info->hwndFrom);
+ if (child)
+ {
+ IFnotify cb = (IFnotify)IupGetCallback(child, "_IUPWIN_NOTIFY_CB");
+ if (cb)
+ {
+ if (cb(child, (void*)msg_info, result))
+ return 1;
+ }
+ }
+ break;
+ }
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+void iupwinChangeProc(Ihandle *ih, WNDPROC new_proc)
+{
+ IupSetCallback(ih, "_IUPWIN_OLDPROC_CB", (Icallback)GetWindowLongPtr(ih->handle, GWLP_WNDPROC));
+ SetWindowLongPtr(ih->handle, GWLP_WNDPROC, (LONG_PTR)new_proc);
+}
+
+void iupdrvBaseUnMapMethod(Ihandle* ih)
+{
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB");
+ if (oldProc)
+ {
+ SetWindowLongPtr(ih->handle, GWLP_WNDPROC, (LONG_PTR)oldProc);
+ IupSetCallback(ih, "_IUPWIN_OLDPROC_CB", NULL);
+ }
+
+ /* remove the association before destroying */
+ iupwinHandleRemove(ih);
+
+ /* destroys window (it will remove from parent) */
+ DestroyWindow(ih->handle);
+}
+
+void iupwinDropFiles(HDROP hDrop, Ihandle *ih)
+{
+ char *filename;
+ int i, numFiles, numchar, ret;
+ POINT point;
+
+ IFnsiii cb = (IFnsiii)IupGetCallback(ih, "DROPFILES_CB");
+ if (!cb) return;
+
+ numFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
+ DragQueryPoint(hDrop, &point);
+ for (i = 0; i < numFiles; i++)
+ {
+ numchar = DragQueryFile(hDrop, i, NULL, 0);
+ filename = malloc(numchar+1);
+ if (!filename)
+ break;
+
+ DragQueryFile(hDrop, i, filename, numchar+1);
+
+ ret = cb(ih, filename, numFiles-i-1, (int) point.x, (int) point.y);
+
+ free(filename);
+
+ if (ret == IUP_IGNORE)
+ break;
+ }
+ DragFinish(hDrop);
+}
+
+int iupwinGetColorRef(Ihandle *ih, char *name, COLORREF *color)
+{
+ unsigned char r, g, b;
+ /* must use IupGetAttribute to use inheritance */
+ if (iupStrToRGB(IupGetAttribute(ih, name), &r, &g, &b))
+ {
+ *color = RGB(r,g,b);
+ return 1;
+ }
+ return 0;
+}
+
+int iupwinGetParentBgColor(Ihandle* ih, COLORREF* cr)
+{
+ unsigned char r, g, b;
+ char* color = iupBaseNativeParentGetBgColorAttrib(ih);
+ if (iupStrToRGB(color, &r, &g, &b))
+ {
+ *cr = RGB(r,g,b);
+ return 1;
+ }
+ return 0;
+}
+
+int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value)
+{
+ if (IsWindowVisible(ih->handle))
+ {
+ if (iupStrEqualNoCase(value, "TOP"))
+ SetWindowPos(ih->handle, HWND_TOP, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
+ else
+ SetWindowPos(ih->handle, HWND_BOTTOM, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
+ }
+
+ return 0;
+}
+
+void iupdrvSetVisible(Ihandle* ih, int visible)
+{
+ ShowWindow(ih->handle, visible? SW_SHOWNORMAL: SW_HIDE);
+}
+
+int iupdrvIsVisible(Ihandle* ih)
+{
+ return IsWindowVisible(ih->handle);
+}
+
+int iupdrvIsActive(Ihandle* ih)
+{
+ return IsWindowEnabled(ih->handle);
+}
+
+void iupdrvSetActive(Ihandle* ih, int enable)
+{
+ EnableWindow(ih->handle, enable);
+}
+
+int iupdrvBaseSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (!value) value = "";
+ SetWindowText(ih->handle, value);
+ return 0;
+}
+
+char* iupdrvBaseGetTitleAttrib(Ihandle* ih)
+{
+ int nc = GetWindowTextLength(ih->handle);
+ if (nc)
+ {
+ char* str = iupStrGetMemory(nc+1);
+ GetWindowText(ih->handle, str, nc+1);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+int iupwinSetDragDropAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ DragAcceptFiles(ih->handle, TRUE);
+ else
+ DragAcceptFiles(ih->handle, FALSE);
+ return 1;
+}
+
+char *iupdrvBaseGetXAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+ RECT rect;
+ GetWindowRect(ih->handle, &rect);
+ sprintf(str, "%d", (int)rect.left);
+ return str;
+}
+
+char *iupdrvBaseGetYAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+ RECT rect;
+ GetWindowRect(ih->handle, &rect);
+ sprintf(str, "%d", (int)rect.top);
+ return str;
+}
+
+char* iupdrvBaseGetClientSizeAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(20);
+ RECT rect;
+ GetClientRect(ih->handle, &rect);
+ sprintf(str, "%dx%d", (int)(rect.right-rect.left), (int)(rect.bottom-rect.top));
+ return str;
+}
+
+#ifndef IDC_HAND
+#define IDC_HAND MAKEINTRESOURCE(32649)
+#endif
+#ifndef IDC_APPSTARTING
+#define IDC_APPSTARTING MAKEINTRESOURCE(32650)
+#endif
+#ifndef IDC_HELP
+#define IDC_HELP MAKEINTRESOURCE(32651)
+#endif
+
+static HCURSOR winGetCursor(Ihandle* ih, const char* name)
+{
+ static struct {
+ const char* iupname;
+ const char* sysname;
+ } table[] = {
+ {"NONE", NULL},
+ {"NULL", NULL},
+ {"ARROW", IDC_ARROW},
+ {"BUSY", IDC_WAIT},
+ {"CROSS", IDC_CROSS},
+ {"HAND", IDC_HAND},
+ {"MOVE", IDC_SIZEALL},
+ {"RESIZE_N", IDC_SIZENS},
+ {"RESIZE_S", IDC_SIZENS},
+ {"RESIZE_NS", IDC_SIZENS},
+ {"RESIZE_W", IDC_SIZEWE},
+ {"RESIZE_E", IDC_SIZEWE},
+ {"RESIZE_WE", IDC_SIZEWE},
+ {"RESIZE_NE", IDC_SIZENESW},
+ {"RESIZE_SE", IDC_SIZENWSE},
+ {"RESIZE_NW", IDC_SIZENWSE},
+ {"RESIZE_SW", IDC_SIZENESW},
+ {"TEXT", IDC_IBEAM},
+ {"HELP", IDC_HELP},
+ {"IUP", IDC_HELP},
+ {"NO", IDC_NO},
+ {"UPARROW", IDC_UPARROW},
+ {"APPSTARTING", IDC_APPSTARTING}
+ };
+
+ HCURSOR cur;
+ char str[50];
+ int i, count = sizeof(table)/sizeof(table[0]);
+
+ /* check the cursor cache first (per control)*/
+ sprintf(str, "_IUPWIN_CURSOR_%s", name);
+ cur = (HCURSOR)iupAttribGet(ih, str);
+ if (cur)
+ return cur;
+
+ /* check the pre-defined IUP names first */
+ for (i = 0; i < count; i++)
+ {
+ if (iupStrEqualNoCase(name, table[i].iupname))
+ {
+ if (table[i].sysname)
+ cur = LoadCursor(NULL, table[i].sysname);
+ else
+ cur = NULL;
+
+ break;
+ }
+ }
+
+ if (i == count)
+ {
+ /* check other system cursors */
+ /* cursor PEN is handled here */
+ if (iupStrEqualNoCase(name, "PEN"))
+ name = "CURSOR_PEN";
+
+ /* check for an name defined cursor */
+ cur = iupImageGetCursor(name);
+ }
+
+ iupAttribSetStr(ih, str, (char*)cur);
+ return cur;
+}
+
+int iupdrvBaseSetCursorAttrib(Ihandle* ih, const char* value)
+{
+ /* Cursor can be NULL in Windows. */
+ HCURSOR hCur = winGetCursor(ih, value);
+ iupAttribSetStr(ih, "_IUPWIN_HCURSOR", (char*)hCur); /* To be used in WM_SETCURSOR */
+ /* refresh the cursor */
+ SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE));
+ return 1;
+}
+
+void iupdrvBaseRegisterCommonAttrib(Iclass* ic)
+{
+ iupClassRegisterAttribute(ic, "HFONT", iupwinGetHFontAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+}
+
+int iupwinButtonDown(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp)
+{
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ int ret, doubleclick = 0;
+ int b = 0;
+
+ IFniiiis cb = (IFniiiis) IupGetCallback(ih, "BUTTON_CB");
+ if (!cb)
+ return 0;
+
+ if (msg==WM_XBUTTONDBLCLK ||
+ msg==WM_LBUTTONDBLCLK ||
+ msg==WM_MBUTTONDBLCLK ||
+ msg==WM_RBUTTONDBLCLK)
+ doubleclick = 1;
+
+ iupwinButtonKeySetStatus(LOWORD(wp), status, doubleclick);
+
+ if (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONDBLCLK)
+ b = IUP_BUTTON1;
+ else if (msg==WM_MBUTTONDOWN || msg==WM_MBUTTONDBLCLK)
+ b = IUP_BUTTON2;
+ else if (msg==WM_RBUTTONDOWN || msg==WM_RBUTTONDBLCLK)
+ b = IUP_BUTTON3;
+ else if (msg==WM_XBUTTONDOWN || msg==WM_XBUTTONDBLCLK)
+ {
+ if (HIWORD(wp) == XBUTTON1)
+ b = IUP_BUTTON4;
+ else
+ b = IUP_BUTTON5;
+ }
+
+ ret = cb(ih, b, 1, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp), status);
+ if (ret == IUP_CLOSE)
+ IupExitLoop();
+ else if (ret == IUP_IGNORE)
+ return -1;
+
+ return 1;
+}
+
+int iupwinButtonUp(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp)
+{
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ int ret, b=0;
+ IFniiiis cb = (IFniiiis) IupGetCallback(ih, "BUTTON_CB");
+ if (!cb)
+ return 0;
+
+ iupwinButtonKeySetStatus(LOWORD(wp), status, 0);
+
+ /* also updates the button status, since wp could not have the flag */
+ if (msg==WM_LBUTTONUP)
+ {
+ b = IUP_BUTTON1;
+ iupKEYSETBUTTON1(status);
+ }
+ else if (msg==WM_MBUTTONUP)
+ {
+ b = IUP_BUTTON2;
+ iupKEYSETBUTTON2(status);
+ }
+ else if (msg==WM_RBUTTONUP)
+ {
+ b = IUP_BUTTON3;
+ iupKEYSETBUTTON3(status);
+ }
+ else if (msg==WM_XBUTTONUP)
+ {
+ if (HIWORD(wp) == XBUTTON1)
+ {
+ b = IUP_BUTTON4;
+ iupKEYSETBUTTON4(status);
+ }
+ else
+ {
+ b = IUP_BUTTON5;
+ iupKEYSETBUTTON5(status);
+ }
+ }
+
+ ret = cb(ih, b, 0, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp), status);
+ if (ret == IUP_CLOSE)
+ IupExitLoop();
+ else if (ret == IUP_IGNORE)
+ return -1;
+
+ return 1;
+}
+
+int iupwinMouseMove(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp)
+{
+ IFniis cb = (IFniis)IupGetCallback(ih, "MOTION_CB");
+ if (cb)
+ {
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ iupwinButtonKeySetStatus(LOWORD(wp), status, 0);
+ cb(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp), status);
+ return 1;
+ }
+ (void)msg;
+ return 0;
+}
+
+int iupwinCreateWindowEx(Ihandle* ih, LPCSTR lpClassName, DWORD dwExStyle, DWORD dwStyle)
+{
+ ih->serial = iupDialogGetChildId(ih);
+
+ ih->handle = CreateWindowEx(dwExStyle, /* extended window style */
+ lpClassName, /* window class */
+ NULL, /* title */
+ dwStyle, /* window style */
+ 0, /* x-position */
+ 0, /* y-position */
+ 10, /* default width to avoid 0 */
+ 10, /* default height to avoid 0 */
+ iupChildTreeGetNativeParentHandle(ih), /* window parent */
+ (HMENU)ih->serial, /* child identifier */
+ iupwin_hinstance, /* instance of app. */
+ NULL);
+
+ if (!ih->handle)
+ return 0;
+
+ /* associate HWND with Ihandle*, all Win32 controls must call this. */
+ iupwinHandleSet(ih);
+
+ /* replace the WinProc to handle base callbacks */
+ iupwinChangeProc(ih, iupwinBaseWinProc);
+
+ return 1;
+}
+
+char* iupwinGetClipboardText(Ihandle* ih)
+{
+ HANDLE Handle;
+ char* str;
+
+ if (!IsClipboardFormatAvailable(CF_TEXT))
+ return NULL;
+
+ if (!OpenClipboard(ih->handle))
+ return NULL;
+
+ Handle = GetClipboardData(CF_TEXT);
+ if (!Handle)
+ {
+ CloseClipboard();
+ return NULL;
+ }
+
+ str = (char*)GlobalLock(Handle);
+ str = iupStrDup(str);
+
+ GlobalUnlock(Handle);
+
+ CloseClipboard();
+
+ return str;
+}
diff --git a/iup/src/win/iupwin_dialog.c b/iup/src/win/iupwin_dialog.c
new file mode 100755
index 0000000..39fdc0c
--- /dev/null
+++ b/iup/src/win/iupwin_dialog.c
@@ -0,0 +1,1439 @@
+/** \file
+ * \brief IupDialog class
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_dlglist.h"
+#include "iup_attrib.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_drvfont.h"
+#include "iup_focus.h"
+#include "iup_str.h"
+#define _IUPDLG_PRIVATE
+#include "iup_dialog.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_brush.h"
+#include "iupwin_info.h"
+
+
+#define IWIN_TRAY_NOTIFICATION 102
+
+static int WM_HELPMSG;
+
+static int winDialogSetBgColorAttrib(Ihandle* ih, const char* value);
+static int winDialogSetTrayAttrib(Ihandle *ih, const char *value);
+
+/****************************************************************
+ Utilities
+****************************************************************/
+
+int iupdrvDialogIsVisible(Ihandle* ih)
+{
+ return iupdrvIsVisible(ih);
+}
+
+void iupdrvDialogUpdateSize(Ihandle* ih)
+{
+ RECT rect;
+ GetWindowRect(ih->handle, &rect);
+ ih->currentwidth = rect.right-rect.left;
+ ih->currentheight = rect.bottom-rect.top;
+}
+
+void iupdrvDialogGetSize(InativeHandle* handle, int *w, int *h)
+{
+ RECT rect;
+ GetWindowRect(handle, &rect);
+ if (w) *w = rect.right-rect.left;
+ if (h) *h = rect.bottom-rect.top;
+}
+
+void iupdrvDialogSetVisible(Ihandle* ih, int visible)
+{
+ ShowWindow(ih->handle, visible? ih->data->cmd_show: SW_HIDE);
+}
+
+void iupdrvDialogGetPosition(InativeHandle* handle, int *x, int *y)
+{
+ RECT rect;
+ GetWindowRect(handle, &rect);
+ if (x) *x = rect.left;
+ if (y) *y = rect.top;
+}
+
+void iupdrvDialogSetPosition(Ihandle *ih, int x, int y)
+{
+ /* Only moves the window and places it at the top of the Z order. */
+ SetWindowPos(ih->handle, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
+}
+
+void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu)
+{
+ if (ih->data->menu)
+ *menu = iupdrvMenuGetMenuBarSize(ih->data->menu);
+ else
+ *menu = 0;
+
+ if (ih->handle)
+ {
+ iupdrvGetWindowDecor(ih->handle, border, caption);
+
+ if (*menu)
+ *caption -= *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 */
+
+ *caption = 0;
+ if (has_titlebar)
+ {
+ if (iupAttribGetBoolean(ih, "TOOLBOX") && iupAttribGet(ih, "PARENTDIALOG"))
+ *caption = GetSystemMetrics(SM_CYSMCAPTION); /* tool window */
+ else
+ *caption = GetSystemMetrics(SM_CYCAPTION); /* normal window */
+ }
+
+ *border = 0;
+ if (iupAttribGetBoolean(ih, "RESIZE"))
+ {
+ *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)
+ {
+ *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"))
+ {
+ *border = GetSystemMetrics(SM_CXBORDER);
+ }
+ }
+}
+
+int iupdrvDialogSetPlacement(Ihandle* ih)
+{
+ char* placement;
+
+ ih->data->cmd_show = SW_SHOWNORMAL;
+ ih->data->show_state = IUP_SHOW;
+
+ if (iupAttribGetBoolean(ih, "FULLSCREEN"))
+ return 1;
+
+ placement = iupAttribGet(ih, "PLACEMENT");
+ if (!placement)
+ {
+ if (IsIconic(ih->handle) || IsZoomed(ih->handle))
+ ih->data->show_state = IUP_RESTORE;
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(placement, "MAXIMIZED"))
+ {
+ ih->data->cmd_show = SW_SHOWMAXIMIZED;
+ ih->data->show_state = IUP_MAXIMIZE;
+ }
+ else if (iupStrEqualNoCase(placement, "MINIMIZED"))
+ {
+ ih->data->cmd_show = SW_SHOWMINIMIZED;
+ ih->data->show_state = IUP_MINIMIZE;
+ }
+ else if (iupStrEqualNoCase(placement, "FULL"))
+ {
+ int width, height, x, y;
+ int caption, border, menu;
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ /* the dialog will cover the task bar */
+ iupdrvGetFullSize(&width, &height);
+
+ /* position the decoration and menu outside the screen */
+ x = -(border);
+ y = -(border+caption+menu);
+
+ width += 2*border;
+ height += 2*border + caption + menu;
+
+ /* set the new size and position */
+ /* WM_SIZE will update the layout */
+ SetWindowPos(ih->handle, HWND_TOP, x, y, width, height, 0);
+
+ if (IsIconic(ih->handle) || IsZoomed(ih->handle))
+ ih->data->show_state = IUP_RESTORE;
+ }
+
+ iupAttribSetStr(ih, "PLACEMENT", NULL); /* reset to NORMAL */
+
+ return 1;
+}
+
+static int winDialogMDICloseChildren(Ihandle* ih)
+{
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (iupObjectCheck(client))
+ {
+ HWND hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+
+ /* As long as the MDI client has a child, close it */
+ while (hWndChild)
+ {
+ Ihandle* child = iupwinHandleGet(hWndChild);
+ if (iupObjectCheck(child) && iupAttribGetBoolean(child, "MDICHILD"))
+ {
+ Icallback cb = IupGetCallback(child, "CLOSE_CB");
+ if (cb)
+ {
+ int ret = cb(child);
+ if (ret == IUP_IGNORE)
+ return 0;
+ if (ret == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ IupDestroy(child);
+ }
+
+ hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+ }
+ }
+ return 1;
+}
+
+
+/****************************************************************************
+ WindowProc
+****************************************************************************/
+
+
+static Ihandle* winMinMaxHandle = NULL;
+
+static int winDialogCheckMinMaxInfo(Ihandle* ih, MINMAXINFO* minmax)
+{
+ int min_w = 1, min_h = 1; /* MINSIZE default value */
+ int max_w = 65535, max_h = 65535; /* MAXSIZE default value */
+
+ iupStrToIntInt(iupAttribGet(ih, "MINSIZE"), &min_w, &min_h, 'x');
+ iupStrToIntInt(iupAttribGet(ih, "MAXSIZE"), &max_w, &max_h, 'x');
+
+ minmax->ptMinTrackSize.x = min_w;
+ minmax->ptMinTrackSize.y = min_h;
+ minmax->ptMaxTrackSize.x = max_w;
+ minmax->ptMaxTrackSize.y = max_h;
+
+ if (winMinMaxHandle == ih)
+ winMinMaxHandle = NULL;
+
+ return 1;
+}
+
+static void winDialogResize(Ihandle* ih, int width, int height)
+{
+ IFnii cb;
+
+ iupdrvDialogUpdateSize(ih);
+
+ cb = (IFnii)IupGetCallback(ih, "RESIZE_CB");
+ if (!cb || cb(ih, width, height)!=IUP_IGNORE) /* width and height here are for the client area */
+ {
+ ih->data->ignore_resize = 1;
+ IupRefresh(ih);
+ ih->data->ignore_resize = 0;
+ }
+}
+
+static int winDialogBaseProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ if (iupwinBaseContainerProc(ih, msg, wp, lp, result))
+ return 1;
+
+ iupwinMenuDialogProc(ih, msg, wp, lp);
+
+ switch (msg)
+ {
+ case WM_GETMINMAXINFO:
+ {
+ if (winDialogCheckMinMaxInfo(ih, (MINMAXINFO*)lp))
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ }
+ case WM_MOVE:
+ {
+ IFnii cb = (IFnii)IupGetCallback(ih, "MOVE_CB");
+ RECT rect;
+ GetWindowRect(ih->handle, &rect); /* ignore LPARAM because they are the clientpos and not X/Y */
+ if (cb) cb(ih, rect.left, rect.top);
+ break;
+ }
+ case WM_SIZE:
+ {
+ if (ih->data->ignore_resize)
+ break;
+
+ switch(wp)
+ {
+ case SIZE_MINIMIZED:
+ {
+ if (ih->data->show_state != IUP_MINIMIZE)
+ {
+ IFni show_cb = (IFni)IupGetCallback(ih, "SHOW_CB");
+ if (show_cb && show_cb(ih, IUP_MINIMIZE) == IUP_CLOSE)
+ IupExitLoop();
+ ih->data->show_state = IUP_MINIMIZE;
+ }
+ break;
+ }
+ case SIZE_MAXIMIZED:
+ {
+ if (ih->data->show_state != IUP_MAXIMIZE)
+ {
+ IFni show_cb = (IFni)IupGetCallback(ih, "SHOW_CB");
+ if (show_cb && show_cb(ih, IUP_MAXIMIZE) == IUP_CLOSE)
+ IupExitLoop();
+ ih->data->show_state = IUP_MAXIMIZE;
+ }
+
+ winDialogResize(ih, LOWORD(lp), HIWORD(lp));
+ break;
+ }
+ case SIZE_RESTORED:
+ {
+ if (ih->data->show_state == IUP_MAXIMIZE || ih->data->show_state == IUP_MINIMIZE)
+ {
+ IFni show_cb = (IFni)IupGetCallback(ih, "SHOW_CB");
+ if (show_cb && show_cb(ih, IUP_RESTORE) == IUP_CLOSE)
+ IupExitLoop();
+ ih->data->show_state = IUP_RESTORE;
+ }
+
+ winDialogResize(ih, LOWORD(lp), HIWORD(lp));
+ break;
+ }
+ }
+
+ break;
+ }
+ case WM_USER+IWIN_TRAY_NOTIFICATION:
+ {
+ int dclick = 0;
+ int button = 0;
+ int pressed = 0;
+
+ switch (lp)
+ {
+ case WM_LBUTTONDOWN:
+ pressed = 1;
+ button = 1;
+ break;
+ case WM_MBUTTONDOWN:
+ pressed = 1;
+ button = 2;
+ break;
+ case WM_RBUTTONDOWN:
+ pressed = 1;
+ button = 3;
+ break;
+ case WM_LBUTTONDBLCLK:
+ dclick = 1;
+ button = 1;
+ break;
+ case WM_MBUTTONDBLCLK:
+ dclick = 1;
+ button = 2;
+ break;
+ case WM_RBUTTONDBLCLK:
+ dclick = 1;
+ button = 3;
+ break;
+ case WM_LBUTTONUP:
+ button = 1;
+ break;
+ case WM_MBUTTONUP:
+ button = 2;
+ break;
+ case WM_RBUTTONUP:
+ button = 3;
+ break;
+ }
+
+ if (button != 0)
+ {
+ IFniii cb = (IFniii)IupGetCallback(ih, "TRAYCLICK_CB");
+ if (cb && cb(ih, button, pressed, dclick) == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ break;
+ }
+ case WM_CLOSE:
+ {
+ Icallback cb = IupGetCallback(ih, "CLOSE_CB");
+ if (cb)
+ {
+ int ret = cb(ih);
+ if (ret == IUP_IGNORE)
+ {
+ *result = 0;
+ return 1;
+ }
+ if (ret == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ /* child mdi is automatically destroyed */
+ if (iupAttribGetBoolean(ih, "MDICHILD"))
+ IupDestroy(ih);
+ else
+ {
+ if (!winDialogMDICloseChildren(ih))
+ {
+ *result = 0;
+ return 1;
+ }
+
+ IupHide(ih); /* IUP default processing */
+ }
+
+ *result = 0;
+ return 1;
+ }
+ case WM_SETCURSOR:
+ {
+ if (ih->handle == (HWND)wp && LOWORD(lp)==HTCLIENT)
+ {
+ HCURSOR hCur = (HCURSOR)iupAttribGet(ih, "_IUPWIN_HCURSOR");
+ if (hCur)
+ {
+ SetCursor(hCur);
+ *result = 1;
+ return 1;
+ }
+ else if (iupAttribGet(ih, "CURSOR"))
+ {
+ SetCursor(NULL);
+ *result = 1;
+ return 1;
+ }
+ }
+ break;
+ }
+ case WM_ERASEBKGND:
+ {
+ HBITMAP hBitmap = (HBITMAP)iupAttribGet(ih, "_IUPWIN_BACKGROUND_BITMAP");
+ if (hBitmap)
+ {
+ RECT rect;
+ HDC hdc = (HDC)wp;
+
+ HBRUSH hBrush = CreatePatternBrush(hBitmap);
+ GetClientRect(ih->handle, &rect);
+ FillRect(hdc, &rect, hBrush);
+ DeleteObject(hBrush);
+
+ /* return non zero value */
+ *result = 1;
+ return 1;
+ }
+ else
+ {
+ unsigned char r, g, b;
+ char* color = iupAttribGet(ih, "_IUPWIN_BACKGROUND_COLOR");
+ if (iupStrToRGB(color, &r, &g, &b))
+ {
+ RECT rect;
+ HDC hdc = (HDC)wp;
+
+ SetDCBrushColor(hdc, RGB(r,g,b));
+ GetClientRect(ih->handle, &rect);
+ FillRect(hdc, &rect, (HBRUSH)GetStockObject(DC_BRUSH));
+
+ /* return non zero value */
+ *result = 1;
+ return 1;
+ }
+ }
+ break;
+ }
+ case WM_DESTROY:
+ {
+ /* Since WM_CLOSE changed the Windows default processing */
+ /* WM_DESTROY is NOT received by IupDialogs */
+ /* Except when they are children of other IupDialogs and the parent is destroyed. */
+ /* So we have to destroy the child dialog. */
+ /* The application is responsable for destroying the children before this happen. */
+ IupDestroy(ih);
+ break;
+ }
+ }
+
+ if (msg == (UINT)WM_HELPMSG)
+ {
+ Ihandle* child = NULL;
+ DWORD* struct_ptr = (DWORD*)lp;
+ if (*struct_ptr == sizeof(CHOOSECOLOR))
+ {
+ CHOOSECOLOR* choosecolor = (CHOOSECOLOR*)lp;
+ child = (Ihandle*)choosecolor->lCustData;
+ }
+ if (*struct_ptr == sizeof(CHOOSEFONT))
+ {
+ CHOOSEFONT* choosefont = (CHOOSEFONT*)lp;
+ child = (Ihandle*)choosefont->lCustData;
+ }
+
+ if (child)
+ {
+ Icallback cb = IupGetCallback(child, "HELP_CB");
+ if (cb && cb(child) == IUP_CLOSE)
+ EndDialog((HWND)iupAttribGet(child, "HWND"), IDCANCEL);
+ }
+ }
+
+ return 0;
+}
+
+static LRESULT CALLBACK winDialogProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ LRESULT result;
+ Ihandle *ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ {
+ /* the first time WM_GETMINMAXINFO is called, Ihandle is not associated yet */
+ if (msg == WM_GETMINMAXINFO && winMinMaxHandle)
+ {
+ if (winDialogCheckMinMaxInfo(winMinMaxHandle, (MINMAXINFO*)lp))
+ return 0;
+ }
+
+ return DefWindowProc(hwnd, msg, wp, lp);
+ }
+
+ if (winDialogBaseProc(ih, msg, wp, lp, &result))
+ return result;
+
+ return DefWindowProc(hwnd, msg, wp, lp);
+}
+
+static LRESULT CALLBACK winDialogMDIChildProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ LRESULT result;
+ Ihandle *ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ {
+ /* the first time WM_GETMINMAXINFO is called, Ihandle is not associated yet */
+ if (msg == WM_GETMINMAXINFO && winMinMaxHandle)
+ {
+ if (winDialogCheckMinMaxInfo(winMinMaxHandle, (MINMAXINFO*)lp))
+ return 0;
+ }
+
+ return DefMDIChildProc(hwnd, msg, wp, lp);
+ }
+
+ switch (msg)
+ {
+ case WM_MDIACTIVATE:
+ {
+ HWND hNewActive = (HWND)lp;
+ if (hNewActive == ih->handle)
+ {
+ Icallback cb = (Icallback)IupGetCallback(ih, "MDIACTIVATE_CB");
+ if (cb) cb(ih);
+ }
+ break;
+ }
+ }
+
+ if (winDialogBaseProc(ih, msg, wp, lp, &result))
+ return result;
+
+ return DefMDIChildProc(hwnd, msg, wp, lp);
+}
+
+static Ihandle* winDialogGetMdiChildId(Ihandle* ih, int mdi_child_id)
+{
+ int id, max_child_id, real_id = -1;
+ char name[50];
+ Ihandle* child;
+
+ max_child_id = iupAttribGetInt(ih, "_IUPWIN_MAX_MDI_ID");
+
+ for (id = 0; id < max_child_id; id++)
+ {
+ sprintf(name, "_IUPWIN_MDI_ID_[%d]", id);
+ child = (Ihandle*)iupAttribGet(ih, name);
+ if (iupObjectCheck(child))
+ {
+ real_id++;
+ if (real_id == mdi_child_id)
+ return child;
+ }
+ }
+
+ return NULL;
+}
+
+static LRESULT CALLBACK winDialogMDIFrameProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ LRESULT result;
+ HWND hWndClient = NULL;
+ Ihandle *ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ {
+ /* the first time WM_GETMINMAXINFO is called, Ihandle is not associated yet */
+ if (msg == WM_GETMINMAXINFO && winMinMaxHandle)
+ {
+ if (winDialogCheckMinMaxInfo(winMinMaxHandle, (MINMAXINFO*)lp))
+ return 0;
+ }
+
+ return DefFrameProc(hwnd, hWndClient, msg, wp, lp);
+ }
+
+ {
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (client) hWndClient = client->handle;
+ }
+
+ if (winDialogBaseProc(ih, msg, wp, lp, &result))
+ return result;
+
+ switch (msg)
+ {
+ case WM_MENUCOMMAND:
+ {
+ int menuId = GetMenuItemID((HMENU)lp, (int)wp);
+ if (menuId >= IUP_MDICHILD_START && hWndClient)
+ {
+ Ihandle* child = winDialogGetMdiChildId(ih, menuId-IUP_MDICHILD_START);
+ if (child)
+ SendMessage(hWndClient, WM_MDIACTIVATE, (WPARAM)child->handle, 0);
+ break;
+ }
+ }
+ }
+
+
+ return DefFrameProc(hwnd, hWndClient, msg, wp, lp);
+}
+
+static void winDialogRegisterClass(int mdi)
+{
+ char* name;
+ WNDCLASS wndclass;
+ WNDPROC winproc;
+ ZeroMemory(&wndclass, sizeof(WNDCLASS));
+
+ if (mdi == 2)
+ {
+ name = "IupDialogMDIChild";
+ winproc = (WNDPROC)winDialogMDIChildProc;
+ }
+ else if (mdi == 1)
+ {
+ name = "IupDialogMDIFrame";
+ winproc = (WNDPROC)winDialogMDIFrameProc;
+ }
+ else
+ {
+ if (mdi == -1)
+ name = "IupDialogControl";
+ else
+ name = "IupDialog";
+ winproc = (WNDPROC)winDialogProc;
+ }
+
+ wndclass.hInstance = iupwin_hinstance;
+ wndclass.lpszClassName = name;
+ wndclass.lpfnWndProc = (WNDPROC)winproc;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+
+ /* To use a standard system color, must increase the background-color value by one */
+ if (mdi == 1)
+ wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1);
+ else
+ wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
+
+ if (mdi == 0)
+ wndclass.style |= CS_SAVEBITS;
+
+ if (mdi == -1)
+ wndclass.style |= CS_HREDRAW | CS_VREDRAW;
+
+ RegisterClass(&wndclass);
+}
+
+
+/****************************************************************
+ dialog class functions
+****************************************************************/
+
+
+static int winDialogMapMethod(Ihandle* ih)
+{
+ InativeHandle* native_parent;
+ DWORD dwStyle = WS_CLIPSIBLINGS,
+ dwExStyle = 0;
+ int has_titlebar = 0,
+ has_border = 0;
+ char* classname = "IupDialog";
+
+ char* title = iupAttribGet(ih, "TITLE");
+ if (title)
+ has_titlebar = 1;
+
+ if (iupAttribGetBoolean(ih, "DIALOGFRAME"))
+ {
+ iupAttribSetStr(ih, "RESIZE", "NO");
+ iupAttribSetStr(ih, "MINBOX", "NO");
+ }
+
+ if (iupAttribGetBoolean(ih, "RESIZE"))
+ dwStyle |= WS_THICKFRAME;
+ 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;
+
+ if (iupAttribGetBoolean(ih, "MDICHILD"))
+ {
+ static int mdi_child_id = 0;
+ Ihandle *client;
+ char name[50];
+
+ /* must have a parent dialog (the mdi frame) */
+ Ihandle* parent = IupGetAttributeHandle(ih, "PARENTDIALOG");
+ if (!parent || !parent->handle)
+ return IUP_ERROR;
+
+ /* set when the mdi client is mapped */
+ client = (Ihandle*)iupAttribGet(parent, "MDICLIENT_HANDLE");
+ if (!client)
+ return IUP_ERROR;
+
+ /* store the mdi client handle in each mdi child also */
+ iupAttribSetStr(ih, "MDICLIENT_HANDLE", (char*)client);
+
+ sprintf(name, "_IUPWIN_MDI_ID_[%d]", mdi_child_id);
+ iupAttribSetStr(parent, name, (char*)ih);
+ mdi_child_id++;
+ iupAttribSetInt(parent, "_IUPWIN_MAX_MDI_ID", mdi_child_id);
+
+ classname = "IupDialogMDIChild";
+
+ /* The actual parent is the mdi client */
+ native_parent = client->handle;
+
+ dwStyle |= WS_CHILD;
+ if (has_titlebar)
+ dwStyle |= WS_CAPTION;
+ else if (has_border)
+ dwStyle |= WS_BORDER;
+
+ if (!IupGetName(ih))
+ iupAttribSetHandleName(ih);
+ }
+ else
+ {
+ native_parent = iupDialogGetNativeParent(ih);
+
+ if (native_parent)
+ {
+ dwStyle |= WS_POPUP;
+
+ if (has_titlebar)
+ dwStyle |= WS_CAPTION;
+ else if (has_border)
+ dwStyle |= WS_BORDER;
+ }
+ else
+ {
+ if (has_titlebar)
+ {
+ dwStyle |= WS_OVERLAPPED;
+ }
+ else
+ {
+ if (has_border)
+ dwStyle |= WS_POPUP | WS_BORDER;
+ else
+ dwStyle |= WS_POPUP;
+
+ dwExStyle |= WS_EX_NOACTIVATE; /* this will hide it from the taskbar */
+ }
+ }
+
+ if (iupAttribGet(ih, "MDIFRAME"))
+ classname = "IupDialogMDIFrame";
+ }
+
+ if (iupAttribGetBoolean(ih, "TOOLBOX") && native_parent)
+ dwExStyle |= WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE;
+
+ 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;
+
+ if (iupAttribGetBoolean(ih, "HELPBUTTON"))
+ dwExStyle |= WS_EX_CONTEXTHELP;
+
+ if (iupAttribGetBoolean(ih, "CONTROL") && native_parent)
+ {
+ /* TODO: this were used by LuaCom to create embeded controls,
+ don't know if it is still working */
+ dwStyle = WS_CHILD | WS_TABSTOP | WS_CLIPCHILDREN;
+ classname = "IupDialogControl";
+ }
+
+ /* CreateWindowEx will send WM_GETMINMAXINFO before Ihandle is associated with HWND */
+ if (iupAttribGet(ih, "MINSIZE") || iupAttribGet(ih, "MAXSIZE"))
+ winMinMaxHandle = ih;
+
+ /* size will be updated in IupRefresh -> winDialogLayoutUpdate */
+ /* position will be updated in iupDialogShowXY */
+
+ if (iupAttribGetBoolean(ih, "MDICHILD"))
+ ih->handle = CreateMDIWindow(classname,
+ title, /* title */
+ dwStyle, /* style */
+ 0, /* x-position */
+ 0, /* y-position */
+ 100, /* horizontal size - set this to avoid size calculation problems */
+ 100, /* vertical size */
+ native_parent, /* owner window */
+ iupwin_hinstance, /* instance of app. */
+ 0); /* no creation parameters */
+ else
+ ih->handle = CreateWindowEx(dwExStyle, /* extended styles */
+ classname, /* class */
+ title, /* title */
+ dwStyle, /* style */
+ 0, /* x-position */
+ 0, /* y-position */
+ 100, /* horizontal size - set this to avoid size calculation problems */
+ 100, /* vertical size */
+ native_parent, /* owner window */
+ (HMENU)0, /* Menu or child-window identifier */
+ iupwin_hinstance, /* instance of app. */
+ NULL); /* no creation parameters */
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* associate HWND with Ihandle*, all Win32 controls must call this. */
+ iupwinHandleSet(ih);
+
+ if (iupStrEqual(classname, "IupDialogMDIChild")) /* hides the mdi child */
+ ShowWindow(ih->handle, SW_HIDE);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ /* 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);
+
+ /* Set the default CmdShow for ShowWindow */
+ ih->data->cmd_show = SW_SHOWNORMAL;
+
+ return IUP_NOERROR;
+}
+
+static void winDialogUnMapMethod(Ihandle* ih)
+{
+ if (ih->data->menu)
+ {
+ ih->data->menu->handle = NULL; /* the dialog will destroy the native menu */
+ IupDestroy(ih->data->menu);
+ }
+
+ if (iupAttribGet(ih, "_IUPDLG_HASTRAY"))
+ winDialogSetTrayAttrib(ih, NULL);
+
+ /* remove the association before destroying */
+ iupwinHandleRemove(ih);
+
+ /* Destroys the window, so we can destroy the class */
+ if (iupAttribGetBoolean(ih, "MDICHILD"))
+ {
+ /* for MDICHILDs must send WM_MDIDESTROY, instead of calling DestroyWindow */
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ SendMessage(client->handle, WM_MDIDESTROY, (WPARAM)ih->handle, 0);
+ }
+ else
+ DestroyWindow(ih->handle); /* this will destroy the Windows children also. */
+ /* but IupDestroy already destroyed the IUP children */
+ /* so it is safe to call DestroyWindow */
+}
+
+static void winDialogLayoutUpdateMethod(Ihandle *ih)
+{
+ if (ih->data->ignore_resize)
+ return;
+
+ ih->data->ignore_resize = 1;
+
+ /* for dialogs the position is not updated here */
+ SetWindowPos(ih->handle, 0, 0, 0, ih->currentwidth, ih->currentheight,
+ SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSENDCHANGING);
+
+ ih->data->ignore_resize = 0;
+}
+
+static void winDialogReleaseMethod(Iclass* ic)
+{
+ (void)ic;
+ if (iupwinClassExist("IupDialog"))
+ {
+ UnregisterClass("IupDialog", iupwin_hinstance);
+ UnregisterClass("IupDialogControl", iupwin_hinstance);
+ UnregisterClass("IupDialogMDIChild", iupwin_hinstance);
+ UnregisterClass("IupDialogMDIFrame", iupwin_hinstance);
+ }
+}
+
+
+
+/****************************************************************************
+ Attributes
+****************************************************************************/
+
+
+static int winDialogSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ 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 */
+ return 1;
+ }
+ return 0;
+}
+
+static int winDialogSetBackgroundAttrib(Ihandle* ih, const char* value)
+{
+ if (winDialogSetBgColorAttrib(ih, value))
+ return 1;
+ else
+ {
+ HBITMAP hBitmap = iupImageGetImage(value, ih, 0);
+ if (hBitmap)
+ {
+ 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 */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static HWND iupwin_mdifirst = NULL;
+static HWND iupwin_mdinext = NULL;
+
+static char* winDialogGetMdiActiveAttrib(Ihandle *ih)
+{
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (client)
+ {
+ HWND hchild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+ Ihandle* child = iupwinHandleGet(hchild);
+ if (child)
+ {
+ iupwin_mdinext = NULL;
+ iupwin_mdifirst = hchild;
+ return IupGetName(child);
+ }
+ }
+
+ iupwin_mdifirst = NULL;
+ iupwin_mdinext = NULL;
+ return NULL;
+}
+
+static char* winDialogGetMdiNextAttrib(Ihandle *ih)
+{
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (client)
+ {
+ Ihandle* child;
+ HWND hchild = iupwin_mdinext? iupwin_mdinext: iupwin_mdifirst;
+
+ /* Skip the icon title windows */
+ while (hchild && GetWindow (hchild, GW_OWNER))
+ hchild = GetWindow(hchild, GW_HWNDNEXT);
+
+ if (!hchild || hchild == iupwin_mdifirst)
+ {
+ iupwin_mdinext = NULL;
+ return NULL;
+ }
+
+ child = iupwinHandleGet(hchild);
+ if (child)
+ {
+ iupwin_mdinext = hchild;
+ return IupGetName(child);
+ }
+ }
+
+ iupwin_mdinext = NULL;
+ return NULL;
+}
+
+/* define this here, so we do not need to define _WIN32_WINNT=0x0500 */
+#ifndef WS_EX_LAYERED
+#define WS_EX_LAYERED 0x00080000
+#endif
+
+#ifndef LWA_ALPHA
+#define LWA_ALPHA 0x00000002
+#endif
+
+typedef BOOL (WINAPI*winSetLayeredWindowAttributes)(
+ HWND hwnd,
+ COLORREF crKey,
+ BYTE bAlpha,
+ DWORD dwFlags);
+
+static int winDialogSetOpacityAttrib(Ihandle *ih, const char *value)
+{
+ DWORD dwExStyle = GetWindowLong(ih->handle, GWL_EXSTYLE);
+ if (!value)
+ {
+ if (dwExStyle & WS_EX_LAYERED)
+ {
+ dwExStyle &= ~WS_EX_LAYERED; /* remove the style */
+ SetWindowLong(ih->handle, GWL_EXSTYLE, dwExStyle);
+ RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_FRAME|RDW_ALLCHILDREN); /* invalidate everything and all children */
+ }
+ return 0;
+ }
+
+ if (!(dwExStyle & WS_EX_LAYERED))
+ {
+ dwExStyle |= WS_EX_LAYERED; /* add the style */
+ SetWindowLong(ih->handle, GWL_EXSTYLE, dwExStyle);
+ }
+
+ {
+ static winSetLayeredWindowAttributes mySetLayeredWindowAttributes = NULL;
+
+ int opacity;
+ if (!iupStrToInt(value, &opacity))
+ return 0;
+
+ if (!mySetLayeredWindowAttributes)
+ {
+ HMODULE hinstDll = LoadLibrary("user32.dll");
+ if (hinstDll)
+ mySetLayeredWindowAttributes = (winSetLayeredWindowAttributes)GetProcAddress(hinstDll, "SetLayeredWindowAttributes");
+ }
+
+ if (mySetLayeredWindowAttributes)
+ mySetLayeredWindowAttributes(ih->handle, 0, (BYTE)opacity, LWA_ALPHA);
+ }
+
+ RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_FRAME|RDW_ALLCHILDREN); /* invalidate everything and all children */
+ return 1;
+}
+
+static int winDialogSetMdiArrangeAttrib(Ihandle *ih, const char *value)
+{
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (client)
+ {
+ UINT msg = 0;
+ WPARAM wp = 0;
+
+ if (iupStrEqualNoCase(value, "TILEHORIZONTAL"))
+ {
+ msg = WM_MDITILE;
+ wp = MDITILE_HORIZONTAL;
+ }
+ else if (iupStrEqualNoCase(value, "TILEVERTICAL"))
+ {
+ msg = WM_MDITILE;
+ wp = MDITILE_VERTICAL;
+ }
+ else if (iupStrEqualNoCase(value, "CASCADE"))
+ msg = WM_MDICASCADE;
+ else if (iupStrEqualNoCase(value, "ICON"))
+ msg = WM_MDIICONARRANGE;
+
+ if (msg)
+ SendMessage(client->handle, msg, wp, 0);
+ }
+ return 0;
+}
+
+static int winDialogSetMdiActivateAttrib(Ihandle *ih, const char *value)
+{
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (client)
+ {
+ Ihandle* child = IupGetHandle(value);
+ if (child)
+ SendMessage(client->handle, WM_MDIACTIVATE, (WPARAM)child->handle, 0);
+ else
+ {
+ HWND hchild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+ if (iupStrEqualNoCase(value, "NEXT"))
+ SendMessage(client->handle, WM_MDINEXT, (WPARAM)hchild, TRUE);
+ else if (iupStrEqualNoCase(value, "PREVIOUS"))
+ SendMessage(client->handle, WM_MDINEXT, (WPARAM)hchild, FALSE);
+ }
+ }
+ return 0;
+}
+
+static int winDialogSetMdiCloseAllAttrib(Ihandle *ih, const char *value)
+{
+ (void)value;
+ winDialogMDICloseChildren(ih);
+ return 0;
+}
+
+static void winDialogTrayMessage(HWND hWnd, DWORD dwMessage, HICON hIcon, PSTR pszTip)
+{
+ NOTIFYICONDATA tnd;
+ memset(&tnd, 0, sizeof(NOTIFYICONDATA));
+
+ tnd.cbSize = sizeof(NOTIFYICONDATA);
+ tnd.hWnd = hWnd;
+ tnd.uID = 1000;
+
+ if (dwMessage == NIM_ADD)
+ {
+ tnd.uFlags = NIF_MESSAGE;
+ tnd.uCallbackMessage = WM_USER+IWIN_TRAY_NOTIFICATION;
+ }
+ else if (dwMessage == NIM_MODIFY)
+ {
+ if (hIcon)
+ {
+ tnd.uFlags |= NIF_ICON;
+ tnd.hIcon = hIcon;
+ }
+
+ if (pszTip)
+ {
+ tnd.uFlags |= NIF_TIP;
+ lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip));
+ }
+ }
+
+ Shell_NotifyIcon(dwMessage, &tnd);
+}
+
+static int winDialogCheckTray(Ihandle *ih)
+{
+ if (iupAttribGet(ih, "_IUPDLG_HASTRAY"))
+ return 1;
+
+ if (iupAttribGetBoolean(ih, "TRAY"))
+ {
+ winDialogTrayMessage(ih->handle, NIM_ADD, NULL, NULL);
+ iupAttribSetStr(ih, "_IUPDLG_HASTRAY", "YES");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int winDialogSetTrayAttrib(Ihandle *ih, const char *value)
+{
+ int tray = iupStrBoolean(value);
+ if (iupAttribGet(ih, "_IUPDLG_HASTRAY"))
+ {
+ if (!tray)
+ {
+ winDialogTrayMessage(ih->handle, NIM_DELETE, NULL, NULL);
+ iupAttribSetStr(ih, "_IUPDLG_HASTRAY", NULL);
+ }
+ }
+ else
+ {
+ if (tray)
+ {
+ winDialogTrayMessage(ih->handle, NIM_ADD, NULL, NULL);
+ iupAttribSetStr(ih, "_IUPDLG_HASTRAY", "YES");
+ }
+ }
+ return 1;
+}
+
+static int winDialogSetTrayTipAttrib(Ihandle *ih, const char *value)
+{
+ if (winDialogCheckTray(ih))
+ winDialogTrayMessage(ih->handle, NIM_MODIFY, NULL, (PSTR)value);
+ return 1;
+}
+
+static int winDialogSetTrayImageAttrib(Ihandle *ih, const char *value)
+{
+ if (winDialogCheckTray(ih))
+ {
+ HICON hIcon = (HICON)iupImageGetIcon(value);
+ if (hIcon)
+ winDialogTrayMessage(ih->handle, NIM_MODIFY, hIcon, NULL);
+ }
+ return 1;
+}
+
+static int winDialogSetBringFrontAttrib(Ihandle *ih, const char *value)
+{
+ if (iupStrBoolean(value))
+ SetForegroundWindow(ih->handle);
+ return 0;
+}
+
+static int winDialogSetTopMostAttrib(Ihandle *ih, const char *value)
+{
+ if (iupStrBoolean(value))
+ SetWindowPos(ih->handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+ else
+ SetWindowPos(ih->handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+ return 1;
+}
+
+static int winDialogSetIconAttrib(Ihandle* ih, const char *value)
+{
+ if (!value)
+ SendMessage(ih->handle, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)NULL);
+ else
+ {
+ HICON icon = iupImageGetIcon(value);
+ if (icon)
+ SendMessage(ih->handle, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM)icon);
+ }
+
+ if (IsIconic(ih->handle))
+ RedrawWindow(ih->handle, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW); /* redraw the icon */
+ else
+ RedrawWindow(ih->handle, NULL, NULL, RDW_FRAME|RDW_UPDATENOW); /* only the frame needs to be redrawn */
+
+ return 1;
+}
+
+static int winDialogSetFullScreenAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ {
+ if (!iupAttribGet(ih, "_IUPWIN_FS_STYLE"))
+ {
+ int width, height;
+ LONG off_style, new_style;
+
+ BOOL visible = ShowWindow (ih->handle, SW_HIDE);
+
+ /* remove the decorations */
+ off_style = WS_BORDER | WS_THICKFRAME | WS_CAPTION |
+ WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU;
+ new_style = GetWindowLong(ih->handle, GWL_STYLE);
+ iupAttribSetStr(ih, "_IUPWIN_FS_STYLE", (char*)new_style);
+ new_style &= (~off_style);
+ SetWindowLong(ih->handle, GWL_STYLE, new_style);
+
+ /* save the previous decoration attributes */
+ iupAttribStoreStr(ih, "_IUPWIN_FS_MAXBOX", iupAttribGet(ih, "MAXBOX"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_MINBOX", iupAttribGet(ih, "MINBOX"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_MENUBOX",iupAttribGet(ih, "MENUBOX"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_RESIZE", iupAttribGet(ih, "RESIZE"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_BORDER", iupAttribGet(ih, "BORDER"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_TITLE", IupGetAttribute(ih, "TITLE")); /* must use IupGetAttribute to check from the native implementation */
+
+ /* save the previous position and size */
+ iupAttribStoreStr(ih, "_IUPWIN_FS_X", IupGetAttribute(ih, "X")); /* must use IupGetAttribute to check from the native implementation */
+ iupAttribStoreStr(ih, "_IUPWIN_FS_Y", IupGetAttribute(ih, "Y"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_SIZE", IupGetAttribute(ih, "RASTERSIZE"));
+
+ /* remove the decorations attributes */
+ iupAttribSetStr(ih, "MAXBOX", "NO");
+ iupAttribSetStr(ih, "MINBOX", "NO");
+ iupAttribSetStr(ih, "MENUBOX", "NO");
+ IupSetAttribute(ih, "TITLE", NULL);
+ iupAttribSetStr(ih, "RESIZE", "NO");
+ iupAttribSetStr(ih, "BORDER", "NO");
+
+ /* full screen size */
+ iupdrvGetFullSize(&width, &height);
+
+ SetWindowPos(ih->handle, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED);
+
+ /* layout will be updated in WM_SIZE */
+ if (visible)
+ ShowWindow(ih->handle, SW_SHOW);
+ }
+ }
+ else
+ {
+ LONG style = (LONG)iupAttribGet(ih, "_IUPWIN_FS_STYLE");
+ if (style)
+ {
+ BOOL visible = ShowWindow(ih->handle, SW_HIDE);
+
+ /* restore the decorations attributes */
+ iupAttribStoreStr(ih, "MAXBOX", iupAttribGet(ih, "_IUPWIN_FS_MAXBOX"));
+ iupAttribStoreStr(ih, "MINBOX", iupAttribGet(ih, "_IUPWIN_FS_MINBOX"));
+ iupAttribStoreStr(ih, "MENUBOX",iupAttribGet(ih, "_IUPWIN_FS_MENUBOX"));
+ IupSetAttribute(ih, "TITLE", iupAttribGet(ih, "_IUPWIN_FS_TITLE")); /* TITLE is not stored in the HashTable */
+ iupAttribStoreStr(ih, "RESIZE", iupAttribGet(ih, "_IUPWIN_FS_RESIZE"));
+ iupAttribStoreStr(ih, "BORDER", iupAttribGet(ih, "_IUPWIN_FS_BORDER"));
+
+ /* restore the decorations */
+ SetWindowLong(ih->handle, GWL_STYLE, style);
+
+ /* restore position and size */
+ SetWindowPos(ih->handle, HWND_TOP,
+ iupAttribGetInt(ih, "_IUPWIN_FS_X"),
+ iupAttribGetInt(ih, "_IUPWIN_FS_Y"),
+ IupGetInt(ih, "_IUPWIN_FS_SIZE"),
+ IupGetInt2(ih, "_IUPWIN_FS_SIZE"), 0);
+
+ /* layout will be updated in WM_SIZE */
+ if (visible)
+ ShowWindow(ih->handle, SW_SHOW);
+
+ /* remove auxiliar attributes */
+ iupAttribSetStr(ih, "_IUPWIN_FS_MAXBOX", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_MINBOX", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_MENUBOX",NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_TITLE", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_RESIZE", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_BORDER", NULL);
+
+ iupAttribSetStr(ih, "_IUPWIN_FS_X", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_Y", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_SIZE", NULL);
+
+ iupAttribSetStr(ih, "_IUPWIN_FS_STYLE", NULL);
+ }
+ }
+ return 1;
+}
+
+
+void iupdrvDialogInitClass(Iclass* ic)
+{
+ if (!iupwinClassExist("IupDialog"))
+ {
+ winDialogRegisterClass(0);
+ winDialogRegisterClass(1);
+ winDialogRegisterClass(2);
+ winDialogRegisterClass(-1);
+
+ WM_HELPMSG = RegisterWindowMessage(HELPMSGSTRING);
+ }
+
+ /* Driver Dependent Class functions */
+ ic->Map = winDialogMapMethod;
+ ic->UnMap = winDialogUnMapMethod;
+ ic->LayoutUpdate = winDialogLayoutUpdateMethod;
+ ic->Release = winDialogReleaseMethod;
+
+ /* Callback Windows Only*/
+ iupClassRegisterCallback(ic, "MDIACTIVATE_CB", "");
+
+ /* Callback Windows and GTK Only */
+ iupClassRegisterCallback(ic, "TRAYCLICK_CB", "iii");
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winDialogSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", iupdrvBaseGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ /* IupDialog only */
+ iupClassRegisterAttribute(ic, "BACKGROUND", NULL, winDialogSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ICON", NULL, winDialogSetIconAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FULLSCREEN", NULL, winDialogSetFullScreenAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SAVEUNDER", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MINSIZE", NULL, NULL, IUPAF_SAMEASSYSTEM, "1x1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MAXSIZE", NULL, NULL, IUPAF_SAMEASSYSTEM, "65535x65535", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ /* IupDialog Windows Only */
+ iupClassRegisterAttribute(ic, "HWND", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDIARRANGE", NULL, winDialogSetMdiArrangeAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDIACTIVATE", NULL, winDialogSetMdiActivateAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDICLOSEALL", NULL, winDialogSetMdiCloseAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDIACTIVE", winDialogGetMdiActiveAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDINEXT", winDialogGetMdiNextAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "OPACITY", NULL, winDialogSetOpacityAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "LAYERALPHA", NULL, winDialogSetOpacityAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "BRINGFRONT", NULL, winDialogSetBringFrontAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "COMPOSITED", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED);
+
+ iupClassRegisterAttribute(ic, "CONTROL", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "HELPBUTTON", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TOOLBOX", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDIFRAME", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDICLIENT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDIMENU", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDICHILD", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ /* IupDialog Windows and GTK Only */
+ iupClassRegisterAttribute(ic, "TOPMOST", NULL, winDialogSetTopMostAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TRAY", NULL, winDialogSetTrayAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TRAYIMAGE", NULL, winDialogSetTrayImageAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TRAYTIP", NULL, winDialogSetTrayTipAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_draw.c b/iup/src/win/iupwin_draw.c
new file mode 100755
index 0000000..4a810e6
--- /dev/null
+++ b/iup/src/win/iupwin_draw.c
@@ -0,0 +1,328 @@
+/** \file
+ * \brief Draw Functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#include <windows.h>
+#include <uxtheme.h>
+#include <tmschema.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_attrib.h"
+#include "iup_class.h"
+#include "iup_str.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_info.h"
+#include "iupwin_draw.h"
+
+
+#ifndef TABP_AEROWIZARDBODY
+#define TABP_AEROWIZARDBODY 11 /* manually added definition */
+#endif
+
+#ifndef TMT_FILLCOLORHINT
+#define TMT_FILLCOLORHINT 3821
+#endif
+#ifndef TMT_TEXTCOLOR
+#define TMT_TEXTCOLOR 3823
+#endif
+
+
+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);
+typedef HRESULT (STDAPICALLTYPE *_winThemeGetColor)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, COLORREF *pColor);
+
+static _winThemeOpenData winThemeOpenData = NULL;
+static _winThemeCloseData winThemeCloseData = NULL;
+static _winThemeDrawBackground winThemeDrawBackground = NULL;
+static _winThemeGetColor winThemeGetColor = NULL;
+
+typedef BOOL (CALLBACK* _winAlphaBlendFunc)( HDC hdcDest,
+ int xoriginDest, int yoriginDest,
+ int wDest, int hDest, HDC hdcSrc,
+ int xoriginSrc, int yoriginSrc,
+ int wSrc, int hSrc,
+ BLENDFUNCTION ftn);
+static _winAlphaBlendFunc winAlphaBlend = NULL;
+
+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)
+ {
+ HINSTANCE lib = LoadLibrary("Msimg32");
+ if (lib)
+ winAlphaBlend = (_winAlphaBlendFunc)GetProcAddress(lib, "AlphaBlend");
+ }
+
+ if (!winThemeOpenData && iupwin_comctl32ver6)
+ {
+ HMODULE hinstDll = LoadLibrary("uxtheme.dll");
+ if (hinstDll)
+ {
+ winThemeOpenData = (_winThemeOpenData)GetProcAddress(hinstDll, "OpenThemeData");
+ winThemeCloseData = (_winThemeCloseData)GetProcAddress(hinstDll, "CloseThemeData");
+ winThemeDrawBackground = (_winThemeDrawBackground)GetProcAddress(hinstDll, "DrawThemeBackground");
+ winThemeGetColor = (_winThemeGetColor)GetProcAddress(hinstDll, "GetThemeColor");
+ }
+ }
+}
+
+static int winDrawGetThemeStateId(int itemState)
+{
+ if (itemState & ODS_DISABLED)
+ return PBS_DISABLED;
+ else if (itemState & ODS_SELECTED)
+ return PBS_PRESSED;
+ else if (itemState & ODS_HOTLIGHT)
+ return PBS_HOT;
+ else if (itemState & ODS_DEFAULT)
+ return PBS_DEFAULTED;
+ else
+ return PBS_NORMAL;
+}
+
+static int winDrawThemeButtonBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState)
+{
+ int iStateId;
+ HTHEME hTheme;
+
+ if (!winDrawThemeEnabled())
+ return 0;
+
+ hTheme = winThemeOpenData(hWnd, L"BUTTON");
+ if (!hTheme)
+ return 0;
+
+ iStateId = winDrawGetThemeStateId(itemState);
+
+ winThemeDrawBackground(hTheme, hDC, BP_PUSHBUTTON, iStateId, rect, NULL);
+
+ winThemeCloseData(hTheme);
+ return 1;
+}
+
+void iupwinDrawThemeFrameBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState)
+{
+ int iStateId = GBS_NORMAL;
+ HTHEME hTheme;
+
+ if (!winDrawThemeEnabled())
+ return;
+
+ hTheme = winThemeOpenData(hWnd, L"BUTTON");
+ if (!hTheme)
+ return;
+
+ if (itemState & ODS_DISABLED)
+ iStateId = GBS_DISABLED;
+
+ winThemeDrawBackground(hTheme, hDC, BP_GROUPBOX, iStateId, rect, NULL);
+
+ winThemeCloseData(hTheme);
+}
+
+int iupwinDrawGetThemeTabsBgColor(HWND hWnd, COLORREF *color)
+{
+ HTHEME hTheme;
+ HRESULT ret;
+
+ if (!winDrawThemeEnabled())
+ return 0;
+
+ hTheme = winThemeOpenData(hWnd, L"TAB");
+ if (!hTheme)
+ return 0;
+
+ if (iupwinIsVista())
+ ret = winThemeGetColor(hTheme, TABP_AEROWIZARDBODY, TIS_NORMAL, TMT_FILLCOLORHINT, color);
+ else
+ ret = winThemeGetColor(hTheme, TABP_BODY, TIS_NORMAL, TMT_FILLCOLORHINT, color);
+
+ winThemeCloseData(hTheme);
+ return (ret == S_OK)? 1: 0;
+}
+
+int iupwinDrawGetThemeButtonBgColor(HWND hWnd, COLORREF *color)
+{
+ HTHEME hTheme;
+ HRESULT ret;
+
+ if (!winDrawThemeEnabled())
+ return 0;
+
+ hTheme = winThemeOpenData(hWnd, L"BUTTON");
+ if (!hTheme)
+ return 0;
+
+ ret = winThemeGetColor(hTheme, BP_PUSHBUTTON, PBS_NORMAL, TMT_FILLCOLORHINT, color);
+
+ winThemeCloseData(hTheme);
+ return (ret == S_OK)? 1: 0;
+}
+
+int iupwinDrawGetThemeFrameFgColor(HWND hWnd, COLORREF *color)
+{
+ HTHEME hTheme;
+ HRESULT ret;
+
+ if (!winDrawThemeEnabled())
+ return 0;
+
+ hTheme = winThemeOpenData(hWnd, L"BUTTON");
+ if (!hTheme)
+ return 0;
+
+ ret = winThemeGetColor(hTheme, BP_GROUPBOX, GBS_NORMAL, TMT_TEXTCOLOR, color);
+
+ winThemeCloseData(hTheme);
+ return (ret == S_OK)? 1: 0;
+}
+
+static int winDrawGetStateId(int itemState)
+{
+ if (itemState & ODS_DISABLED)
+ return DFCS_INACTIVE;
+ else if (itemState & ODS_SELECTED)
+ return DFCS_PUSHED;
+ else if (itemState & ODS_HOTLIGHT)
+ return DFCS_HOT;
+ else
+ return 0;
+}
+
+void iupwinDrawButtonBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState)
+{
+ if (!winDrawThemeButtonBorder(hWnd, hDC, rect, itemState))
+ {
+ DrawFrameControl(hDC, rect, DFC_BUTTON, DFCS_BUTTONPUSH | winDrawGetStateId(itemState));
+ if (itemState & ODS_DEFAULT) /* if a button has the focus, must draw the default button frame */
+ FrameRect(hDC, rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ }
+}
+
+void iupdrvDrawFocusRect(Ihandle* ih, void* gc, int x, int y, int w, int h)
+{
+ HDC hDC = (HDC)gc;
+ RECT rect;
+ (void)ih;
+
+ rect.left = x;
+ rect.top = y;
+ rect.right = x+w;
+ rect.bottom = y+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;
+ char* color = iupBaseNativeParentGetBgColorAttrib(ih);
+ iupStrToRGB(color, &r, &g, &b);
+ SetDCBrushColor(hDC, RGB(r,g,b));
+ FillRect(hDC, rect, (HBRUSH)GetStockObject(DC_BRUSH));
+}
+
+HDC iupwinDrawCreateBitmapDC(iupwinBitmapDC *bmpDC, HDC hDC, int w, int h)
+{
+ bmpDC->w = w;
+ bmpDC->h = h;
+ bmpDC->hDC = hDC;
+
+ bmpDC->hBitmap = CreateCompatibleBitmap(bmpDC->hDC, w, h);
+ bmpDC->hBitmapDC = CreateCompatibleDC(bmpDC->hDC);
+ bmpDC->hOldBitmap = SelectObject(bmpDC->hBitmapDC, bmpDC->hBitmap);
+ return bmpDC->hBitmapDC;
+}
+
+void iupwinDrawDestroyBitmapDC(iupwinBitmapDC *bmpDC)
+{
+ BitBlt(bmpDC->hDC, 0, 0, bmpDC->w, bmpDC->h, bmpDC->hBitmapDC, 0, 0, SRCCOPY);
+ SelectObject(bmpDC->hBitmapDC, bmpDC->hOldBitmap);
+ DeleteObject(bmpDC->hBitmap);
+ DeleteDC(bmpDC->hBitmapDC);
+}
+
diff --git a/iup/src/win/iupwin_draw.h b/iup/src/win/iupwin_draw.h
new file mode 100755
index 0000000..c9a57e6
--- /dev/null
+++ b/iup/src/win/iupwin_draw.h
@@ -0,0 +1,47 @@
+/** \file
+ * \brief Draw Functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPWIN_DRAW_H
+#define __IUPWIN_DRAW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void iupwinDrawInit(void);
+
+void iupwinDrawBitmap(HDC hDC, HBITMAP hBitmap, HBITMAP hMask, int x, int y, int width, int height, int bpp);
+void iupwinDrawText(HDC hDC, const char* text, int x, int y, int width, int height, HFONT hFont, COLORREF fgcolor, int style);
+
+void iupwinDrawParentBackground(Ihandle* ih, HDC hDC, RECT* rect);
+void iupwinDrawButtonBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState);
+
+void iupwinDrawThemeFrameBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState);
+int iupwinDrawGetThemeTabsBgColor(HWND hWnd, COLORREF *color);
+int iupwinDrawGetThemeButtonBgColor(HWND hWnd, COLORREF *color);
+int iupwinDrawGetThemeFrameFgColor(HWND hWnd, COLORREF *color);
+void iupwinDrawRemoveTheme(HWND hWnd);
+
+typedef struct _iupwinBitmapDC
+{
+ HBITMAP hBitmap, hOldBitmap;
+ HDC hBitmapDC, hDC;
+ int w, h;
+} iupwinBitmapDC;
+
+HDC iupwinDrawCreateBitmapDC(iupwinBitmapDC *bmpDC, HDC hDC, int w, int h);
+void iupwinDrawDestroyBitmapDC(iupwinBitmapDC *bmpDC);
+
+#ifndef ODS_HOTLIGHT /* Only defined if WINVER >= 0x0500 */
+#define ODS_HOTLIGHT 0x0040
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/win/iupwin_drv.h b/iup/src/win/iupwin_drv.h
new file mode 100755
index 0000000..3372c1a
--- /dev/null
+++ b/iup/src/win/iupwin_drv.h
@@ -0,0 +1,113 @@
+/** \file
+ * \brief Windows Driver
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPWIN_DRV_H
+#define __IUPWIN_DRV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifndef WS_EX_COMPOSITED
+#define WS_EX_COMPOSITED 0x02000000L /* it is defined only when _WIN32_WINNT >= 0x0501 */
+#endif
+
+
+/* global variables */
+/* declared where they are initialized */
+extern HINSTANCE iupwin_hinstance; /* winopen.c */
+extern HINSTANCE iupwin_dll_hinstance; /* winmain.c */
+extern int iupwin_comctl32ver6; /* winopen.c */
+
+void iupwinShowLastError(void);
+
+/* focus */
+void iupwinWmSetFocus(Ihandle *ih);
+
+/* key */
+int iupwinKeyEvent(Ihandle* ih, int wincode, int press);
+void iupwinButtonKeySetStatus(WORD keys, char* status, int doubleclick);
+void iupwinKeyEncode(int key, unsigned int *keyval, unsigned int *state);
+
+/* tips */
+void iupwinTipsGetDispInfo(LPARAM lp);
+
+/* font */
+char* iupwinGetHFontAttrib(Ihandle *ih);
+HFONT iupwinGetHFont(const char* value);
+char* iupwinFindHFont(HFONT hFont);
+
+/* menu */
+void iupwinMenuDialogProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp);
+
+/* common */
+
+/* Definition of a callback used to return the background brush of controls called "_IUPWIN_CTLCOLOR_CB". */
+typedef int (*IFctlColor)(Ihandle* ih, HDC hdc, LRESULT *result);
+
+/* Definition of a callback used to draw custom controls called "_IUPWIN_DRAWITEM_CB".
+ drawitem is a pointer to a DRAWITEMSTRUCT struct. */
+typedef void (*IFdrawItem)(Ihandle* ih, void* drawitem);
+
+/* Definition of a callback used to notify custom controls called "_IUPWIN_NOTIFY_CB".
+ msg_info is a pointer to a NMHDR struct. */
+typedef int (*IFnotify)(Ihandle* ih, void* msg_info, HRESULT *result);
+
+/* Definition of callback used for custom WinProc. Can return 0 or 1.
+ 0 = do default processing.
+ 1 = ABORT default processing and the result value should be returned.
+*/
+typedef int (*IwinProc)(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result);
+
+/* Base WinProc used by all native elements. Configure base message handling
+ and custom IwinProc using "_IUPWIN_CTRLPROC_CB" callback. */
+LRESULT CALLBACK iupwinBaseWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
+
+/* Base IwinProc callback used by native controls. */
+int iupwinBaseProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result);
+
+/* Base IwinProc callback used by native containers.
+ Handle messages that are sent to the parent Window. */
+int iupwinBaseContainerProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result);
+
+/* 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);
+
+int iupwinClassExist(const char* name);
+int iupwinGetColorRef(Ihandle *ih, char *name, COLORREF *color);
+int iupwinGetParentBgColor(Ihandle* ih, COLORREF* cr);
+void iupwinDropFiles(HDROP hDrop, Ihandle *ih);
+Ihandle* iupwinMenuGetItemHandle(HMENU hmenu, int menuId);
+Ihandle* iupwinMenuGetHandle(HMENU hMenu);
+int iupwinSetDragDropAttrib(Ihandle* ih, const char* value);
+void iupwinChangeProc(Ihandle *ih, WNDPROC new_proc);
+void iupwinMergeStyle(Ihandle* ih, DWORD old_mask, DWORD value);
+void iupwinSetStyle(Ihandle* ih, DWORD value, int set);
+WCHAR* iupwinStrChar2Wide(const char* str);
+int iupwinButtonUp(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp);
+int iupwinButtonDown(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp);
+int iupwinMouseMove(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp);
+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)) */
+
+
+/* child window identifier of the first MDI child window created,
+ should not conflict with any other command identifiers. */
+#define IUP_MDICHILD_START 100000000
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/win/iupwin_filedlg.c b/iup/src/win/iupwin_filedlg.c
new file mode 100755
index 0000000..da66b4b
--- /dev/null
+++ b/iup/src/win/iupwin_filedlg.c
@@ -0,0 +1,580 @@
+/** \file
+ * \brief IupFileDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commdlg.h>
+#include <shlobj.h>
+
+#include <stdio.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+#include "iup_drvinfo.h"
+
+#include "iupwin_drv.h"
+
+
+#ifndef OFN_FORCESHOWHIDDEN
+#define OFN_FORCESHOWHIDDEN 0x10000000 /* Show All files including System and hidden files */
+#endif
+
+#define MAX_FILENAME_SIZE 65000
+#define IUP_PREVIEWCANVAS 3000
+
+enum {IUP_DIALOGOPEN, IUP_DIALOGSAVE, IUP_DIALOGDIR};
+
+
+static void winFileDlgStrReplacePathSlash(char* name)
+{
+ /* check for "/" */
+ int i, len = strlen(name);
+ for (i = 0; i < len; i++)
+ {
+ if (name[i] == '/')
+ name[i] = '\\';
+ }
+}
+
+static INT CALLBACK winFileDlgBrowseCallback(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ (void)lParam;
+ if (uMsg == BFFM_INITIALIZED)
+ {
+ char* value;
+ Ihandle* ih = (Ihandle*)lpData;
+ ih->handle = hWnd;
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+ value = iupStrDup(iupAttribGet(ih, "DIRECTORY"));
+ if (value)
+ {
+ winFileDlgStrReplacePathSlash(value);
+ SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)value);
+ free(value);
+ }
+ }
+ else if (uMsg == BFFM_SELCHANGED)
+ {
+ char* buffer = iupStrGetMemory(MAX_FILENAME_SIZE);
+ ITEMIDLIST* selecteditem = (ITEMIDLIST*)lParam;
+ buffer[0] = 0;
+ SHGetPathFromIDList(selecteditem, buffer);
+ if (buffer[0] == 0)
+ SendMessage(hWnd, BFFM_ENABLEOK, 0, (LPARAM)FALSE);
+ else
+ SendMessage(hWnd, BFFM_ENABLEOK, 0, (LPARAM)TRUE);
+ }
+ return 0;
+}
+
+static void winFileDlgGetFolder(Ihandle *ih)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ BROWSEINFO browseinfo;
+ char buffer[MAX_PATH];
+ ITEMIDLIST *selecteditem;
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ ZeroMemory(&browseinfo, sizeof(BROWSEINFO));
+ browseinfo.lpszTitle = iupAttribGet(ih, "TITLE");
+ browseinfo.pszDisplayName = buffer;
+ browseinfo.lpfn = winFileDlgBrowseCallback;
+ browseinfo.lParam = (LPARAM)ih;
+ browseinfo.ulFlags = BIF_NEWDIALOGSTYLE;
+ browseinfo.hwndOwner = parent;
+
+ selecteditem = SHBrowseForFolder(&browseinfo);
+ if (!selecteditem)
+ {
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "STATUS", "-1");
+ }
+ else
+ {
+ SHGetPathFromIDList(selecteditem, buffer);
+ iupAttribStoreStr(ih, "VALUE", buffer);
+ iupAttribSetStr(ih, "STATUS", "0");
+ }
+
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "FILTERUSED", NULL);
+}
+
+/************************************************************************************************/
+
+static UINT_PTR CALLBACK winFileDlgSimpleHook(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+ (void)wParam;
+ switch(uiMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ OPENFILENAME* openfilename = (OPENFILENAME*)lParam;
+ Ihandle* ih = (Ihandle*)openfilename->lCustData;
+ ih->handle = GetParent(hWnd);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+ SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)ih);
+ break;
+ }
+ case WM_DESTROY:
+ {
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (cb) cb(ih, NULL, "FINISH");
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ LPOFNOTIFY pofn = (LPOFNOTIFY)lParam;
+ Ihandle* ih = (Ihandle*)pofn->lpOFN->lCustData;
+ switch (pofn->hdr.code)
+ {
+ case CDN_INITDONE:
+ {
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (cb) cb(ih, NULL, "INIT");
+ break;
+ }
+ case CDN_FILEOK:
+ case CDN_SELCHANGE:
+ {
+ 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)
+ {
+ int ret;
+ char* file_msg;
+
+ if (!iupdrvIsFile(filename))
+ break;
+
+ if (pofn->hdr.code == CDN_FILEOK)
+ file_msg = "OK";
+ else
+ file_msg = "SELECT";
+
+ ret = cb(ih, filename, file_msg);
+ if (pofn->hdr.code == CDN_FILEOK && ret == IUP_IGNORE)
+ {
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1L);
+ return 1; /* will refuse the file */
+ }
+ }
+ }
+ break;
+ }
+ case CDN_HELP:
+ {
+ Icallback cb = (Icallback) IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ EndDialog(GetParent(hWnd), IDCANCEL);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static void winFileDlgSetPreviewCanvasPos(HWND hWnd, HWND hWndPreview)
+{
+ int height, width, ypos, xpos;
+ RECT rect, dlgrect;
+ HWND hWndFileList = GetDlgItem(GetParent(hWnd), 0x0471);
+ HWND hWndFileCombo = GetDlgItem(GetParent(hWnd), 0x047C);
+
+ /* GetWindowRect return screen coordinates, must convert to parent's client coordinates */
+ GetWindowRect(hWnd, &dlgrect);
+
+ GetWindowRect(hWndPreview, &rect);
+ ypos = rect.top - dlgrect.top; /* keep the same vertical position, at first time this is 0 */
+ height = rect.bottom-rect.top; /* keep the same height */
+
+ GetWindowRect(hWndFileList, &rect);
+ xpos = rect.left - dlgrect.left; /* horizontally align with file list at left */
+
+ GetWindowRect(hWndFileCombo, &rect);
+ width = (rect.right - dlgrect.left) - xpos; /* set size to align with file combo at right */
+
+ /* also position the child window that contains the template, must have room for the preview canvas */
+ if (ypos) /* first time does nothing */
+ SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, (rect.right - dlgrect.left), (dlgrect.bottom - dlgrect.top), SWP_NOMOVE|SWP_NOZORDER);
+
+ SetWindowPos(hWndPreview, HWND_TOP, xpos, ypos, width, height, SWP_NOZORDER);
+}
+
+static void winFileDlgUpdatePreviewGLCanvas(Ihandle* ih)
+{
+ Ihandle* glcanvas = IupGetAttributeHandle(ih, "PREVIEWGLCANVAS");
+ if (glcanvas)
+ {
+ iupAttribSetStr(glcanvas, "HWND", iupAttribGet(ih, "HWND"));
+ glcanvas->iclass->Map(glcanvas);
+ }
+}
+
+static UINT_PTR CALLBACK winFileDlgPreviewHook(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+ /* hWnd here is a handle to the child window that contains the template,
+ NOT the file dialog. Only the preview canvas is a child of this window. */
+
+ switch(uiMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ OPENFILENAME* openfilename = (OPENFILENAME*)lParam;
+ Ihandle* ih = (Ihandle*)openfilename->lCustData;
+ HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS);
+
+ ih->handle = GetParent(hWnd);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+
+ if (hWndPreview)
+ {
+ RECT rect;
+
+ winFileDlgSetPreviewCanvasPos(hWnd, hWndPreview);
+
+ GetClientRect(hWndPreview, &rect);
+ iupAttribSetInt(ih, "PREVIEWWIDTH", rect.right - rect.left);
+ iupAttribSetInt(ih, "PREVIEWHEIGHT", rect.bottom - rect.top);
+ }
+ SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)ih);
+ iupAttribSetStr(ih, "WID", (char*)hWndPreview);
+ iupAttribSetStr(ih, "HWND", (char*)hWndPreview);
+ winFileDlgUpdatePreviewGLCanvas(ih);
+ break;
+ }
+ case WM_DRAWITEM:
+ {
+ if (wParam == IUP_PREVIEWCANVAS)
+ {
+ LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam;
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ char* filename = iupStrGetMemory(MAX_FILENAME_SIZE);
+ iupAttribSetStr(ih, "PREVIEWDC", (char*)lpDrawItem->hDC);
+ if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE)
+ {
+ if (iupdrvIsFile(filename))
+ cb(ih, filename, "PAINT");
+ else
+ cb(ih, NULL, "PAINT");
+ }
+ else
+ cb(ih, NULL, "PAINT");
+ iupAttribSetStr(ih, "PREVIEWDC", NULL);
+ }
+ break;
+ }
+ case WM_SIZE:
+ {
+ HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS);
+ if (hWndPreview)
+ {
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ RECT rect;
+
+ winFileDlgSetPreviewCanvasPos(hWnd, hWndPreview);
+
+ GetClientRect(hWndPreview, &rect);
+ iupAttribSetInt(ih, "PREVIEWWIDTH", rect.right-rect.left);
+
+ RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW);
+ }
+ break;
+ }
+ case WM_DESTROY:
+ {
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ cb(ih, NULL, "FINISH");
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ LPOFNOTIFY pofn = (LPOFNOTIFY)lParam;
+ Ihandle* ih = (Ihandle*)pofn->lpOFN->lCustData;
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ switch (pofn->hdr.code)
+ {
+ case CDN_INITDONE:
+ {
+ HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS);
+ cb(ih, NULL, "INIT");
+ if (hWndPreview) RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW);
+ break;
+ }
+ case CDN_FILEOK:
+ 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)
+ {
+ int ret;
+ char* file_msg;
+
+ if (!iupdrvIsFile(filename))
+ break;
+
+ if (pofn->hdr.code == CDN_FILEOK)
+ file_msg = "OK";
+ else
+ file_msg = "SELECT";
+
+ ret = cb(ih, filename, file_msg);
+ if (pofn->hdr.code == CDN_FILEOK && ret == IUP_IGNORE)
+ {
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1L);
+ return 1; /* will refuse the file */
+ }
+ }
+ if (pofn->hdr.code == CDN_SELCHANGE && hWndPreview)
+ RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW);
+ break;
+ }
+ case CDN_HELP:
+ {
+ Icallback cb = (Icallback) IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ EndDialog(GetParent(hWnd), IDCANCEL);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static char* winFileDlgStrReplaceSeparator(const char* name)
+{
+ int i=0;
+ char* buffer = (char*)malloc(strlen(name)+2);
+
+ /* replace symbols "|" by terminator "\0" */
+
+ while (*name)
+ {
+ buffer[i] = *name;
+
+ if (buffer[i] == '|')
+ buffer[i] = 0;
+
+ i++;
+ name++;
+ }
+
+ buffer[i] = 0;
+ buffer[i+1] = 0; /* additional 0 at the end */
+ return buffer;
+}
+
+static int winFileDlgPopup(Ihandle *ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ OPENFILENAME openfilename;
+ int result, dialogtype;
+ char *value;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ value = iupAttribGetStr(ih, "DIALOGTYPE");
+ if (iupStrEqualNoCase(value, "SAVE"))
+ dialogtype = IUP_DIALOGSAVE;
+ else if (iupStrEqualNoCase(value, "DIR"))
+ dialogtype = IUP_DIALOGDIR;
+ else
+ dialogtype = IUP_DIALOGOPEN;
+
+ if (dialogtype == IUP_DIALOGDIR)
+ {
+ winFileDlgGetFolder(ih);
+ return IUP_NOERROR;
+ }
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ ZeroMemory(&openfilename, sizeof(OPENFILENAME));
+ openfilename.lStructSize = sizeof(OPENFILENAME);
+ openfilename.hwndOwner = parent;
+
+ value = iupAttribGet(ih, "EXTFILTER");
+ if (value)
+ {
+ int index;
+ openfilename.lpstrFilter = winFileDlgStrReplaceSeparator(value);
+
+ value = iupAttribGet(ih, "FILTERUSED");
+ if (iupStrToInt(value, &index))
+ openfilename.nFilterIndex = index;
+ else
+ openfilename.nFilterIndex = 1;
+ }
+ else
+ {
+ value = iupAttribGet(ih, "FILTER");
+ if (value)
+ {
+ int sz1, sz2;
+ char* info = iupAttribGet(ih, "FILTERINFO");
+ if (!info)
+ info = value;
+
+ /* concat FILTERINFO+FILTER */
+ sz1 = strlen(info)+1;
+ sz2 = strlen(value)+1;
+ openfilename.lpstrFilter = (char*)malloc(sz1+sz2+1);
+
+ memcpy((char*)openfilename.lpstrFilter, info, sz1);
+ memcpy((char*)openfilename.lpstrFilter+sz1, value, sz2);
+ ((char*)openfilename.lpstrFilter)[sz1+sz2] = 0; /* additional 0 at the end */
+ openfilename.nFilterIndex = 1;
+ }
+ }
+
+ openfilename.lpstrFile = (char*)malloc(MAX_FILENAME_SIZE+1);
+ value = iupAttribGet(ih, "FILE");
+ if (value)
+ {
+ strncpy(openfilename.lpstrFile, value, MAX_FILENAME_SIZE);
+ winFileDlgStrReplacePathSlash(openfilename.lpstrFile);
+ }
+ else
+ openfilename.lpstrFile[0] = 0;
+
+ openfilename.nMaxFile = MAX_FILENAME_SIZE;
+
+ openfilename.lpstrInitialDir = iupStrDup(iupAttribGet(ih, "DIRECTORY"));
+ if (openfilename.lpstrInitialDir)
+ winFileDlgStrReplacePathSlash((char*)openfilename.lpstrInitialDir);
+
+ openfilename.lpstrTitle = iupAttribGet(ih, "TITLE");
+ openfilename.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
+
+ if (!iupAttribGetBoolean(ih, "NOOVERWRITEPROMPT"))
+ openfilename.Flags |= OFN_OVERWRITEPROMPT;
+
+ if (iupAttribGetBoolean(ih, "SHOWHIDDEN"))
+ openfilename.Flags |= OFN_FORCESHOWHIDDEN;
+
+ value = iupAttribGet(ih, "ALLOWNEW");
+ if (!value)
+ {
+ if (dialogtype == IUP_DIALOGSAVE)
+ value = "YES";
+ else
+ value = "NO";
+ }
+ if (iupStrBoolean(value))
+ openfilename.Flags |= OFN_CREATEPROMPT;
+ else
+ openfilename.Flags |= OFN_FILEMUSTEXIST;
+
+ if (iupAttribGetBoolean(ih, "NOCHANGEDIR"))
+ openfilename.Flags |= OFN_NOCHANGEDIR;
+
+ if (iupAttribGetBoolean(ih, "MULTIPLEFILES"))
+ openfilename.Flags |= OFN_ALLOWMULTISELECT;
+
+ openfilename.lpfnHook = winFileDlgSimpleHook;
+ openfilename.Flags |= OFN_ENABLEHOOK | OFN_EXPLORER | OFN_ENABLESIZING;
+ openfilename.lCustData = (LPARAM)ih;
+
+ if (iupAttribGetBoolean(ih, "SHOWPREVIEW") && IupGetCallback(ih, "FILE_CB"))
+ {
+ openfilename.Flags |= OFN_ENABLETEMPLATE;
+ openfilename.hInstance = iupwin_dll_hinstance? iupwin_dll_hinstance: iupwin_hinstance;
+ openfilename.lpTemplateName = "iupPreviewDlg";
+ openfilename.lpfnHook = winFileDlgPreviewHook;
+ }
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ openfilename.Flags |= OFN_SHOWHELP;
+
+ if (dialogtype == IUP_DIALOGOPEN)
+ result = GetOpenFileName(&openfilename);
+ else
+ result = GetSaveFileName(&openfilename);
+
+ if (result)
+ {
+ if (iupAttribGetBoolean(ih, "MULTIPLEFILES"))
+ {
+ int i = 0;
+
+ /* If there is more than one file, replace terminator by the separator */
+ if (openfilename.lpstrFile && openfilename.lpstrFile[openfilename.nFileOffset-1] == 0 && openfilename.nFileOffset>0)
+ {
+ while (openfilename.lpstrFile[i] != 0 || openfilename.lpstrFile[i+1] != 0)
+ {
+ if (openfilename.lpstrFile[i]==0)
+ openfilename.lpstrFile[i] = '|';
+ i++;
+ }
+ openfilename.lpstrFile[i] = '|';
+ }
+
+ iupAttribSetStr(ih, "STATUS", "0");
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ }
+ else
+ {
+ if (iupdrvIsFile(openfilename.lpstrFile)) /* check if file exists */
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "YES");
+ iupAttribSetStr(ih, "STATUS", "0");
+ }
+ else
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "NO");
+ iupAttribSetStr(ih, "STATUS", "1");
+ }
+ }
+
+ iupAttribStoreStr(ih, "VALUE", openfilename.lpstrFile);
+ iupAttribSetInt(ih, "FILTERUSED", (int)openfilename.nFilterIndex);
+ }
+ else
+ {
+ iupAttribSetStr(ih, "FILTERUSED", NULL);
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "STATUS", "-1");
+ }
+
+ if (openfilename.lpstrFilter) free((char*)openfilename.lpstrFilter);
+ if (openfilename.lpstrInitialDir) free((char*)openfilename.lpstrInitialDir);
+ if (openfilename.lpstrFile) free(openfilename.lpstrFile);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFileDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = winFileDlgPopup;
+
+ /* IupFileDialog Windows and GTK Only */
+ iupClassRegisterAttribute(ic, "EXTFILTER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTERINFO", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTERUSED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MULTIPLEFILES", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_focus.c b/iup/src/win/iupwin_focus.c
new file mode 100755
index 0000000..63da02d
--- /dev/null
+++ b/iup/src/win/iupwin_focus.c
@@ -0,0 +1,62 @@
+/** \file
+ * \brief Windows Focus
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <windows.h>
+
+#include "iup.h"
+#include "iup_object.h"
+#include "iup_focus.h"
+#include "iup_assert.h"
+#include "iup_drv.h"
+#include "iup_attrib.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+
+/* not defined for gcc */
+#ifndef WM_CHANGEUISTATE
+#define WM_CHANGEUISTATE 0x0127
+#endif
+#ifndef UIS_CLEAR
+#define UIS_CLEAR 2
+#endif
+#ifndef UISF_HIDEFOCUS
+#define UISF_HIDEFOCUS 0x1
+#endif
+
+/* 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.
+
+ 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.
+
+ TODO: I would like a form to always show the feedback, but could not understand how WM_CHANGEUISTATE works.
+ Neither SystemParametersInfo(SPI_SETKEYBOARDCUES, TRUE) or SystemParametersInfo(SPI_SETKEYBOARDPREF, TRUE) worked.
+*/
+void iupdrvSetFocus(Ihandle *ih)
+{
+ SetFocus(ih->handle);
+ SendMessage(ih->handle, WM_CHANGEUISTATE, UIS_CLEAR|UISF_HIDEFOCUS, 0);
+}
+
+void iupwinWmSetFocus(Ihandle *ih)
+{
+ Ihandle* dialog = IupGetDialog(ih);
+ if (ih != dialog)
+ iupAttribSetStr(dialog, "_IUPWIN_LASTFOCUS", (char*)ih); /* used by IupMenu */
+ 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);
+ }
+
+ iupCallGetFocusCb(ih);
+}
diff --git a/iup/src/win/iupwin_font.c b/iup/src/win/iupwin_font.c
new file mode 100755
index 0000000..659e2d9
--- /dev/null
+++ b/iup/src/win/iupwin_font.c
@@ -0,0 +1,342 @@
+/** \file
+ * \brief Windows Font mapping
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <windows.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_array.h"
+#include "iup_attrib.h"
+#include "iup_object.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_assert.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_info.h"
+
+
+typedef struct IwinFont_
+{
+ char standardfont[200];
+ HFONT hFont;
+ int charwidth, charheight;
+} IwinFont;
+
+static Iarray* win_fonts = NULL;
+
+static IwinFont* winFindFont(const char *standardfont)
+{
+ HFONT hFont;
+ int height_pixels;
+ char typeface[50] = "";
+ int height = 8;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ int res = iupwinGetScreenRes();
+ int i, count = iupArrayCount(win_fonts);
+ const char* mapped_name;
+
+ /* Check if the standardfont already exists in cache */
+ IwinFont* fonts = (IwinFont*)iupArrayGetData(win_fonts);
+ for (i = 0; i < count; i++)
+ {
+ if (iupStrEqualNoCase(standardfont, fonts[i].standardfont))
+ return &fonts[i];
+ }
+
+ /* parse the old format first */
+ if (!iupFontParseWin(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return NULL;
+ }
+
+ mapped_name = iupFontGetWinName(typeface);
+ if (mapped_name)
+ strcpy(typeface, mapped_name);
+
+ /* get in pixels */
+ if (height < 0)
+ height_pixels = height; /* already in pixels */
+ else
+ height_pixels = -IUPWIN_PT2PIXEL(height, res);
+
+ if (height_pixels == 0)
+ return NULL;
+
+ hFont = CreateFont(height_pixels,
+ 0,0,0,
+ (is_bold) ? FW_BOLD : FW_NORMAL,
+ is_italic,
+ is_underline,
+ is_strikeout,
+ DEFAULT_CHARSET,OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
+ FF_DONTCARE|DEFAULT_PITCH,
+ typeface);
+ if (!hFont)
+ return NULL;
+
+ /* create room in the array */
+ fonts = (IwinFont*)iupArrayInc(win_fonts);
+
+ strcpy(fonts[i].standardfont, standardfont);
+ fonts[i].hFont = hFont;
+
+ {
+ TEXTMETRIC tm;
+ HDC hdc = GetDC(NULL);
+ HFONT oldfont = SelectObject(hdc, hFont);
+
+ GetTextMetrics(hdc, &tm);
+
+ SelectObject(hdc, oldfont);
+ ReleaseDC(NULL, hdc);
+
+ fonts[i].charwidth = tm.tmAveCharWidth;
+ fonts[i].charheight = tm.tmHeight;
+ }
+
+ return &fonts[i];
+}
+
+static void winFontFromLogFont(LOGFONT* logfont, char * font)
+{
+ int is_bold = (logfont->lfWeight == FW_NORMAL)? 0: 1;
+ int is_italic = logfont->lfItalic;
+ int is_underline = logfont->lfUnderline;
+ 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 */
+
+ sprintf(font, "%s, %s%s%s%s %d", logfont->lfFaceName,
+ is_bold?"Bold ":"",
+ is_italic?"Italic ":"",
+ is_underline?"Underline ":"",
+ is_strikeout?"Strikeout ":"",
+ height);
+}
+
+char* iupdrvGetSystemFont(void)
+{
+ static char systemfont[200] = "";
+ NONCLIENTMETRICS ncm;
+ ncm.cbSize = sizeof(NONCLIENTMETRICS);
+ if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, FALSE))
+ winFontFromLogFont(&ncm.lfMessageFont, systemfont);
+ else
+ strcpy(systemfont, "Tahoma, 10");
+ return systemfont;
+}
+
+char* iupwinFindHFont(HFONT hFont)
+{
+ int i, count = iupArrayCount(win_fonts);
+
+ /* Check if the standardfont already exists in cache */
+ IwinFont* fonts = (IwinFont*)iupArrayGetData(win_fonts);
+ for (i = 0; i < count; i++)
+ {
+ if (hFont == fonts[i].hFont)
+ return fonts[i].standardfont;
+ }
+
+ return NULL;
+}
+
+HFONT iupwinGetHFont(const char* value)
+{
+ IwinFont* winfont = winFindFont(value);
+ if (!winfont)
+ return NULL;
+ else
+ return winfont->hFont;
+}
+
+static IwinFont* winFontCreateNativeFont(Ihandle *ih, const char* value)
+{
+ IwinFont* winfont = winFindFont(value);
+ if (!winfont)
+ {
+ iupERROR1("Failed to create Font: %s", value);
+ return NULL;
+ }
+
+ iupAttribSetStr(ih, "_IUP_WINFONT", (char*)winfont);
+ return winfont;
+}
+
+static IwinFont* winFontGet(Ihandle *ih)
+{
+ IwinFont* winfont = (IwinFont*)iupAttribGet(ih, "_IUP_WINFONT");
+ if (!winfont)
+ winfont = winFontCreateNativeFont(ih, iupGetFontAttrib(ih));
+ return winfont;
+}
+
+char* iupwinGetHFontAttrib(Ihandle *ih)
+{
+ IwinFont* winfont = winFontGet(ih);
+ if (!winfont)
+ return NULL;
+ else
+ return (char*)winfont->hFont;
+}
+
+int iupdrvSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ IwinFont* winfont = winFontCreateNativeFont(ih, value);
+ if (!winfont)
+ return 1;
+
+ /* If FONT is changed, must update the SIZE attribute */
+ iupBaseUpdateSizeFromFont(ih);
+
+ /* FONT attribute must be able to be set before mapping,
+ so the font is enable for size calculation. */
+ if (ih->handle && (ih->iclass->nativetype != IUP_TYPEVOID))
+ SendMessage(ih->handle, WM_SETFONT, (WPARAM)winfont->hFont, MAKELPARAM(TRUE,0));
+
+ return 1;
+}
+
+static HDC winFontGetDC(Ihandle* ih)
+{
+ if (ih->iclass->nativetype == IUP_TYPEVOID)
+ return GetDC(NULL);
+ else
+ return GetDC(ih->handle); /* handle can be NULL here */
+}
+
+static void winFontReleaseDC(Ihandle* ih, HDC hdc)
+{
+ if (ih->iclass->nativetype == IUP_TYPEVOID)
+ ReleaseDC(NULL, hdc);
+ else
+ ReleaseDC(ih->handle, hdc); /* handle can be NULL here */
+}
+
+void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h)
+{
+ int num_lin, max_w;
+
+ IwinFont* winfont = winFontGet(ih);
+ if (!winfont)
+ {
+ if (w) *w = 0;
+ if (h) *h = 0;
+ return;
+ }
+
+ if (!str)
+ {
+ if (w) *w = 0;
+ if (h) *h = winfont->charheight * 1;
+ return;
+ }
+
+ max_w = 0;
+ num_lin = 1;
+ if (str[0])
+ {
+ SIZE size;
+ int len;
+ const char *nextstr;
+ const char *curstr = str;
+
+ HDC hdc = winFontGetDC(ih);
+ HFONT oldhfont = SelectObject(hdc, winfont->hFont);
+
+ do
+ {
+ nextstr = iupStrNextLine(curstr, &len);
+ GetTextExtentPoint32(hdc, curstr, len, &size);
+ max_w = iupMAX(max_w, size.cx);
+
+ curstr = nextstr;
+ if (*nextstr)
+ num_lin++;
+ } while(*nextstr);
+
+ SelectObject(hdc, oldhfont);
+ winFontReleaseDC(ih, hdc);
+ }
+
+ if (w) *w = max_w;
+ if (h) *h = winfont->charheight*num_lin;
+}
+
+int iupdrvFontGetStringWidth(Ihandle* ih, const char* str)
+{
+ HDC hdc;
+ HFONT oldhfont, hFont;
+ SIZE size;
+ int len;
+ char* line_end;
+
+ if (!str || str[0]==0)
+ return 0;
+
+ hFont = (HFONT)iupwinGetHFontAttrib(ih);
+ if (!hFont)
+ return 0;
+
+ hdc = winFontGetDC(ih);
+ oldhfont = SelectObject(hdc, hFont);
+
+ line_end = strchr(str, '\n');
+ if (line_end)
+ len = line_end-str;
+ else
+ len = strlen(str);
+
+ GetTextExtentPoint32(hdc, str, len, &size);
+
+ SelectObject(hdc, oldhfont);
+ winFontReleaseDC(ih, hdc);
+
+ return size.cx;
+}
+
+void iupdrvFontGetCharSize(Ihandle* ih, int *charwidth, int *charheight)
+{
+ IwinFont* winfont = winFontGet(ih);
+ if (!winfont)
+ {
+ if (charwidth) *charwidth = 0;
+ if (charheight) *charheight = 0;
+ return;
+ }
+
+ if (charwidth) *charwidth = winfont->charwidth;
+ if (charheight) *charheight = winfont->charheight;
+}
+
+void iupdrvFontInit(void)
+{
+ win_fonts = iupArrayCreate(50, sizeof(IwinFont));
+}
+
+void iupdrvFontFinish(void)
+{
+ int i, count = iupArrayCount(win_fonts);
+ IwinFont* fonts = (IwinFont*)iupArrayGetData(win_fonts);
+ for (i = 0; i < count; i++)
+ {
+ DeleteObject(fonts[i].hFont);
+ fonts[i].hFont = NULL;
+ }
+ iupArrayDestroy(win_fonts);
+}
diff --git a/iup/src/win/iupwin_fontdlg.c b/iup/src/win/iupwin_fontdlg.c
new file mode 100755
index 0000000..0602441
--- /dev/null
+++ b/iup/src/win/iupwin_fontdlg.c
@@ -0,0 +1,160 @@
+/** \file
+ * \brief IupFontDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+#include "iup_drvfont.h"
+
+#include "iupwin_drv.h"
+
+
+#define IUP_FONTFAMILYCOMBOBOX 0x0470
+
+static UINT_PTR winFontDlgHookProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+ (void)wParam;
+ if (uiMsg == WM_INITDIALOG)
+ {
+ HWND hWndItem;
+ CHOOSEFONT* choosefont = (CHOOSEFONT*)lParam;
+ Ihandle* ih = (Ihandle*)choosefont->lCustData;
+
+ char* value = iupAttribGet(ih, "TITLE");
+ if (value)
+ SetWindowText(hWnd, value);
+
+ ih->handle = hWnd;
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+ iupAttribSetStr(ih, "HWND", (char*)hWnd); /* used by HELP_CB in winDialogBaseProc */
+
+ hWndItem = GetDlgItem(hWnd, IUP_FONTFAMILYCOMBOBOX);
+ SetFocus(hWndItem);
+ }
+ return 0;
+}
+
+static int winFontDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ unsigned char r, g, b;
+ CHOOSEFONT choosefont;
+ LOGFONT logfont;
+ char* standardfont;
+ int height_pixels;
+ char typeface[50] = "";
+ int height = 8;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ int res = iupwinGetScreenRes();
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ standardfont = iupAttribGet(ih, "VALUE");
+ if (!standardfont)
+ return IUP_ERROR;
+
+ /* parse the old format first */
+ if (!iupFontParseWin(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return IUP_ERROR;
+ }
+
+ /* get size in pixels */
+ if (height < 0)
+ height_pixels = height; /* already in pixels */
+ else
+ height_pixels = -IUPWIN_PT2PIXEL(height, res);
+
+ if (height_pixels == 0)
+ return IUP_ERROR;
+
+ ZeroMemory(&choosefont, sizeof(CHOOSEFONT));
+ choosefont.lStructSize = sizeof(CHOOSEFONT);
+
+ if (iupStrToRGB(iupAttribGet(ih, "COLOR"), &r, &g, &b))
+ choosefont.rgbColors = RGB(r, g, b);
+
+ choosefont.hwndOwner = parent;
+ choosefont.lpLogFont = &logfont;
+ choosefont.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_ENABLEHOOK;
+ choosefont.lCustData = (LPARAM)ih;
+ choosefont.lpfnHook = (LPCFHOOKPROC)winFontDlgHookProc;
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ choosefont.Flags |= CF_SHOWHELP;
+
+ strcpy(logfont.lfFaceName, typeface);
+ logfont.lfHeight = height_pixels;
+ logfont.lfWeight = (is_bold)? FW_BOLD: FW_NORMAL;
+ logfont.lfItalic = (BYTE)is_italic;
+ logfont.lfUnderline = (BYTE)is_underline;
+ logfont.lfStrikeOut = (BYTE)is_strikeout;
+
+ logfont.lfCharSet = DEFAULT_CHARSET;
+ logfont.lfEscapement = 0;
+ logfont.lfOrientation = 0;
+ logfont.lfWidth = 0;
+ logfont.lfOutPrecision = OUT_TT_PRECIS;
+ logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ logfont.lfQuality = DEFAULT_QUALITY;
+ logfont.lfPitchAndFamily = FF_DONTCARE|DEFAULT_PITCH;
+
+ if (!ChooseFont(&choosefont))
+ {
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "COLOR", NULL);
+ iupAttribSetStr(ih, "STATUS", NULL);
+ return IUP_NOERROR;
+ }
+
+ is_bold = (logfont.lfWeight == FW_NORMAL)? 0: 1;
+ is_italic = logfont.lfItalic;
+ is_underline = logfont.lfUnderline;
+ is_strikeout = logfont.lfStrikeOut;
+ height_pixels = logfont.lfHeight;
+
+ 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 */
+
+ iupAttribSetStrf(ih, "VALUE", "%s, %s%s%s%s %d", logfont.lfFaceName,
+ is_bold?"Bold ":"",
+ is_italic?"Italic ":"",
+ is_underline?"Underline ":"",
+ is_strikeout?"Strikeout ":"",
+ height);
+
+ iupAttribSetStrf(ih, "COLOR", "%d %d %d", GetRValue(choosefont.rgbColors),
+ GetGValue(choosefont.rgbColors),
+ GetBValue(choosefont.rgbColors));
+ iupAttribSetStr(ih, "STATUS", "1");
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFontDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = winFontDlgPopup;
+
+ /* IupFontDialog Windows Only */
+ iupClassRegisterAttribute(ic, "COLOR", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_frame.c b/iup/src/win/iupwin_frame.c
new file mode 100755
index 0000000..0949b5d
--- /dev/null
+++ b/iup/src/win/iupwin_frame.c
@@ -0,0 +1,203 @@
+/** \file
+ * \brief Frame Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_stdcontrols.h"
+#include "iup_frame.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+#include "iupwin_info.h"
+
+
+void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y)
+{
+ if (iupwin_comctl32ver6)
+ {
+ *x = 3;
+ *y = 3;
+ }
+ else
+ {
+ *x = 2;
+ *y = 2;
+ }
+
+ if (iupAttribGet(ih, "_IUPFRAME_HAS_TITLE") || iupAttribGet(ih, "TITLE"))
+ {
+ (*y) += iupFrameGetTitleHeight(ih);
+ }
+}
+
+static void winFrameDrawText(HDC hDC, const char* text, int x, int y, COLORREF fgcolor)
+{
+ COLORREF oldcolor;
+
+ SetTextAlign(hDC, TA_TOP|TA_LEFT);
+ SetBkMode(hDC, TRANSPARENT);
+ oldcolor = SetTextColor(hDC, fgcolor);
+
+ TextOut(hDC, x, y, text, strlen(text));
+
+ SetTextColor(hDC, oldcolor);
+ SetBkMode(hDC, OPAQUE);
+}
+
+static void winFrameDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem)
+{
+ iupwinBitmapDC bmpDC;
+ HDC hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, drawitem->rcItem.right-drawitem->rcItem.left,
+ drawitem->rcItem.bottom-drawitem->rcItem.top);
+
+ iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem);
+
+ if (iupAttribGet(ih, "_IUPFRAME_HAS_TITLE"))
+ {
+ int x, y;
+ HFONT hOldFont, hFont = (HFONT)iupwinGetHFontAttrib(ih);
+ int txt_height = iupFrameGetTitleHeight(ih);
+ COLORREF fgcolor;
+ SIZE size;
+
+ char* title = iupdrvBaseGetTitleAttrib(ih);
+ if (!title) title = "";
+
+ x = drawitem->rcItem.left+7;
+ y = drawitem->rcItem.top;
+
+ hOldFont = SelectObject(hDC, hFont);
+ GetTextExtentPoint32(hDC, title, strlen(title), &size);
+ ExcludeClipRect(hDC, x-2, y, x+size.cx+2, y+size.cy);
+
+ drawitem->rcItem.top += txt_height/2;
+ if (iupwin_comctl32ver6)
+ iupwinDrawThemeFrameBorder(ih->handle, hDC, &drawitem->rcItem, drawitem->itemState);
+ else
+ DrawEdge(hDC, &drawitem->rcItem, EDGE_ETCHED, BF_RECT);
+
+ SelectClipRgn(hDC, NULL);
+
+ if (drawitem->itemState & ODS_DISABLED)
+ fgcolor = GetSysColor(COLOR_GRAYTEXT);
+ else
+ {
+ unsigned char r, g, b;
+ char* color = iupAttribGetInherit(ih, "FGCOLOR");
+ if (!color)
+ {
+ if (!iupwinDrawGetThemeFrameFgColor(ih->handle, &fgcolor))
+ fgcolor = 0; /* black */
+ }
+ else
+ {
+ if (iupStrToRGB(color, &r, &g, &b))
+ fgcolor = RGB(r,g,b);
+ else
+ fgcolor = 0; /* black */
+ }
+ }
+
+ winFrameDrawText(hDC, title, x, y, fgcolor);
+
+ SelectObject(hDC, hOldFont);
+ }
+ else
+ {
+ char* value = iupAttribGetStr(ih, "SUNKEN");
+ if (iupStrBoolean(value))
+ DrawEdge(hDC, &drawitem->rcItem, EDGE_SUNKEN, BF_RECT);
+ else
+ DrawEdge(hDC, &drawitem->rcItem, EDGE_ETCHED, BF_RECT);
+ }
+
+ iupwinDrawDestroyBitmapDC(&bmpDC);
+}
+
+static int winFrameProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch (msg)
+ {
+ case WM_GETDLGCODE:
+ {
+ *result = DLGC_STATIC; /* same return as GROUPBOX */
+ return 1;
+ }
+ case WM_NCHITTEST:
+ {
+ *result = HTTRANSPARENT; /* same return as GROUPBOX */
+ return 1;
+ }
+ case WM_ERASEBKGND:
+ {
+ /* just to ignore the internal processing */
+ *result = 1;
+ return 1;
+ }
+ }
+
+ return iupwinBaseContainerProc(ih, msg, wp, lp, result);
+}
+
+static int winFrameMapMethod(Ihandle* ih)
+{
+ char *title;
+ DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS|
+ BS_OWNERDRAW, /* owner draw necessary because BS_GROUPBOX does not work ok */
+ dwExStyle = 0;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ 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 (!iupwinCreateWindowEx(ih, "BUTTON", dwExStyle, dwStyle))
+ return IUP_ERROR;
+
+ /* replace the WinProc to handle other messages */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winFrameProc);
+
+ /* Process WM_DRAWITEM */
+ IupSetCallback(ih, "_IUPWIN_DRAWITEM_CB", (Icallback)winFrameDrawItem);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFrameInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winFrameMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", iupBaseNativeParentGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_globalattrib.c b/iup/src/win/iupwin_globalattrib.c
new file mode 100755
index 0000000..a176925
--- /dev/null
+++ b/iup/src/win/iupwin_globalattrib.c
@@ -0,0 +1,243 @@
+/** \file
+ * \brief Windows Driver iupdrvSetGlobal
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <windows.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_strmessage.h"
+
+#include "iupwin_drv.h"
+
+static int win_monitor_index = 0;
+
+/* Not defined in compilers older than VC9 */
+#ifndef MAPVK_VK_TO_VSC
+#define MAPVK_VK_TO_VSC (0)
+#endif
+
+static void winGlobalSendKey(int key, int press)
+{
+ unsigned int keyval, state;
+ INPUT input[2];
+ LPARAM extra_info;
+ WORD state_scan = 0, key_scan;
+ ZeroMemory(input, 2*sizeof(INPUT));
+
+ iupwinKeyEncode(key, &keyval, &state);
+ if (!keyval)
+ return;
+
+ extra_info = GetMessageExtraInfo();
+ if (state)
+ state_scan = (WORD)MapVirtualKey(state, MAPVK_VK_TO_VSC);
+ key_scan = (WORD)MapVirtualKey(keyval, MAPVK_VK_TO_VSC);
+
+ if (press & 0x01)
+ {
+ if (state)
+ {
+ /* modifier first */
+ input[0].type = INPUT_KEYBOARD;
+ input[0].ki.wVk = (WORD)state;
+ input[0].ki.wScan = state_scan;
+ input[0].ki.dwExtraInfo = extra_info;
+
+ /* key second */
+ input[1].type = INPUT_KEYBOARD;
+ input[1].ki.wVk = (WORD)keyval;
+ input[1].ki.wScan = key_scan;
+ input[1].ki.dwExtraInfo = extra_info;
+
+ SendInput(2, input, sizeof(INPUT));
+ }
+ else
+ {
+ input[0].type = INPUT_KEYBOARD;
+ input[0].ki.wVk = (WORD)keyval;
+ input[0].ki.wScan = key_scan;
+ input[0].ki.dwExtraInfo = extra_info;
+
+ SendInput(1, input, sizeof(INPUT));
+ }
+ }
+
+ if (press & 0x02)
+ {
+ if (state)
+ {
+ /* key first */
+ input[0].type = INPUT_KEYBOARD;
+ input[0].ki.dwFlags = KEYEVENTF_KEYUP;
+ input[0].ki.wVk = (WORD)keyval;
+ input[0].ki.wScan = key_scan;
+ input[0].ki.dwExtraInfo = extra_info;
+
+ /* modifier second */
+ input[1].type = INPUT_KEYBOARD;
+ input[1].ki.dwFlags = KEYEVENTF_KEYUP;
+ input[1].ki.wVk = (WORD)state;
+ input[1].ki.wScan = state_scan;
+ input[1].ki.dwExtraInfo = extra_info;
+
+ SendInput(2, input, sizeof(INPUT));
+ }
+ else
+ {
+ input[0].type = INPUT_KEYBOARD;
+ input[0].ki.dwFlags = KEYEVENTF_KEYUP;
+ input[0].ki.wVk = (WORD)keyval;
+ input[0].ki.wScan = key_scan;
+ input[0].ki.dwExtraInfo = extra_info;
+
+ SendInput(1, input, sizeof(INPUT));
+ }
+ }
+}
+
+static BOOL CALLBACK winMonitorInfoEnum(HMONITOR handle, HDC handle_dc, LPRECT rect, LPARAM data)
+{
+ RECT* monitors_rect = (RECT*)data;
+ monitors_rect[win_monitor_index] = *rect;
+ win_monitor_index++;
+ (void)handle_dc;
+ (void)handle;
+ return TRUE;
+}
+
+int iupdrvSetGlobal(const char *name, const char *value)
+{
+ if (iupStrEqual(name, "LANGUAGE"))
+ {
+ iupStrMessageUpdateLanguage(value);
+ return 1;
+ }
+ if (iupStrEqual(name, "CURSORPOS"))
+ {
+ int x, y;
+ if (iupStrToIntInt(value, &x, &y, 'x') == 2)
+ SetCursorPos(x, y);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEYPRESS"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ winGlobalSendKey(key, 0x01);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEYRELEASE"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ winGlobalSendKey(key, 0x02);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEY"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ winGlobalSendKey(key, 0x03);
+ return 0;
+ }
+ return 1;
+}
+
+char *iupdrvGetGlobal(const char *name)
+{
+ if (iupStrEqual(name, "CURSORPOS"))
+ {
+ int x, y;
+ char* str = iupStrGetMemory(50);
+ iupdrvGetCursorPos(&x, &y);
+ sprintf(str, "%dx%d", x, y);
+ return str;
+ }
+ if (iupStrEqual(name, "SHIFTKEY"))
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[0] == 'S')
+ return "ON";
+ return "OFF";
+ }
+ if (iupStrEqual(name, "CONTROLKEY"))
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[1] == 'C')
+ return "ON";
+ return "OFF";
+ }
+ if (iupStrEqual(name, "MODKEYSTATE"))
+ {
+ char *str = iupStrGetMemory(5);
+ iupdrvGetKeyState(str);
+ return str;
+ }
+ if (iupStrEqual(name, "SCREENSIZE"))
+ {
+ char *str = iupStrGetMemory(50);
+ int w, h;
+ iupdrvGetScreenSize(&w, &h);
+ sprintf(str, "%dx%d", w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "FULLSIZE"))
+ {
+ char *str = iupStrGetMemory(50);
+ int w, h;
+ iupdrvGetFullSize(&w, &h);
+ sprintf(str, "%dx%d", w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "SCREENDEPTH"))
+ {
+ char *str = iupStrGetMemory(50);
+ int bpp = iupdrvGetScreenDepth();
+ sprintf(str, "%d", bpp);
+ return str;
+ }
+ if (iupStrEqual(name, "VIRTUALSCREEN"))
+ {
+ char *str = iupStrGetMemory(50);
+ int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
+ int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
+ int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
+ sprintf(str, "%d %d %d %d", x, y, w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "MONITORSINFO"))
+ {
+ int i;
+ int monitors_count = GetSystemMetrics(SM_CMONITORS);
+ RECT* monitors_rect = malloc(monitors_count*sizeof(RECT));
+ char *str = iupStrGetMemory(monitors_count*50);
+ char* pstr = str;
+
+ win_monitor_index = 0;
+ EnumDisplayMonitors(NULL, NULL, winMonitorInfoEnum, (LPARAM)monitors_rect);
+
+ for (i=0; i < monitors_count; i++)
+ pstr += sprintf(pstr, "%d %d %d %d\n", (int)monitors_rect[i].left, (int)monitors_rect[i].top, (int)(monitors_rect[i].right-monitors_rect[i].left), (int)(monitors_rect[i].bottom-monitors_rect[i].top));
+
+ free(monitors_rect);
+ return str;
+ }
+ if (iupStrEqual(name, "TRUECOLORCANVAS"))
+ {
+ if (iupdrvGetScreenDepth() > 8)
+ return "YES";
+ return "NO";
+ }
+ return NULL;
+}
diff --git a/iup/src/win/iupwin_handle.c b/iup/src/win/iupwin_handle.c
new file mode 100755
index 0000000..d5a7f77
--- /dev/null
+++ b/iup/src/win/iupwin_handle.c
@@ -0,0 +1,56 @@
+/** \file
+ * \brief HWND to ihandle table
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_table.h"
+
+#include "iupwin_handle.h"
+
+
+static Itable* winhandle_table; /* table indexed by HWND containing Ihandle* address */
+
+Ihandle* iupwinHandleGet(void* handle)
+{
+ Ihandle* ih;
+ if (!handle)
+ return NULL;
+ ih = (Ihandle*)iupTableGet(winhandle_table, (char*)handle);
+ if (ih && !iupObjectCheck(ih))
+ return NULL;
+ return ih;
+}
+
+void iupwinHandleSet(Ihandle *ih)
+{
+ iupTableSet(winhandle_table, (char*)ih->handle, ih, IUPTABLE_POINTER);
+}
+
+void iupwinHandleAdd(Ihandle *ih, InativeHandle* hWnd)
+{
+ iupTableSet(winhandle_table, (char*)hWnd, ih, IUPTABLE_POINTER);
+}
+
+void iupwinHandleRemove(Ihandle *ih)
+{
+ iupTableRemove(winhandle_table, (char*)ih->handle);
+}
+
+void iupwinHandleInit(void)
+{
+ winhandle_table = iupTableCreate(IUPTABLE_POINTERINDEXED);
+}
+
+void iupwinHandleFinish(void)
+{
+ iupTableDestroy(winhandle_table);
+ winhandle_table = NULL;
+}
diff --git a/iup/src/win/iupwin_handle.h b/iup/src/win/iupwin_handle.h
new file mode 100755
index 0000000..4a8643d
--- /dev/null
+++ b/iup/src/win/iupwin_handle.h
@@ -0,0 +1,28 @@
+/** \file
+ * \brief HWND to ihandle table
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPWIN_HANDLE_H
+#define __IUPWIN_HANDLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Returns the IUP handle given the Windows handle. */
+
+Ihandle* iupwinHandleGet(void* handle);
+void iupwinHandleSet(Ihandle *ih);
+void iupwinHandleAdd(Ihandle *ih, InativeHandle* hWnd);
+void iupwinHandleRemove(Ihandle *ih);
+void iupwinHandleInit(void);
+void iupwinHandleFinish(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/win/iupwin_image.c b/iup/src/win/iupwin_image.c
new file mode 100755
index 0000000..2db9800
--- /dev/null
+++ b/iup/src/win/iupwin_image.c
@@ -0,0 +1,668 @@
+/** \file
+ * \brief Image Resource.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+
+/* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */
+#define iupALPHAPRE(_src, _alpha) (((_src)*(_alpha))/255)
+
+static int winDibNumColors(BITMAPINFOHEADER* bmih)
+{
+ if (bmih->biBitCount > 8)
+ {
+ if (bmih->biCompression == BI_BITFIELDS)
+ return 3;
+ else
+ return 0;
+ }
+ else
+ {
+ if (bmih->biClrUsed != 0)
+ return bmih->biClrUsed;
+ else
+ return 1 << bmih->biBitCount;
+ }
+}
+
+void iupdrvImageGetRawData(void* handle, unsigned char* imgdata)
+{
+ int x, y, w, h, bpp, bmp_line_size, bits_size;
+ BYTE* bits;
+ HANDLE hHandle = (HANDLE)handle;
+ void* dib = GlobalLock(hHandle);
+ BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)dib;
+
+ w = bmih->biWidth;
+ h = abs(bmih->biHeight);
+ bpp = iupImageNormBpp(bmih->biBitCount);
+ bmp_line_size = ((w * bmih->biBitCount + 31) / 32) * 4; /* DWORD aligned, 4 bytes boundary in a N bpp image */
+ bits_size = bmp_line_size*h;
+
+ bits = ((BYTE*)dib) + sizeof(BITMAPINFOHEADER) + winDibNumColors(bmih)*sizeof(RGBQUAD);
+
+ /* windows bitmaps are bottom up */
+ /* imgdata is bottom up */
+
+ if (bmih->biHeight < 0)
+ bits = bits + (bits_size - bmp_line_size); /* start of last line */
+
+ if (bpp == 8)
+ {
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ switch (bmih->biBitCount)
+ {
+ case 1:
+ *imgdata++ = (unsigned char)((bits[x / 8] >> (7 - x % 8)) & 0x01);
+ break;
+ case 4:
+ *imgdata++ = (unsigned char)((bits[x / 2] >> ((1 - x % 2) * 4)) & 0x0F);
+ break;
+ case 8:
+ *imgdata++ = bits[x];
+ break;
+ }
+ }
+
+ if (bmih->biHeight < 0)
+ bits -= bmp_line_size;
+ else
+ bits += bmp_line_size;
+ }
+ }
+ else
+ {
+ int offset, planesize;
+ unsigned short color;
+ unsigned int rmask = 0, gmask = 0, bmask = 0,
+ roff = 0, goff = 0, boff = 0; /* pixel bit mask control when reading 16 and 32 bpp images */
+ unsigned char *red, *green, *blue, *alpha;
+
+ planesize = w*h;
+ red = imgdata;
+ green = imgdata+planesize;
+ blue = imgdata+2*planesize;
+ alpha = imgdata+3*planesize;
+
+ if (bmih->biBitCount == 16)
+ offset = bmp_line_size; /* do not increment for each pixel, jump line */
+ else
+ offset = bmp_line_size - (w*bmih->biBitCount)/8; /* increment for each pixel, jump pad */
+
+ if (bmih->biCompression == BI_BITFIELDS)
+ {
+ unsigned int Mask;
+ unsigned int* palette = (unsigned int*)(((BYTE*)bmih) + sizeof(BITMAPINFOHEADER));
+
+ rmask = Mask = palette[0];
+ while (!(Mask & 0x01))
+ {Mask >>= 1; roff++;}
+
+ gmask = Mask = palette[1];
+ while (!(Mask & 0x01))
+ {Mask >>= 1; goff++;}
+
+ bmask = Mask = palette[2];
+ while (!(Mask & 0x01))
+ {Mask >>= 1; boff++;}
+ }
+ else if (bmih->biBitCount == 16)
+ {
+ bmask = 0x001F;
+ gmask = 0x03E0;
+ rmask = 0x7C00;
+ boff = 0;
+ goff = 5;
+ roff = 10;
+ }
+
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ if (bmih->biBitCount == 16)
+ {
+ color = ((unsigned short*)bits)[x];
+ *red++ = (unsigned char)((((rmask & color) >> roff) * 255) / (rmask >> roff));
+ *green++ = (unsigned char)((((gmask & color) >> goff) * 255) / (gmask >> goff));
+ *blue++ = (unsigned char)((((bmask & color) >> boff) * 255) / (bmask >> boff));
+ }
+ else
+ {
+ *blue++ = *bits++;
+ *green++ = *bits++;
+ *red++ = *bits++;
+
+ if (bmih->biBitCount == 32)
+ {
+ if (alpha)
+ *alpha++ = *bits++;
+ else
+ bits++;
+ }
+ }
+ }
+
+ bits += offset;
+
+ if (bmih->biHeight < 0)
+ bits -= 2*bmp_line_size;
+ }
+ }
+
+ GlobalUnlock(hHandle);
+}
+
+void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata)
+{
+ int y,x,bmp_line_size,channels,bits_size,header_size;
+ HANDLE hHandle;
+ BYTE* bits; /* DIB bitmap bits, created in CreateDIBSection and filled here */
+ void* dib;
+ BITMAPINFOHEADER* bmih;
+
+ bmp_line_size = ((width * bpp + 31) / 32) * 4; /* DWORD aligned, 4 bytes boundary in a N bpp image */
+ bits_size = bmp_line_size*height;
+ header_size = sizeof(BITMAPINFOHEADER) + colors_count*sizeof(RGBQUAD);
+
+ hHandle = GlobalAlloc(GMEM_MOVEABLE, header_size+bits_size);
+ if (!hHandle)
+ return NULL;
+
+ dib = GlobalLock(hHandle);
+ bits = ((BYTE*)dib) + header_size;
+
+ bmih = (BITMAPINFOHEADER*)dib;
+
+ memset(bmih, 0, sizeof(BITMAPINFOHEADER));
+ bmih->biSize = sizeof(BITMAPINFOHEADER);
+ bmih->biWidth = width;
+ bmih->biHeight = height;
+ bmih->biPlanes = 1; /* not the same as PLANES */
+ bmih->biBitCount = (WORD)bpp;
+ bmih->biCompression = BI_RGB;
+ bmih->biClrUsed = colors_count;
+
+ if (colors_count)
+ {
+ RGBQUAD* bitmap_colors = (RGBQUAD*)(((BYTE*)dib) + sizeof(BITMAPINFOHEADER));
+ int i;
+ for (i=0;i<colors_count;i++)
+ {
+ bitmap_colors[i].rgbRed = colors[i].r;
+ bitmap_colors[i].rgbGreen = colors[i].g;
+ bitmap_colors[i].rgbBlue = colors[i].b;
+ bitmap_colors[i].rgbReserved = 0;
+ }
+ }
+
+ channels = 1;
+ if (bpp == 24)
+ channels = 3;
+ else if (bpp == 32)
+ channels = 4;
+
+ /* windows bitmaps are bottom up */
+ /* imgdata is bottom up */
+
+ if (bpp != 8) /* (bpp == 32 || bpp == 24) */
+ {
+ unsigned char *r, *g, *b, *a;
+
+ int planesize = width*height;
+ r = imgdata;
+ g = imgdata+planesize;
+ b = imgdata+2*planesize;
+ a = imgdata+3*planesize;
+
+ for (y=0; y<height; y++)
+ {
+ int lineoffset = y*width;
+ for (x=0; x<width; x++)
+ {
+ int offset = channels*x;
+ /* Windows Bitmap order is BGRA */
+ BYTE *bmp_b = &bits[offset],
+ *bmp_g = bmp_b+1,
+ *bmp_r = bmp_g+1,
+ *bmp_a = bmp_r+1;
+
+ *bmp_r = r[lineoffset+x];
+ *bmp_g = g[lineoffset+x];
+ *bmp_b = b[lineoffset+x];
+
+ if (channels == 4) /* bpp==32 */
+ {
+ *bmp_a = a[lineoffset+x];
+
+ /* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */
+ *bmp_r = iupALPHAPRE(*bmp_r,*bmp_a);
+ *bmp_g = iupALPHAPRE(*bmp_g,*bmp_a);
+ *bmp_b = iupALPHAPRE(*bmp_b,*bmp_a);
+ }
+ }
+
+ bits += bmp_line_size;
+ }
+ }
+ else
+ {
+ for (y=0; y<height; y++)
+ {
+ int lineoffset = y*width;
+ for (x=0; x<width; x++)
+ {
+ bits[x] = imgdata[lineoffset+x];
+ }
+
+ bits += bmp_line_size;
+ }
+ }
+
+ GlobalUnlock(hHandle);
+ return hHandle;
+}
+
+int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count)
+{
+ HANDLE hHandle = (HANDLE)handle;
+ void* dib = GlobalLock(hHandle);
+ BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)dib;
+
+ if (w) *w = bmih->biWidth;
+ if (h) *h = abs(bmih->biHeight);
+ if (bpp) *bpp = iupImageNormBpp(bmih->biBitCount);
+
+ if (bmih->biBitCount <= 8)
+ {
+ RGBQUAD* bitmap_colors = (RGBQUAD*)(((BYTE*)bmih) + sizeof(BITMAPINFOHEADER));
+ int i;
+
+ if (bmih->biClrUsed != 0)
+ *colors_count = bmih->biClrUsed;
+ else
+ *colors_count = 1 << bmih->biBitCount;
+
+ for (i=0;i<*colors_count;i++)
+ {
+ colors[i].r = bitmap_colors[i].rgbRed;
+ colors[i].g = bitmap_colors[i].rgbGreen;
+ colors[i].b = bitmap_colors[i].rgbBlue;
+ }
+ }
+
+ GlobalUnlock(hHandle);
+ return 1;
+}
+
+static int winImageInitDibColors(iupColor* colors, RGBQUAD* bmpcolors, int colors_count,
+ unsigned char bg_r, unsigned char bg_g, unsigned char bg_b, int make_inactive)
+{
+ int i, ret = 0;
+ for (i=0;i<colors_count;i++)
+ {
+ bmpcolors[i].rgbRed = colors[i].r;
+ bmpcolors[i].rgbGreen = colors[i].g;
+ bmpcolors[i].rgbBlue = colors[i].b;
+ bmpcolors[i].rgbReserved = colors[i].a;
+
+ if (bmpcolors[i].rgbReserved == 0) /* full transparent alpha */
+ {
+ bmpcolors[i].rgbBlue = bg_b;
+ bmpcolors[i].rgbGreen = bg_g;
+ bmpcolors[i].rgbRed = bg_r;
+ ret = 1;
+ }
+ else
+ bmpcolors[i].rgbReserved = 0; /* clear non transparent mark */
+
+ if (make_inactive)
+ iupImageColorMakeInactive(&(bmpcolors[i].rgbRed), &(bmpcolors[i].rgbGreen), &(bmpcolors[i].rgbBlue),
+ bg_r, bg_g, bg_b);
+ }
+
+ return ret;
+}
+
+static HBITMAP winImageCreateBitmap(Ihandle *ih, int width, int height, int bpp, BYTE** bits,
+ unsigned char bg_r, unsigned char bg_g, unsigned char bg_b, int make_inactive)
+{
+ HDC hDC;
+ int colors_count;
+ HBITMAP hBitmap;
+ BITMAPINFOHEADER* bmih; /* bitmap info header */
+ iupColor colors[256];
+
+ if (bpp == 32 || bpp == 24)
+ colors_count = 0;
+ else /* bpp == 8 */
+ iupImageInitColorTable(ih, colors, &colors_count);
+
+ bmih = malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*colors_count);
+ if (!bmih)
+ return NULL;
+
+ memset(bmih, 0, sizeof(BITMAPINFOHEADER));
+ bmih->biSize = sizeof(BITMAPINFOHEADER);
+ bmih->biWidth = width;
+ bmih->biHeight = height;
+ bmih->biPlanes = 1; /* not the same as PLANES */
+ bmih->biBitCount = (WORD)bpp;
+ bmih->biCompression = BI_RGB;
+ bmih->biClrUsed = colors_count;
+
+ if (colors_count)
+ {
+ /* since colors are only passed to the CreateDIBSection here, must update BGCOLOR and inactive here */
+ RGBQUAD* bitmap_colors = (RGBQUAD*)(((BYTE*)bmih) + sizeof(BITMAPINFOHEADER));
+ if (winImageInitDibColors(colors, bitmap_colors, colors_count, bg_r, bg_g, bg_b, make_inactive))
+ iupAttribSetStr(ih, "_IUP_BGCOLOR_DEPEND", "1");
+ }
+
+ hDC = GetDC(NULL);
+ hBitmap = CreateDIBSection(hDC, (BITMAPINFO*)bmih, DIB_RGB_COLORS, (void**)bits, NULL, 0x0);
+ ReleaseDC(NULL, hDC);
+ free(bmih);
+
+ return hBitmap;
+}
+
+void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive)
+{
+ unsigned char bg_r = 0, bg_g = 0, bg_b = 0;
+ int y,x,bmp_line_size,data_line_size,
+ width = ih->currentwidth,
+ height = ih->currentheight,
+ channels = iupAttribGetInt(ih, "CHANNELS"),
+ flat_alpha = iupAttribGetBoolean(ih, "FLAT_ALPHA"),
+ bpp = iupAttribGetInt(ih, "BPP");
+ unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+ HBITMAP hBitmap;
+ BYTE* bits; /* DIB bitmap bits, created in CreateDIBSection and filled here */
+
+ iupStrToRGB(bgcolor, &bg_r, &bg_g, &bg_b);
+
+ hBitmap = winImageCreateBitmap(ih, width, height, bpp, &bits, bg_r, bg_g, bg_b, make_inactive);
+ if (!hBitmap)
+ return NULL;
+
+ bmp_line_size = ((width * bpp + 31) / 32) * 4; /* DWORD aligned, 4 bytes boundary in a N bpp image */
+ data_line_size = width*channels;
+
+ /* windows bitmaps are bottom up */
+ imgdata += (height-1)*data_line_size; /* iupimage is top down */
+
+ for (y=0; y<height; y++)
+ {
+ for (x=0; x<width; x++)
+ {
+ if (bpp != 8) /* (bpp == 32 || bpp == 24) */
+ {
+ int offset = channels*x;
+ /* Windows Bitmap order is BGRA */
+ BYTE *b = &bits[offset],
+ *g = b+1,
+ *r = g+1,
+ *a = r+1,
+ *dat = &imgdata[offset];
+
+ *r = *(dat);
+ *g = *(dat+1);
+ *b = *(dat+2);
+
+ if (channels == 4) /* bpp==32 */
+ {
+ if (flat_alpha)
+ {
+ *a = *(dat+3);
+ *r = iupALPHABLEND(*r, bg_r, *a);
+ *g = iupALPHABLEND(*g, bg_g, *a);
+ *b = iupALPHABLEND(*b, bg_b, *a);
+ *a = 255;
+ }
+
+ if (make_inactive)
+ iupImageColorMakeInactive(r, g, b, bg_r, bg_g, bg_b);
+
+ if (!flat_alpha)
+ {
+ *a = *(dat+3);
+
+ /* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */
+ *r = iupALPHAPRE(*r,*a);
+ *g = iupALPHAPRE(*g,*a);
+ *b = iupALPHAPRE(*b,*a);
+ }
+ }
+ }
+ else /* bpp == 8 */
+ {
+ bits[x] = imgdata[x];
+ }
+ }
+
+ bits += bmp_line_size;
+ imgdata -= data_line_size; /* iupimage is top down */
+ }
+
+ if (make_inactive || (channels == 4 && flat_alpha))
+ iupAttribSetStr(ih, "_IUP_BGCOLOR_DEPEND", "1");
+
+ return hBitmap;
+}
+
+static HBITMAP winImageCreateBitmask(Ihandle *ih, int invert)
+{
+ int y, x, mask_line_size,data_line_size, colors_count, set,
+ width = ih->currentwidth,
+ height = ih->currentheight,
+ channels = iupAttribGetInt(ih, "CHANNELS"),
+ bpp = iupAttribGetInt(ih, "BPP");
+ unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+ HBITMAP hBitmap;
+ BYTE* bitmask, *bitmask_ptr;
+ iupColor colors[256];
+
+ if (bpp == 8)
+ iupImageInitColorTable(ih, colors, &colors_count);
+
+ mask_line_size = ((width + 15) / 16) * 2; /* WORD aligned, 2 bytes boundary in a 1 bpp image */
+ data_line_size = width*channels;
+
+ bitmask = malloc(height * mask_line_size);
+ memset(bitmask, 0, height * mask_line_size); /* opaque */
+
+ /* mask and iupimage are top down */
+
+ bitmask_ptr = bitmask;
+ for (y=0; y<height; y++)
+ {
+ for (x=0; x<width; x++)
+ {
+ set = 0;
+
+ if (bpp == 32)
+ {
+ BYTE* dat = &imgdata[channels*x];
+ if (*(dat+3) == 0) /* full transparent alpha */
+ set = 1;
+ }
+ else if (bpp == 8)
+ {
+ unsigned char index = imgdata[x];
+ if (colors[index].a == 0) /* full transparent alpha */
+ set = 1;
+ }
+
+ if (set)
+ bitmask_ptr[x/8] |= 1 << (7 - (x % 8)); /* set transparent mask bit */
+ }
+
+ bitmask_ptr += mask_line_size;
+ imgdata += data_line_size;
+ }
+
+ if (invert)
+ {
+ int k, size = height * mask_line_size;
+ for (k = 0; k < size; k++)
+ bitmask[k] = ~bitmask[k];
+ }
+
+ hBitmap = CreateBitmap(width, height, 1, 1, bitmask);
+ free(bitmask);
+ return hBitmap;
+}
+
+static HICON winImageCreateIcon(Ihandle *ih, int is_cursor)
+{
+ HBITMAP hBitmap, hBitmapMask;
+ ICONINFO iconinfo;
+ HICON icon;
+ char* color0 = NULL;
+
+ /* If cursor and no transparency defined, assume 0 if transparent.
+ We do this only in Windows and because of backward compatibility. */
+ if (is_cursor)
+ {
+ int bpp = iupAttribGetInt(ih, "BPP");
+ if (bpp == 8)
+ {
+ if (!iupStrEqual(iupAttribGet(ih, "0"), "BGCOLOR") &&
+ !iupStrEqual(iupAttribGet(ih, "1"), "BGCOLOR") &&
+ !iupStrEqual(iupAttribGet(ih, "2"), "BGCOLOR"))
+ {
+ color0 = iupStrDup(iupAttribGet(ih, "0"));
+ iupAttribSetStr(ih, "0", "BGCOLOR");
+ }
+ }
+ }
+
+ hBitmap = iupdrvImageCreateImage(ih, NULL, 0);
+ if (!hBitmap)
+ {
+ if (color0) free(color0);
+ return NULL;
+ }
+
+ /* Transparency mask */
+ hBitmapMask = winImageCreateBitmask(ih, 0);
+ if (!hBitmapMask)
+ {
+ DeleteObject(hBitmap);
+ if (color0) free(color0);
+ return NULL;
+ }
+
+ /* destination = (destination AND bitmask) XOR bitmap */
+ iconinfo.hbmMask = hBitmapMask; /* AND */
+ iconinfo.hbmColor = hBitmap; /* XOR */
+
+ if (is_cursor)
+ {
+ int x=0,y=0;
+ iupStrToIntInt(iupAttribGet(ih, "HOTSPOT"), &x, &y, ':');
+
+ iconinfo.xHotspot = x;
+ iconinfo.yHotspot = y;
+ iconinfo.fIcon = FALSE;
+ }
+ else
+ iconinfo.fIcon = TRUE;
+
+ icon = CreateIconIndirect(&iconinfo);
+
+ DeleteObject(hBitmap);
+ DeleteObject(hBitmapMask);
+
+ if (color0)
+ {
+ iupAttribStoreStr(ih, "0", color0);
+ free(color0);
+ }
+
+ return icon;
+}
+
+void* iupdrvImageCreateIcon(Ihandle *ih)
+{
+ return winImageCreateIcon(ih, 0);
+}
+
+void* iupdrvImageCreateCursor(Ihandle *ih)
+{
+ return winImageCreateIcon(ih, 1);
+}
+
+void* iupdrvImageCreateMask(Ihandle *ih)
+{
+ int invert = 1;
+ if (!ih) return NULL;
+ if (iupAttribGet(ih, "_IUPIMG_NO_INVERT")) invert = 0;
+ return (void*)winImageCreateBitmask(ih, invert);
+}
+
+void* iupdrvImageLoad(const char* name, int type)
+{
+ int iup2win[3] = {IMAGE_BITMAP, IMAGE_ICON, IMAGE_CURSOR};
+ HANDLE hImage = LoadImage(iupwin_hinstance, (LPCTSTR)name, iup2win[type], 0, 0, type==0?LR_CREATEDIBSECTION:0);
+ if (!hImage && iupwin_dll_hinstance)
+ hImage = LoadImage(iupwin_dll_hinstance, (LPCTSTR)name, iup2win[type], 0, 0, type==0?LR_CREATEDIBSECTION:0);
+ if (!hImage)
+ hImage = LoadImage(NULL, (LPCTSTR)name, iup2win[type], 0, 0, LR_LOADFROMFILE|(type==0?LR_CREATEDIBSECTION:0));
+ return hImage;
+}
+
+int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp)
+{
+ BITMAP bm;
+ if (!GetObject((HBITMAP)handle, sizeof(BITMAP), (LPSTR)&bm))
+ {
+ if (w) *w = 0;
+ if (h) *h = 0;
+ if (bpp) *bpp = 0;
+ return 0;
+ }
+ if (w) *w = bm.bmWidth;
+ if (h) *h = abs(bm.bmHeight);
+ if (bpp) *bpp = iupImageNormBpp(bm.bmBitsPixel*bm.bmPlanes);
+ return 1;
+}
+
+void iupdrvImageDestroy(void* handle, int type)
+{
+ switch (type)
+ {
+ case IUPIMAGE_IMAGE:
+ if (GetObjectType((HBITMAP)handle)==OBJ_BITMAP)
+ DeleteObject((HBITMAP)handle);
+ else
+ GlobalFree((HANDLE)handle);
+ break;
+ case IUPIMAGE_ICON:
+ DestroyIcon((HICON)handle);
+ break;
+ case IUPIMAGE_CURSOR:
+ DestroyCursor((HCURSOR)handle);
+ break;
+ }
+}
+
diff --git a/iup/src/win/iupwin_info.c b/iup/src/win/iupwin_info.c
new file mode 100755
index 0000000..8ea7dd4
--- /dev/null
+++ b/iup/src/win/iupwin_info.c
@@ -0,0 +1,277 @@
+/** \file
+ * \brief Windows System Information
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <windows.h>
+#include <uxtheme.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_drv.h"
+
+#include "iupwin_info.h"
+
+
+int iupwinIsVista(void)
+{
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osvi);
+
+ if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 6)
+ return 1;
+
+ return 0;
+}
+
+int iupwinGetSystemMajorVersion(void)
+{
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osvi);
+ return osvi.dwMajorVersion;
+}
+
+char *iupwinGetSystemLanguage(void)
+{
+ LANGID id = GetSystemDefaultUILanguage();
+ char *lang = NULL;
+ switch(id)
+ {
+ case 0x0000: lang = "Language Neutral"; break;
+ case 0x007f: lang = "Locale Invariant"; break;
+ case 0x0400: lang = "User Default Language"; break;
+ case 0x0800: lang = "System Default Language"; break;
+ case 0x0436: lang = "Afrikaans"; break;
+ case 0x041c: lang = "Albanian"; break;
+ case 0x0401: lang = "Arabic (Saudi Arabia)"; break;
+ case 0x0801: lang = "Arabic (Iraq)"; break;
+ case 0x0c01: lang = "Arabic (Egypt)"; break;
+ case 0x1001: lang = "Arabic (Libya)"; break;
+ case 0x1401: lang = "Arabic (Algeria)"; break;
+ case 0x1801: lang = "Arabic (Morocco)"; break;
+ case 0x1c01: lang = "Arabic (Tunisia)"; break;
+ case 0x2001: lang = "Arabic (Oman)"; break;
+ case 0x2401: lang = "Arabic (Yemen)"; break;
+ case 0x2801: lang = "Arabic (Syria)"; break;
+ case 0x2c01: lang = "Arabic (Jordan)"; break;
+ case 0x3001: lang = "Arabic (Lebanon)"; break;
+ case 0x3401: lang = "Arabic (Kuwait)"; break;
+ case 0x3801: lang = "Arabic (U.A.E.)"; break;
+ case 0x3c01: lang = "Arabic (Bahrain)"; break;
+ case 0x4001: lang = "Arabic (Qatar)"; break;
+ case 0x042b: lang = "Armenian"; break;
+ case 0x042c: lang = "Azeri (Latin)"; break;
+ case 0x082c: lang = "Azeri (Cyrillic)"; break;
+ case 0x042d: lang = "Basque"; break;
+ case 0x0423: lang = "Belarusian"; break;
+ case 0x0402: lang = "Bulgarian"; break;
+ case 0x0455: lang = "Burmese"; break;
+ case 0x0403: lang = "Catalan"; break;
+ case 0x0404: lang = "Chinese (Taiwan)"; break;
+ case 0x0804: lang = "Chinese"; break;
+ case 0x0c04: lang = "Chinese (Hong Kong)"; break;
+ case 0x1004: lang = "Chinese (Singapore)"; break;
+ case 0x1404: lang = "Chinese (Macau)"; break;
+ case 0x041a: lang = "Croatian"; break;
+ case 0x0405: lang = "Czech"; break;
+ case 0x0406: lang = "Danish"; break;
+ case 0x0465: lang = "Divehi"; break;
+ case 0x0413: lang = "Dutch (Netherlands)"; break;
+ case 0x0813: lang = "Dutch (Belgium)"; break;
+ case 0x0409: lang = "English (United States)"; break;
+ case 0x0809: lang = "English (United Kingdom)"; break;
+ case 0x0c09: lang = "English (Australian)"; break;
+ case 0x1009: lang = "English (Canadian)"; break;
+ case 0x1409: lang = "English (New Zealand)"; break;
+ case 0x1809: lang = "English (Ireland)"; break;
+ case 0x1c09: lang = "English (South Africa)"; break;
+ case 0x2009: lang = "English (Jamaica)"; break;
+ case 0x2409: lang = "English (Caribbean)"; break;
+ case 0x2809: lang = "English (Belize)"; break;
+ case 0x2c09: lang = "English (Trinidad)"; break;
+ case 0x3009: lang = "English (Zimbabwe)"; break;
+ case 0x3409: lang = "English (Philippines)"; break;
+ case 0x0425: lang = "Estonian"; break;
+ case 0x0438: lang = "Faeroese"; break;
+ case 0x0429: lang = "Farsi"; break;
+ case 0x040b: lang = "Finnish"; break;
+ case 0x040c: lang = "French (Standard)"; break;
+ case 0x080c: lang = "French (Belgian)"; break;
+ case 0x0c0c: lang = "French (Canadian)"; break;
+ case 0x100c: lang = "French (Switzerland)"; break;
+ case 0x140c: lang = "French (Luxembourg)"; break;
+ case 0x180c: lang = "French (Monaco)"; break;
+ case 0x0456: lang = "Galician"; break;
+ case 0x0437: lang = "Georgian"; break;
+ case 0x0407: lang = "German (Standard)"; break;
+ case 0x0807: lang = "German (Switzerland)"; break;
+ case 0x0c07: lang = "German (Austria)"; break;
+ case 0x1007: lang = "German (Luxembourg)"; break;
+ case 0x1407: lang = "German (Liechtenstein)"; break;
+ case 0x0408: lang = "Greek"; break;
+ case 0x0447: lang = "Gujarati"; break;
+ case 0x040d: lang = "Hebrew"; break;
+ case 0x0439: lang = "Hindi"; break;
+ case 0x040e: lang = "Hungarian"; break;
+ case 0x040f: lang = "Icelandic"; break;
+ case 0x0421: lang = "Indonesian"; break;
+ case 0x0410: lang = "Italian (Standard)"; break;
+ case 0x0810: lang = "Italian (Switzerland)"; break;
+ case 0x0411: lang = "Japanese"; break;
+ case 0x044b: lang = "Kannada"; break;
+ case 0x0457: lang = "Konkani"; break;
+ case 0x0412: lang = "Korean"; break;
+ case 0x0812: lang = "Korean (Johab)"; break;
+ case 0x0440: lang = "Kyrgyz"; break;
+ case 0x0426: lang = "Latvian"; break;
+ case 0x0427: lang = "Lithuanian"; break;
+ case 0x0827: lang = "Lithuanian (Classic)"; break;
+ case 0x042f: lang = "Macedonian"; break;
+ case 0x043e: lang = "Malay (Malaysian)"; break;
+ case 0x083e: lang = "Malay (Brunei Darussalam)"; break;
+ case 0x044e: lang = "Marathi"; break;
+ case 0x0450: lang = "Mongolian"; break;
+ case 0x0414: lang = "Norwegian (Bokmal)"; break;
+ case 0x0814: lang = "Norwegian (Nynorsk)"; break;
+ case 0x0415: lang = "Polish"; break;
+ case 0x0416: lang = "Portuguese (Brazil)"; break;
+ case 0x0816: lang = "Portuguese (Portugal)"; break;
+ case 0x0446: lang = "Punjabi"; break;
+ case 0x0418: lang = "Romanian"; break;
+ case 0x0419: lang = "Russian"; break;
+ case 0x044f: lang = "Sanskrit"; break;
+ case 0x0c1a: lang = "Serbian (Cyrillic)"; break;
+ case 0x081a: lang = "Serbian (Latin)"; break;
+ case 0x041b: lang = "Slovak"; break;
+ case 0x0424: lang = "Slovenian"; break;
+ case 0x040a: lang = "Spanish (Spain, Traditional Sort)"; break;
+ case 0x080a: lang = "Spanish (Mexican)"; break;
+ case 0x0c0a: lang = "Spanish (Spain, International Sort)"; break;
+ case 0x100a: lang = "Spanish (Guatemala)"; break;
+ case 0x140a: lang = "Spanish (Costa Rica)"; break;
+ case 0x180a: lang = "Spanish (Panama)"; break;
+ case 0x1c0a: lang = "Spanish (Dominican Republic)"; break;
+ case 0x200a: lang = "Spanish (Venezuela)"; break;
+ case 0x240a: lang = "Spanish (Colombia)"; break;
+ case 0x280a: lang = "Spanish (Peru)"; break;
+ case 0x2c0a: lang = "Spanish (Argentina)"; break;
+ case 0x300a: lang = "Spanish (Ecuador)"; break;
+ case 0x340a: lang = "Spanish (Chile)"; break;
+ case 0x380a: lang = "Spanish (Uruguay)"; break;
+ case 0x3c0a: lang = "Spanish (Paraguay)"; break;
+ case 0x400a: lang = "Spanish (Bolivia)"; break;
+ case 0x440a: lang = "Spanish (El Salvador)"; break;
+ case 0x480a: lang = "Spanish (Honduras)"; break;
+ case 0x4c0a: lang = "Spanish (Nicaragua)"; break;
+ case 0x500a: lang = "Spanish (Puerto Rico)"; break;
+ case 0x0430: lang = "Sutu"; break;
+ case 0x0441: lang = "Swahili (Kenya)"; break;
+ case 0x041d: lang = "Swedish"; break;
+ case 0x081d: lang = "Swedish (Finland)"; break;
+ case 0x045a: lang = "Syriac"; break;
+ case 0x0449: lang = "Tamil"; break;
+ case 0x0444: lang = "Tatar (Tatarstan)"; break;
+ case 0x044a: lang = "Telugu"; break;
+ case 0x041e: lang = "Thai"; break;
+ case 0x041f: lang = "Turkish"; break;
+ case 0x0422: lang = "Ukrainian"; break;
+ case 0x0420: lang = "Urdu (Pakistan)"; break;
+ case 0x0820: lang = "Urdu (India)"; break;
+ case 0x0443: lang = "Uzbek (Latin)"; break;
+ case 0x0843: lang = "Uzbek (Cyrillic)"; break;
+ case 0x042a: lang = "Vietnamese"; break;
+ }
+ return lang;
+}
+
+#define PACKVERSION(major,minor) MAKELONG(minor,major)
+typedef struct _DLLVERSIONINFO
+{
+ DWORD cbSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformID;
+} DLLVERSIONINFO;
+typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
+
+static DWORD winGetDllVersion(LPCTSTR lpszDllName)
+{
+ HINSTANCE hinstDll;
+ DWORD dwVersion = 0;
+
+ /* For security purposes, LoadLibrary should be provided with a
+ fully-qualified path to the DLL. The lpszDllName variable should be
+ tested to ensure that it is a fully qualified path before it is used. */
+ hinstDll = LoadLibrary(lpszDllName);
+
+ if (hinstDll)
+ {
+ DLLGETVERSIONPROC pDllGetVersion;
+ pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion");
+
+ /* Because some DLLs might not implement this function, you
+ must test for it explicitly. Depending on the particular
+ DLL, the lack of a DllGetVersion function can be a useful
+ indicator of the version. */
+
+ if (pDllGetVersion)
+ {
+ DLLVERSIONINFO dvi;
+ HRESULT hr;
+
+ ZeroMemory(&dvi, sizeof(dvi));
+ dvi.cbSize = sizeof(dvi);
+
+ hr = pDllGetVersion(&dvi);
+ if (SUCCEEDED(hr))
+ dwVersion = PACKVERSION(dvi.dwMajorVersion, dvi.dwMinorVersion);
+ }
+
+ FreeLibrary(hinstDll);
+ }
+
+ return dwVersion;
+}
+
+int iupwinGetComCtl32Version(void)
+{
+ return winGetDllVersion(TEXT("comctl32.dll"));
+}
+
+void iupwinGetSysColor(char* color, int wincolor)
+{
+ COLORREF syscolor = GetSysColor(wincolor);
+ sprintf(color, "%d %d %d", (int)GetRValue(syscolor), (int)GetGValue(syscolor), (int)GetBValue(syscolor));
+}
+
+char* iupwinGetSystemFgColor(void)
+{
+ static char def_fgcolor[50];
+ iupwinGetSysColor(def_fgcolor, COLOR_WINDOWTEXT);
+ return def_fgcolor;
+}
+
+int iupwinIsAppThemed(void)
+{
+ typedef BOOL (STDAPICALLTYPE *winIsAppThemed)(void);
+ static winIsAppThemed myIsAppThemed = NULL;
+ if (!myIsAppThemed)
+ {
+ HMODULE hinstDll = LoadLibrary("uxtheme.dll");
+ if (hinstDll)
+ myIsAppThemed = (winIsAppThemed)GetProcAddress(hinstDll, "IsAppThemed");
+ }
+
+ if (myIsAppThemed)
+ return myIsAppThemed();
+ else
+ return 0;
+}
diff --git a/iup/src/win/iupwin_info.h b/iup/src/win/iupwin_info.h
new file mode 100755
index 0000000..d39bae0
--- /dev/null
+++ b/iup/src/win/iupwin_info.h
@@ -0,0 +1,29 @@
+/** \file
+ * \brief Windows System Information
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPWIN_INFO_H
+#define __IUPWIN_INFO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* system */
+int iupwinGetSystemMajorVersion(void);
+int iupwinGetComCtl32Version(void);
+char* iupwinGetSystemLanguage(void);
+int iupwinIsAppThemed(void);
+int iupwinIsVista(void);
+
+/* color */
+void iupwinGetSysColor(char* color, int wincolor);
+char* iupwinGetSystemFgColor(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/win/iupwin_key.c b/iup/src/win/iupwin_key.c
new file mode 100755
index 0000000..921ed94
--- /dev/null
+++ b/iup/src/win/iupwin_key.c
@@ -0,0 +1,348 @@
+/** \file
+ * \brief Windows Driver keyboard mapping
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+
+#include <windows.h>
+
+#include "iup.h"
+#include "iupkey.h"
+
+#include "iup_object.h"
+#include "iup_key.h"
+
+#include "iupwin_drv.h"
+
+
+#ifndef VK_OEM_PLUS
+#define VK_OEM_PLUS 0xBB /* '+' any country */
+#define VK_OEM_COMMA 0xBC /* ',' any country */
+#define VK_OEM_MINUS 0xBD /* '-' any country */
+#define VK_OEM_PERIOD 0xBE /* '.' any country */
+#define VK_OEM_102 0xE2 /* "<>" or "\|" on RT 102-key kbd. */
+#endif
+
+typedef struct _Iwin2iupkey
+{
+ int wincode;
+ int iupcode;
+ int s_iupcode;
+ int c_iupcode;
+ int m_iupcode;
+ int y_iupcode;
+} Iwin2iupkey;
+
+static Iwin2iupkey winkey_map[] = {
+
+{ VK_ESCAPE, K_ESC, K_sESC, K_cESC, K_mESC, K_yESC },
+{ VK_PAUSE, K_PAUSE, K_sPAUSE, K_cPAUSE, K_mPAUSE, K_yPAUSE },
+{ VK_SNAPSHOT, K_Print, K_sPrint, K_cPrint, K_mPrint, K_yPrint },
+{ VK_APPS, K_Menu, K_sMenu, K_cMenu, K_mMenu, K_yMenu },
+
+{ VK_HOME, K_HOME, K_sHOME, K_cHOME, K_mHOME, K_yHOME },
+{ VK_UP, K_UP, K_sUP, K_cUP, K_mUP, K_yUP },
+{ VK_PRIOR, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP, K_yPGUP },
+{ VK_LEFT, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT, K_yLEFT },
+{ VK_CLEAR, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE},
+{ VK_RIGHT, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT, K_yRIGHT },
+{ VK_END, K_END, K_sEND, K_cEND, K_mEND, K_yEND },
+{ VK_DOWN, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN, K_yDOWN },
+{ VK_NEXT, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN, K_yPGDN },
+{ VK_INSERT, K_INS, K_sINS, K_cINS, K_mINS, K_yINS },
+{ VK_DELETE, K_DEL, K_sDEL, K_cDEL, K_mDEL, K_yDEL },
+{ VK_SPACE, K_SP, K_sSP, K_cSP, K_mSP, K_ySP },
+{ VK_TAB, K_TAB, K_sTAB, K_cTAB, K_mTAB, K_yTAB },
+{ VK_RETURN, K_CR, K_sCR, K_cCR, K_mCR, K_yCR },
+{ VK_BACK, K_BS, K_sBS, K_cBS, K_mBS, K_yBS },
+
+/* VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39) */
+{ '1', K_1, K_exclam, K_c1, K_m1, K_y1 },
+{ '2', K_2, K_at, K_c2, K_m2, K_y2 },
+{ '3', K_3, K_numbersign, K_c3, K_m3, K_y3 },
+{ '4', K_4, K_dollar, K_c4, K_m4, K_y4 },
+{ '5', K_5, K_percent, K_c5, K_m5, K_y5 },
+{ '6', K_6, K_circum, K_c6, K_m6, K_y6 },
+{ '7', K_7, K_ampersand, K_c7, K_m7, K_y7 },
+{ '8', K_8, K_asterisk, K_c8, K_m8, K_y8 },
+{ '9', K_9, K_parentleft, K_c9, K_m9, K_y9 },
+{ '0', K_0, K_parentright, K_c0, K_m0, K_y0 },
+
+/* VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A) */
+{ 'A', K_a, K_A, K_cA, K_mA, K_yA},
+{ 'B', K_b, K_B, K_cB, K_mB, K_yB},
+{ 'C', K_c, K_C, K_cC, K_mC, K_yC},
+{ 'D', K_d, K_D, K_cD, K_mD, K_yD},
+{ 'E', K_e, K_E, K_cE, K_mE, K_yE},
+{ 'F', K_f, K_F, K_cF, K_mF, K_yF},
+{ 'G', K_g, K_G, K_cG, K_mG, K_yG},
+{ 'H', K_h, K_H, K_cH, K_mH, K_yH},
+{ 'I', K_i, K_I, K_cI, K_mI, K_yI},
+{ 'J', K_j, K_J, K_cJ, K_mJ, K_yJ},
+{ 'K', K_k, K_K, K_cK, K_mK, K_yK},
+{ 'L', K_l, K_L, K_cL, K_mL, K_yL},
+{ 'M', K_m, K_M, K_cM, K_mM, K_yM},
+{ 'N', K_n, K_N, K_cN, K_mN, K_yN},
+{ 'O', K_o, K_O, K_cO, K_mO, K_yO},
+{ 'P', K_p, K_P, K_cP, K_mP, K_yP},
+{ 'Q', K_q, K_Q, K_cQ, K_mQ, K_yQ},
+{ 'R', K_r, K_R, K_cR, K_mR, K_yR},
+{ 'S', K_s, K_S, K_cS, K_mS, K_yS},
+{ 'T', K_t, K_T, K_cT, K_mT, K_yT},
+{ 'U', K_u, K_U, K_cU, K_mU, K_yU},
+{ 'V', K_v, K_V, K_cV, K_mV, K_yV},
+{ 'W', K_w, K_W, K_cW, K_mW, K_yW},
+{ 'X', K_x, K_X, K_cX, K_mX, K_yX},
+{ 'Y', K_y, K_Y, K_cY, K_mY, K_yY},
+{ 'Z', K_z, K_Z, K_cZ, K_mZ, K_yZ},
+
+{ VK_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 },
+{ VK_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 },
+{ VK_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 },
+{ VK_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 },
+{ VK_F5, K_F5, K_sF5, K_cF5, K_mF5, K_yF5 },
+{ VK_F6, K_F6, K_sF6, K_cF6, K_mF6, K_yF6 },
+{ VK_F7, K_F7, K_sF7, K_cF7, K_mF7, K_yF7 },
+{ VK_F8, K_F8, K_sF8, K_cF8, K_mF8, K_yF8 },
+{ VK_F9, K_F9, K_sF9, K_cF9, K_mF9, K_yF9 },
+{ VK_F10, K_F10, K_sF10, K_cF10, K_mF10, K_yF10 },
+{ VK_F11, K_F11, K_sF11, K_cF11, K_mF11, K_yF11 },
+{ VK_F12, K_F12, K_sF12, K_cF12, K_mF12, K_yF12 },
+
+{ VK_OEM_1, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon },
+{ VK_OEM_PLUS, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual },
+{ VK_OEM_COMMA, K_comma, K_less, K_cComma, K_mComma, K_yComma },
+{ VK_OEM_MINUS, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus },
+{ VK_OEM_PERIOD, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod },
+{ VK_OEM_2, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash },
+{ VK_OEM_3, K_grave, K_tilde, 0, 0, 0 },
+{ VK_OEM_4, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft },
+{ VK_OEM_5, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash },
+{ VK_OEM_6, K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright },
+{ VK_OEM_7, K_apostrophe, K_quotedbl, 0, 0, 0 },
+{ VK_OEM_102, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash },
+
+{ VK_NUMPAD0, K_0, K_0, K_c0, K_m0, K_y0 },
+{ VK_NUMPAD1, K_1, K_1, K_c1, K_m1, K_y1 },
+{ VK_NUMPAD2, K_2, K_2, K_c2, K_m2, K_y2 },
+{ VK_NUMPAD3, K_3, K_3, K_c3, K_m3, K_y3 },
+{ VK_NUMPAD4, K_4, K_4, K_c4, K_m4, K_y4 },
+{ VK_NUMPAD5, K_5, K_5, K_c5, K_m5, K_y5 },
+{ VK_NUMPAD6, K_6, K_6, K_c6, K_m6, K_y6 },
+{ VK_NUMPAD7, K_7, K_7, K_c7, K_m7, K_y7 },
+{ VK_NUMPAD8, K_8, K_8, K_c8, K_m8, K_y8 },
+{ VK_NUMPAD9, K_9, K_9, K_c9, K_m9, K_y9 },
+{ VK_MULTIPLY, K_asterisk, K_sAsterisk, K_cAsterisk, K_mAsterisk, K_yAsterisk },
+{ VK_ADD, K_plus, K_sPlus, K_cPlus, K_mPlus, K_yPlus },
+{ VK_SUBTRACT, K_minus, K_sMinus, K_cMinus, K_mMinus, K_yMinus },
+{ VK_DECIMAL, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod },
+{ VK_DIVIDE, K_slash, K_sSlash, K_cSlash, K_mSlash, K_ySlash },
+{ VK_SEPARATOR, K_comma, K_sComma, K_cComma, K_mComma, K_yComma }
+};
+
+static Iwin2iupkey keytable_abnt[] = {
+{ '1', K_1, K_exclam, K_c1, K_m1, K_y1 },
+{ '2', K_2, K_at, K_c2, K_m2, K_y2 },
+{ '3', K_3, K_numbersign, K_c3, K_m3, K_y3 },
+{ '4', K_4, K_dollar, K_c4, K_m4, K_y4 },
+{ '5', K_5, K_percent, K_c5, K_m5, K_y5 },
+{ '6', K_6, K_circum, K_c6, K_m6, K_y6 },
+
+{ VK_OEM_1, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla },
+{ VK_OEM_2, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon },
+{ VK_OEM_3, K_apostrophe, K_quotedbl, 0, 0, 0 },
+{ VK_OEM_4, K_acute, K_grave, 0, 0, 0 },
+{ VK_OEM_5, K_bracketright, K_braceright, K_cBracketleft, K_mBracketleft, K_yBracketleft },
+{ VK_OEM_6, K_bracketleft, K_braceleft, K_cBracketright, K_mBracketright, K_yBracketright },
+{ VK_OEM_7, K_tilde, K_circum, 0, 0, 0 },
+{ VK_OEM_102, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash },
+{ VK_OEM_PLUS, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual },
+{ 0xC1, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash },
+{ 0xC2, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod },
+{ VK_SEPARATOR,K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod },
+{ VK_DECIMAL, K_comma, K_sComma, K_cComma, K_mComma, K_yComma }
+};
+
+
+void iupwinKeyEncode(int key, unsigned int *keyval, unsigned int *state)
+{
+ int i, iupcode = key & 0xFF; /* 0-255 interval */
+ int count = sizeof(winkey_map)/sizeof(winkey_map[0]);
+ for (i = 0; i < count; i++)
+ {
+ Iwin2iupkey* key_map = &(winkey_map[i]);
+ if (key_map->iupcode == iupcode)
+ {
+ *keyval = key_map->wincode;
+ *state = 0;
+
+ if (iupcode != key)
+ {
+ if (key_map->c_iupcode == key)
+ *state = VK_CONTROL;
+ else if (key_map->m_iupcode == key)
+ *state = VK_MENU;
+ else if (key_map->y_iupcode == key)
+ *state = VK_LWIN;
+ else if (key_map->s_iupcode == key)
+ *state = VK_SHIFT;
+ }
+ return;
+ }
+ else if (key_map->s_iupcode == key) /* There are Shift keys bellow 256 */
+ {
+ *keyval = key_map->wincode;
+ *state = VK_SHIFT;
+ return;
+ }
+ }
+}
+
+static int winKeyMap2Iup(Iwin2iupkey* table, int i)
+{
+ int code = 0;
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ code = table[i].c_iupcode;
+ else if (GetKeyState(VK_MENU) & 0x8000)
+ code = table[i].m_iupcode;
+ else if ((GetKeyState(VK_LWIN) & 0x8000) || (GetKeyState(VK_RWIN) & 0x8000))
+ code = table[i].y_iupcode;
+ else if (GetKeyState(VK_CAPITAL) & 0x01) /* if it's on */
+ {
+ if ((GetKeyState(VK_SHIFT) & 0x8000) || !iupKeyCanCaps(table[i].iupcode))
+ return table[i].iupcode;
+ else
+ code = table[i].s_iupcode;
+ }
+ else if (GetKeyState(VK_SHIFT) & 0x8000)
+ code = table[i].s_iupcode;
+ else
+ return table[i].iupcode;
+
+ if (!code)
+ code = table[i].iupcode;
+
+ return code;
+}
+
+static int winKeyDecode(int wincode)
+{
+ HKL k;
+ int i, count;
+
+ k = GetKeyboardLayout(0);
+ if ((int)HIWORD(k) == 0x0416) /* ABNT */
+ {
+ int abnt_count = sizeof(keytable_abnt)/sizeof(keytable_abnt[0]);
+ for (i = 0; i < abnt_count; i++)
+ {
+ if (keytable_abnt[i].wincode == wincode)
+ return winKeyMap2Iup(keytable_abnt, i);
+ }
+ }
+
+ count = sizeof(winkey_map)/sizeof(winkey_map[0]);
+ for (i = 0; i < count; i++)
+ {
+ if (winkey_map[i].wincode == wincode)
+ return winKeyMap2Iup(winkey_map, i);
+ }
+
+ return 0;
+}
+
+int iupwinKeyEvent(Ihandle* ih, int wincode, int press)
+{
+ int result, code;
+
+ if (!ih->iclass->is_interactive)
+ return 1;
+
+ code = winKeyDecode(wincode);
+ if (code == 0)
+ return 1;
+
+ if (press)
+ {
+ result = iupKeyCallKeyCb(ih, code);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return 1;
+ }
+ else if (result == IUP_IGNORE)
+ return 0;
+
+ /* in the previous callback the dialog could be destroyed */
+ if (iupObjectCheck(ih))
+ {
+ /* this is called only for canvas */
+ if (ih->iclass->nativetype == IUP_TYPECANVAS)
+ {
+ result = iupKeyCallKeyPressCb(ih, code, 1);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return 1;
+ }
+ else if (result == IUP_IGNORE)
+ return 0;
+ }
+ }
+
+ if (!iupKeyProcessNavigation(ih, code, (GetKeyState(VK_SHIFT) & 0x8000)))
+ return 0;
+ }
+ else
+ {
+ /* this is called only for canvas */
+ if (ih->iclass->nativetype == IUP_TYPECANVAS)
+ {
+ result = iupKeyCallKeyPressCb(ih, code, 0);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return 1;
+ }
+ else if (result == IUP_IGNORE)
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void iupwinButtonKeySetStatus(WORD keys, char* status, int doubleclick)
+{
+ if (keys & MK_SHIFT)
+ iupKEYSETSHIFT(status);
+
+ if (keys & MK_CONTROL)
+ iupKEYSETCONTROL(status);
+
+ if (keys & MK_LBUTTON)
+ iupKEYSETBUTTON1(status);
+
+ if (keys & MK_MBUTTON)
+ iupKEYSETBUTTON2(status);
+
+ if (keys & MK_RBUTTON)
+ iupKEYSETBUTTON3(status);
+
+ if (doubleclick)
+ iupKEYSETDOUBLE(status);
+
+ if (GetKeyState(VK_MENU) & 0x8000)
+ iupKEYSETALT(status);
+
+ if ((GetKeyState(VK_LWIN) & 0x8000) || (GetKeyState(VK_RWIN) & 0x8000))
+ iupKEYSETSYS(status);
+
+ if (keys & MK_XBUTTON1)
+ iupKEYSETBUTTON4(status);
+
+ if (keys & MK_XBUTTON2)
+ iupKEYSETBUTTON5(status);
+}
diff --git a/iup/src/win/iupwin_label.c b/iup/src/win/iupwin_label.c
new file mode 100755
index 0000000..d5a1f53
--- /dev/null
+++ b/iup/src/win/iupwin_label.c
@@ -0,0 +1,339 @@
+/** \file
+ * \brief Label Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_label.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+
+
+static void winLabelDrawImage(Ihandle* ih, HDC hDC, int rect_width, int rect_height)
+{
+ int xpad = ih->data->horiz_padding,
+ ypad = ih->data->vert_padding;
+ int x, y, width, height, bpp;
+ HBITMAP hBitmap, hMask = NULL;
+ char *name;
+ int make_inactive = 0;
+
+ if (iupdrvIsActive(ih))
+ name = iupAttribGet(ih, "IMAGE");
+ else
+ {
+ name = iupAttribGet(ih, "IMINACTIVE");
+ if (!name)
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ make_inactive = 1;
+ }
+ }
+
+ hBitmap = iupImageGetImage(name, ih, make_inactive);
+ if (!hBitmap)
+ return;
+
+ /* must use this info, since image can be a driver image loaded from resources */
+ iupdrvImageGetInfo(hBitmap, &width, &height, &bpp);
+
+ if (ih->data->horiz_alignment == IUP_ALIGN_ARIGHT)
+ x = rect_width - (width + 2*xpad);
+ else if (ih->data->horiz_alignment == IUP_ALIGN_ACENTER)
+ x = (rect_width - (width + 2*xpad))/2;
+ else /* ALEFT */
+ x = 0;
+
+ if (ih->data->vert_alignment == IUP_ALIGN_ABOTTOM)
+ y = rect_height - (height + 2*ypad);
+ else if (ih->data->vert_alignment == IUP_ALIGN_ATOP)
+ y = 0;
+ else /* ACENTER */
+ y = (rect_height - (height + 2*ypad))/2;
+
+ x += xpad;
+ y += ypad;
+
+ if (bpp == 8)
+ hMask = iupdrvImageCreateMask(IupGetHandle(name));
+
+ iupwinDrawBitmap(hDC, hBitmap, hMask, x, y, width, height, bpp);
+
+ if (hMask)
+ DeleteObject(hMask);
+}
+
+static void winLabelDrawText(Ihandle* ih, HDC hDC, int rect_width, int rect_height)
+{
+ int xpad = ih->data->horiz_padding,
+ ypad = ih->data->vert_padding;
+ int x, y, width, height, style;
+ HFONT hFont = (HFONT)iupwinGetHFontAttrib(ih);
+ COLORREF fgcolor;
+
+ char* title = iupdrvBaseGetTitleAttrib(ih);
+ char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */
+ iupdrvFontGetMultiLineStringSize(ih, str, &width, &height);
+ if (str && str!=title) free(str);
+
+ if (ih->data->horiz_alignment == IUP_ALIGN_ARIGHT)
+ style = DT_RIGHT;
+ else if (ih->data->horiz_alignment == IUP_ALIGN_ACENTER)
+ style = DT_CENTER;
+ else /* ALEFT */
+ style = DT_LEFT;
+
+ if (ih->data->vert_alignment == IUP_ALIGN_ABOTTOM)
+ y = rect_height - (height + 2*ypad);
+ else if (ih->data->vert_alignment == IUP_ALIGN_ATOP)
+ y = 0;
+ else /* ACENTER */
+ y = (rect_height - (height + 2*ypad))/2;
+
+ /* let DrawText do the horizontal alignment */
+ x = xpad;
+ width = rect_width - 2*xpad;
+ y += ypad;
+
+ if (iupdrvIsActive(ih))
+ fgcolor = ih->data->fgcolor;
+ else
+ fgcolor = GetSysColor(COLOR_GRAYTEXT);
+
+ /* WORDWRAP and ELLIPSIS */
+ style |= ih->data->text_style;
+
+ iupwinDrawText(hDC, title, x, y, width, height, hFont, fgcolor, style);
+}
+
+static void winLabelDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem)
+{
+ HDC hDC;
+ iupwinBitmapDC bmpDC;
+ int width, height;
+
+ if (!(drawitem->itemAction & ODA_DRAWENTIRE))
+ return;
+
+ width = drawitem->rcItem.right - drawitem->rcItem.left;
+ height = drawitem->rcItem.bottom - drawitem->rcItem.top;
+
+ hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height);
+
+ iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem);
+
+ if (ih->data->type == IUP_LABEL_IMAGE)
+ winLabelDrawImage(ih, hDC, width, height);
+ else
+ winLabelDrawText(ih, hDC, width, height);
+
+ iupwinDrawDestroyBitmapDC(&bmpDC);
+}
+
+/************************************************************************************************/
+
+static int winLabelSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ char value1[30] = "", value2[30] = "";
+
+ iupStrToStrStr(value, value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ ih->data->horiz_alignment = IUP_ALIGN_ARIGHT;
+ else if (iupStrEqualNoCase(value1, "ACENTER"))
+ ih->data->horiz_alignment = IUP_ALIGN_ACENTER;
+ else /* "ALEFT" */
+ ih->data->horiz_alignment = IUP_ALIGN_ALEFT;
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ ih->data->vert_alignment = IUP_ALIGN_ABOTTOM;
+ else if (iupStrEqualNoCase(value2, "ACENTER"))
+ ih->data->vert_alignment = IUP_ALIGN_ACENTER;
+ else /* "ATOP" */
+ ih->data->vert_alignment = IUP_ALIGN_ATOP;
+
+ iupdrvDisplayRedraw(ih);
+ }
+ return 0;
+}
+
+static char* winLabelGetAlignmentAttrib(Ihandle *ih)
+{
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ char* horiz_align2str[3] = {"ALEFT", "ACENTER", "ARIGHT"};
+ char* vert_align2str[3] = {"ATOP", "ACENTER", "ABOTTOM"};
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%s:%s", horiz_align2str[ih->data->horiz_alignment], vert_align2str[ih->data->vert_alignment]);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+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);
+
+ return 0;
+}
+
+static int winLabelSetWordWrapAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ {
+ if (iupStrBoolean(value))
+ ih->data->text_style |= DT_WORDBREAK;
+ else
+ ih->data->text_style &= ~DT_WORDBREAK;
+
+ iupdrvDisplayRedraw(ih);
+ }
+
+ return 1;
+}
+
+static int winLabelSetEllipsisAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ {
+ if (iupStrBoolean(value))
+ ih->data->text_style |= DT_END_ELLIPSIS;
+ else
+ ih->data->text_style &= ~DT_END_ELLIPSIS;
+
+ iupdrvDisplayRedraw(ih);
+ }
+
+ return 1;
+}
+
+static int winLabelSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ ih->data->fgcolor = RGB(r,g,b);
+ iupdrvDisplayRedraw(ih);
+ }
+ }
+ return 1;
+}
+
+static int winLabelProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch (msg)
+ {
+ case WM_NCCALCSIZE:
+ {
+ if (wp == TRUE)
+ {
+ *result = WVR_HREDRAW|WVR_VREDRAW;
+ return 1;
+ }
+ }
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+static int winLabelMapMethod(Ihandle* ih)
+{
+ char* value;
+ DWORD dwStyle = WS_CHILD |
+ SS_NOTIFY; /* SS_NOTIFY is necessary because of the base messages */
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ value = iupAttribGet(ih, "SEPARATOR");
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "HORIZONTAL"))
+ {
+ ih->data->type = IUP_LABEL_SEP_HORIZ;
+ dwStyle |= SS_ETCHEDHORZ;
+ }
+ else /* "VERTICAL" */
+ {
+ ih->data->type = IUP_LABEL_SEP_VERT;
+ dwStyle |= SS_ETCHEDVERT;
+ }
+ }
+ else
+ {
+ /* The lack for good alignment support in STATIC control forces IUP to draw its own label,
+ but uses the Windows functions to draw text and images in native format. */
+ dwStyle |= SS_OWNERDRAW;
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ ih->data->type = IUP_LABEL_IMAGE;
+ else
+ ih->data->type = IUP_LABEL_TEXT;
+ }
+
+ if (!iupwinCreateWindowEx(ih, "STATIC", 0, dwStyle))
+ return IUP_ERROR;
+
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ /* replace the WinProc to handle other messages */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winLabelProc);
+
+ IupSetCallback(ih, "_IUPWIN_DRAWITEM_CB", (Icallback)winLabelDrawItem);
+ }
+
+ return IUP_NOERROR;
+}
+
+void iupdrvLabelInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winLabelMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ /* the most important use of this is to provide the correct background for images */
+ iupClassRegisterAttribute(ic, "BGCOLOR", iupBaseNativeParentGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winLabelSetFgColorAttrib, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force new default value */
+ iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* 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, "PADDING", iupLabelGetPaddingAttrib, winLabelSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+
+ /* IupLabel Windows and GTK only */
+ iupClassRegisterAttribute(ic, "WORDWRAP", NULL, winLabelSetWordWrapAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "ELLIPSIS", NULL, winLabelSetEllipsisAttrib, NULL, NULL, IUPAF_DEFAULT);
+}
diff --git a/iup/src/win/iupwin_list.c b/iup/src/win/iupwin_list.c
new file mode 100755
index 0000000..8fdadb6
--- /dev/null
+++ b/iup/src/win/iupwin_list.c
@@ -0,0 +1,1460 @@
+/** \file
+ * \brief List Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_mask.h"
+#include "iup_focus.h"
+#include "iup_list.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+
+
+#ifndef EM_SETCUEBANNER /* defined only if _WIN32_WINNT >= 0x501 */
+#define ECM_FIRST 0x1500 /* Edit control messages */
+#define EM_SETCUEBANNER (ECM_FIRST + 1)
+#endif
+
+#define WM_CARET WM_APP+1 /* Custom IUP message */
+
+#define WIN_GETCOUNT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETCOUNT: LB_GETCOUNT)
+#define WIN_GETTEXTLEN(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETLBTEXTLEN: LB_GETTEXTLEN)
+#define WIN_GETTEXT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETLBTEXT: LB_GETTEXT)
+#define WIN_ADDSTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_ADDSTRING: LB_ADDSTRING)
+#define WIN_DELETESTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_DELETESTRING: LB_DELETESTRING)
+#define WIN_INSERTSTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_INSERTSTRING: LB_INSERTSTRING)
+#define WIN_RESETCONTENT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_RESETCONTENT: LB_RESETCONTENT)
+#define WIN_SETCURSEL(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETCURSEL: LB_SETCURSEL)
+#define WIN_GETCURSEL(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETCURSEL: LB_GETCURSEL)
+#define WIN_SETHORIZONTALEXTENT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETHORIZONTALEXTENT: LB_SETHORIZONTALEXTENT)
+#define WIN_SETITEMDATA(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETITEMDATA: LB_SETITEMDATA)
+#define WIN_GETITEMDATA(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETITEMDATA: LB_GETITEMDATA)
+#define WIN_SETTOPINDEX(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETTOPINDEX: LB_SETTOPINDEX)
+#define WIN_SETITEMHEIGHT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETITEMHEIGHT: LB_SETITEMHEIGHT)
+
+
+void iupdrvListAddItemSpace(Ihandle* ih, int *h)
+{
+ (void)ih;
+ (void)h;
+}
+
+void iupdrvListAddBorders(Ihandle* ih, int *x, int *y)
+{
+ int border_size = 2*4;
+ (*x) += border_size;
+ (*y) += border_size;
+
+ if (ih->data->is_dropdown)
+ {
+ (*x) += 3; /* extra space for the dropdown button */
+
+ if (ih->data->has_editbox)
+ {
+ /* extra border for the editbox */
+ int internal_border_size = 2*6;
+ (*x) += internal_border_size;
+ (*y) += internal_border_size;
+ }
+ }
+ else
+ {
+ if (ih->data->has_editbox)
+ (*y) += 2*3; /* internal border between editbox and list */
+ }
+}
+
+int iupdrvListGetCount(Ihandle* ih)
+{
+ return SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0);
+}
+
+static int winListConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ int pos;
+
+ if (ih->data->has_editbox)
+ {
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+
+ pos = SendMessage(cbedit, EM_CHARFROMPOS, 0, MAKELPARAM(x, y));
+ pos = LOWORD(pos);
+ }
+
+ if (ih->data->has_editbox)
+ {
+ HWND cblist = (HWND)iupAttribGet(ih, "_IUPWIN_LISTBOX");
+ pos = SendMessage(cblist, LB_ITEMFROMPOINT, 0, MAKELPARAM(x, y))+1; /* IUP Starts at 1 */
+ pos = LOWORD(pos);
+ }
+ else
+ {
+ pos = SendMessage(ih->handle, LB_ITEMFROMPOINT, 0, MAKELPARAM(x, y))+1;
+ pos = LOWORD(pos);
+ }
+
+ return pos;
+}
+
+static int winListGetMaxWidth(Ihandle* ih)
+{
+ int i, item_w, max_w = 0,
+ count = SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0);
+
+ for (i=0; i<count; i++)
+ {
+ item_w = SendMessage(ih->handle, WIN_GETITEMDATA(ih), i, 0);
+ if (item_w > max_w)
+ max_w = item_w;
+ }
+
+ return max_w;
+}
+
+static void winListUpdateScrollWidth(Ihandle* ih)
+{
+ if (ih->data->is_dropdown && iupAttribGetBoolean(ih, "DROPEXPAND"))
+ {
+ int w = 3+winListGetMaxWidth(ih)+iupdrvGetScrollbarSize()+3;
+ SendMessage(ih->handle, CB_SETDROPPEDWIDTH, w, 0);
+ }
+ else
+ SendMessage(ih->handle, WIN_SETHORIZONTALEXTENT(ih), winListGetMaxWidth(ih), 0);
+}
+
+void iupdrvListAppendItem(Ihandle* ih, const char* value)
+{
+ int pos = SendMessage(ih->handle, WIN_ADDSTRING(ih), 0, (LPARAM)value);
+ SendMessage(ih->handle, WIN_SETITEMDATA(ih), pos, (LPARAM)iupdrvFontGetStringWidth(ih, value));
+ winListUpdateScrollWidth(ih);
+}
+
+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);
+}
+
+void iupdrvListRemoveItem(Ihandle* ih, int pos)
+{
+ if (ih->data->is_dropdown && !ih->data->has_editbox)
+ {
+ /* must check if removing the current item */
+ int curpos = SendMessage(ih->handle, WIN_GETCURSEL(ih), 0, 0);
+ if (pos == curpos)
+ {
+ if (curpos > 0) curpos--;
+ else curpos++;
+
+ SendMessage(ih->handle, WIN_SETCURSEL(ih), curpos, 0);
+ }
+ }
+
+ SendMessage(ih->handle, WIN_DELETESTRING(ih), pos, 0L);
+ winListUpdateScrollWidth(ih);
+}
+
+void iupdrvListRemoveAllItems(Ihandle* ih)
+{
+ SendMessage(ih->handle, WIN_RESETCONTENT(ih), 0, 0L);
+ if (ih->data->is_dropdown && iupAttribGetBoolean(ih, "DROPEXPAND"))
+ SendMessage(ih->handle, CB_SETDROPPEDWIDTH, 0, 0);
+ else
+ SendMessage(ih->handle, WIN_SETHORIZONTALEXTENT(ih), 0, 0);
+}
+
+static int winListGetCaretPos(HWND cbedit)
+{
+ int pos = 0;
+ POINT point;
+
+ if (GetFocus() != cbedit || !GetCaretPos(&point))
+ {
+ /* if does not have the focus, or could not get caret position,
+ then use the selection start position */
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&pos, 0);
+ }
+ else
+ {
+ pos = SendMessage(cbedit, EM_CHARFROMPOS, 0, MAKELPARAM(point.x, point.y));
+ pos = LOWORD(pos);
+ }
+
+ return pos;
+}
+
+
+/*********************************************************************************/
+
+
+static void winListUpdateItemWidth(Ihandle* ih)
+{
+ int i, count = SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0);
+ for (i=0; i<count; i++)
+ {
+ int len = SendMessage(ih->handle, WIN_GETTEXTLEN(ih), (WPARAM)i, 0);
+ char* str = iupStrGetMemory(len+1);
+ SendMessage(ih->handle, WIN_GETTEXT(ih), (WPARAM)i, (LPARAM)str);
+ SendMessage(ih->handle, WIN_SETITEMDATA(ih), i, (LPARAM)iupdrvFontGetStringWidth(ih, str));
+ }
+}
+
+static int winListSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+ winListUpdateItemWidth(ih);
+ winListUpdateScrollWidth(ih);
+ return 1;
+}
+
+static char* winListGetIdValueAttrib(Ihandle* ih, const char* name_id)
+{
+ int pos = iupListGetPos(ih, name_id);
+ if (pos != -1)
+ {
+ int len = SendMessage(ih->handle, WIN_GETTEXTLEN(ih), (WPARAM)pos, 0);
+ char* str = iupStrGetMemory(len+1);
+ SendMessage(ih->handle, WIN_GETTEXT(ih), (WPARAM)pos, (LPARAM)str);
+ return str;
+ }
+ return NULL;
+}
+
+static char* winListGetValueAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ int nc = GetWindowTextLength(ih->handle);
+ if (nc)
+ {
+ char* str = iupStrGetMemory(nc+1);
+ GetWindowText(ih->handle, str, nc+1);
+ return str;
+ }
+ }
+ else
+ {
+ if (ih->data->is_dropdown || !ih->data->is_multiple)
+ {
+ int pos = SendMessage(ih->handle, WIN_GETCURSEL(ih), 0, 0);
+ char* str = iupStrGetMemory(50);
+ sprintf(str, "%d", pos+1); /* IUP starts at 1 */
+ return str;
+ }
+ else
+ {
+ int i, count = SendMessage(ih->handle, LB_GETCOUNT, 0, 0);
+ int* pos = malloc(sizeof(int)*count);
+ int sel_count = SendMessage(ih->handle, LB_GETSELITEMS, count, (LPARAM)pos);
+ char* str = iupStrGetMemory(count+1);
+ memset(str, '-', count);
+ str[count]=0;
+ for (i=0; i<sel_count; i++)
+ str[pos[i]] = '+';
+ str[count]=0;
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+static int winListSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->has_editbox)
+ {
+ if (!value) value = "";
+ SetWindowText(ih->handle, value);
+ }
+ else
+ {
+ if (ih->data->is_dropdown || !ih->data->is_multiple)
+ {
+ int pos;
+ if (iupStrToInt(value, &pos)==1)
+ {
+ SendMessage(ih->handle, WIN_SETCURSEL(ih), pos-1, 0); /* IUP starts at 1 */
+ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos);
+ }
+ else
+ {
+ SendMessage(ih->handle, WIN_SETCURSEL(ih), (WPARAM)-1, 0); /* no selection */
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ }
+ }
+ else
+ {
+ /* User has changed a multiple selection on a simple list. */
+ int i, len, count;
+
+ /* Clear all selections */
+ SendMessage(ih->handle, LB_SETSEL, FALSE, -1);
+
+ if (!value)
+ {
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ return 0;
+ }
+
+ count = SendMessage(ih->handle, LB_GETCOUNT, 0, 0L);
+ len = strlen(value);
+ if (len < count)
+ count = len;
+
+ /* update selection list */
+ for (i = 0; i<count; i++)
+ {
+ if (value[i]=='+')
+ SendMessage(ih->handle, LB_SETSEL, TRUE, i);
+ }
+
+ iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value);
+ }
+ }
+
+ return 0;
+}
+
+static int winListSetShowDropdownAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_dropdown)
+ SendMessage(ih->handle, CB_SHOWDROPDOWN, iupStrBoolean(value), 0);
+ return 0;
+}
+
+static int winListSetTopItemAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->is_dropdown)
+ {
+ int pos = 1;
+ if (iupStrToInt(value, &pos))
+ SendMessage(ih->handle, WIN_SETTOPINDEX(ih), pos-1, 0); /* IUP starts at 1 */
+ }
+ return 0;
+}
+
+static int winListSetSpacingAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_dropdown)
+ return 0;
+
+ if (!iupStrToInt(value, &ih->data->spacing))
+ ih->data->spacing = 0;
+
+ if (ih->handle)
+ {
+ int height;
+ iupdrvFontGetCharSize(ih, NULL, &height);
+ height += 2*ih->data->spacing;
+ SendMessage(ih->handle, WIN_SETITEMHEIGHT(ih), 0, height);
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int winListSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ iupStrToIntInt(value, &(ih->data->horiz_padding), &(ih->data->vert_padding), 'x');
+ ih->data->vert_padding = 0;
+ if (ih->handle)
+ {
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELPARAM(ih->data->horiz_padding, ih->data->horiz_padding));
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int winListSetFilterAttrib(Ihandle *ih, const char *value)
+{
+ int style = 0;
+
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (iupStrEqualNoCase(value, "LOWERCASE"))
+ style = ES_LOWERCASE;
+ else if (iupStrEqualNoCase(value, "NUMBER"))
+ style = ES_NUMBER;
+ else if (iupStrEqualNoCase(value, "UPPERCASE"))
+ style = ES_UPPERCASE;
+
+ if (style)
+ {
+ HWND old_handle = ih->handle;
+ ih->handle = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ iupwinMergeStyle(ih, ES_LOWERCASE|ES_NUMBER|ES_UPPERCASE, style);
+ ih->handle = old_handle;
+ }
+
+ return 1;
+}
+
+static int winListSetCueBannerAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->has_editbox && iupwin_comctl32ver6)
+ {
+ WCHAR* wstr = iupwinStrChar2Wide(value);
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETCUEBANNER, (WPARAM)FALSE, (LPARAM)wstr);
+ free(wstr);
+ return 1;
+ }
+ return 0;
+}
+
+static int winListSetClipboardAttrib(Ihandle *ih, const char *value)
+{
+ UINT msg = 0;
+
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (iupStrEqualNoCase(value, "COPY"))
+ msg = WM_COPY;
+ else if (iupStrEqualNoCase(value, "CUT"))
+ msg = WM_CUT;
+ else if (iupStrEqualNoCase(value, "PASTE"))
+ msg = WM_PASTE;
+ else if (iupStrEqualNoCase(value, "CLEAR"))
+ msg = WM_CLEAR;
+ else if (iupStrEqualNoCase(value, "UNDO"))
+ msg = WM_UNDO;
+
+ if (msg)
+ {
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, msg, 0, 0);
+ }
+
+ return 0;
+}
+
+static int winListSetSelectedTextAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (value)
+ {
+ int start = 0, end = 0;
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return 0;
+ SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value);
+ }
+ return 0;
+}
+
+static char* winListGetSelectedTextAttrib(Ihandle* ih)
+{
+ int nc;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ nc = GetWindowTextLength(cbedit);
+ if (nc)
+ {
+ int start = 0, end = 0;
+ char* str;
+
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ str = iupStrGetMemory(nc+1);
+ GetWindowText(cbedit, str, nc+1);
+ str[end] = 0; /* returns only the selected text */
+ str += start;
+
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int winListSetNCAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!iupStrToInt(value, &ih->data->nc))
+ ih->data->nc = 0;
+
+ if (ih->handle)
+ {
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_LIMITTEXT, ih->data->nc, 0L);
+ }
+ return 0;
+}
+
+static int winListSetSelectionAttrib(Ihandle* ih, const char* value)
+{
+ HWND cbedit;
+ int start=1, end=1;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)-1, (LPARAM)0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<1 || end<1)
+ return 0;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)start, (LPARAM)end);
+
+ return 0;
+}
+
+static char* winListGetSelectionAttrib(Ihandle* ih)
+{
+ int start = 0, end = 0;
+ char* str;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ str = iupStrGetMemory(100);
+
+ start++; /* IUP starts at 1 */
+ end++;
+ sprintf(str, "%d:%d", start, end);
+
+ return str;
+}
+
+static int winListSetSelectionPosAttrib(Ihandle* ih, const char* value)
+{
+ int start=0, end=0;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)-1, (LPARAM)0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<0 || end<0)
+ return 0;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)start, (LPARAM)end);
+
+ return 0;
+}
+
+static char* winListGetSelectionPosAttrib(Ihandle* ih)
+{
+ int start = 0, end = 0;
+ char* str;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", start, end);
+ return str;
+}
+
+static int winListSetInsertAttrib(Ihandle* ih, const char* value)
+{
+ if (value && ih->data->has_editbox)
+ {
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value);
+ }
+ return 0;
+}
+
+static int winListSetAppendAttrib(Ihandle* ih, const char* value)
+{
+ int len;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value) value = "";
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ len = GetWindowTextLength(cbedit)+1;
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)len, (LPARAM)len);
+ SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value);
+
+ return 0;
+}
+
+static int winListSetReadOnlyAttrib(Ihandle* ih, const char* value)
+{
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETREADONLY, (WPARAM)iupStrBoolean(value), 0);
+ return 0;
+}
+
+static char* winListGetReadOnlyAttrib(Ihandle* ih)
+{
+ DWORD style;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ style = GetWindowLong(cbedit, GWL_STYLE);
+ if (style & ES_READONLY)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int winListSetCaretAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+ pos--; /* IUP starts at 1 */
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)pos, (LPARAM)pos);
+ SendMessage(cbedit, EM_SCROLLCARET, 0L, 0L);
+
+ return 0;
+}
+
+static char* winListGetCaretAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char* str = iupStrGetMemory(100);
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ sprintf(str, "%d", winListGetCaretPos(cbedit)+1);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int winListSetCaretPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos); /* be permissive in SetCaret, do not abort if invalid */
+ if (pos < 0) pos = 0;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)pos, (LPARAM)pos);
+ SendMessage(cbedit, EM_SCROLLCARET, 0L, 0L);
+
+ return 0;
+}
+
+static char* winListGetCaretPosAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char* str = iupStrGetMemory(100);
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ sprintf(str, "%d", winListGetCaretPos(cbedit));
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int winListSetScrollToAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+
+ pos--; /* return to Windows referece */
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_LINESCROLL, (WPARAM)pos, (LPARAM)0);
+
+ return 0;
+}
+
+static int winListSetScrollToPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_LINESCROLL, (WPARAM)pos, (LPARAM)0);
+
+ return 0;
+}
+
+
+/*********************************************************************************/
+
+
+static int winListCtlColor(Ihandle* ih, HDC hdc, LRESULT *result)
+{
+ COLORREF cr;
+
+ if (iupwinGetColorRef(ih, "FGCOLOR", &cr))
+ SetTextColor(hdc, cr);
+
+ if (iupwinGetColorRef(ih, "BGCOLOR", &cr))
+ {
+ SetBkColor(hdc, cr);
+ SetDCBrushColor(hdc, cr);
+ *result = (LRESULT)GetStockObject(DC_BRUSH);
+ return 1;
+ }
+ return 0;
+}
+
+static int winListWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp)
+{
+ (void)lp;
+
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ {
+ switch (HIWORD(wp))
+ {
+ case CBN_EDITCHANGE:
+ {
+ iupBaseCallValueChangedCb(ih);
+ break;
+ }
+ case CBN_SETFOCUS:
+ iupwinWmSetFocus(ih);
+ break;
+ case CBN_KILLFOCUS:
+ iupCallKillFocusCb(ih);
+ break;
+ case CBN_CLOSEUP:
+ case CBN_DROPDOWN:
+ {
+ IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB");
+ if (cb)
+ cb(ih, HIWORD(wp)==CBN_DROPDOWN? 1: 0);
+ break;
+ }
+ case CBN_DBLCLK:
+ {
+ IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB");
+ if (cb)
+ {
+ int pos = SendMessage(ih->handle, CB_GETCURSEL, 0, 0);
+ pos++; /* IUP starts at 1 */
+ iupListSingleCallDblClickCallback(ih, cb, pos);
+ }
+ break;
+ }
+ case CBN_SELCHANGE:
+ {
+ IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ int pos = SendMessage(ih->handle, CB_GETCURSEL, 0, 0);
+ pos++; /* IUP starts at 1 */
+ iupListSingleCallActionCallback(ih, cb, pos);
+ }
+
+ iupBaseCallValueChangedCb(ih);
+ break;
+ }
+ }
+ }
+ else
+ {
+ switch (HIWORD(wp))
+ {
+ case LBN_DBLCLK:
+ {
+ IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB");
+ if (cb)
+ {
+ int pos = SendMessage(ih->handle, LB_GETCURSEL, 0, 0);
+ pos++; /* IUP starts at 1 */
+ iupListSingleCallDblClickCallback(ih, cb, pos);
+ }
+ break;
+ }
+ case LBN_SELCHANGE:
+ {
+ if (!ih->data->is_multiple)
+ {
+ IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ int pos = SendMessage(ih->handle, LB_GETCURSEL, 0, 0);
+ pos++; /* IUP starts at 1 */
+ iupListSingleCallActionCallback(ih, cb, pos);
+ }
+ }
+ else
+ {
+ IFns multi_cb = (IFns)IupGetCallback(ih, "MULTISELECT_CB");
+ IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION");
+ if (multi_cb || cb)
+ {
+ int sel_count = SendMessage(ih->handle, LB_GETSELCOUNT, 0, 0);
+ int* pos = malloc(sizeof(int)*sel_count);
+ SendMessage(ih->handle, LB_GETSELITEMS, sel_count, (LPARAM)pos);
+ iupListMultipleCallActionCallback(ih, cb, multi_cb, pos, sel_count);
+ free(pos);
+ }
+ }
+
+ iupBaseCallValueChangedCb(ih);
+ break;
+ }
+ }
+ }
+
+ return 0; /* not used */
+}
+
+static void winListCallCaretCb(Ihandle* ih, HWND cbedit)
+{
+ int pos;
+
+ IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB");
+ if (!cb) return;
+
+ pos = winListGetCaretPos(cbedit);
+
+ if (pos != ih->data->last_caret_pos)
+ {
+ ih->data->last_caret_pos = pos;
+ cb(ih, 1, pos+1, pos);
+ }
+}
+
+static int winListCallEditCb(Ihandle* ih, HWND cbedit, const char* insert_value, int key, int dir)
+{
+ int start, end, ret = 1;
+ char *value, *new_value;
+
+ IFnis cb = (IFnis)IupGetCallback(ih, "EDIT_CB");
+ if (!cb && !ih->data->mask)
+ return 1;
+
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+
+ value = winListGetValueAttrib(ih);
+
+ if (!value)
+ new_value = iupStrDup(insert_value);
+ else if (insert_value)
+ new_value = iupStrInsert(value, insert_value, start, end);
+ else
+ {
+ new_value = value;
+ iupStrRemove(value, start, end, dir);
+ }
+
+ if (!new_value)
+ return 0; /* abort */
+
+ if (ih->data->nc && (int)strlen(new_value) > ih->data->nc)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (cb)
+ {
+ int cb_ret = cb(ih, key, (char*)new_value);
+ if (cb_ret==IUP_IGNORE)
+ ret = 0; /* abort processing */
+ else if (cb_ret==IUP_CLOSE)
+ {
+ IupExitLoop();
+ ret = 0; /* abort processing */
+ }
+ else if (cb_ret!=0 && key!=0 &&
+ cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE)
+ {
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB");
+ CallWindowProc(oldProc, cbedit, WM_CHAR, cb_ret, 0); /* replace key */
+ ret = 0; /* abort processing */
+ }
+ }
+
+ if (new_value != value) free(new_value);
+ return ret;
+}
+
+static int winListEditProc(Ihandle* ih, HWND cbedit, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ int ret = 0;
+
+ if (msg==WM_KEYDOWN) /* process K_ANY before text callbacks */
+ {
+ ret = iupwinBaseProc(ih, msg, wp, lp, result);
+ if (ret) return 1;
+ }
+
+ switch (msg)
+ {
+ case WM_CHAR:
+ {
+ if ((char)wp == '\b')
+ {
+ if (!winListCallEditCb(ih, cbedit, NULL, 0, -1))
+ ret = 1;
+ }
+ else if ((char)wp == '\n' || (char)wp == '\r')
+ {
+ ret = 1;
+ }
+ else if (!(GetKeyState(VK_CONTROL) & 0x8000 ||
+ GetKeyState(VK_MENU) & 0x8000 ||
+ GetKeyState(VK_LWIN) & 0x8000 ||
+ GetKeyState(VK_RWIN) & 0x8000))
+ {
+ char insert_value[2];
+ insert_value[0] = (char)wp;
+ insert_value[1] = 0;
+
+ if (!winListCallEditCb(ih, cbedit, insert_value, wp, 1))
+ ret = 1;
+ }
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+
+ if (wp==VK_TAB) /* the keys have the same definitions as the chars */
+ ret = 1; /* abort default processing to avoid beep */
+
+ break;
+ }
+ case WM_KEYDOWN:
+ {
+ if (wp == VK_DELETE) /* Del does not generates a WM_CHAR */
+ {
+ if (!winListCallEditCb(ih, cbedit, NULL, 0, 1))
+ ret = 1;
+ }
+ else if (wp == 'A' && GetKeyState(VK_CONTROL) & 0x8000) /* Ctrl+A = Select All */
+ {
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ }
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_CLEAR:
+ {
+ if (!winListCallEditCb(ih, cbedit, NULL, 0, 1))
+ ret = 1;
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_CUT:
+ {
+ if (!winListCallEditCb(ih, cbedit, NULL, 0, 1))
+ ret = 1;
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_PASTE:
+ {
+ if (IupGetCallback(ih, "EDIT_CB") || ih->data->mask) /* test before to avoid alocate clipboard text memory */
+ {
+ char* insert_value = iupwinGetClipboardText(ih);
+ if (insert_value)
+ {
+ if (!winListCallEditCb(ih, cbedit, insert_value, 0, 1))
+ ret = 1;
+ free(insert_value);
+ }
+ }
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_UNDO:
+ {
+ IFnis cb = (IFnis)IupGetCallback(ih, "EDIT_CB");
+ if (cb)
+ {
+ char* value;
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB");
+ CallWindowProc(oldProc, cbedit, WM_UNDO, 0, 0);
+
+ value = winListGetValueAttrib(ih);
+ cb(ih, 0, (char*)value);
+
+ ret = 1;
+ }
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_KEYUP:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONUP:
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ case WM_CARET:
+ winListCallCaretCb(ih, cbedit);
+ break;
+ }
+
+ if (ret) /* if abort processing, then the result is 0 */
+ {
+ *result = 0;
+ return 1;
+ }
+ else
+ {
+ if (msg==WM_KEYDOWN)
+ return 0;
+ else
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+ }
+}
+
+static LRESULT CALLBACK winListEditWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ int ret = 0;
+ LRESULT result = 0;
+ WNDPROC oldProc;
+ Ihandle *ih;
+
+ ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */
+
+ /* retrieve the control previous procedure for subclassing */
+ oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB");
+
+ ret = winListEditProc(ih, hwnd, msg, wp, lp, &result);
+
+ if (ret)
+ return result;
+ else
+ return CallWindowProc(oldProc, hwnd, msg, wp, lp);
+}
+
+static int winListComboListProc(Ihandle* ih, HWND cblist, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ (void)cblist;
+
+ switch (msg)
+ {
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ if (iupwinButtonDown(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONUP:
+ if (iupwinButtonUp(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ case WM_MOUSEMOVE:
+ iupwinMouseMove(ih, msg, wp, lp);
+ iupwinBaseProc(ih, msg, wp, lp, result); /* to process ENTER/LEAVE */
+ break;
+ case WM_MOUSELEAVE:
+ iupwinBaseProc(ih, msg, wp, lp, result); /* to process ENTER/LEAVE */
+ break;
+ }
+
+ return 0;
+}
+
+static LRESULT CALLBACK winListComboListWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ int ret = 0;
+ LRESULT result = 0;
+ WNDPROC oldProc;
+ Ihandle *ih;
+
+ ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */
+
+ /* retrieve the control previous procedure for subclassing */
+ oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_LISTOLDPROC_CB");
+
+ ret = winListComboListProc(ih, hwnd, msg, wp, lp, &result);
+
+ if (ret)
+ return result;
+ else
+ return CallWindowProc(oldProc, hwnd, msg, wp, lp);
+}
+
+static int winListProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ if (!ih->data->is_dropdown && !ih->data->has_editbox)
+ {
+ switch (msg)
+ {
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ if (iupwinButtonDown(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONUP:
+ if (iupwinButtonUp(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ case WM_MOUSEMOVE:
+ iupwinMouseMove(ih, msg, wp, lp);
+ break;
+ }
+ }
+
+ switch (msg)
+ {
+ case WM_CHAR:
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ {
+ /* avoid item search when Ctrl is pressed */
+ *result = 0;
+ return 1;
+ }
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ case WM_MOUSELEAVE:
+ case WM_MOUSEMOVE:
+ if (ih->data->has_editbox)
+ return 0; /* do not call base procedure to avoid duplicate messages */
+ break;
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+
+/*********************************************************************************/
+
+
+static void winListLayoutUpdateMethod(Ihandle *ih)
+{
+ if (ih->data->is_dropdown)
+ {
+ /* Must add the dropdown area, or it will not be visible */
+ RECT rect;
+ int charheight, calc_h, win_h, win_w, voptions;
+
+ voptions = iupAttribGetInt(ih, "VISIBLE_ITEMS");
+ if (voptions <= 0)
+ voptions = 1;
+
+ iupdrvFontGetCharSize(ih, NULL, &charheight);
+ calc_h = ih->currentheight + voptions*charheight;
+
+ SendMessage(ih->handle, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rect);
+ win_h = rect.bottom-rect.top;
+ win_w = rect.right-rect.left;
+
+ if (ih->currentwidth != win_w || calc_h != win_h)
+ SetWindowPos(ih->handle, HWND_TOP, ih->x, ih->y, ih->currentwidth, calc_h,
+ SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOOWNERZORDER);
+ else
+ SetWindowPos(ih->handle, HWND_TOP, ih->x, ih->y, 0, 0,
+ SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOOWNERZORDER);
+ }
+ else
+ iupdrvBaseLayoutUpdateMethod(ih);
+}
+
+static int winListMapMethod(Ihandle* ih)
+{
+ char* class_name;
+ DWORD dwStyle = WS_CHILD,
+ dwExStyle = WS_EX_CLIENTEDGE;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ {
+ class_name = "COMBOBOX";
+
+ dwStyle |= CBS_NOINTEGRALHEIGHT;
+
+ if (ih->data->is_dropdown)
+ dwStyle |= WS_VSCROLL|WS_HSCROLL;
+ else if (ih->data->sb)
+ {
+ dwStyle |= WS_VSCROLL|WS_HSCROLL;
+
+ if (!iupAttribGetBoolean(ih, "AUTOHIDE"))
+ dwStyle |= CBS_DISABLENOSCROLL;
+ }
+
+ if (ih->data->has_editbox)
+ {
+ dwStyle |= CBS_AUTOHSCROLL;
+
+ if (ih->data->is_dropdown)
+ dwStyle |= CBS_DROPDOWN; /* hidden-list+edit */
+ else
+ dwStyle |= CBS_SIMPLE; /* visible-list+edit */
+ }
+ else
+ dwStyle |= CBS_DROPDOWNLIST; /* hidden-list */
+
+ if (iupAttribGetBoolean(ih, "SORT"))
+ dwStyle |= CBS_SORT;
+ }
+ else
+ {
+ class_name = "LISTBOX";
+
+ dwStyle |= LBS_NOINTEGRALHEIGHT|LBS_NOTIFY;
+
+ if (ih->data->is_multiple)
+ dwStyle |= LBS_EXTENDEDSEL;
+
+ if (ih->data->sb)
+ {
+ dwStyle |= WS_VSCROLL|WS_HSCROLL;
+
+ if (!iupAttribGetBoolean(ih, "AUTOHIDE"))
+ dwStyle |= LBS_DISABLENOSCROLL;
+ }
+
+ if (iupAttribGetBoolean(ih, "SORT"))
+ dwStyle |= LBS_SORT;
+ }
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ if (!iupwinCreateWindowEx(ih, class_name, dwExStyle, dwStyle))
+ return IUP_ERROR;
+
+ /* Custom Procedure */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winListProc);
+
+ /* Process background color */
+ IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winListCtlColor);
+
+ /* Process WM_COMMAND */
+ IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winListWmCommand);
+
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ {
+ COMBOBOXINFO boxinfo;
+
+ ZeroMemory(&boxinfo, sizeof(COMBOBOXINFO));
+ boxinfo.cbSize = sizeof(COMBOBOXINFO);
+
+ GetComboBoxInfo(ih->handle, &boxinfo);
+
+ iupwinHandleAdd(ih, boxinfo.hwndList);
+ iupAttribSetStr(ih, "_IUPWIN_LISTBOX", (char*)boxinfo.hwndList);
+
+ /* subclass the list box. */
+ IupSetCallback(ih, "_IUPWIN_LISTOLDPROC_CB", (Icallback)GetWindowLongPtr(boxinfo.hwndList, GWLP_WNDPROC));
+ SetWindowLongPtr(boxinfo.hwndList, GWLP_WNDPROC, (LONG_PTR)winListComboListWinProc);
+
+ if (ih->data->has_editbox)
+ {
+ iupwinHandleAdd(ih, boxinfo.hwndItem);
+ iupAttribSetStr(ih, "_IUPWIN_EDITBOX", (char*)boxinfo.hwndItem);
+
+ /* subclass the edit box. */
+ IupSetCallback(ih, "_IUPWIN_EDITOLDPROC_CB", (Icallback)GetWindowLongPtr(boxinfo.hwndItem, GWLP_WNDPROC));
+ SetWindowLongPtr(boxinfo.hwndItem, GWLP_WNDPROC, (LONG_PTR)winListEditWinProc);
+
+ /* set defaults */
+ SendMessage(ih->handle, CB_LIMITTEXT, 0, 0L);
+ }
+ }
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winListConvertXYToPos);
+
+ iupListSetInitialItems(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvListInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winListMapMethod;
+ ic->LayoutUpdate = winListLayoutUpdateMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, winListSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED);
+
+ /* IupList only */
+ iupClassRegisterAttributeId(ic, "IDVALUE", winListGetIdValueAttrib, iupListSetIdValueAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE", winListGetValueAttrib, winListSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWDROPDOWN", NULL, winListSetShowDropdownAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TOPITEM", NULL, winListSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VISIBLE_ITEMS", NULL, NULL, IUPAF_SAMEASSYSTEM, "5", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "DROPEXPAND", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPACING", iupListGetSpacingAttrib, winListSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupListGetPaddingAttrib, winListSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "SELECTEDTEXT", winListGetSelectedTextAttrib, winListSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTION", winListGetSelectionAttrib, winListSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTIONPOS", winListGetSelectionPosAttrib, winListSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARET", winListGetCaretAttrib, winListSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARETPOS", winListGetCaretPosAttrib, winListSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INSERT", NULL, winListSetInsertAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPEND", NULL, winListSetAppendAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "READONLY", winListGetReadOnlyAttrib, winListSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "NC", iupListGetNCAttrib, winListSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, winListSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTO", NULL, winListSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, winListSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "CUEBANNER", NULL, winListSetCueBannerAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTER", NULL, winListSetFilterAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_loop.c b/iup/src/win/iupwin_loop.c
new file mode 100755
index 0000000..7c5dbe7
--- /dev/null
+++ b/iup/src/win/iupwin_loop.c
@@ -0,0 +1,135 @@
+/** \file
+ * \brief Windows Message Loop
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <windows.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+
+
+static IFidle win_idle_cb = NULL;
+static int win_main_loop = 0;
+
+
+void iupdrvSetIdleFunction(Icallback f)
+{
+ win_idle_cb = (IFidle)f;
+}
+
+void IupExitLoop(void)
+{
+ PostQuitMessage(0);
+}
+
+static int winLoopProcessMessage(MSG* msg)
+{
+ if (msg->message == WM_QUIT) /* IUP_CLOSE returned in a callback or IupHide in a popup dialog or all dialogs closed */
+ return IUP_CLOSE;
+ else
+ {
+ TranslateMessage(msg);
+ DispatchMessage(msg);
+ return IUP_DEFAULT;
+ }
+}
+
+int IupMainLoopLevel(void)
+{
+ return win_main_loop;
+}
+
+int IupMainLoop(void)
+{
+ MSG msg;
+ int ret;
+
+ win_main_loop++;
+
+ do
+ {
+ if (win_idle_cb)
+ {
+ ret = 1;
+ if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ {
+ if (winLoopProcessMessage(&msg) == IUP_CLOSE)
+ {
+ win_main_loop--;
+ return IUP_CLOSE;
+ }
+ }
+ else
+ {
+ int ret = win_idle_cb();
+ if (ret == IUP_CLOSE)
+ {
+ win_idle_cb = NULL;
+ win_main_loop--;
+ return IUP_CLOSE;
+ }
+ if (ret == IUP_IGNORE)
+ win_idle_cb = NULL;
+ }
+ }
+ else
+ {
+ ret = GetMessage(&msg, NULL, 0, 0);
+ if (ret == -1) /* error */
+ {
+ win_main_loop--;
+ return IUP_ERROR;
+ }
+ if (ret == 0 || /* WM_QUIT */
+ winLoopProcessMessage(&msg) == IUP_CLOSE) /* ret != 0 */
+ {
+ win_main_loop--;
+ return IUP_NOERROR;
+ }
+ }
+ } while (ret);
+
+ win_main_loop--;
+ return IUP_NOERROR;
+}
+
+int IupLoopStep(void)
+{
+ MSG msg;
+ if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ return winLoopProcessMessage(&msg);
+
+ return IUP_DEFAULT;
+}
+
+void IupFlush(void)
+{
+ int post_quit = 0;
+ MSG msg;
+
+ while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ {
+ if (winLoopProcessMessage(&msg) == IUP_CLOSE)
+ {
+ post_quit = 1;
+ break;
+ }
+ }
+
+ /* re post the quit message if still inside MainLoop */
+ if (post_quit && win_main_loop>0)
+ PostQuitMessage(0);
+}
diff --git a/iup/src/win/iupwin_menu.c b/iup/src/win/iupwin_menu.c
new file mode 100755
index 0000000..74a8b52
--- /dev/null
+++ b/iup/src/win/iupwin_menu.c
@@ -0,0 +1,667 @@
+/** \file
+ * \brief Menu Resources
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_dlglist.h"
+#include "iup_focus.h"
+#include "iup_menu.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_brush.h"
+
+
+Ihandle* iupwinMenuGetHandle(HMENU hMenu)
+{
+ MENUINFO menuinfo;
+ menuinfo.cbSize = sizeof(MENUINFO);
+ menuinfo.fMask = MIM_MENUDATA;
+ if (GetMenuInfo(hMenu, &menuinfo))
+ return (Ihandle*)menuinfo.dwMenuData;
+ else
+ return NULL;
+}
+
+Ihandle* iupwinMenuGetItemHandle(HMENU hMenu, int menuId)
+{
+ MENUITEMINFO menuiteminfo;
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_DATA;
+
+ if (GetMenuItemInfo(hMenu, menuId, FALSE, &menuiteminfo))
+ return (Ihandle*)menuiteminfo.dwItemData;
+ else
+ return NULL;
+}
+
+int iupdrvMenuGetMenuBarSize(Ihandle* ih)
+{
+ (void)ih;
+ return GetSystemMetrics(SM_CYMENU);
+}
+
+static void winMenuUpdateBar(Ihandle* ih)
+{
+ if (iupMenuIsMenuBar(ih) && ih->parent->handle)
+ DrawMenuBar(ih->parent->handle);
+ else if (ih->parent)
+ {
+ ih = ih->parent; /* check also for children of a menu bar */
+ if (iupMenuIsMenuBar(ih) && ih->parent->handle)
+ DrawMenuBar(ih->parent->handle);
+ }
+}
+
+static void winMenuGetLastPos(Ihandle* ih, int *last_pos, int *pos)
+{
+ Ihandle* child;
+ *last_pos=0;
+ *pos=0;
+ for (child=ih->parent->firstchild; child; child=child->brother)
+ {
+ if (child == ih)
+ *pos = *last_pos;
+ (*last_pos)++;
+ }
+}
+
+static void winItemCheckToggle(Ihandle* ih)
+{
+ if (iupAttribGetBoolean(ih->parent, "RADIO"))
+ {
+ int last_pos, pos;
+ winMenuGetLastPos(ih, &last_pos, &pos);
+ CheckMenuRadioItem((HMENU)ih->handle, 0, last_pos, pos, MF_BYPOSITION);
+
+ winMenuUpdateBar(ih);
+ }
+ else if (iupAttribGetBoolean(ih, "AUTOTOGGLE"))
+ {
+ if (GetMenuState((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND) & MF_CHECKED)
+ CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_UNCHECKED|MF_BYCOMMAND);
+ else
+ CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_CHECKED|MF_BYCOMMAND);
+
+ winMenuUpdateBar(ih);
+ }
+}
+
+typedef struct _IchildId
+{
+ int id, menuid;
+ Ihandle* child;
+} IchildId;
+
+void iupwinMenuDialogProc(Ihandle* ih_dialog, UINT msg, WPARAM wp, LPARAM lp)
+{
+ /* called only from winDialogBaseProc */
+
+ switch (msg)
+ {
+ case WM_INITMENUPOPUP:
+ {
+ HMENU hMenu = (HMENU)wp;
+ Ihandle *ih = iupwinMenuGetHandle(hMenu);
+ if (ih)
+ {
+ Icallback cb = (Icallback)IupGetCallback(ih, "OPEN_CB");
+ if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "OPEN_CB"); /* check also in the Submenu */
+ if (cb) cb(ih);
+ }
+ break;
+ }
+ case WM_UNINITMENUPOPUP:
+ {
+ HMENU hMenu = (HMENU)wp;
+ Ihandle *ih = iupwinMenuGetHandle(hMenu);
+ if (ih)
+ {
+ Icallback cb = (Icallback)IupGetCallback(ih, "MENUCLOSE_CB");
+ if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "MENUCLOSE_CB"); /* check also in the Submenu */
+ if (cb) cb(ih);
+ }
+ break;
+ }
+ case WM_MENUSELECT:
+ {
+ HMENU hMenu = (HMENU)lp;
+ Ihandle *ih;
+
+ if (!lp)
+ break;
+
+ if ((HIWORD(wp) & MF_POPUP) || (HIWORD(wp) & MF_SYSMENU)) /* drop-down ih or submenu. */
+ {
+ UINT menuindex = LOWORD(wp);
+ HMENU hsubmenu = GetSubMenu(hMenu, menuindex);
+ ih = iupwinMenuGetHandle(hsubmenu); /* returns the handle of a IupMenu */
+ if (ih) ih = ih->parent; /* gets the submenu */
+ }
+ else /* ih item */
+ {
+ UINT menuID = LOWORD(wp);
+ ih = iupwinMenuGetItemHandle(hMenu, menuID);
+ }
+
+ if (ih)
+ {
+ Icallback cb = IupGetCallback(ih, "HIGHLIGHT_CB");
+ if (cb) cb(ih);
+ }
+ break;
+ }
+ case WM_MENUCOMMAND:
+ {
+ int menuId = GetMenuItemID((HMENU)lp, (int)wp);
+ Icallback cb;
+ Ihandle* ih;
+
+ if (menuId >= IUP_MDICHILD_START)
+ break;
+
+ ih = iupwinMenuGetItemHandle((HMENU)lp, menuId);
+ if (!ih)
+ break;
+
+ winItemCheckToggle(ih);
+
+ cb = IupGetCallback(ih, "ACTION");
+ if (cb && cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+
+ break;
+ }
+ case WM_ENTERMENULOOP:
+ {
+ /* Simulate WM_KILLFOCUS when the menu interaction is started */
+ Ihandle* lastfocus = (Ihandle*)iupAttribGet(ih_dialog, "_IUPWIN_LASTFOCUS");
+ if (lastfocus) iupCallKillFocusCb(lastfocus);
+ break;
+ }
+ case WM_EXITMENULOOP:
+ {
+ /* Simulate WM_GETFOCUS when the menu interaction is stopped */
+ Ihandle* lastfocus = (Ihandle*)iupAttribGet(ih_dialog, "_IUPWIN_LASTFOCUS");
+ if (lastfocus) iupCallGetFocusCb(lastfocus);
+ break;
+ }
+ }
+}
+
+int iupdrvMenuPopup(Ihandle* ih, int x, int y)
+{
+ HWND hWndActive = GetActiveWindow();
+ int tray_menu = 0;
+ int menuId;
+
+ if (!hWndActive)
+ {
+ /* search for a valid handle */
+ Ihandle* dlg = iupDlgListFirst();
+ do
+ {
+ if (dlg->handle)
+ {
+ hWndActive = dlg->handle; /* found a valid handle */
+
+ /* if not a "TRAY" dialog, keep searching, because TRAY is a special case */
+ if (iupAttribGetBoolean(dlg, "TRAY"))
+ break;
+ }
+ dlg = iupDlgListNext();
+ } while (dlg);
+ }
+
+ /* Necessary to avoid tray dialogs to lock popup menus (they get sticky after the 1st time) */
+ if (hWndActive)
+ {
+ Ihandle* dlg = iupwinHandleGet(hWndActive);
+ if (dlg && iupAttribGetBoolean(dlg, "TRAY"))
+ {
+ /* To display a context menu for a notification icon,
+ the current window must be the foreground window. */
+ SetForegroundWindow(hWndActive);
+ tray_menu = 1;
+ }
+ }
+
+ /* stop processing here. messages will not go to the message loop */
+ menuId = TrackPopupMenu((HMENU)ih->handle, TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD, x, y, 0, hWndActive, NULL);
+
+ if (tray_menu)
+ {
+ /* You must force a task switch to the application that
+ called TrackPopupMenu at some time in the near future.
+ This is done by posting a benign message to the window. */
+ PostMessage(hWndActive, WM_NULL, 0, 0);
+ }
+
+ if (menuId)
+ {
+ Icallback cb;
+ Ihandle* ih_item = iupwinMenuGetItemHandle((HMENU)ih->handle, menuId);
+ if (!ih_item) return IUP_NOERROR;
+
+ winItemCheckToggle(ih_item);
+
+ cb = IupGetCallback(ih_item, "ACTION");
+ if (cb && cb(ih_item) == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ return IUP_NOERROR;
+}
+
+
+/*******************************************************************************************/
+
+
+static int winMenuSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ /* must use IupGetAttribute to use inheritance */
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ MENUINFO menuinfo;
+ menuinfo.cbSize = sizeof(MENUINFO);
+ menuinfo.fMask = MIM_BACKGROUND;
+ menuinfo.hbrBack = iupwinBrushGet(RGB(r,g,b));
+ SetMenuInfo((HMENU)ih->handle, &menuinfo);
+ winMenuUpdateBar(ih);
+ }
+ return 1;
+}
+
+static void winMenuChildUnMapMethod(Ihandle* ih)
+{
+ RemoveMenu((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND);
+}
+
+static int winMenuAddParentSubmenu(Ihandle* ih)
+{
+ int pos;
+ MENUITEMINFO menuiteminfo;
+
+ pos = IupGetChildPos(ih->parent, ih);
+ ih->serial = iupMenuGetChildId(ih);
+
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_ID|MIIM_DATA|MIIM_SUBMENU|MIIM_STRING;
+ menuiteminfo.dwTypeData = ""; /* must set or it will be not possible to update */
+ menuiteminfo.cch = 0;
+ menuiteminfo.wID = (UINT)ih->serial;
+ menuiteminfo.dwItemData = (ULONG_PTR)ih;
+ menuiteminfo.hSubMenu = (HMENU)ih->firstchild->handle;
+
+ if (!InsertMenuItem((HMENU)ih->parent->handle, pos, TRUE, &menuiteminfo))
+ return IUP_ERROR;
+
+ ih->handle = ih->parent->handle; /* gets the HMENU of the parent */
+
+ /* must update attributes since submenu is actually created after it is mapped */
+ iupAttribUpdate(ih);
+ iupAttribUpdateFromParent(ih);
+
+ winMenuUpdateBar(ih);
+
+ return IUP_NOERROR;
+}
+
+static int winMenuMapMethod(Ihandle* ih)
+{
+ MENUINFO menuinfo;
+
+ if (iupMenuIsMenuBar(ih))
+ {
+ /* top level menu used for MENU attribute in IupDialog (a menu bar) */
+
+ ih->handle = (InativeHandle*)CreateMenu();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ SetMenu(ih->parent->handle, (HMENU)ih->handle);
+ }
+ else
+ {
+ if (ih->parent)
+ {
+ /* parent is a submenu */
+
+ ih->handle = (InativeHandle*)CreatePopupMenu();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ if (winMenuAddParentSubmenu(ih->parent) == IUP_ERROR)
+ {
+ DestroyMenu((HMENU)ih->handle);
+ return IUP_ERROR;
+ }
+ }
+ else
+ {
+ /* top level menu used for IupPopup */
+
+ ih->handle = (InativeHandle*)CreatePopupMenu();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ iupAttribSetStr(ih, "_IUPWIN_POPUP_MENU", "1");
+ }
+ }
+
+ menuinfo.cbSize = sizeof(MENUINFO);
+ menuinfo.fMask = MIM_MENUDATA;
+ menuinfo.dwMenuData = (ULONG_PTR)ih;
+
+ if (!iupAttribGetInherit(ih, "_IUPWIN_POPUP_MENU")) /* check in the top level menu using inheritance */
+ {
+ menuinfo.fMask |= MIM_STYLE;
+ menuinfo.dwStyle = MNS_NOTIFYBYPOS;
+ }
+
+ SetMenuInfo((HMENU)ih->handle, &menuinfo);
+
+ winMenuUpdateBar(ih);
+
+ return IUP_NOERROR;
+}
+
+static void winMenuUnMapMethod(Ihandle* ih)
+{
+ if (iupMenuIsMenuBar(ih))
+ SetMenu(ih->parent->handle, NULL);
+
+ DestroyMenu((HMENU)ih->handle); /* DestroyMenu is recursive */
+}
+
+void iupdrvMenuInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winMenuMapMethod;
+ ic->UnMap = winMenuUnMapMethod;
+
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winMenuSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "MENUBGCOLOR", IUPAF_DEFAULT);
+}
+
+
+/*******************************************************************************************/
+
+
+static int winItemSetImageAttrib(Ihandle* ih, const char* value)
+{
+ HBITMAP hBitmapUnchecked, hBitmapChecked;
+ char* impress;
+
+ if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */
+ return 1;
+
+ hBitmapUnchecked = iupImageGetImage(value, ih, 0);
+
+ impress = iupAttribGet(ih, "IMPRESS");
+ if (impress)
+ hBitmapChecked = iupImageGetImage(impress, ih, 0);
+ else
+ hBitmapChecked = hBitmapUnchecked;
+
+ SetMenuItemBitmaps((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND, hBitmapUnchecked, hBitmapChecked);
+
+ winMenuUpdateBar(ih);
+
+ return 1;
+}
+
+static int winItemSetImpressAttrib(Ihandle* ih, const char* value)
+{
+ HBITMAP hBitmapUnchecked, hBitmapChecked;
+
+ char *image = iupAttribGet(ih, "IMPRESS");
+ hBitmapUnchecked = iupImageGetImage(image, ih, 0);
+
+ if (value)
+ hBitmapChecked = iupImageGetImage(value, ih, 0);
+ else
+ hBitmapChecked = hBitmapUnchecked;
+
+ SetMenuItemBitmaps((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND, hBitmapUnchecked, hBitmapChecked);
+
+ winMenuUpdateBar(ih);
+
+ return 1;
+}
+
+static int winItemSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ char *str;
+ MENUITEMINFO menuiteminfo;
+
+ if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */
+ return 1;
+
+ if (!value)
+ {
+ str = " ";
+ value = str;
+ }
+ else
+ str = iupMenuProcessTitle(ih, value);
+
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_TYPE;
+ menuiteminfo.fType = MFT_STRING;
+ menuiteminfo.dwTypeData = str;
+ menuiteminfo.cch = strlen(str);
+
+ SetMenuItemInfo((HMENU)ih->handle, (UINT)ih->serial, FALSE, &menuiteminfo);
+
+ if (str != value) free(str);
+
+ winMenuUpdateBar(ih);
+
+ return 1;
+}
+
+static int winItemSetTitleImageAttrib(Ihandle* ih, const char* value)
+{
+ HBITMAP hBitmap;
+ MENUITEMINFO menuiteminfo;
+
+ if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */
+ return 1;
+
+ hBitmap = iupImageGetImage(value, ih, 0);
+
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_BITMAP;
+ menuiteminfo.hbmpItem = hBitmap;
+
+ SetMenuItemInfo((HMENU)ih->handle, (UINT)ih->serial, FALSE, &menuiteminfo);
+
+ winMenuUpdateBar(ih);
+
+ return 1;
+}
+
+static int winItemSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */
+ return 1;
+
+ if (iupStrBoolean(value))
+ EnableMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_ENABLED|MF_BYCOMMAND);
+ else
+ EnableMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_GRAYED|MF_BYCOMMAND);
+
+ winMenuUpdateBar(ih);
+
+ return 0;
+}
+
+static char* winItemGetActiveAttrib(Ihandle* ih)
+{
+ if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */
+ return NULL;
+
+ if (GetMenuState((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND) & MF_GRAYED)
+ return "NO";
+ else
+ return "YES";
+}
+
+static int winItemSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (iupAttribGetBoolean(ih->parent, "RADIO"))
+ {
+ int last_pos, pos;
+ winMenuGetLastPos(ih, &last_pos, &pos);
+ CheckMenuRadioItem((HMENU)ih->handle, 0, last_pos, pos, MF_BYPOSITION);
+ }
+ else
+ {
+ if (iupStrBoolean(value))
+ CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_CHECKED|MF_BYCOMMAND);
+ else
+ CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_UNCHECKED|MF_BYCOMMAND);
+ }
+
+ winMenuUpdateBar(ih);
+
+ return 0;
+}
+
+static char* winItemGetValueAttrib(Ihandle* ih)
+{
+ if (GetMenuState((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND) & MF_CHECKED)
+ return "ON";
+ else
+ return "OFF";
+}
+
+static int winItemMapMethod(Ihandle* ih)
+{
+ int pos;
+ MENUITEMINFO menuiteminfo;
+
+ if (!ih->parent || !IsMenu((HMENU)ih->parent->handle))
+ return IUP_ERROR;
+
+ pos = IupGetChildPos(ih->parent, ih);
+ ih->serial = iupMenuGetChildId(ih);
+
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_ID|MIIM_DATA|MIIM_STRING;
+ menuiteminfo.dwTypeData = ""; /* must set or it will be not possible to update */
+ menuiteminfo.cch = 0;
+ menuiteminfo.wID = (UINT)ih->serial;
+ menuiteminfo.dwItemData = (ULONG_PTR)ih;
+
+ if (!InsertMenuItem((HMENU)ih->parent->handle, pos, TRUE, &menuiteminfo))
+ return IUP_ERROR;
+
+ ih->handle = ih->parent->handle; /* gets the HMENU of the parent */
+ winMenuUpdateBar(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvItemInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winItemMapMethod;
+ ic->UnMap = winMenuChildUnMapMethod;
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", winItemGetActiveAttrib, winItemSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "MENUBGCOLOR", IUPAF_DEFAULT); /* used by IupImage */
+
+ /* IupItem only */
+ iupClassRegisterAttribute(ic, "VALUE", winItemGetValueAttrib, winItemSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, winItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TITLEIMAGE", NULL, winItemSetTitleImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, winItemSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, winItemSetImpressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* Used by iupdrvImageCreateImage */
+ /* necessary because it uses an old HBITMAP solution */
+ iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+}
+
+
+/*******************************************************************************************/
+
+
+static int winSubmenuMapMethod(Ihandle* ih)
+{
+ if (!ih->parent || !IsMenu((HMENU)ih->parent->handle))
+ return IUP_ERROR;
+
+ return iupBaseTypeVoidMapMethod(ih);
+}
+
+void iupdrvSubmenuInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winSubmenuMapMethod;
+
+ /* IupSubmenu only */
+ iupClassRegisterAttribute(ic, "ACTIVE", winItemGetActiveAttrib, winItemSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, winItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, winItemSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "MENUBGCOLOR", IUPAF_DEFAULT); /* used by IupImage */
+
+ /* Used by iupdrvImageCreateImage */
+ /* necessary because it uses an old HBITMAP solution */
+ iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+}
+
+
+/*******************************************************************************************/
+
+
+static int winSeparatorMapMethod(Ihandle* ih)
+{
+ int pos;
+ MENUITEMINFO menuiteminfo;
+
+ if (!ih->parent || !IsMenu((HMENU)ih->parent->handle))
+ return IUP_ERROR;
+
+ pos = IupGetChildPos(ih->parent, ih);
+ ih->serial = iupMenuGetChildId(ih);
+
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_FTYPE|MIIM_ID|MIIM_DATA;
+ menuiteminfo.fType = MFT_SEPARATOR;
+ menuiteminfo.wID = (UINT)ih->serial;
+ menuiteminfo.dwItemData = (ULONG_PTR)ih;
+
+ if (!InsertMenuItem((HMENU)ih->parent->handle, pos, TRUE, &menuiteminfo))
+ return IUP_ERROR;
+
+ ih->handle = ih->parent->handle; /* gets the HMENU of the parent */
+ winMenuUpdateBar(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvSeparatorInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winSeparatorMapMethod;
+ ic->UnMap = winMenuChildUnMapMethod;
+}
diff --git a/iup/src/win/iupwin_messagedlg.c b/iup/src/win/iupwin_messagedlg.c
new file mode 100755
index 0000000..63159aa
--- /dev/null
+++ b/iup/src/win/iupwin_messagedlg.c
@@ -0,0 +1,105 @@
+/** \file
+ * \brief Windows IupMessageDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+
+
+static void winMessageDlgHelpCallback(HELPINFO* HelpInfo)
+{
+ Ihandle* ih = (Ihandle*)HelpInfo->dwContextId;
+ Icallback cb = (Icallback)IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ {
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "BUTTONS"), "OK")) /* only one button */
+ EndDialog((HWND)HelpInfo->hItemHandle, IDOK);
+ else
+ EndDialog((HWND)HelpInfo->hItemHandle, IDCANCEL);
+ }
+}
+
+static int winMessageDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ MSGBOXPARAMS MsgBoxParams;
+ int result, num_but = 2;
+ DWORD dwStyle = MB_TASKMODAL;
+ char *icon, *buttons;
+ (void)x;
+ (void)y;
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ icon = iupAttribGetStr(ih, "DIALOGTYPE");
+ if (iupStrEqualNoCase(icon, "ERROR"))
+ dwStyle |= MB_ICONERROR;
+ else if (iupStrEqualNoCase(icon, "WARNING"))
+ dwStyle |= MB_ICONWARNING;
+ else if (iupStrEqualNoCase(icon, "INFORMATION"))
+ dwStyle |= MB_ICONINFORMATION;
+ else if (iupStrEqualNoCase(icon, "QUESTION"))
+ dwStyle |= MB_ICONQUESTION;
+
+ buttons = iupAttribGetStr(ih, "BUTTONS");
+ if (iupStrEqualNoCase(buttons, "OKCANCEL"))
+ dwStyle |= MB_OKCANCEL;
+ else if (iupStrEqualNoCase(buttons, "YESNO"))
+ dwStyle |= MB_YESNO;
+ else
+ {
+ dwStyle |= MB_OK;
+ num_but = 1;
+ }
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ dwStyle |= MB_HELP;
+
+ if (num_but == 2 && iupAttribGetInt(ih, "BUTTONDEFAULT") == 2)
+ dwStyle |= MB_DEFBUTTON2;
+ else
+ dwStyle |= MB_DEFBUTTON1;
+
+ MsgBoxParams.cbSize = sizeof(MSGBOXPARAMS);
+ MsgBoxParams.hwndOwner = parent;
+ MsgBoxParams.hInstance = NULL;
+ MsgBoxParams.lpszText = iupAttribGet(ih, "VALUE");
+ MsgBoxParams.lpszCaption = iupAttribGet(ih, "TITLE");
+ MsgBoxParams.dwStyle = dwStyle;
+ MsgBoxParams.lpszIcon = NULL;
+ MsgBoxParams.dwContextHelpId = (DWORD_PTR)ih;
+ MsgBoxParams.lpfnMsgBoxCallback = (MSGBOXCALLBACK)winMessageDlgHelpCallback;
+ MsgBoxParams.dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
+
+ result = MessageBoxIndirect(&MsgBoxParams);
+ if (result == 0)
+ {
+ iupAttribSetStr(ih, "BUTTONRESPONSE", NULL);
+ return IUP_ERROR;
+ }
+
+ if (result == IDNO || result == IDCANCEL)
+ iupAttribSetStr(ih, "BUTTONRESPONSE", "2");
+ else
+ iupAttribSetStr(ih, "BUTTONRESPONSE", "1");
+
+ return IUP_NOERROR;
+}
+
+void iupdrvMessageDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = winMessageDlgPopup;
+}
+
+/*
+In Windows it will always sound a beep. The beep is different for each dialog type.
+*/
diff --git a/iup/src/win/iupwin_open.c b/iup/src/win/iupwin_open.c
new file mode 100755
index 0000000..7357cde
--- /dev/null
+++ b/iup/src/win/iupwin_open.c
@@ -0,0 +1,124 @@
+/** \file
+ * \brief Windows Driver Core
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_globalattrib.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_info.h"
+#include "iupwin_handle.h"
+#include "iupwin_brush.h"
+#include "iupwin_draw.h"
+
+
+HINSTANCE iupwin_hinstance = 0;
+int iupwin_comctl32ver6 = 0;
+
+void* iupdrvGetDisplay(void)
+{
+ return NULL;
+}
+
+void iupwinShowLastError(void)
+{
+ int error = GetLastError();
+ if (error)
+ {
+ LPVOID lpMsgBuf;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
+ MessageBox(NULL, (LPCTSTR)lpMsgBuf, "GetLastError:", MB_OK|MB_ICONERROR);
+ LocalFree(lpMsgBuf);
+ }
+}
+
+static void winSetGlobalColor(int index, const char* name)
+{
+ COLORREF color = GetSysColor(index);
+ iupGlobalSetDefaultColorAttrib(name, (int)GetRValue(color),
+ (int)GetGValue(color),
+ (int)GetBValue(color));
+}
+
+int iupdrvOpen(int *argc, char ***argv)
+{
+ (void)argc; /* unused in the Windows driver */
+ (void)argv;
+
+ if (iupwinGetSystemMajorVersion() < 5) /* older than Windows 2000 */
+ return IUP_ERROR;
+
+ IupSetGlobal("DRIVER", "Win32");
+
+ {
+#ifdef __MINGW32__
+ /* MingW fails to create windows if using a console and HINSTANCE is not from the console */
+ HWND win = GetConsoleWindow();
+ if (win)
+ iupwin_hinstance = (HINSTANCE)GetWindowLongPtr(win, GWLP_HINSTANCE);
+ else
+#endif
+ iupwin_hinstance = GetModuleHandle(NULL);
+ IupSetGlobal("HINSTANCE", (char*)iupwin_hinstance);
+ }
+
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+ {
+ INITCOMMONCONTROLSEX InitCtrls;
+ InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ InitCtrls.dwICC = ICC_WIN95_CLASSES; /* trackbar, tooltips, updown, tab, progress */
+ InitCommonControlsEx(&InitCtrls);
+ }
+
+ iupwin_comctl32ver6 = (iupwinGetComCtl32Version() >= 0x060000)? 1: 0;
+ if (iupwin_comctl32ver6 && !iupwinIsAppThemed()) /* When the user seleted the Windows Classic theme */
+ iupwin_comctl32ver6 = 0;
+
+ IupSetGlobal("SYSTEMLANGUAGE", iupwinGetSystemLanguage());
+
+ /* default colors */
+ winSetGlobalColor(COLOR_BTNFACE, "DLGBGCOLOR");
+ winSetGlobalColor(COLOR_BTNTEXT, "DLGFGCOLOR");
+ winSetGlobalColor(COLOR_WINDOW, "TXTBGCOLOR");
+ winSetGlobalColor(COLOR_WINDOWTEXT, "TXTFGCOLOR");
+ winSetGlobalColor(COLOR_MENU, "MENUBGCOLOR");
+ winSetGlobalColor(COLOR_MENUTEXT, "MENUFGCOLOR");
+
+ iupwinHandleInit();
+ iupwinBrushInit();
+ iupwinDrawInit();
+
+#ifdef __WATCOMC__
+ {
+ /* this is used to force Watcom to link the winmain.c module. */
+ void iupwinMainDummy(void);
+ iupwinMainDummy();
+ }
+#endif
+
+ return IUP_NOERROR;
+}
+
+void iupdrvClose(void)
+{
+ iupwinHandleFinish();
+ iupwinBrushFinish();
+
+ CoUninitialize();
+}
diff --git a/iup/src/win/iupwin_progressbar.c b/iup/src/win/iupwin_progressbar.c
new file mode 100755
index 0000000..9038d79
--- /dev/null
+++ b/iup/src/win/iupwin_progressbar.c
@@ -0,0 +1,164 @@
+/** \file
+ * \brief Progress bar Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_progressbar.h"
+#include "iup_drv.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+
+
+#ifndef PBS_MARQUEE /* it is defined only when _WIN32_WINNT >= 0x0501 */
+#define PBS_MARQUEE 0x08
+#define PBM_SETMARQUEE (WM_USER+10)
+#endif
+
+#define IUP_PB_MAX 32000
+
+
+static int winProgressBarSetMarqueeAttrib(Ihandle* ih, const char* value)
+{
+ /* MARQUEE only works when using XP Styles */
+ if (!iupwin_comctl32ver6)
+ return 0;
+
+ if (iupStrBoolean(value))
+ SendMessage(ih->handle, PBM_SETMARQUEE, TRUE, 100);
+ else
+ SendMessage(ih->handle, PBM_SETMARQUEE, FALSE, 0);
+
+ return 1;
+}
+
+static int winProgressBarSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ ih->data->value = 0;
+ else
+ ih->data->value = atof(value);
+
+ iProgressBarCropValue(ih);
+
+ /* Shows when the marquee style is not set */
+ if (!ih->data->marquee)
+ {
+ double factor = (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin);
+ int val = (int)(IUP_PB_MAX * factor);
+ SendMessage(ih->handle, PBM_SETPOS, (WPARAM)val, 0);
+ }
+
+ return 0;
+}
+
+static int winProgressBarSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+
+ /* Only works when using Classic style */
+ if (iupwin_comctl32ver6)
+ return 0;
+
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ COLORREF color = RGB(r,g,b);
+ SendMessage(ih->handle, PBM_SETBKCOLOR, 0, (LPARAM)color);
+ }
+ else
+ SendMessage(ih->handle, PBM_SETBKCOLOR, 0, (LPARAM)CLR_DEFAULT);
+ return 1;
+}
+
+static int winProgressBarSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+
+ /* Only works when using Classic style */
+ if (iupwin_comctl32ver6)
+ return 0;
+
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ COLORREF color = RGB(r,g,b);
+ SendMessage(ih->handle, PBM_SETBARCOLOR, 0, (LPARAM)color);
+ }
+ else
+ SendMessage(ih->handle, PBM_SETBARCOLOR, 0, (LPARAM)CLR_DEFAULT);
+ return 1;
+}
+
+static int winProgressBarMapMethod(Ihandle* ih)
+{
+ DWORD dwStyle = WS_CHILD;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL"))
+ {
+ dwStyle |= PBS_VERTICAL;
+
+ if (ih->currentheight < ih->currentwidth)
+ {
+ int tmp = ih->currentheight;
+ ih->currentheight = ih->currentwidth;
+ ih->currentwidth = tmp;
+ }
+ }
+
+ if (!iupwin_comctl32ver6 && !iupAttribGetBoolean(ih, "DASHED"))
+ dwStyle |= PBS_SMOOTH;
+
+ if (iupwin_comctl32ver6 && iupAttribGetBoolean(ih, "MARQUEE"))
+ {
+ dwStyle |= PBS_MARQUEE;
+ ih->data->marquee = 1;
+ }
+
+ if (!iupwinCreateWindowEx(ih, PROGRESS_CLASS, 0, dwStyle))
+ return IUP_ERROR;
+
+ /* configure the native range */
+ SendMessage(ih->handle, PBM_SETRANGE, 0, MAKELPARAM(0, IUP_PB_MAX));
+
+ return IUP_NOERROR;
+}
+
+void iupdrvProgressBarInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winProgressBarMapMethod;
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winProgressBarSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ /* Only works when using Classic style */
+ if (iupwin_comctl32ver6)
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winProgressBarSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ else
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED);
+
+ /* IupProgressBar only */
+ iupClassRegisterAttribute(ic, "VALUE", iProgressBarGetValueAttrib, winProgressBarSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MARQUEE", NULL, winProgressBarSetMarqueeAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DASHED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_tabs.c b/iup/src/win/iupwin_tabs.c
new file mode 100755
index 0000000..682f451
--- /dev/null
+++ b/iup/src/win/iupwin_tabs.c
@@ -0,0 +1,680 @@
+/** \file
+* \brief Tabs Control
+*
+* See Copyright Notice in "iup.h"
+*/
+
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_stdcontrols.h"
+#include "iup_tabs.h"
+#include "iup_image.h"
+#include "iup_array.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+#include "iupwin_info.h"
+
+
+int iupdrvTabsExtraDecor(Ihandle* ih)
+{
+ (void)ih;
+ return 0;
+}
+
+int iupdrvTabsGetLineCountAttrib(Ihandle* ih)
+{
+ return (int)SendMessage(ih->handle, TCM_GETROWCOUNT, 0, 0);
+}
+
+static HWND winTabsGetPageWindow(Ihandle* ih, int pos)
+{
+ TCITEM tie;
+ tie.mask = TCIF_PARAM;
+ SendMessage(ih->handle, TCM_GETITEM, pos, (LPARAM)&tie);
+ return (HWND)tie.lParam;
+}
+
+void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos)
+{
+ int prev_pos = SendMessage(ih->handle, TCM_GETCURSEL, 0, 0);
+ HWND tab_page = winTabsGetPageWindow(ih, prev_pos);
+ ShowWindow(tab_page, SW_HIDE);
+
+ SendMessage(ih->handle, TCM_SETCURSEL, pos, 0);
+
+ tab_page = winTabsGetPageWindow(ih, pos);
+ ShowWindow(tab_page, SW_SHOW);
+}
+
+int iupdrvTabsGetCurrentTab(Ihandle* ih)
+{
+ return (int)SendMessage(ih->handle, TCM_GETCURSEL, 0, 0);
+}
+
+static int winTabsGetImageIndex(Ihandle* ih, const char* name)
+{
+ HIMAGELIST image_list;
+ int count, i, bpp, ret;
+ Iarray* bmp_array;
+ HBITMAP *bmp_array_data, hMask=NULL;
+ HBITMAP bmp = iupImageGetImage(name, ih, 0);
+ if (!bmp)
+ return -1;
+
+ /* the array is used to avoi adding the same bitmap twice */
+ bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY");
+ if (!bmp_array)
+ {
+ /* create the array if does not exist */
+ bmp_array = iupArrayCreate(50, sizeof(HBITMAP));
+ iupAttribSetStr(ih, "_IUPWIN_BMPARRAY", (char*)bmp_array);
+ }
+
+ bmp_array_data = iupArrayGetData(bmp_array);
+
+ image_list = (HIMAGELIST)SendMessage(ih->handle, TCM_GETIMAGELIST, 0, 0);
+ if (!image_list)
+ {
+ int width, height;
+ UINT flags = ILC_COLOR32|ILC_MASK;
+
+ /* must use this info, since image can be a driver image loaded from resources */
+ iupdrvImageGetInfo(bmp, &width, &height, &bpp);
+
+ /* create the image list if does not exist */
+ image_list = ImageList_Create(width, height, flags, 0, 50);
+ SendMessage(ih->handle, TCM_SETIMAGELIST, 0, (LPARAM)image_list);
+ }
+ else
+ iupdrvImageGetInfo(bmp, NULL, NULL, &bpp);
+
+ /* check if that bitmap is already added to the list,
+ but we can not compare with the actual bitmap at the list since it is a copy */
+ count = ImageList_GetImageCount(image_list);
+ for (i=0; i<count; i++)
+ {
+ if (bmp_array_data[i] == bmp)
+ return i;
+ }
+
+ if (bpp == 8)
+ {
+ Ihandle* image = IupGetHandle(name);
+ if (image)
+ {
+ iupAttribSetStr(image, "_IUPIMG_NO_INVERT", "1");
+ hMask = iupdrvImageCreateMask(image);
+ iupAttribSetStr(image, "_IUPIMG_NO_INVERT", NULL);
+ }
+ }
+
+ bmp_array_data = iupArrayInc(bmp_array);
+ bmp_array_data[i] = bmp;
+ ret = ImageList_Add(image_list, bmp, hMask); /* the bmp is duplicated at the list */
+ DeleteObject(hMask);
+ return ret;
+}
+
+static int winTabsGetPageWindowPos(Ihandle* ih, HWND tab_page)
+{
+ TCITEM tie;
+ int pos, num_tabs;
+
+ num_tabs = (int)SendMessage(ih->handle, TCM_GETITEMCOUNT, 0, 0);
+ tie.mask = TCIF_PARAM;
+
+ for (pos=0; pos<num_tabs; pos++)
+ {
+ SendMessage(ih->handle, TCM_GETITEM, pos, (LPARAM)&tie);
+ if (tab_page == (HWND)tie.lParam)
+ return pos;
+ }
+
+ return -1;
+}
+
+static void winTabsPlacePageWindows(Ihandle* ih, int w, int h)
+{
+ TCITEM tie;
+ int pos, num_tabs;
+ RECT rect;
+
+ num_tabs = (int)SendMessage(ih->handle, TCM_GETITEMCOUNT, 0, 0);
+ tie.mask = TCIF_PARAM;
+
+ /* Calculate the display rectangle, assuming the
+ tab control is the size of the client area. */
+ SetRect(&rect, 0, 0, w, h);
+ SendMessage(ih->handle, TCM_ADJUSTRECT, FALSE, (LPARAM)&rect);
+
+ for (pos=0; pos<num_tabs; pos++)
+ {
+ SendMessage(ih->handle, TCM_GETITEM, pos, (LPARAM)&tie);
+
+ SetWindowPos((HWND)tie.lParam, NULL,
+ rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOACTIVATE|SWP_NOZORDER);
+ }
+}
+
+static int winTabsUsingXPStyles(Ihandle* ih)
+{
+ return iupwin_comctl32ver6 && ih->data->type == ITABS_TOP;
+}
+
+static void winTabsDrawPageBackground(Ihandle* ih, HDC hDC, RECT* rect)
+{
+ unsigned char r=0, g=0, b=0;
+ char* color = iupAttribGetInheritNativeParent(ih, "BGCOLOR");
+ if (!color) color = iupAttribGetInheritNativeParent(ih, "BACKGROUND");
+ if (!color) color = iupAttribGet(ih, "BACKGROUND");
+ if (!color) color = IupGetGlobal("DLGBGCOLOR");
+ iupStrToRGB(color, &r, &g, &b);
+ SetDCBrushColor(hDC, RGB(r,g,b));
+ FillRect(hDC, rect, (HBRUSH)GetStockObject(DC_BRUSH));
+}
+
+static LRESULT CALLBACK winTabsPageWinProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ switch (msg)
+ {
+ case WM_ERASEBKGND:
+ {
+ RECT rect;
+ HDC hDC = (HDC)wp;
+ Ihandle* ih = iupwinHandleGet(hWnd);
+ GetClientRect(ih->handle, &rect);
+ winTabsDrawPageBackground(ih, hDC, &rect);
+
+ /* return non zero value */
+ return 1;
+ }
+ case WM_COMMAND:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORSTATIC:
+ case WM_DRAWITEM:
+ case WM_HSCROLL:
+ case WM_NOTIFY:
+ case WM_VSCROLL:
+ /* Forward the container messages to its parent. */
+ return SendMessage(GetParent(hWnd), msg, wp, lp);
+ }
+
+ return DefWindowProc(hWnd, msg, wp, lp);
+}
+
+static HWND winTabCreatePageWindow(Ihandle* ih)
+{
+ HWND hWnd;
+ DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS,
+ dwExStyle = 0;
+
+ if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED"))
+ dwExStyle |= WS_EX_COMPOSITED;
+ else
+ dwStyle |= WS_CLIPCHILDREN;
+
+ hWnd = CreateWindowEx(dwExStyle, "IupTabsPage", NULL, dwStyle,
+ 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
+ ih->handle, NULL, iupwin_hinstance, NULL);
+
+ iupwinHandleAdd(ih, hWnd);
+
+ return hWnd;
+}
+
+/* ------------------------------------------------------------------------- */
+/* winTabs - Sets and Gets accessors */
+/* ------------------------------------------------------------------------- */
+
+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;
+}
+
+static int winTabsSetMultilineAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->handle) /* allow to set only before mapping */
+ return 0;
+
+ if (iupStrBoolean(value))
+ ih->data->is_multiline = 1;
+ else
+ {
+ if (ih->data->type == ITABS_BOTTOM || ih->data->type == ITABS_TOP)
+ ih->data->is_multiline = 0;
+ else
+ ih->data->is_multiline = 1; /* always true if left/right */
+ }
+
+ return 0;
+}
+
+static char* winTabsGetMultilineAttrib(Ihandle* ih)
+{
+ if (ih->data->is_multiline)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int winTabsSetTabTypeAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->handle) /* allow to set only before mapping */
+ return 0;
+
+ if(iupStrEqualNoCase(value, "BOTTOM"))
+ {
+ ih->data->is_multiline = 0;
+ ih->data->type = ITABS_BOTTOM;
+ ih->data->orientation = ITABS_HORIZONTAL;
+ }
+ else if(iupStrEqualNoCase(value, "LEFT"))
+ {
+ ih->data->type = ITABS_LEFT;
+ ih->data->orientation = ITABS_VERTICAL;
+ ih->data->is_multiline = 1; /* VERTICAL works only with MULTILINE */
+ }
+ else if(iupStrEqualNoCase(value, "RIGHT"))
+ {
+ ih->data->is_multiline = 1; /* VERTICAL works only with MULTILINE */
+ ih->data->type = ITABS_RIGHT;
+ ih->data->orientation = ITABS_VERTICAL;
+ }
+ else /* "TOP" */
+ {
+ ih->data->is_multiline = 0;
+ ih->data->type = ITABS_TOP;
+ ih->data->orientation = ITABS_HORIZONTAL;
+ }
+
+ return 0;
+}
+
+static int winTabsSetTabTitleAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int pos;
+ if (value && iupStrToInt(name_id, &pos)==1)
+ {
+ TCITEM tie;
+
+ tie.mask = TCIF_TEXT;
+ tie.pszText = (char*)value;
+ tie.cchTextMax = strlen(value);
+
+ SendMessage(ih->handle, TCM_SETITEM, pos, (LPARAM)&tie);
+ }
+ return 1;
+}
+
+static int winTabsSetTabImageAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int pos;
+ if (value && iupStrToInt(name_id, &pos)==1)
+ {
+ TCITEM tie;
+
+ tie.mask = TCIF_IMAGE;
+ tie.iImage = winTabsGetImageIndex(ih, value);
+
+ SendMessage(ih->handle, TCM_SETITEM, pos, (LPARAM)&tie);
+ }
+ return 1;
+}
+
+static char* winTabsGetBgColorAttrib(Ihandle* ih)
+{
+ /* the most important use of this is to provide
+ the correct background for images */
+ if (iupwin_comctl32ver6)
+ {
+ COLORREF cr;
+ if (iupwinDrawGetThemeTabsBgColor(ih->handle, &cr))
+ {
+ char* str = iupStrGetMemory(20);
+ sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr));
+ return str;
+ }
+ }
+
+ return IupGetGlobal("DLGBGCOLOR");
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* winTabs - Calls the user callback to change of tab */
+/* ------------------------------------------------------------------------- */
+
+static int winTabsCtlColor(Ihandle* ih, HDC hdc, LRESULT *result)
+{
+ /* works only when NOT winTabsUsingXPStyles */
+ unsigned char r, g, b;
+ char* color = iupBaseNativeParentGetBgColorAttrib(ih);
+ if (iupStrToRGB(color, &r, &g, &b))
+ {
+ SetDCBrushColor(hdc, RGB(r,g,b));
+ *result = (LRESULT)GetStockObject(DC_BRUSH);
+ return 1;
+ }
+ return 0;
+}
+
+static int winTabsWmNotify(Ihandle* ih, NMHDR* msg_info, int *result)
+{
+ (void)result;
+
+ if (msg_info->code == TCN_SELCHANGING)
+ {
+ IFnnn cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB");
+ int prev_pos = SendMessage(ih->handle, TCM_GETCURSEL, 0, 0);
+ iupAttribSetInt(ih, "_IUPTABS_PREV_CHILD_POS", prev_pos);
+
+ if (cb)
+ {
+ Ihandle* prev_child = IupGetChild(ih, prev_pos);
+ iupAttribSetStr(ih, "_IUPTABS_PREV_CHILD", (char*)prev_child);
+ }
+ }
+
+ if (msg_info->code == TCN_SELCHANGE)
+ {
+ IFnnn cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB");
+ int pos = SendMessage(ih->handle, TCM_GETCURSEL, 0, 0);
+ int prev_pos = iupAttribGetInt(ih, "_IUPTABS_PREV_CHILD_POS");
+ HWND tab_page = winTabsGetPageWindow(ih, pos);
+ ShowWindow(tab_page, SW_SHOW);
+ tab_page = winTabsGetPageWindow(ih, prev_pos);
+ ShowWindow(tab_page, SW_HIDE);
+
+ if (cb)
+ {
+ Ihandle* child = IupGetChild(ih, pos);
+ Ihandle* prev_child = (Ihandle*)iupAttribGet(ih, "_IUPTABS_PREV_CHILD");
+ iupAttribSetStr(ih, "_IUPTABS_PREV_CHILD", NULL);
+
+ cb(ih, child, prev_child);
+ }
+ }
+
+ return 0; /* result not used */
+}
+
+static int winTabsProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch(msg)
+ {
+ case WM_SIZE:
+ {
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB");
+ CallWindowProc(oldProc, ih->handle, msg, wp, lp);
+
+ winTabsPlacePageWindows(ih, LOWORD(lp), HIWORD(lp));
+
+ *result = 0;
+ return 1;
+ }
+ }
+
+ return iupwinBaseContainerProc(ih, msg, wp, lp, result);
+}
+
+/* ------------------------------------------------------------------------- */
+/* winTabs - Methods and Init Class */
+/* ------------------------------------------------------------------------- */
+
+static void winTabsChildAddedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (IupGetName(child) == NULL)
+ iupAttribSetHandleName(child);
+
+ if (ih->handle)
+ {
+ TCITEM tie;
+ HWND tab_page;
+ char *tabtitle, *tabimage;
+ int pos, old_rowcount;
+ RECT rect;
+
+ pos = IupGetChildPos(ih, child);
+
+ tab_page = winTabCreatePageWindow(ih);
+
+ if (pos == 0)
+ ShowWindow(tab_page, SW_SHOW);
+
+ tabtitle = iupAttribGet(child, "TABTITLE");
+ if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos);
+ tabimage = iupAttribGet(child, "TABIMAGE");
+ if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos);
+ if (!tabtitle && !tabimage)
+ tabtitle = " ";
+
+ old_rowcount = (int)SendMessage(ih->handle, TCM_GETROWCOUNT, 0, 0);
+
+ tie.mask = TCIF_PARAM;
+
+ if (tabtitle)
+ {
+ tie.mask |= TCIF_TEXT;
+ tie.pszText = tabtitle;
+ tie.cchTextMax = strlen(tabtitle);
+ }
+
+ if (tabimage)
+ {
+ tie.mask |= TCIF_IMAGE;
+ tie.iImage = winTabsGetImageIndex(ih, tabimage);
+ }
+
+ /* create tabs and label them */
+ tie.lParam = (LPARAM)tab_page;
+ SendMessage(ih->handle, TCM_INSERTITEM, pos, (LPARAM)&tie);
+
+ /* Calculate the display rectangle, assuming the
+ tab control is the size of the client area. */
+ GetClientRect(ih->handle, &rect);
+ SendMessage(ih->handle, TCM_ADJUSTRECT, FALSE, (LPARAM)&rect);
+
+ SetWindowPos(tab_page, NULL,
+ rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOACTIVATE|SWP_NOZORDER);
+
+ iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)tab_page);
+
+ if (ih->data->is_multiline)
+ {
+ if (ih->data->type == ITABS_LEFT || ih->data->type == ITABS_RIGHT)
+ {
+ int rowcount = (int)SendMessage(ih->handle, TCM_GETROWCOUNT, 0, 0);
+ if (rowcount != old_rowcount)
+ {
+ GetClientRect(ih->handle, &rect);
+ winTabsPlacePageWindows(ih, rect.right - rect.left, rect.bottom - rect.top);
+ }
+ }
+
+ iupdrvDisplayRedraw(ih);
+ }
+ }
+}
+
+static void winTabsChildRemovedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (ih->handle)
+ {
+ HWND tab_page = (HWND)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ if (tab_page)
+ {
+ int pos = winTabsGetPageWindowPos(ih, tab_page);
+ SendMessage(ih->handle, TCM_DELETEITEM, pos, 0);
+ DestroyWindow(tab_page);
+
+ if (pos==0) pos++;
+ iupdrvTabsSetCurrentTab(ih, pos-1);
+
+ iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL);
+ }
+ }
+}
+
+static int winTabsMapMethod(Ihandle* ih)
+{
+ DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | TCS_HOTTRACK | WS_TABSTOP,
+ dwExStyle = 0;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (ih->data->type == ITABS_BOTTOM)
+ dwStyle |= TCS_BOTTOM;
+ else if (ih->data->type == ITABS_RIGHT)
+ dwStyle |= TCS_VERTICAL|TCS_RIGHT;
+ else if (ih->data->type == ITABS_LEFT)
+ dwStyle |= TCS_VERTICAL;
+
+ if (ih->data->is_multiline)
+ dwStyle |= TCS_MULTILINE;
+
+ if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED"))
+ {
+ dwExStyle |= WS_EX_COMPOSITED;
+
+ if (!ih->data->is_multiline && iupwinIsVista())
+ {
+ /* 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;
+
+ /* replace the WinProc to handle other messages */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTabsProc);
+
+ /* Process WM_NOTIFY */
+ IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTabsWmNotify);
+
+ /* Process background color */
+ IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winTabsCtlColor);
+
+ if (iupwin_comctl32ver6 && ih->data->type != ITABS_TOP)
+ {
+ /* XP Styles support only TABTYPE=TOP */
+ iupwinDrawRemoveTheme(ih->handle);
+ }
+
+ /* Change children background */
+ if (winTabsUsingXPStyles(ih))
+ {
+ char* color = iupAttribGetInheritNativeParent(ih, "BGCOLOR");
+ if (!color)
+ color = iupAttribGetInheritNativeParent(ih, "BACKGROUND");
+ if (!color)
+ {
+ COLORREF cr;
+ if (iupwinDrawGetThemeTabsBgColor(ih->handle, &cr))
+ iupAttribSetStrf(ih, "BACKGROUND", "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr));
+ }
+ }
+
+ /* Create pages and tabs */
+ if (ih->firstchild)
+ {
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ winTabsChildAddedMethod(ih, child);
+ }
+
+ return IUP_NOERROR;
+}
+
+static void winTabsUnMapMethod(Ihandle* ih)
+{
+ Iarray* bmp_array;
+
+ HIMAGELIST image_list = (HIMAGELIST)SendMessage(ih->handle, TCM_GETIMAGELIST, 0, 0);
+ if (image_list)
+ ImageList_Destroy(image_list);
+
+ bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY");
+ if (bmp_array)
+ iupArrayDestroy(bmp_array);
+
+ iupdrvBaseUnMapMethod(ih);
+}
+
+static void winTabsRegisterClass(void)
+{
+ WNDCLASS wndclass;
+ ZeroMemory(&wndclass, sizeof(WNDCLASS));
+
+ wndclass.hInstance = iupwin_hinstance;
+ wndclass.lpszClassName = "IupTabsPage";
+ wndclass.lpfnWndProc = (WNDPROC)winTabsPageWinProc;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.style = CS_PARENTDC;
+ wndclass.hbrBackground = NULL; /* remove the background to optimize redraw */
+
+ RegisterClass(&wndclass);
+}
+
+void iupdrvTabsInitClass(Iclass* ic)
+{
+ if (!iupwinClassExist("IupTabsPage"))
+ winTabsRegisterClass();
+
+ /* Driver Dependent Class functions */
+ ic->Map = winTabsMapMethod;
+ ic->UnMap = winTabsUnMapMethod;
+ ic->ChildAdded = winTabsChildAddedMethod;
+ ic->ChildRemoved = winTabsChildRemovedMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", winTabsGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_NOT_MAPPED);
+
+ /* IupTabs only */
+ iupClassRegisterAttribute(ic, "TABTYPE", iupTabsGetTabTypeAttrib, winTabsSetTabTypeAttrib, IUPAF_SAMEASSYSTEM, "TOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TABORIENTATION", iupTabsGetTabOrientationAttrib, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* can not be set, depends on TABTYPE in Windows */
+ 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);
+}
diff --git a/iup/src/win/iupwin_text.c b/iup/src/win/iupwin_text.c
new file mode 100755
index 0000000..dfe489a
--- /dev/null
+++ b/iup/src/win/iupwin_text.c
@@ -0,0 +1,1993 @@
+/** \file
+ * \brief Text Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+#include <richedit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_mask.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_array.h"
+#include "iup_text.h"
+#include "iup_key.h"
+#include "iup_dialog.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+
+/* Cygwin and MingW Win32api does not define these */
+
+#ifndef PFN_ARABIC
+#define PFN_ARABIC 2
+#define PFN_LCLETTER 3
+#define PFN_UCLETTER 4
+#define PFN_LCROMAN 5
+#define PFN_UCROMAN 6
+#endif
+
+#ifndef PFNS_PAREN
+#define PFNS_PAREN 0x000
+#define PFNS_PARENS 0x100
+#define PFNS_PERIOD 0x200
+#define PFNS_PLAIN 0x300
+#define PFNS_NONUMBER 0x400
+#endif
+
+#ifndef CFM_BACKCOLOR
+#define CFM_BACKCOLOR 0x04000000
+#define CFM_UNDERLINETYPE 0x00800000
+#define CFM_WEIGHT 0x00400000
+#define CFM_DISABLED 0x2000
+#define CFE_DISABLED CFM_DISABLED
+#endif
+
+#ifndef CFU_UNDERLINEDOTTED
+#define CFU_UNDERLINEDOTTED 4
+#define CFU_UNDERLINEDOUBLE 3
+#define CFU_UNDERLINE 1
+#define CFU_UNDERLINENONE 0
+#endif
+
+#ifndef SES_UPPERCASE
+#define SES_UPPERCASE 512
+#define SES_LOWERCASE 1024
+#endif
+/* End Cygwin/MingW */
+
+#ifndef EM_SETCUEBANNER /* defined only if _WIN32_WINNT >= 0x501 */
+#define ECM_FIRST 0x1500 /* Edit control messages */
+#define EM_SETCUEBANNER (ECM_FIRST + 1)
+#endif
+
+#define WM_CARET WM_APP+1 /* Custom IUP message */
+
+
+void iupdrvTextAddSpin(int *w, int h)
+{
+ *w += h;
+}
+
+void iupdrvTextAddBorders(int *w, int *h)
+{
+ int border_size = 2*3;
+ (*w) += border_size;
+ (*h) += border_size;
+}
+
+static void winTextParseParagraphFormat(Ihandle* formattag, PARAFORMAT2 *paraformat, int convert2twips)
+{
+ int val;
+ char* format;
+
+ ZeroMemory(paraformat, sizeof(PARAFORMAT2));
+ paraformat->cbSize = sizeof(PARAFORMAT2);
+
+ format = iupAttribGet(formattag, "NUMBERING");
+ if (format)
+ {
+ paraformat->dwMask |= PFM_NUMBERING;
+
+ if (iupStrEqualNoCase(format, "BULLET"))
+ paraformat->wNumbering = PFN_BULLET;
+ else if (iupStrEqualNoCase(format, "ARABIC"))
+ paraformat->wNumbering = PFN_ARABIC;
+ else if (iupStrEqualNoCase(format, "LCLETTER"))
+ paraformat->wNumbering = PFN_LCLETTER;
+ else if (iupStrEqualNoCase(format, "UCLETTER"))
+ paraformat->wNumbering = PFN_UCLETTER;
+ else if (iupStrEqualNoCase(format, "LCROMAN"))
+ paraformat->wNumbering = PFN_LCROMAN;
+ else if (iupStrEqualNoCase(format, "UCROMAN"))
+ paraformat->wNumbering = PFN_UCROMAN;
+ else
+ paraformat->wNumbering = 0; /* "NONE" */
+
+ format = iupAttribGet(formattag, "NUMBERINGSTYLE");
+ if (format)
+ {
+ paraformat->dwMask |= PFM_NUMBERINGSTYLE;
+
+ if (iupStrEqualNoCase(format, "RIGHTPARENTESES"))
+ paraformat->wNumberingStyle = PFNS_PAREN;
+ else if (iupStrEqualNoCase(format, "PARENTESES"))
+ paraformat->wNumberingStyle = PFNS_PARENS;
+ else if (iupStrEqualNoCase(format, "PERIOD"))
+ paraformat->wNumberingStyle = PFNS_PERIOD;
+ else if (iupStrEqualNoCase(format, "NONUMBER"))
+ paraformat->wNumberingStyle = PFNS_NONUMBER;
+ else
+ paraformat->wNumberingStyle = PFNS_PLAIN; /* "NONE" */
+ }
+
+ format = iupAttribGet(formattag, "NUMBERINGTAB");
+ if (format && iupStrToInt(format, &val))
+ {
+ paraformat->dwMask |= PFM_NUMBERINGTAB;
+ paraformat->wNumberingTab = (WORD)(val*convert2twips);
+ }
+ }
+
+ format = iupAttribGet(formattag, "INDENT");
+ if (format && iupStrToInt(format, &val))
+ {
+ paraformat->dwMask |= PFM_STARTINDENT|PFM_RIGHTINDENT|PFM_OFFSET;
+ paraformat->dxStartIndent = val*convert2twips;
+
+ format = iupAttribGet(formattag, "INDENTRIGHT");
+ if (format && iupStrToInt(format, &val))
+ paraformat->dxRightIndent = val*convert2twips;
+ else
+ paraformat->dxRightIndent = paraformat->dxStartIndent;
+
+ format = iupAttribGet(formattag, "INDENTOFFSET");
+ if (format && iupStrToInt(format, &val))
+ paraformat->dxOffset = val*convert2twips;
+ else
+ paraformat->dxOffset = 0;
+ }
+
+ format = iupAttribGet(formattag, "ALIGNMENT");
+ if (format)
+ {
+ paraformat->dwMask |= PFM_ALIGNMENT;
+
+ if (iupStrEqualNoCase(format, "JUSTIFY"))
+ paraformat->wAlignment = PFA_JUSTIFY;
+ else if (iupStrEqualNoCase(format, "RIGHT"))
+ paraformat->wAlignment = PFA_RIGHT;
+ else if (iupStrEqualNoCase(format, "CENTER"))
+ paraformat->wAlignment = PFA_CENTER;
+ else
+ paraformat->wAlignment = PFA_LEFT; /* "LEFT" */
+ }
+
+ format = iupAttribGet(formattag, "TABSARRAY");
+ if (format)
+ {
+ int pos, align, i = 0;
+ LONG tab;
+ char* str;
+
+ paraformat->dwMask |= PFM_TABSTOPS;
+
+ while (format)
+ {
+ str = iupStrCopyUntil((char**)&format, ' ');
+ if (!str) break;
+ pos = atoi(str)*convert2twips;
+ free(str);
+
+ str = iupStrCopyUntil((char**)&format, ' ');
+ if (!str) break;
+
+ if (iupStrEqualNoCase(str, "DECIMAL"))
+ align = 3;
+ else if (iupStrEqualNoCase(str, "RIGHT"))
+ align = 2;
+ else if (iupStrEqualNoCase(str, "CENTER"))
+ align = 1;
+ else /* "LEFT" */
+ align = 0;
+ free(str);
+
+ tab = (pos&0xFFF)|(align<<24);
+ paraformat->rgxTabs[i] = tab;
+ i++;
+ if (i == 32) break;
+ }
+ paraformat->cTabCount = (SHORT)i;
+ }
+
+ format = iupAttribGet(formattag, "SPACEBEFORE");
+ if (format && iupStrToInt(format, &val))
+ {
+ paraformat->dwMask |= PFM_SPACEBEFORE;
+ paraformat->dySpaceBefore = val*convert2twips;
+ }
+
+ format = iupAttribGet(formattag, "SPACEAFTER");
+ if (format && iupStrToInt(format, &val))
+ {
+ paraformat->dwMask |= PFM_SPACEAFTER;
+ paraformat->dySpaceAfter = val*convert2twips;
+ }
+
+ format = iupAttribGet(formattag, "LINESPACING");
+ if (format)
+ {
+ paraformat->dwMask |= PFM_LINESPACING;
+
+ if (iupStrEqualNoCase(format, "SINGLE"))
+ paraformat->bLineSpacingRule = 0;
+ else if (iupStrEqualNoCase(format, "ONEHALF"))
+ paraformat->bLineSpacingRule = 1;
+ else if (iupStrEqualNoCase(format, "DOUBLE"))
+ paraformat->bLineSpacingRule = 2;
+ else if (iupStrToInt(format, &val))
+ {
+ paraformat->bLineSpacingRule = 3;
+ paraformat->dyLineSpacing = val*convert2twips;
+ }
+ }
+}
+
+static void winTextParseCharacterFormat(Ihandle* formattag, CHARFORMAT2 *charformat, int pixel2twips)
+{
+ int val;
+ char* format;
+
+ ZeroMemory(charformat, sizeof(CHARFORMAT2));
+ charformat->cbSize = sizeof(CHARFORMAT2);
+
+ format = iupAttribGet(formattag, "DISABLED");
+ if (format)
+ {
+ charformat->dwMask |= CFM_DISABLED;
+ if (iupStrBoolean(format))
+ charformat->dwEffects |= CFE_DISABLED;
+ }
+
+ format = iupAttribGet(formattag, "RISE");
+ if (format)
+ {
+ if (iupStrEqualNoCase(format, "SUPERSCRIPT"))
+ {
+ charformat->dwMask |= CFM_SUPERSCRIPT;
+ charformat->dwEffects |= CFE_SUPERSCRIPT;
+ }
+ else if (iupStrEqualNoCase(format, "SUBSCRIPT"))
+ {
+ charformat->dwMask |= CFM_SUBSCRIPT;
+ charformat->dwEffects |= CFE_SUBSCRIPT;
+ }
+ else if (iupStrToInt(format, &val))
+ {
+ charformat->dwMask |= CFM_OFFSET;
+ charformat->yOffset = val;
+ }
+ }
+
+ format = iupAttribGet(formattag, "ITALIC");
+ if (format)
+ {
+ charformat->dwMask |= CFM_ITALIC;
+ if (iupStrBoolean(format))
+ charformat->dwEffects |= CFE_ITALIC;
+ }
+
+ format = iupAttribGet(formattag, "STRIKEOUT");
+ if (format)
+ {
+ charformat->dwMask |= CFM_STRIKEOUT;
+ if (iupStrBoolean(format))
+ charformat->dwEffects |= CFE_STRIKEOUT;
+ }
+
+ format = iupAttribGet(formattag, "PROTECTED");
+ if (format)
+ {
+ charformat->dwMask |= CFM_PROTECTED;
+ if (iupStrBoolean(format))
+ charformat->dwEffects |= CFE_PROTECTED;
+ }
+
+ format = iupAttribGet(formattag, "FONTSIZE");
+ if (format && iupStrToInt(format, &val))
+ {
+ /* (1/1440 of an inch, or 1/20 of a printer's point) */
+ charformat->dwMask |= CFM_SIZE;
+ if (val < 0) /* in pixels */
+ charformat->yHeight = (-val)*pixel2twips;
+ else
+ charformat->yHeight = val*20;
+ }
+
+ format = iupAttribGet(formattag, "FONTSCALE");
+ if (format && charformat->yHeight != 0)
+ {
+ float fval = 0;
+ if (iupStrEqualNoCase(format, "XX-SMALL"))
+ fval = 0.5787037037037f;
+ else if (iupStrEqualNoCase(format, "X-SMALL"))
+ fval = 0.6444444444444f;
+ else if (iupStrEqualNoCase(format, "SMALL"))
+ fval = 0.8333333333333f;
+ else if (iupStrEqualNoCase(format, "MEDIUM"))
+ fval = 1.0f;
+ else if (iupStrEqualNoCase(format, "LARGE"))
+ fval = 1.2f;
+ else if (iupStrEqualNoCase(format, "X-LARGE"))
+ fval = 1.4399999999999f;
+ else if (iupStrEqualNoCase(format, "XX-LARGE"))
+ fval = 1.728f;
+ else
+ iupStrToFloat(format, &fval);
+
+ if (fval > 0)
+ {
+ fval = ((float)charformat->yHeight)*fval;
+ charformat->yHeight = iupROUND(fval);
+ }
+ }
+
+ format = iupAttribGet(formattag, "FONTFACE");
+ if (format)
+ {
+ charformat->dwMask |= CFM_FACE;
+ strcpy(charformat->szFaceName, format);
+ }
+
+ format = iupAttribGet(formattag, "FGCOLOR");
+ if (format)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(format, &r, &g, &b))
+ {
+ charformat->dwMask |= CFM_COLOR;
+ charformat->crTextColor = RGB(r, g, b);
+ }
+ }
+
+ format = iupAttribGet(formattag, "BGCOLOR");
+ if (format)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(format, &r, &g, &b))
+ {
+ charformat->dwMask |= CFM_BACKCOLOR;
+ charformat->crBackColor = RGB(r, g, b);
+ }
+ }
+
+ format = iupAttribGet(formattag, "UNDERLINE");
+ if (format)
+ {
+ charformat->dwMask |= CFM_UNDERLINETYPE;
+
+ if (iupStrEqualNoCase(format, "SINGLE"))
+ charformat->bUnderlineType = CFU_UNDERLINE;
+ else if (iupStrEqualNoCase(format, "DOUBLE"))
+ charformat->bUnderlineType = CFU_UNDERLINEDOUBLE;
+ else if (iupStrEqualNoCase(format, "DOTTED"))
+ charformat->bUnderlineType = CFU_UNDERLINEDOTTED;
+ else /* "NONE" */
+ charformat->bUnderlineType = CFU_UNDERLINENONE;
+
+ if (charformat->bUnderlineType != CFU_UNDERLINENONE)
+ {
+ charformat->dwMask |= CFM_UNDERLINE;
+ charformat->dwEffects |= CFE_UNDERLINE;
+ }
+ }
+
+ format = iupAttribGet(formattag, "WEIGHT");
+ if (format)
+ {
+ charformat->dwMask |= CFM_WEIGHT;
+
+ if (iupStrEqualNoCase(format, "EXTRALIGHT"))
+ charformat->wWeight = FW_EXTRALIGHT;
+ else if (iupStrEqualNoCase(format, "LIGHT"))
+ charformat->wWeight = FW_LIGHT;
+ else if (iupStrEqualNoCase(format, "SEMIBOLD"))
+ charformat->wWeight = FW_SEMIBOLD;
+ else if (iupStrEqualNoCase(format, "BOLD"))
+ charformat->wWeight = FW_BOLD;
+ else if (iupStrEqualNoCase(format, "EXTRABOLD"))
+ charformat->wWeight = FW_EXTRABOLD;
+ else if (iupStrEqualNoCase(format, "HEAVY"))
+ charformat->wWeight = FW_HEAVY;
+ else /* "NORMAL" */
+ charformat->wWeight = FW_NORMAL;
+
+ if (charformat->wWeight != FW_NORMAL)
+ {
+ charformat->dwMask |= CFM_BOLD;
+ charformat->dwEffects |= CFE_BOLD;
+ }
+ }
+}
+
+static int winTextSetLinColToPosition(Ihandle *ih, int lin, int col)
+{
+ int linmax, colmax, lineindex;
+
+ lin--; /* IUP starts at 1 */
+ col--;
+
+ linmax = SendMessage(ih->handle, EM_GETLINECOUNT, 0, 0L);
+ if (lin > linmax)
+ lin = linmax;
+
+ lineindex = SendMessage(ih->handle, EM_LINEINDEX, (WPARAM)lin, 0L);
+
+ colmax = SendMessage(ih->handle, EM_LINELENGTH, (WPARAM)lineindex, 0L);
+ if (col > colmax)
+ col = colmax; /* after the last character */
+
+ return lineindex + col;
+}
+
+static void winTextGetLinColFromPosition(Ihandle* ih, int pos, int* lin, int* col)
+{
+ /* here "pos" must contains the extra chars if the case */
+ int lineindex;
+
+ if (ih->data->has_formatting)
+ *lin = SendMessage(ih->handle, EM_EXLINEFROMCHAR, (WPARAM)0, (LPARAM)pos);
+ else
+ *lin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L);
+
+ lineindex = SendMessage(ih->handle, EM_LINEINDEX, (WPARAM)(*lin), (LPARAM)0L);
+ *col = pos - lineindex; /* lineindex is at the first character of the line */
+
+ (*lin)++; /* IUP starts at 1 */
+ (*col)++;
+}
+
+static int winTextRemoveExtraChars(Ihandle* ih, int pos)
+{
+ /* called only if not single line and not formatting */
+ int lin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L);
+ pos -= lin; /* remove \r characters from count */
+ return pos;
+}
+
+static int winTextAddExtraChars(Ihandle* ih, int pos)
+{
+ /* called only if not single line and not formatting */
+ int lin, clin;
+
+ clin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L);
+
+ /* pos is smaller than the actual pos (missing the \r count),
+ so we must calculate the line until the returned value is the same as the expected. */
+ do
+ {
+ lin = clin;
+ clin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)(pos+lin+1), (LPARAM)0L); /* add one because we can be at the last character */
+ } while (clin != lin); /* and it will not change to the next line by 1 */
+
+ pos += lin; /* add \r characters from count */
+ return pos;
+}
+
+static int winTextGetCaretPos(Ihandle* ih)
+{
+ int pos = 0;
+ POINT point;
+
+ if (GetFocus() != ih->handle || !GetCaretPos(&point))
+ {
+ /* if does not have the focus, or could not get caret position,
+ then use the selection start position */
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)&pos, 0);
+ }
+ else
+ {
+ if (ih->data->has_formatting)
+ pos = SendMessage(ih->handle, EM_CHARFROMPOS, 0, (LPARAM)&point);
+ else
+ {
+ LRESULT ret;
+
+ /* Workaround for weird behavior because of the return value in GetCaretPos */
+ if (ih->data->is_multiline && point.y < 5)
+ point.y += 5;
+
+ ret = SendMessage(ih->handle, EM_CHARFROMPOS, 0, MAKELPARAM(point.x, point.y));
+ pos = LOWORD(ret);
+ }
+ }
+
+ return pos;
+}
+
+static int winTextGetCaret(Ihandle* ih, int *lin, int *col)
+{
+ int pos = winTextGetCaretPos(ih);
+
+ if (ih->data->is_multiline)
+ {
+ winTextGetLinColFromPosition(ih, pos, lin, col);
+
+ if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextRemoveExtraChars(ih, pos);
+ }
+ else
+ {
+ *col = pos;
+ (*col)++; /* IUP starts at 1 */
+ *lin = 1;
+ }
+
+ return pos;
+}
+
+static void winTextGetSelection(Ihandle* ih, int *start, int *end)
+{
+ *start = 0;
+ *end = 0;
+
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)start, (LPARAM)end);
+
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ {
+ (*start) = winTextRemoveExtraChars(ih, *start);
+ (*end) = winTextRemoveExtraChars(ih, *end);
+ }
+}
+
+void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos)
+{
+ *pos = winTextSetLinColToPosition(ih, lin, col);
+
+ if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ *pos = winTextRemoveExtraChars(ih, *pos);
+}
+
+void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col)
+{
+ if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextAddExtraChars(ih, pos);
+
+ winTextGetLinColFromPosition(ih, pos, lin, col);
+}
+
+static int winTextConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ int pos;
+
+ if (ih->data->has_formatting)
+ {
+ POINT point;
+ point.x = x;
+ point.y = y;
+ pos = (int)SendMessage(ih->handle, EM_CHARFROMPOS, 0, (LPARAM)&point);
+ }
+ else
+ {
+ LRESULT ret = SendMessage(ih->handle, EM_CHARFROMPOS, 0, MAKELPARAM(x, y));
+ pos = LOWORD(ret);
+ }
+
+ if (ih->data->is_multiline)
+ {
+ if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextRemoveExtraChars(ih, pos);
+ }
+
+ return pos;
+}
+
+
+/***********************************************************************************************/
+
+
+static int winTextSetValueAttrib(Ihandle* ih, const char* value)
+{
+ char* str;
+ if (!value) value = "";
+ str = (char*)value;
+ if (ih->data->is_multiline)
+ {
+ if (ih->data->has_formatting)
+ str = iupStrToMac(str);
+ else
+ str = iupStrToDos(str);
+ }
+ iupAttribSetStr(ih, "IUPWIN_IGNORECHANGE", "1");
+ SetWindowText(ih->handle, str);
+ iupAttribSetStr(ih, "IUPWIN_IGNORECHANGE", NULL);
+ if (str != value) free(str);
+ return 0;
+}
+
+static char* winTextGetValueAttrib(Ihandle* ih)
+{
+ int nc = GetWindowTextLength(ih->handle);
+ if (nc)
+ {
+ char* str = iupStrGetMemory(nc+1);
+ GetWindowText(ih->handle, str, nc+1); /* notice that this function always returns in DOS format */
+ if (ih->data->is_multiline)
+ iupStrToUnix(str);
+ return str;
+ }
+ else
+ return "";
+}
+
+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;
+}
+
+static int winTextSetSelectedTextAttrib(Ihandle* ih, const char* value)
+{
+ if (value)
+ {
+ int start = 0, end = 0;
+ char* str;
+
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return 0;
+
+ str = (char*)value;
+ if (ih->data->is_multiline)
+ {
+ if (ih->data->has_formatting)
+ str = iupStrToMac(str);
+ else
+ str = iupStrToDos(str);
+ }
+ SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str);
+ if (str != value) free(str);
+ }
+ return 0;
+}
+
+static char* winTextGetSelectedTextAttrib(Ihandle* ih)
+{
+ int nc = GetWindowTextLength(ih->handle);
+ if (nc)
+ {
+ int start = 0, end = 0;
+ char* str;
+
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ if (ih->data->has_formatting)
+ {
+ str = iupStrGetMemory(end-start+1);
+ SendMessage(ih->handle, EM_GETSELTEXT, 0, (LPARAM)str);
+ }
+ else
+ {
+ str = iupStrGetMemory(nc+1);
+ GetWindowText(ih->handle, str, nc+1); /* notice that this function always returns in DOS format */
+ /* returns only the selected text */
+ str[end] = 0;
+ str += start;
+ }
+
+ if (ih->data->is_multiline)
+ iupStrToUnix(str);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int winTextSetNCAttrib(Ihandle* ih, const char* value)
+{
+ if (!iupStrToInt(value, &ih->data->nc))
+ ih->data->nc = 0;
+
+ if (ih->handle)
+ {
+ if (ih->data->has_formatting)
+ 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;
+}
+
+static int winTextSetSelectionAttrib(Ihandle* ih, const char* value)
+{
+ int start=1, end=1;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)-1, (LPARAM)0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ return 0;
+ }
+
+ if (ih->data->is_multiline)
+ {
+ int lin_start=1, col_start=1, lin_end=1, col_end=1;
+
+ if (sscanf(value, "%d,%d:%d,%d", &lin_start, &col_start, &lin_end, &col_end)!=4) return 0;
+ if (lin_start<1 || col_start<1 || lin_end<1 || col_end<1) return 0;
+
+ start = winTextSetLinColToPosition(ih, lin_start, col_start);
+ end = winTextSetLinColToPosition(ih, lin_end, col_end);
+ }
+ else
+ {
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<1 || end<1)
+ return 0;
+
+ start--; /* IUP starts at 1 */
+ end--;
+ }
+
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)start, (LPARAM)end);
+
+ return 0;
+}
+
+static char* winTextGetSelectionAttrib(Ihandle* ih)
+{
+ int start = 0, end = 0;
+ char* str;
+
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ str = iupStrGetMemory(100);
+
+ if (ih->data->is_multiline)
+ {
+ int start_col, start_lin, end_col, end_lin;
+ winTextGetLinColFromPosition(ih, start, &start_lin, &start_col);
+ winTextGetLinColFromPosition(ih, end, &end_lin, &end_col);
+ sprintf(str,"%d,%d:%d,%d", start_lin, start_col, end_lin, end_col);
+ }
+ else
+ {
+ start++; /* IUP starts at 1 */
+ end++;
+ sprintf(str, "%d:%d", start, end);
+ }
+
+ return str;
+}
+
+static int winTextSetSelectionPosAttrib(Ihandle* ih, const char* value)
+{
+ int start=0, end=0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)-1, (LPARAM)0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<0 || end<0)
+ return 0;
+
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ {
+ start = winTextAddExtraChars(ih, start);
+ end = winTextAddExtraChars(ih, end);
+ }
+
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)start, (LPARAM)end);
+
+ return 0;
+}
+
+static char* winTextGetSelectionPosAttrib(Ihandle* ih)
+{
+ int start = 0, end = 0;
+ char* str;
+
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ {
+ start = winTextRemoveExtraChars(ih, start);
+ end = winTextRemoveExtraChars(ih, end);
+ }
+
+ str = iupStrGetMemory(100);
+
+ sprintf(str, "%d:%d", start, end);
+
+ return str;
+}
+
+static int winTextSetInsertAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (value)
+ {
+ char* str = (char*)value;
+ if (ih->data->is_multiline)
+ {
+ if (ih->data->has_formatting)
+ str = iupStrToMac(str);
+ else
+ str = iupStrToDos(str);
+ }
+
+ SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str);
+
+ if (str != value) free(str);
+ }
+ return 0;
+}
+
+static int winTextSetAppendAttrib(Ihandle* ih, const char* value)
+{
+ int len;
+ char* str;
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (!value) value = "";
+ str = (char*)value;
+ if (ih->data->is_multiline)
+ {
+ if (ih->data->has_formatting)
+ str = iupStrToMac(str);
+ else
+ 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)
+ {
+ if (ih->data->has_formatting)
+ SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\r");
+ else
+ SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\r\n");
+ }
+ SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str);
+
+ if (str != value) free(str);
+ return 0;
+}
+
+static int winTextSetReadOnlyAttrib(Ihandle* ih, const char* value)
+{
+ SendMessage(ih->handle, EM_SETREADONLY, (WPARAM)iupStrBoolean(value), 0);
+ return 0;
+}
+
+static char* winTextGetReadOnlyAttrib(Ihandle* ih)
+{
+ DWORD style = GetWindowLong(ih->handle, GWL_STYLE);
+ if (style & ES_READONLY)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int winTextSetTabSizeAttrib(Ihandle* ih, const char* value)
+{
+ int tabsize;
+ if (!ih->data->is_multiline)
+ return 0;
+
+ iupStrToInt(value, &tabsize);
+ tabsize *= 4;
+ SendMessage(ih->handle, EM_SETTABSTOPS, (WPARAM)1L, (LPARAM)&tabsize);
+ iupdrvDisplayRedraw(ih);
+ return 1;
+}
+
+static int winTextSetCaretAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ int lin = 1, col = 1;
+ iupStrToIntInt(value, &lin, &col, ','); /* be permissive in SetCaret, do not abort if invalid */
+ if (lin < 1) lin = 1;
+ if (col < 1) col = 1;
+
+ pos = winTextSetLinColToPosition(ih, lin, col);
+ }
+ else
+ {
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+ pos--; /* IUP starts at 1 */
+ }
+
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)pos, (LPARAM)pos);
+ SendMessage(ih->handle, EM_SCROLLCARET, 0L, 0L);
+
+ return 0;
+}
+
+static char* winTextGetCaretAttrib(Ihandle* ih)
+{
+ int col, lin;
+ char* str;
+
+ str = iupStrGetMemory(100);
+
+ winTextGetCaret(ih, &lin, &col);
+
+ if (ih->data->is_multiline)
+ sprintf(str, "%d,%d", lin, col);
+ else
+ sprintf(str, "%d", col);
+
+ return str;
+}
+
+static int winTextSetCaretPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos); /* be permissive in SetCaret, do not abort if invalid */
+ if (pos < 0) pos = 0;
+
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextAddExtraChars(ih, pos);
+
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)pos, (LPARAM)pos);
+ SendMessage(ih->handle, EM_SCROLLCARET, 0L, 0L);
+
+ return 0;
+}
+
+static char* winTextGetCaretPosAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(100);
+ int pos = winTextGetCaretPos(ih);
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextRemoveExtraChars(ih, pos);
+ sprintf(str, "%d", pos);
+ return str;
+}
+
+static int winTextSetScrollToAttrib(Ihandle* ih, const char* value)
+{
+ int lin = 1, col = 1;
+
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ iupStrToIntInt(value, &lin, &col, ',');
+ if (lin < 1) lin = 1;
+ if (col < 1) col = 1;
+ }
+ else
+ {
+ sscanf(value,"%i",&col);
+ if (col < 1) col = 1;
+ }
+
+ lin--; /* return to Windows referece */
+ col--;
+
+ if (ih->data->has_formatting)
+ SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)0, (LPARAM)lin);
+ else
+ SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)col, (LPARAM)lin);
+
+ return 0;
+}
+
+static int winTextSetScrollToPosAttrib(Ihandle* ih, const char* value)
+{
+ int lin, col, pos = 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextAddExtraChars(ih, pos);
+
+ winTextGetLinColFromPosition(ih, pos, &lin, &col);
+ lin--; /* return to Windows referece */
+ col--;
+
+ if (ih->data->has_formatting)
+ SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)0, (LPARAM)lin);
+ else
+ SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)col, (LPARAM)lin);
+
+ return 0;
+}
+
+static int winTextSetFilterAttrib(Ihandle *ih, const char *value)
+{
+ int style = 0;
+
+ if (iupStrEqualNoCase(value, "LOWERCASE"))
+ {
+ if (ih->data->has_formatting)
+ {
+ SendMessage(ih->handle, EM_SETEDITSTYLE, SES_LOWERCASE, SES_LOWERCASE);
+ return 1;
+ }
+ style = ES_LOWERCASE;
+ }
+ else if (iupStrEqualNoCase(value, "NUMBER"))
+ style = ES_NUMBER;
+ else if (iupStrEqualNoCase(value, "UPPERCASE"))
+ {
+ if (ih->data->has_formatting)
+ {
+ SendMessage(ih->handle, EM_SETEDITSTYLE, SES_UPPERCASE, SES_UPPERCASE);
+ return 1;
+ }
+ style = ES_UPPERCASE;
+ }
+
+ if (style)
+ iupwinMergeStyle(ih, ES_LOWERCASE|ES_NUMBER|ES_UPPERCASE, style);
+
+ return 1;
+}
+
+static int winTextSetClipboardAttrib(Ihandle *ih, const char *value)
+{
+ UINT msg = 0;
+
+ if (iupStrEqualNoCase(value, "COPY"))
+ msg = WM_COPY;
+ else if (iupStrEqualNoCase(value, "CUT"))
+ msg = WM_CUT;
+ else if (iupStrEqualNoCase(value, "PASTE"))
+ msg = WM_PASTE;
+ else if (iupStrEqualNoCase(value, "CLEAR"))
+ msg = WM_CLEAR;
+ else if (iupStrEqualNoCase(value, "UNDO"))
+ msg = WM_UNDO;
+ else if (ih->data->has_formatting && iupStrEqualNoCase(value, "REDO"))
+ msg = EM_REDO;
+
+ if (msg)
+ SendMessage(ih->handle, msg, 0, 0);
+
+ return 0;
+}
+
+static int winTextSetBgColorAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->has_formatting)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ COLORREF color;
+ color = RGB(r,g,b);
+ SendMessage(ih->handle, EM_SETBKGNDCOLOR, 0, (LPARAM)color);
+ }
+ }
+ return 1;
+}
+
+static int winTextSetCueBannerAttrib(Ihandle *ih, const char *value)
+{
+ if (!ih->data->is_multiline && iupwin_comctl32ver6)
+ {
+ WCHAR* wstr = iupwinStrChar2Wide(value);
+ SendMessage(ih->handle, EM_SETCUEBANNER, (WPARAM)FALSE, (LPARAM)wstr);
+ free(wstr);
+ return 1;
+ }
+ return 0;
+}
+
+static int winTextSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ int new_style;
+
+ if (iupStrEqualNoCase(value, "ARIGHT"))
+ new_style = ES_RIGHT;
+ else if (iupStrEqualNoCase(value, "ACENTER"))
+ new_style = ES_CENTER;
+ else /* "ALEFT" */
+ new_style = ES_LEFT;
+
+ iupwinMergeStyle(ih, ES_LEFT|ES_CENTER|ES_RIGHT, new_style);
+
+ return 1;
+}
+
+static int winTextSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ /* ignore the first call that is done in IupMap,
+ it is already done before calling iupTextUpdateFormatTags. */
+ if (ih->data->has_formatting && iupAttribGet(ih, "_IUPWIN_IGNORE_FONT"))
+ {
+ iupAttribSetStr(ih, "_IUPWIN_IGNORE_FONT", NULL);
+ return 0;
+ }
+ return iupdrvSetStandardFontAttrib(ih, value);
+}
+
+void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag)
+{
+ int convert2twips, pixel2twips;
+ char *selection, *units;
+ PARAFORMAT2 paraformat;
+ CHARFORMAT2 charformat;
+
+ /* one twip is 1/1440 inch */
+ /* twip = (pixel*1440)/(pixel/inch) */
+ pixel2twips = 1440/iupwinGetScreenRes();
+
+ /* default is PIXELS */
+ convert2twips = pixel2twips;
+ units = iupAttribGet(formattag, "UNITS");
+ if (units)
+ {
+ int val;
+ if (iupStrEqualNoCase(units, "TWIPS"))
+ convert2twips = 1;
+ else if (iupStrToInt(units, &val))
+ convert2twips = val;
+ }
+
+ selection = iupAttribGet(formattag, "SELECTION");
+ if (selection)
+ {
+ /* In Windows, the format message use the current selection */
+ winTextSetSelectionAttrib(ih, selection);
+ iupAttribSetStr(ih, "SELECTION", NULL);
+ }
+ else
+ {
+ char* selectionpos = iupAttribGet(formattag, "SELECTIONPOS");
+ if (selectionpos)
+ {
+ /* In Windows, the format message use the current selection */
+ winTextSetSelectionPosAttrib(ih, selectionpos);
+ iupAttribSetStr(ih, "SELECTIONPOS", NULL);
+ }
+ }
+
+ if (iupAttribGet(formattag, "FONTSCALE") && !iupAttribGet(formattag, "FONTSIZE"))
+ iupAttribSetStr(formattag, "FONTSIZE", iupGetFontSizeAttrib(ih));
+
+ winTextParseParagraphFormat(formattag, &paraformat, convert2twips);
+ if (paraformat.dwMask != 0)
+ SendMessage(ih->handle, EM_SETPARAFORMAT, 0, (LPARAM)&paraformat);
+
+ winTextParseCharacterFormat(formattag, &charformat, pixel2twips);
+ if (charformat.dwMask != 0)
+ SendMessage(ih->handle, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charformat);
+
+ /* reset the selection, if changed here */
+ if (selection)
+ winTextSetSelectionAttrib(ih, NULL);
+}
+
+static int winTextSetRemoveFormattingAttrib(Ihandle* ih, const char* value)
+{
+ PARAFORMAT2 paraformat;
+ CHARFORMAT2 charformat;
+ COLORREF colorref;
+ int val;
+
+ if (!ih->data->has_formatting)
+ return 0;
+
+ ZeroMemory(&paraformat, sizeof(PARAFORMAT2));
+ paraformat.cbSize = sizeof(PARAFORMAT2);
+ paraformat.dwMask = PFM_NUMBERING|PFM_STARTINDENT|PFM_RIGHTINDENT|PFM_OFFSET|
+ PFM_ALIGNMENT|PFM_SPACEBEFORE|PFM_SPACEAFTER|PFM_LINESPACING;
+ paraformat.wAlignment = PFA_LEFT;
+
+ ZeroMemory(&charformat, sizeof(CHARFORMAT2));
+ charformat.cbSize = sizeof(CHARFORMAT2);
+ charformat.dwMask = CFM_DISABLED|CFM_OFFSET|CFM_ITALIC|CFM_STRIKEOUT|CFM_PROTECTED|
+ CFM_UNDERLINETYPE|CFM_UNDERLINE|CFM_WEIGHT|CFM_FACE;
+ charformat.wWeight = FW_NORMAL;
+ strcpy(charformat.szFaceName, iupGetFontFaceAttrib(ih));
+
+ if (iupwinGetColorRef(ih, "FGCOLOR", &colorref))
+ {
+ charformat.dwMask |= CFM_COLOR;
+ charformat.crTextColor = colorref;
+ }
+
+ if (iupwinGetColorRef(ih, "BGCOLOR", &colorref))
+ {
+ charformat.dwMask |= CFM_BACKCOLOR;
+ charformat.crBackColor = colorref;
+ }
+
+ if (iupStrToInt(iupGetFontSizeAttrib(ih), &val))
+ {
+ /* (1/1440 of an inch, or 1/20 of a printer's point) */
+ charformat.dwMask |= CFM_SIZE;
+ if (val < 0) /* in pixels */
+ {
+ int pixel2twips = 1440/iupwinGetScreenRes();
+ charformat.yHeight = (-val)*pixel2twips;
+ }
+ else
+ charformat.yHeight = val*20;
+ }
+
+ SendMessage(ih->handle, EM_SETPARAFORMAT, 0, (LPARAM)&paraformat);
+ SendMessage(ih->handle, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charformat);
+
+ (void)value;
+ return 0;
+}
+
+static int winTextSetOverwriteAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_formatting)
+ return 0;
+
+ if (iupAttribGetBoolean(ih, "OVERWRITE"))
+ {
+ if (!iupStrBoolean(value))
+ SendMessage(ih->handle, WM_KEYDOWN, VK_INSERT, 0); /* toggle from ON to OFF */
+ }
+ else
+ {
+ if (iupStrBoolean(value))
+ SendMessage(ih->handle, WM_KEYDOWN, VK_INSERT, 0); /* toggle from OFF to ON */
+ }
+ return 1;
+}
+
+
+static int winTextSetVisibleAttrib(Ihandle* ih, const char* value)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ ShowWindow(hSpin, iupStrBoolean(value)? SW_SHOWNORMAL: SW_HIDE);
+
+ return iupBaseSetVisibleAttrib(ih, value);
+}
+
+static void winTextCropSpinValue(HWND hSpin, int min, int max)
+{
+ /* refresh if internally cropped, but text still shows an invalid value */
+ int pos = SendMessage(hSpin, UDM_GETPOS32, 0, 0);
+ if (pos <= min)
+ SendMessage(hSpin, UDM_SETPOS32, 0, min);
+ if (pos >= max)
+ SendMessage(hSpin, UDM_SETPOS32, 0, max);
+}
+
+static int winTextSetSpinMinAttrib(Ihandle* ih, const char* value)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ int min;
+ if (iupStrToInt(value, &min))
+ {
+ int max = iupAttribGetInt(ih, "SPINMAX");
+ SendMessage(hSpin, UDM_SETRANGE32, min, max);
+
+ winTextCropSpinValue(hSpin, min, max);
+ }
+ }
+ return 1;
+}
+
+static int winTextSetSpinMaxAttrib(Ihandle* ih, const char* value)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ int max;
+ if (iupStrToInt(value, &max))
+ {
+ int min = iupAttribGetInt(ih, "SPINMIN");
+ SendMessage(hSpin, UDM_SETRANGE32, min, max);
+
+ winTextCropSpinValue(hSpin, min, max);
+ }
+ }
+ return 1;
+}
+
+static int winTextSetSpinIncAttrib(Ihandle* ih, const char* value)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ int inc;
+ if (iupStrToInt(value, &inc))
+ {
+ UDACCEL paAccels[3];
+ paAccels[0].nInc = inc;
+ paAccels[0].nSec = 0;
+ paAccels[1].nInc = inc*5;
+ paAccels[1].nSec = 2;
+ paAccels[2].nInc = inc*20;
+ paAccels[2].nSec = 5;
+ SendMessage(hSpin, UDM_SETACCEL, 3, (LPARAM)paAccels);
+ }
+ }
+ return 1;
+}
+
+static int winTextSetSpinValueAttrib(Ihandle* ih, const char* value)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ int pos;
+ if (iupStrToInt(value, &pos))
+ SendMessage(hSpin, UDM_SETPOS32, 0, pos);
+ }
+ return 1;
+}
+
+static char* winTextGetSpinValueAttrib(Ihandle* ih)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ int pos = SendMessage(hSpin, UDM_GETPOS32, 0, 0);
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%d", pos);
+ return str;
+ }
+ return NULL;
+}
+
+
+/****************************************************************************************/
+
+
+static int winTextCtlColor(Ihandle* ih, HDC hdc, LRESULT *result)
+{
+ COLORREF cr;
+
+ if (iupwinGetColorRef(ih, "FGCOLOR", &cr))
+ SetTextColor(hdc, cr);
+
+ if (iupwinGetColorRef(ih, "BGCOLOR", &cr))
+ {
+ SetBkColor(hdc, cr);
+ SetDCBrushColor(hdc, cr);
+ *result = (LRESULT)GetStockObject(DC_BRUSH);
+ return 1;
+ }
+ return 0;
+}
+
+static void winTextCallCaretCb(Ihandle* ih)
+{
+ int col, lin, pos;
+
+ IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB");
+ if (!cb) return;
+
+ pos = winTextGetCaret(ih, &lin, &col);
+
+ if (pos != ih->data->last_caret_pos)
+ {
+ ih->data->last_caret_pos = pos;
+
+ cb(ih, lin, col, pos);
+ }
+}
+
+static int winTextCallActionCb(Ihandle* ih, const char* insert_value, int key, int dir)
+{
+ int start, end, ret = 1;
+ char *value, *new_value;
+
+ IFnis cb = (IFnis)IupGetCallback(ih, "ACTION");
+ if (!cb && !ih->data->mask)
+ return 1;
+
+ winTextGetSelection(ih, &start, &end);
+
+ value = winTextGetValueAttrib(ih);
+
+ if (value[0]==0)
+ new_value = iupStrDup(insert_value);
+ else if (insert_value)
+ new_value = iupStrInsert(value, insert_value, start, end);
+ else
+ {
+ new_value = value;
+ iupStrRemove(value, start, end, dir);
+ }
+
+ if (!new_value)
+ return 0; /* abort */
+
+ if (ih->data->nc && (int)strlen(new_value) > ih->data->nc)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (cb)
+ {
+ int cb_ret = cb(ih, key, (char*)new_value);
+ if (cb_ret==IUP_IGNORE)
+ ret = 0; /* abort processing */
+ else if (cb_ret==IUP_CLOSE)
+ {
+ IupExitLoop();
+ ret = 0; /* abort processing */
+ }
+ else if (cb_ret!=0 && key!=0 &&
+ cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE)
+ {
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB");
+ CallWindowProc(oldProc, ih->handle, WM_CHAR, cb_ret, 0); /* replace key */
+ ret = 0; /* abort processing */
+ }
+ }
+
+ if (new_value != value) free(new_value);
+ return ret;
+}
+
+static int winTextSpinWmNotify(Ihandle* ih, NMHDR* msg_info, int *result)
+{
+ if (msg_info->code == UDN_DELTAPOS)
+ {
+ NMUPDOWN *updown = (NMUPDOWN*)msg_info;
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ int pos = updown->iPos+updown->iDelta;
+ int min, max;
+ SendMessage(hSpin, UDM_GETRANGE32, (WPARAM)&min, (LPARAM)&max);
+ if (pos>=min && pos<=max)
+ {
+ IFni cb = (IFni) IupGetCallback(ih, "SPIN_CB");
+ if (cb)
+ {
+ int ret = cb(ih, pos);
+ if (ret == IUP_IGNORE)
+ {
+ *result = 1;
+ return 1;
+ }
+ }
+ }
+ }
+
+ (void)result;
+ return 0; /* result not used */
+}
+
+static int winTextProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ int ret = 0;
+
+ if (msg==WM_KEYDOWN) /* process K_ANY before text callbacks */
+ {
+ ret = iupwinBaseProc(ih, msg, wp, lp, result);
+ if (ret)
+ {
+ *result = 0;
+ return 1;
+ }
+ }
+
+ switch (msg)
+ {
+ case WM_CHAR:
+ {
+ if ((char)wp == '\b')
+ {
+ if (!winTextCallActionCb(ih, NULL, 0, -1))
+ ret = 1;
+ }
+ else if ((char)wp == '\n' || (char)wp == '\r')
+ {
+ if (!ih->data->has_formatting && !(GetKeyState(VK_CONTROL) & 0x8000)) /* when formatting is processed in WM_KEYDOWN */
+ {
+ char insert_value[2];
+ insert_value[0] = '\n';
+ insert_value[1] = 0;
+
+ if (!winTextCallActionCb(ih, insert_value, wp, 1))
+ ret = 1;
+ }
+ }
+ else if (!(GetKeyState(VK_CONTROL) & 0x8000 ||
+ GetKeyState(VK_MENU) & 0x8000 ||
+ GetKeyState(VK_LWIN) & 0x8000 ||
+ GetKeyState(VK_RWIN) & 0x8000))
+ {
+ char insert_value[2];
+ insert_value[0] = (char)wp;
+ insert_value[1] = 0;
+
+ if (!winTextCallActionCb(ih, insert_value, wp, 1))
+ ret = 1;
+ }
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+
+ if (!ih->data->is_multiline &&
+ (wp==VK_RETURN || wp==VK_ESCAPE || wp==VK_TAB)) /* the keys have the same definitions as the chars */
+ ret = 1; /* abort default processing to avoid beep */
+
+ if (ih->data->is_multiline &&
+ (wp=='\n' && (GetKeyState(VK_CONTROL) & 0x8000)))
+ ret = 1; /* abort default processing to avoid inserting a new line */
+
+ break;
+ }
+ case WM_KEYDOWN:
+ {
+ if (wp == VK_DELETE) /* Del does not generates a WM_CHAR */
+ {
+ if (!winTextCallActionCb(ih, NULL, 0, 1))
+ ret = 1;
+ }
+ else if (wp == VK_INSERT && ih->data->has_formatting)
+ {
+ if (iupAttribGetBoolean(ih, "OVERWRITE"))
+ iupAttribSetStr(ih, "OVERWRITE", "OFF"); /* toggle from ON to OFF */
+ else
+ iupAttribSetStr(ih, "OVERWRITE", "ON"); /* toggle from OFF to ON */
+ }
+ else if (wp == 'A' && GetKeyState(VK_CONTROL) & 0x8000) /* Ctrl+A = Select All */
+ {
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ }
+ else if (wp == VK_RETURN && ih->data->has_formatting && !(GetKeyState(VK_CONTROL) & 0x8000))
+ {
+ char insert_value[2];
+ insert_value[0] = '\n';
+ insert_value[1] = 0;
+
+ if (!winTextCallActionCb(ih, insert_value, '\n', 1))
+ ret = 1;
+ }
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+
+ if (ret) /* if abort processing, then the result is 0 */
+ {
+ *result = 0;
+ return 1;
+ }
+ else
+ return 0; /* already processed at the begining of this function */
+ }
+ case WM_KEYUP:
+ {
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_CLEAR:
+ {
+ if (!winTextCallActionCb(ih, NULL, 0, 1))
+ ret = 1;
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_CUT:
+ {
+ if (!winTextCallActionCb(ih, NULL, 0, 1))
+ ret = 1;
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_PASTE:
+ {
+ if (IupGetCallback(ih,"ACTION") || ih->data->mask) /* test before to avoid alocate clipboard text memory */
+ {
+ char* insert_value = iupwinGetClipboardText(ih);
+ if (insert_value)
+ {
+ if (!winTextCallActionCb(ih, insert_value, 0, 1))
+ ret = 1;
+ free(insert_value);
+ }
+ }
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_UNDO:
+ {
+ IFnis cb = (IFnis)IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ char* value;
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB");
+ CallWindowProc(oldProc, ih->handle, WM_UNDO, 0, 0);
+
+ value = winTextGetValueAttrib(ih);
+ cb(ih, 0, (char*)value);
+
+ ret = 1;
+ }
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ {
+ if (iupwinButtonDown(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONUP:
+ {
+ if (iupwinButtonUp(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_CARET:
+ {
+ winTextCallCaretCb(ih);
+ break;
+ }
+ case WM_MOUSEMOVE:
+ {
+ iupwinMouseMove(ih, msg, wp, lp);
+ break;
+ }
+ case WM_VSCROLL:
+ case WM_HSCROLL:
+ {
+ if (ih->data->has_formatting)
+ {
+ /* fix weird behavior when dialog has COMPOSITE=YES,
+ scrollbars are not updated when dragging */
+ if (LOWORD(wp) == SB_THUMBTRACK)
+ SendMessage(ih->handle, EM_SHOWSCROLLBAR, msg==WM_VSCROLL? SB_VERT: SB_HORZ, TRUE);
+ }
+ break;
+ }
+ }
+
+ if (ret) /* if abort processing, then the result is 0 */
+ {
+ *result = 0;
+ return 1;
+ }
+ else
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+static void winTextCreateSpin(Ihandle* ih)
+{
+ HWND hSpin;
+ DWORD dwStyle = WS_CHILD|UDS_ARROWKEYS|UDS_HOTTRACK|UDS_NOTHOUSANDS;
+ int serial = iupDialogGetChildId(ih);
+
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT"))
+ dwStyle |= UDS_ALIGNLEFT;
+ else
+ dwStyle |= UDS_ALIGNRIGHT;
+
+ if (iupAttribGetBoolean(ih, "SPINWRAP"))
+ dwStyle |= UDS_WRAP;
+
+ if (iupAttribGetBoolean(ih, "SPINAUTO"))
+ dwStyle |= UDS_SETBUDDYINT;
+
+ hSpin = CreateWindowEx(0, /* extended window style */
+ UPDOWN_CLASS, /* window class */
+ NULL, /* title */
+ dwStyle, /* window style */
+ 0, /* x-position */
+ 0, /* y-position */
+ 10, /* default width to avoid 0 */
+ 10, /* default height to avoid 0 */
+ GetParent(ih->handle), /* window parent */
+ (HMENU)serial, /* child identifier */
+ iupwin_hinstance, /* instance of app. */
+ NULL);
+
+ if (!hSpin)
+ return;
+
+ iupwinHandleAdd(ih, hSpin);
+
+ /* Process WM_NOTIFY */
+ IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTextSpinWmNotify);
+
+ SendMessage(hSpin, UDM_SETBUDDY, (WPARAM)ih->handle, 0);
+ iupAttribSetStr(ih, "_IUPWIN_SPIN", (char*)hSpin);
+
+ /* default values */
+ SendMessage(hSpin, UDM_SETRANGE32, 0, 100);
+ SendMessage(hSpin, UDM_SETPOS32, 0, 0);
+}
+
+static int winTextWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp)
+{
+ int cmd = HIWORD(wp);
+ switch (cmd)
+ {
+ case EN_CHANGE:
+ {
+ if (iupAttribGetStr(ih, "IUPWIN_IGNORECHANGE"))
+ return 0;
+
+ iupBaseCallValueChangedCb(ih);
+ break;
+ }
+ }
+
+ (void)lp;
+ return 0; /* not used */
+}
+
+static void winTextLayoutUpdateMethod(Ihandle* ih)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT"))
+ {
+ SetWindowPos(ih->handle, NULL, ih->x+ih->currentheight-1, ih->y, ih->currentwidth-ih->currentheight, ih->currentheight,
+ SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
+
+ SetWindowPos(hSpin, NULL, ih->x, ih->y, ih->currentheight, ih->currentheight,
+ SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
+ }
+ else
+ {
+ SetWindowPos(ih->handle, NULL, ih->x, ih->y, ih->currentwidth-ih->currentheight, ih->currentheight,
+ SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
+
+ SetWindowPos(hSpin, NULL, ih->x+ih->currentwidth-ih->currentheight-1, ih->y, ih->currentheight, ih->currentheight,
+ SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
+ }
+ }
+ else
+ iupdrvBaseLayoutUpdateMethod(ih);
+}
+
+static int winTextMapMethod(Ihandle* ih)
+{
+ DWORD dwStyle = WS_CHILD,
+ dwExStyle = 0;
+ char* winclass = "EDIT", *value;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ if (ih->data->has_formatting)
+ {
+ /* enable richedit 3.0 */
+ static HMODULE richedit = NULL;
+ if (!richedit)
+ richedit = LoadLibrary("Riched20.dll");
+ if (!richedit)
+ return IUP_ERROR;
+
+ winclass = RICHEDIT_CLASS;
+ }
+
+ if (ih->data->is_multiline)
+ {
+ dwStyle |= ES_AUTOVSCROLL|ES_MULTILINE|ES_WANTRETURN;
+
+ if (iupAttribGetBoolean(ih, "WORDWRAP"))
+ {
+ ih->data->sb &= ~IUP_SB_HORIZ; /* must remove the horizontal scroolbar */
+ /* and do not specify ES_AUTOHSCROLL, the control automatically wraps words */
+ }
+ else
+ dwStyle |= ES_AUTOHSCROLL;
+
+ if (ih->data->sb & IUP_SB_HORIZ)
+ dwStyle |= WS_HSCROLL;
+ if (ih->data->sb & IUP_SB_VERT)
+ dwStyle |= WS_VSCROLL;
+
+ if (ih->data->has_formatting && ih->data->sb != IUP_SB_NONE)
+ {
+ if (!iupAttribGetBoolean(ih, "AUTOHIDE"))
+ dwStyle |= ES_DISABLENOSCROLL;
+ }
+ }
+ else
+ {
+ dwStyle |= ES_AUTOHSCROLL|ES_NOHIDESEL;
+
+ if (iupAttribGetBoolean(ih, "PASSWORD"))
+ dwStyle |= ES_PASSWORD;
+ }
+
+ value = iupAttribGet(ih, "ALIGNMENT");
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "ARIGHT"))
+ dwStyle |= ES_RIGHT;
+ else if (iupStrEqualNoCase(value, "ACENTER"))
+ dwStyle |= ES_CENTER;
+ else /* default "ALEFT" */
+ dwStyle |= ES_LEFT;
+ }
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ dwExStyle |= WS_EX_CLIENTEDGE;
+
+ if (!iupwinCreateWindowEx(ih, winclass, dwExStyle, dwStyle))
+ return IUP_ERROR;
+
+ /* Process ACTION_CB and CARET_CB */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTextProc);
+
+ /* Process background color */
+ IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winTextCtlColor);
+
+ /* Process WM_COMMAND */
+ IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winTextWmCommand);
+
+ /* set defaults */
+ SendMessage(ih->handle, EM_LIMITTEXT, 0, 0L);
+ {
+ int tabsize = 8*4;
+ SendMessage(ih->handle, EM_SETTABSTOPS, (WPARAM)1L, (LPARAM)&tabsize);
+ }
+
+ if (!ih->data->is_multiline && iupAttribGetBoolean(ih, "SPIN"))
+ winTextCreateSpin(ih);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ if (ih->data->has_formatting)
+ {
+ SendMessage(ih->handle, EM_SETTEXTMODE, (WPARAM)(TM_RICHTEXT|TM_MULTILEVELUNDO|TM_SINGLECODEPAGE), 0);
+ SendMessage(ih->handle, EM_SETEVENTMASK, 0, ENM_CHANGE);
+ }
+
+ if (ih->data->formattags)
+ {
+ /* must update FONT before updating the format during map */
+ iupUpdateStandardFontAttrib(ih);
+ iupAttribSetStr(ih, "_IUPWIN_IGNORE_FONT", "1");
+
+ iupTextUpdateFormatTags(ih);
+ }
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winTextConvertXYToPos);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTextInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winTextMapMethod;
+ ic->LayoutUpdate = winTextLayoutUpdateMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ 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);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED); /* usually black */
+
+ /* IupText only */
+ iupClassRegisterAttribute(ic, "PADDING", iupTextGetPaddingAttrib, winTextSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "VALUE", winTextGetValueAttrib, winTextSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTEDTEXT", winTextGetSelectedTextAttrib, winTextSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTION", winTextGetSelectionAttrib, winTextSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTIONPOS", winTextGetSelectionPosAttrib, winTextSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARET", winTextGetCaretAttrib, winTextSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARETPOS", winTextGetCaretPosAttrib, winTextSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INSERT", NULL, winTextSetInsertAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPEND", NULL, winTextSetAppendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "READONLY", winTextGetReadOnlyAttrib, winTextSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "NC", iupTextGetNCAttrib, winTextSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, winTextSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTO", NULL, winTextSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, winTextSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINMIN", NULL, winTextSetSpinMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINMAX", NULL, winTextSetSpinMaxAttrib, IUPAF_SAMEASSYSTEM, "100", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPININC", NULL, winTextSetSpinIncAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINVALUE", winTextGetSpinValueAttrib, winTextSetSpinValueAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT);
+
+ /* IupText Windows and GTK only */
+ iupClassRegisterAttribute(ic, "ADDFORMATTAG", NULL, iupTextSetAddFormatTagAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ADDFORMATTAG_HANDLE", NULL, iupTextSetAddFormatTagHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, winTextSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FORMATTING", iupTextGetFormattingAttrib, iupTextSetFormattingAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "OVERWRITE", NULL, winTextSetOverwriteAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "REMOVEFORMATTING", NULL, winTextSetRemoveFormattingAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TABSIZE", NULL, winTextSetTabSizeAttrib, IUPAF_SAMEASSYSTEM, "8", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "PASSWORD", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ /* IupText Windows only */
+ iupClassRegisterAttribute(ic, "CUEBANNER", NULL, winTextSetCueBannerAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTER", NULL, winTextSetFilterAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_timer.c b/iup/src/win/iupwin_timer.c
new file mode 100755
index 0000000..f2bb9c5
--- /dev/null
+++ b/iup/src/win/iupwin_timer.c
@@ -0,0 +1,88 @@
+/** \file
+ * \brief Timer for the Windows Driver.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_assert.h"
+#include "iup_timer.h"
+
+
+static Itable* wintimer_id_table = NULL; /* table indexed by ID containing Ihandle* address */
+
+static void CALLBACK winTimerProc(HWND hwnd, UINT msg, UINT_PTR wid, DWORD time)
+{
+ Icallback cb;
+ Ihandle *ih;
+
+ (void)time;
+ (void)msg;
+ (void)hwnd;
+
+ ih = (Ihandle*)iupTableGet(wintimer_id_table, (char*)wid);
+
+ if (!iupObjectCheck(ih)) /* control could be destroyed before timer callback */
+ return;
+
+ cb = IupGetCallback(ih, "ACTION_CB");
+ if(cb)
+ {
+ if (cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+ }
+}
+
+void iupdrvTimerRun(Ihandle *ih)
+{
+ unsigned int time_ms;
+
+ if (ih->serial > 0) /* timer already started */
+ return;
+
+ time_ms = iupAttribGetInt(ih, "TIME");
+ if (time_ms > 0)
+ {
+ ih->serial = SetTimer(NULL, 0, time_ms, (TIMERPROC)winTimerProc);
+ iupTableSet(wintimer_id_table, (const char*)ih->serial, ih, IUPTABLE_POINTER);
+ }
+}
+
+void iupdrvTimerStop(Ihandle* ih)
+{
+ if (ih->serial > 0)
+ {
+ KillTimer(NULL, ih->serial);
+ iupTableRemove(wintimer_id_table, (const char*)ih->serial);
+ ih->serial = -1;
+ }
+}
+
+static void winTimerRelease(Iclass* ic)
+{
+ (void)ic;
+
+ if (wintimer_id_table)
+ {
+ iupTableDestroy(wintimer_id_table);
+ wintimer_id_table = NULL;
+ }
+}
+
+void iupdrvTimerInitClass(Iclass* ic)
+{
+ ic->Release = winTimerRelease;
+
+ if (!wintimer_id_table)
+ wintimer_id_table = iupTableCreate(IUPTABLE_POINTERINDEXED);
+}
diff --git a/iup/src/win/iupwin_tips.c b/iup/src/win/iupwin_tips.c
new file mode 100755
index 0000000..f717ace
--- /dev/null
+++ b/iup/src/win/iupwin_tips.c
@@ -0,0 +1,191 @@
+/** \file
+ * \brief Windows Driver TIPS management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+
+
+#ifndef TTM_POPUP /* it is defined only when _WIN32_WINNT >= 0x0501 */
+#define TTM_POPUP (WM_USER + 34)
+#endif
+
+static HWND winTipsCreate(HWND hParent)
+{
+ RECT rect = {1,1,1,1};
+ HWND tips_hwnd = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, (LPSTR) NULL, TTS_ALWAYSTIP,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ hParent, (HMENU)NULL, iupwin_hinstance, NULL);
+ SendMessage(tips_hwnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)(INT)3000);
+ SendMessage(tips_hwnd, TTM_SETMARGIN, (WPARAM)0, (LPARAM)&rect);
+ return tips_hwnd;
+}
+
+static int winTipsSendMessage(Ihandle* ih, HWND tips_hwnd, UINT msg)
+{
+ TOOLINFO ti;
+ ZeroMemory(&ti, sizeof(TOOLINFO));
+ ti.cbSize = sizeof(TOOLINFO);
+ ti.uFlags = TTF_SUBCLASS;
+ ti.hinst = iupwin_hinstance;
+ ti.uId = 0;
+ ti.hwnd = ih->handle;
+ ti.lpszText = LPSTR_TEXTCALLBACK;
+ ti.rect.right = 3000;
+ ti.rect.bottom = 3000;
+
+ return SendMessage(tips_hwnd, msg, 0, (LPARAM)&ti);
+}
+
+int iupdrvBaseSetTipAttrib(Ihandle* ih, const char* value)
+{
+ HWND tips_hwnd = (HWND)iupAttribGet(ih, "_IUPWIN_TIPSWIN");
+ if (!tips_hwnd)
+ {
+ tips_hwnd = winTipsCreate(ih->handle);
+ iupAttribSetStr(ih, "_IUPWIN_TIPSWIN", (char*)tips_hwnd);
+ iupwinHandleAdd(ih, tips_hwnd);
+ }
+
+ if (value)
+ winTipsSendMessage(ih, tips_hwnd, TTM_ADDTOOL);
+ else
+ winTipsSendMessage(ih, tips_hwnd, TTM_DELTOOL);
+
+ return 1;
+}
+
+int iupdrvBaseSetTipVisibleAttrib(Ihandle* ih, const char* value)
+{
+ HWND tips_hwnd = (HWND)iupAttribGet(ih, "_IUPWIN_TIPSWIN");
+ if (!tips_hwnd)
+ return 0;
+
+ /* must use IupGetAttribute to use inheritance */
+ if (!IupGetAttribute(ih, "TIP"))
+ return 0;
+
+ if (iupStrBoolean(value))
+ SendMessage(tips_hwnd, TTM_POPUP, 0, 0); /* XP Only */
+ else
+ SendMessage(tips_hwnd, TTM_POP, 0, 0);
+
+ return 0;
+}
+
+void iupwinTipsGetDispInfo(LPARAM lp)
+{
+ COLORREF color, tip_color;
+ NMTTDISPINFO* tips_info;
+ Ihandle* ih;
+ HWND tips_hwnd;
+ char* value;
+
+ if (!lp) return;
+
+ tips_info = (NMTTDISPINFO*)lp;
+ ih = iupwinHandleGet(tips_info->hdr.hwndFrom); /* hwndFrom is the tooltip window */
+ if (!ih) return;
+
+ tips_hwnd = (HWND)iupAttribGet(ih, "_IUPWIN_TIPSWIN");
+ if (tips_hwnd != tips_info->hdr.hwndFrom) return;
+
+ tips_info->hinst = NULL;
+ tips_info->lpszText = IupGetAttribute(ih, "TIP"); /* must use IupGetAttribute to use inheritance */
+
+ {
+ HFONT hfont;
+ value = iupAttribGetStr(ih, "TIPFONT");
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "SYSTEM"))
+ hfont = NULL;
+ else
+ hfont = iupwinGetHFont(value);
+ }
+ else
+ hfont = (HFONT)iupwinGetHFontAttrib(ih);
+
+ if (hfont)
+ {
+ HFONT tip_hfont = (HFONT)SendMessage(tips_hwnd, WM_GETFONT, 0, 0);
+ if (tip_hfont != hfont)
+ SendMessage(tips_hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE,0));
+ }
+ }
+
+ iupwinGetColorRef(ih, "TIPBGCOLOR", &color);
+ tip_color = (COLORREF)SendMessage(tips_hwnd, TTM_GETTIPBKCOLOR, 0, 0);
+ if (color != tip_color)
+ SendMessage(tips_hwnd, TTM_SETTIPBKCOLOR, (WPARAM)color, 0);
+
+ iupwinGetColorRef(ih, "TIPFGCOLOR", &color);
+ tip_color = (COLORREF)SendMessage(tips_hwnd, TTM_GETTIPTEXTCOLOR, 0, 0);
+ if (color != tip_color)
+ SendMessage(tips_hwnd, TTM_SETTIPTEXTCOLOR, (WPARAM)color, 0);
+
+ {
+ int ballon = IupGetInt(ih, "TIPBALLON"); /* must use IupGetInt to use inheritance */
+ DWORD style = GetWindowLong(tips_hwnd, GWL_STYLE);
+ int tip_ballon = style & TTS_BALLOON? 1: 0;
+ if (tip_ballon != ballon)
+ {
+ if (ballon)
+ style |= TTS_BALLOON;
+ else
+ style &= ~TTS_BALLOON;
+ SetWindowLong(tips_hwnd, GWL_STYLE, style);
+ }
+
+ if (ballon)
+ {
+ char* ballon_title = IupGetAttribute(ih, "TIPBALLONTITLE"); /* must use IupGetAttribute to use inheritance */
+ int ballon_icon = IupGetInt(ih, "TIPBALLONTITLEICON"); /* must use IupGetInt to use inheritance */
+ SendMessage(tips_hwnd, TTM_SETTITLEA, ballon_icon, (LPARAM)ballon_title);
+ }
+ else
+ SendMessage(tips_hwnd, TTM_SETTITLEA, 0, 0);
+ }
+
+ {
+ int delay = IupGetInt(ih, "TIPDELAY"); /* must use IupGetInt to use inheritance */
+ int tip_delay = SendMessage(tips_hwnd, TTM_GETDELAYTIME, TTDT_AUTOPOP, 0);
+ if (delay != tip_delay)
+ SendMessage(tips_hwnd, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM)MAKELONG(delay, 0));
+ }
+
+ {
+ TOOLINFO ti;
+
+ ZeroMemory(&ti, sizeof(TOOLINFO));
+ ti.cbSize = sizeof(TOOLINFO);
+ ti.uId = 0;
+ ti.hwnd = ih->handle;
+
+ value = iupAttribGet(ih, "TIPRECT");
+ if (value)
+ {
+ int x1, x2, y1, y2;
+ sscanf(value, "%d %d %d %d", &x1, &y1, &x2, &y2);
+ ti.rect.left = x1; ti.rect.right = x2;
+ ti.rect.top = y1; ti.rect.bottom = y2;
+ }
+ else
+ GetClientRect(ih->handle, &ti.rect);
+
+ SendMessage(tips_hwnd, TTM_NEWTOOLRECT, 0, (LPARAM)&ti);
+ }
+}
diff --git a/iup/src/win/iupwin_toggle.c b/iup/src/win/iupwin_toggle.c
new file mode 100755
index 0000000..fcaa438
--- /dev/null
+++ b/iup/src/win/iupwin_toggle.c
@@ -0,0 +1,693 @@
+/** \file
+ * \brief Toggle Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_toggle.h"
+#include "iup_drv.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+
+
+#ifndef CDIS_SHOWKEYBOARDCUES
+#define CDIS_SHOWKEYBOARDCUES 0x0200 /* it is defined only when _WIN32_WINNT >= 0x0501 */
+#endif
+
+
+void iupdrvToggleAddCheckBox(int *x, int *y)
+{
+ (*x) += 16+6;
+ if ((*y) < 16) (*y) = 16; /* minimum height */
+}
+
+static int winToggleIsActive(Ihandle* ih)
+{
+ return iupAttribGetInt(ih, "_IUPWIN_ACTIVE");
+}
+
+static void winToggleSetBitmap(Ihandle* ih, const char* name, int make_inactive)
+{
+ if (name)
+ {
+ HBITMAP bitmap = iupImageGetImage(name, ih, make_inactive);
+ SendMessage(ih->handle, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)bitmap);
+ }
+ else
+ SendMessage(ih->handle, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)NULL); /* if not defined */
+}
+
+static void winToggleUpdateImage(Ihandle* ih, int active, int check)
+{
+ /* called only when (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6) */
+ char* name;
+
+ if (!active)
+ {
+ name = iupAttribGet(ih, "IMINACTIVE");
+ if (name)
+ winToggleSetBitmap(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ winToggleSetBitmap(ih, name, 1); /* make_inactive */
+ }
+ }
+ else
+ {
+ /* must restore the normal image */
+ if (check)
+ {
+ name = iupAttribGet(ih, "IMPRESS");
+ if (name)
+ winToggleSetBitmap(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ winToggleSetBitmap(ih, name, 0);
+ }
+ }
+ else
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ if (name)
+ winToggleSetBitmap(ih, name, 0);
+ }
+ }
+}
+
+static void winToggleGetAlignment(Ihandle* ih, int *horiz_alignment, int *vert_alignment)
+{
+ char value1[30]="", value2[30]="";
+
+ iupStrToStrStr(iupAttribGetStr(ih, "ALIGNMENT"), value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ *horiz_alignment = IUP_ALIGN_ARIGHT;
+ else if (iupStrEqualNoCase(value1, "ALEFT"))
+ *horiz_alignment = IUP_ALIGN_ALEFT;
+ else /* "ACENTER" */
+ *horiz_alignment = IUP_ALIGN_ACENTER;
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ *vert_alignment = IUP_ALIGN_ABOTTOM;
+ else if (iupStrEqualNoCase(value2, "ATOP"))
+ *vert_alignment = IUP_ALIGN_ATOP;
+ else /* "ACENTER" */
+ *vert_alignment = IUP_ALIGN_ACENTER;
+}
+
+static void winToggleDrawImage(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState)
+{
+ int xpad = ih->data->horiz_padding + border,
+ ypad = ih->data->vert_padding + border;
+ int horiz_alignment, vert_alignment;
+ int x, y, width, height, bpp, shift = 1;
+ HBITMAP hBitmap, hMask = NULL;
+ char *name;
+ int make_inactive = 0;
+
+ if (itemState & ODS_DISABLED)
+ {
+ name = iupAttribGet(ih, "IMINACTIVE");
+ if (!name)
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ make_inactive = 1;
+ }
+ }
+ else
+ {
+ name = iupAttribGet(ih, "IMPRESS");
+ if (itemState & ODS_SELECTED && name)
+ shift = 0;
+ else
+ name = iupAttribGet(ih, "IMAGE");
+ }
+
+ hBitmap = iupImageGetImage(name, ih, make_inactive);
+ if (!hBitmap)
+ return;
+
+ /* must use this info, since image can be a driver image loaded from resources */
+ iupdrvImageGetInfo(hBitmap, &width, &height, &bpp);
+
+ winToggleGetAlignment(ih, &horiz_alignment, &vert_alignment);
+ if (horiz_alignment == IUP_ALIGN_ARIGHT)
+ x = rect_width - (width + 2*xpad);
+ else if (horiz_alignment == IUP_ALIGN_ACENTER)
+ x = (rect_width - (width + 2*xpad))/2;
+ else /* ALEFT */
+ x = 0;
+
+ if (vert_alignment == IUP_ALIGN_ABOTTOM)
+ y = rect_height - (height + 2*ypad);
+ else if (vert_alignment == IUP_ALIGN_ATOP)
+ y = 0;
+ else /* ACENTER */
+ y = (rect_height - (height + 2*ypad))/2;
+
+ x += xpad;
+ y += ypad;
+
+ if (itemState & ODS_SELECTED && !iupwin_comctl32ver6 && shift)
+ {
+ x++;
+ y++;
+ }
+
+ if (bpp == 8)
+ hMask = iupdrvImageCreateMask(IupGetHandle(name));
+
+ iupwinDrawBitmap(hDC, hBitmap, hMask, x, y, width, height, bpp);
+
+ if (hMask)
+ DeleteObject(hMask);
+}
+
+static void winToggleDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem)
+{
+ int width, height, border = 4, check;
+ HDC hDC;
+ iupwinBitmapDC bmpDC;
+
+ width = drawitem->rcItem.right - drawitem->rcItem.left;
+ height = drawitem->rcItem.bottom - drawitem->rcItem.top;
+
+ hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height);
+
+ iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem);
+
+ check = SendMessage(ih->handle, BM_GETCHECK, 0, 0L);
+ if (check)
+ drawitem->itemState |= ODS_SELECTED;
+ else
+ drawitem->itemState |= ODS_DEFAULT; /* use default mark for NOT checked */
+
+ iupwinDrawButtonBorder(ih->handle, hDC, &drawitem->rcItem, drawitem->itemState);
+
+ winToggleDrawImage(ih, hDC, width, height, border, drawitem->itemState);
+
+ if (drawitem->itemState & ODS_FOCUS)
+ {
+ border--;
+ iupdrvDrawFocusRect(ih, hDC, border, border, width-2*border, height-2*border);
+ }
+
+ iupwinDrawDestroyBitmapDC(&bmpDC);
+}
+
+
+/***********************************************************************************************/
+
+
+static int winToggleSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMAGE"))
+ iupAttribSetStr(ih, "IMAGE", (char*)value);
+
+ if (iupwin_comctl32ver6)
+ iupdrvDisplayRedraw(ih);
+ else
+ {
+ int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L);
+ winToggleUpdateImage(ih, winToggleIsActive(ih), check);
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winToggleSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMINACTIVE"))
+ iupAttribSetStr(ih, "IMINACTIVE", (char*)value);
+
+ if (iupwin_comctl32ver6)
+ iupdrvDisplayRedraw(ih);
+ else
+ {
+ int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L);
+ winToggleUpdateImage(ih, winToggleIsActive(ih), check);
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winToggleSetImPressAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMPRESS"))
+ iupAttribSetStr(ih, "IMPRESS", (char*)value);
+
+ if (iupwin_comctl32ver6)
+ iupdrvDisplayRedraw(ih);
+ else
+ {
+ int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L);
+ winToggleUpdateImage(ih, winToggleIsActive(ih), check);
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winToggleSetValueAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle *radio;
+ int check;
+
+ if (iupStrEqualNoCase(value,"NOTDEF"))
+ check = BST_INDETERMINATE;
+ else if (iupStrBoolean(value))
+ check = BST_CHECKED;
+ else
+ check = BST_UNCHECKED;
+
+ /* This is necessary because Windows does not handle the radio state
+ when a toggle is programatically changed. */
+ radio = iupRadioFindToggleParent(ih);
+ if (radio)
+ {
+ int oldcheck = (int)SendMessage(ih->handle, BM_GETCHECK, 0, 0L);
+
+ Ihandle* last_tg = (Ihandle*)iupAttribGet(radio, "_IUPWIN_LASTTOGGLE");
+ if (check)
+ {
+ if (iupObjectCheck(last_tg) && last_tg != ih)
+ SendMessage(last_tg->handle, BM_SETCHECK, BST_UNCHECKED, 0L);
+ iupAttribSetStr(radio, "_IUPWIN_LASTTOGGLE", (char*)ih);
+ }
+
+ if (last_tg != ih && oldcheck != check)
+ SendMessage(ih->handle, BM_SETCHECK, check, 0L);
+ }
+ else
+ SendMessage(ih->handle, BM_SETCHECK, check, 0L);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6)
+ winToggleUpdateImage(ih, winToggleIsActive(ih), check);
+
+ return 0;
+}
+
+static char* winToggleGetValueAttrib(Ihandle* ih)
+{
+ int check = (int)SendMessage(ih->handle, BM_GETCHECK, 0, 0L);
+ if (check == BST_INDETERMINATE)
+ return "NOTDEF";
+ else if (check == BST_CHECKED)
+ return "ON";
+ else
+ return "OFF";
+}
+
+static int winToggleSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ /* update the inactive image if necessary */
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (iupwin_comctl32ver6)
+ {
+ iupBaseSetActiveAttrib(ih, value);
+ iupdrvDisplayRedraw(ih);
+ return 0;
+ }
+ else
+ {
+ int active = iupStrBoolean(value);
+ int check = SendMessage(ih->handle, BM_GETCHECK, 0, 0L);
+ if (active)
+ iupAttribSetStr(ih, "_IUPWIN_ACTIVE", "YES");
+ else
+ iupAttribSetStr(ih, "_IUPWIN_ACTIVE", "NO");
+ winToggleUpdateImage(ih, active, check);
+ return 0;
+ }
+ }
+
+ return iupBaseSetActiveAttrib(ih, value);
+}
+
+static char* winToggleGetActiveAttrib(Ihandle* ih)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6)
+ return iupAttribGet(ih, "_IUPWIN_ACTIVE");
+ else
+ return iupBaseGetActiveAttrib(ih);
+}
+
+static int winToggleSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ {
+ if (!value)
+ value = "";
+ SetWindowText(ih->handle, value);
+ }
+ return 0;
+}
+
+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);
+
+ return 0;
+}
+
+static int winToggleSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ (void)value;
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ /* update internal image cache for controls that have the IMAGE attribute */
+ iupAttribSetStr(ih, "BGCOLOR", value);
+ iupImageUpdateParent(ih);
+ iupdrvDisplayRedraw(ih);
+ }
+ return 1;
+}
+
+static char* winToggleGetBgColorAttrib(Ihandle* ih)
+{
+ /* the most important use of this is to provide
+ the correct background for images */
+ if (iupwin_comctl32ver6 && ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ COLORREF cr;
+ if (iupwinDrawGetThemeButtonBgColor(ih->handle, &cr))
+ {
+ char* str = iupStrGetMemory(20);
+ sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr));
+ return str;
+ }
+ }
+
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ return iupBaseNativeParentGetBgColorAttrib(ih);
+ else
+ return IupGetGlobal("DLGBGCOLOR");
+}
+
+
+/****************************************************************************************/
+
+
+static int winToggleCtlColor(Ihandle* ih, HDC hdc, LRESULT *result)
+{
+ COLORREF cr;
+
+ SetBkMode(hdc, TRANSPARENT);
+
+ if (iupwinGetColorRef(ih, "FGCOLOR", &cr))
+ SetTextColor(hdc, cr);
+
+ if (iupwinGetParentBgColor(ih, &cr))
+ {
+ SetDCBrushColor(hdc, cr);
+ *result = (LRESULT)GetStockObject(DC_BRUSH);
+ return 1;
+ }
+ return 0;
+}
+
+static int winToggleWmNotify(Ihandle* ih, NMHDR* msg_info, int *result)
+{
+ if (msg_info->code == NM_CUSTOMDRAW)
+ {
+ /* called only when iupwin_comctl32ver6 AND (ih->data->type==IUP_TOGGLE_IMAGE) */
+ NMCUSTOMDRAW *customdraw = (NMCUSTOMDRAW*)msg_info;
+
+ if (customdraw->dwDrawStage==CDDS_PREERASE)
+ {
+ DRAWITEMSTRUCT drawitem;
+ drawitem.itemState = 0;
+
+ if (customdraw->uItemState & CDIS_DISABLED)
+ drawitem.itemState |= ODS_DISABLED;
+ else if (customdraw->uItemState & CDIS_SELECTED)
+ drawitem.itemState |= ODS_SELECTED;
+ else if (customdraw->uItemState & CDIS_HOT)
+ drawitem.itemState |= ODS_HOTLIGHT;
+ else if (customdraw->uItemState & CDIS_DEFAULT)
+ drawitem.itemState |= ODS_DEFAULT;
+
+ if (customdraw->uItemState & CDIS_FOCUS && (customdraw->uItemState & CDIS_SHOWKEYBOARDCUES))
+ drawitem.itemState |= ODS_FOCUS;
+
+ drawitem.hDC = customdraw->hdc;
+ drawitem.rcItem = customdraw->rc;
+
+ winToggleDrawItem(ih, (void*)&drawitem); /* Simulate a WM_DRAWITEM */
+
+ *result = CDRF_SKIPDEFAULT;
+ return 1;
+ }
+ }
+
+ return 0; /* result not used */
+}
+
+static int winToggleProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ (void)lp;
+ (void)wp;
+
+ switch (msg)
+ {
+ case WM_MOUSEACTIVATE:
+ if (!winToggleIsActive(ih))
+ {
+ *result = MA_NOACTIVATEANDEAT;
+ return 1;
+ }
+ break;
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_ACTIVATE:
+ case WM_SETFOCUS:
+ if (!winToggleIsActive(ih))
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ }
+
+ if (msg == WM_LBUTTONDOWN)
+ winToggleUpdateImage(ih, 1, 1);
+ else if (msg == WM_LBUTTONUP)
+ winToggleUpdateImage(ih, 1, 0);
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+static int winToggleWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp)
+{
+ (void)lp;
+
+ switch (HIWORD(wp))
+ {
+ case BN_DOUBLECLICKED:
+ case BN_CLICKED:
+ {
+ Ihandle *radio;
+ IFni cb;
+ int check = SendMessage(ih->handle, BM_GETCHECK, 0, 0L);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6)
+ {
+ int active = winToggleIsActive(ih);
+ winToggleUpdateImage(ih, active, check);
+ if (!active)
+ return 0;
+ }
+
+ radio = iupRadioFindToggleParent(ih);
+ if (radio)
+ {
+ /* This is necessary because Windows does not send a message
+ when a toggle is unchecked in a Radio.
+ Also if the toggle is already checked in a radio,
+ a click will call the callback again. */
+
+ Ihandle* last_tg = (Ihandle*)iupAttribGet(radio, "_IUPWIN_LASTTOGGLE");
+ if (iupObjectCheck(last_tg) && last_tg != ih)
+ {
+ /* uncheck last toggle */
+ SendMessage(last_tg->handle, BM_SETCHECK, BST_UNCHECKED, 0L);
+
+ cb = (IFni) IupGetCallback(last_tg, "ACTION");
+ if (cb && cb(last_tg, 0) == IUP_CLOSE)
+ IupExitLoop();
+
+ iupBaseCallValueChangedCb(last_tg);
+ }
+ iupAttribSetStr(radio, "_IUPWIN_LASTTOGGLE", (char*)ih);
+
+ if (last_tg != ih)
+ {
+ /* check new toggle */
+ SendMessage(ih->handle, BM_SETCHECK, BST_CHECKED, 0L);
+
+ cb = (IFni)IupGetCallback(ih, "ACTION");
+ if (cb && cb (ih, 1) == IUP_CLOSE)
+ IupExitLoop();
+
+ iupBaseCallValueChangedCb(ih);
+ }
+ }
+ else
+ {
+ if (check == BST_INDETERMINATE)
+ check = -1;
+
+ cb = (IFni)IupGetCallback(ih, "ACTION");
+ if (cb && cb (ih, check) == IUP_CLOSE)
+ IupExitLoop();
+
+ iupBaseCallValueChangedCb(ih);
+ }
+ }
+ }
+
+
+ return 0; /* not used */
+}
+
+static int winToggleMapMethod(Ihandle* ih)
+{
+ Ihandle* radio = iupRadioFindToggleParent(ih);
+ char* value;
+ DWORD dwStyle = WS_CHILD |
+ BS_NOTIFY; /* necessary because of the base messages */
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (radio)
+ ih->data->radio = 1;
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ {
+ ih->data->type = IUP_TOGGLE_IMAGE;
+ dwStyle |= BS_BITMAP|BS_PUSHLIKE;
+ }
+ else
+ {
+ ih->data->type = IUP_TOGGLE_TEXT;
+ dwStyle |= BS_TEXT|BS_MULTILINE;
+
+ if (iupAttribGetBoolean(ih, "RIGHTBUTTON"))
+ dwStyle |= BS_RIGHTBUTTON;
+ }
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ if (radio)
+ {
+ dwStyle |= BS_RADIOBUTTON;
+
+ if (!iupAttribGet(radio, "_IUPWIN_LASTTOGGLE"))
+ {
+ /* this is the first toggle in the radio, and the last toggle with VALUE=ON */
+ iupAttribSetStr(ih, "VALUE","ON");
+ }
+ }
+ else
+ {
+ if (ih->data->type == IUP_TOGGLE_TEXT && iupAttribGetBoolean(ih, "3STATE"))
+ dwStyle |= BS_AUTO3STATE;
+ else
+ dwStyle |= BS_AUTOCHECKBOX;
+ }
+
+ if (!iupwinCreateWindowEx(ih, "BUTTON", 0, dwStyle))
+ return IUP_ERROR;
+
+ /* Process WM_COMMAND */
+ IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winToggleWmCommand);
+
+ /* Process background color */
+ IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winToggleCtlColor);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (iupwin_comctl32ver6)
+ IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winToggleWmNotify); /* Process WM_NOTIFY */
+ else
+ {
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winToggleProc);
+ iupAttribSetStr(ih, "_IUPWIN_ACTIVE", "YES");
+ }
+ }
+
+ return IUP_NOERROR;
+}
+
+void iupdrvToggleInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winToggleMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", winToggleGetActiveAttrib, winToggleSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+
+ /* Visual */
+ 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, "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, "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);
+ iupClassRegisterAttribute(ic, "VALUE", winToggleGetValueAttrib, winToggleSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PADDING", iupToggleGetPaddingAttrib, winToggleSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+
+ /* IupToggle Windows only */
+ iupClassRegisterAttribute(ic, "RIGHTBUTTON", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ /* necessary because it uses an old HBITMAP solution when NOT using 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_tree.c b/iup/src/win/iupwin_tree.c
new file mode 100755
index 0000000..e6877dc
--- /dev/null
+++ b/iup/src/win/iupwin_tree.c
@@ -0,0 +1,2542 @@
+/** \file
+ * \brief Tree Control
+ *
+ * See Copyright Notice in iup.h
+ */
+
+#undef NOTREEVIEW
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_stdcontrols.h"
+#include "iup_tree.h"
+#include "iup_image.h"
+#include "iup_array.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#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 */
+typedef struct tagNMTVITEMCHANGE {
+ NMHDR hdr;
+ UINT uChanged;
+ HTREEITEM hItem;
+ UINT uStateNew;
+ UINT uStateOld;
+ LPARAM lParam;
+} NMTVITEMCHANGE;
+#define TVN_ITEMCHANGINGA (TVN_FIRST-16)
+#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);
+
+ while(hItem != NULL)
+ {
+ if (!func(ih, hItem, userdata))
+ return 0;
+
+ 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);
+ }
+
+ 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;
+}
+
+static int winTreeGetNodeId(Ihandle* ih, HTREEITEM hItem)
+{
+ 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;
+}
+
+static HTREEITEM winTreeFindUserDataID(Ihandle* ih, HTREEITEM hItem, void* userdata)
+{
+ 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;
+}
+
+static int winTreeGetUserDataId(Ihandle* ih, void* userdata)
+{
+ 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;
+}
+
+static HTREEITEM winTreeFindNodeFromID(Ihandle* ih, HTREEITEM hItem)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ 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);
+
+ /* StateID founded! */
+ if(ih->data->id_control < 0)
+ return hItemChild;
+ }
+
+ /* 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)
+{
+ 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);
+}
+
+/* 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)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ while(hBrotherItem != 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));
+
+ if(ih->data->id_control < 0)
+ return hItemChild;
+ }
+
+ hBrotherItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hBrotherItem);
+ }
+
+ return hBrotherItem;
+}
+
+static HTREEITEM winTreeFindNodePointed(Ihandle* ih)
+{
+ 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);
+}
+
+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 */
+/*****************************************************************************/
+void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add)
+{
+ TVITEM item, tviPrevItem;
+ TVINSERTSTRUCT tvins;
+ HTREEITEM hPrevItem = winTreeFindNodeFromString(ih, name_id);
+ int kindPrev;
+ winTreeItemData* itemData;
+
+ if (!hPrevItem)
+ return;
+
+ itemData = calloc(1, sizeof(winTreeItemData));
+ itemData->image = -1;
+ itemData->image_expanded = -1;
+ itemData->kind = (unsigned char)kind;
+
+ item.mask = TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
+ item.pszText = (char*)title;
+ item.lParam = (LPARAM)itemData;
+
+ 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)
+ {
+ /* this is the first child, redraw to update the '+'/'-' buttons */
+ iupdrvDisplayRedraw(ih);
+ }
+}
+
+static void winTreeAddRootNode(Ihandle* ih)
+{
+ TVITEM item;
+ TVINSERTSTRUCT tvins;
+ HTREEITEM hNewItem;
+ winTreeItemData* itemData;
+
+ itemData = calloc(1, sizeof(winTreeItemData));
+ itemData->image = -1;
+ itemData->image_expanded = -1;
+ itemData->kind = ITREE_BRANCH;
+
+ 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;
+
+ iupwinGetColor(iupAttribGetStr(ih, "FGCOLOR"), &itemData->color);
+
+ /* Save the heading level in the node's application-defined data area */
+ tvins.item = item;
+ 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);
+
+ /* MarkStart node */
+ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)hNewItem);
+
+ /* Set the default VALUE */
+ winTreeSetFocusNode(ih, hNewItem);
+}
+
+static int winTreeIsItemExpanded(Ihandle* ih, HTREEITEM hItem)
+{
+ TVITEM item;
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ return (item.state & TVIS_EXPANDED) != 0;
+}
+
+static void winTreeExpandItem(Ihandle* ih, HTREEITEM hItem, int expand)
+{
+ if (expand == -1)
+ expand = !winTreeIsItemExpanded(ih, hItem); /* toggle */
+
+ if (expand)
+ SendMessage(ih->handle, TVM_EXPAND, TVE_EXPAND, (LPARAM)hItem);
+ else
+ SendMessage(ih->handle, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hItem);
+}
+
+/*****************************************************************************/
+/* EXPANDING AND STORING ITEMS */
+/*****************************************************************************/
+static void winTreeExpandTree(Ihandle* ih, HTREEITEM hItem, int expand)
+{
+ HTREEITEM hItemChild;
+ while(hItem != NULL)
+ {
+ hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+
+ /* Check whether we have child items */
+ if (hItemChild)
+ {
+ winTreeExpandItem(ih, hItem, expand);
+
+ /* Recursively traverse child items */
+ winTreeExpandTree(ih, hItemChild, expand);
+ }
+
+ /* Go to next sibling item */
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
+ }
+}
+
+/*****************************************************************************/
+/* SELECTING ITEMS */
+/*****************************************************************************/
+
+static int winTreeIsItemSelected(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)
+{
+ TV_ITEM item;
+ item.mask = TVIF_STATE | TVIF_HANDLE;
+ item.stateMask = TVIS_SELECTED;
+ item.hItem = hItem;
+
+ if (select == -1)
+ select = !winTreeIsItemSelected(ih, hItem);
+
+ item.state = select ? TVIS_SELECTED : 0;
+
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)&item);
+}
+
+static HTREEITEM winTreeGetFocusNode(Ihandle* ih)
+{
+ return (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CARET, 0);
+}
+
+/* ------------Comment from wxWidgets--------------------
+ Helper function which tricks the standard control into changing the focused
+ item without changing anything else. */
+static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem)
+{
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ if (hItem != hItemFocus)
+ {
+ /* remember the selection state of the item */
+ int wasSelected = winTreeIsItemSelected(ih, hItem);
+ int wasFocusSelected = 0;
+
+ if (iupwinIsVista())
+ iupAttribSetStr(ih, "_IUPTREE_ALLOW_CHANGE", (char*)hItem); /* Vista Only */
+ else
+ wasFocusSelected = hItemFocus && winTreeIsItemSelected(ih, hItemFocus);
+
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1");
+
+ if (wasFocusSelected)
+ {
+ /* 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 */
+ }
+
+ 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 */
+
+ 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)
+{
+ int end_range = 0;
+
+ if (range->inside == 0) /* detect the range start */
+ {
+ if (range->hItem1 == hItem) range->inside=1;
+ else if (range->hItem2 == hItem) range->inside=1;
+ }
+ else if (range->inside == 1) /* detect the range end */
+ {
+ if (range->hItem1 == hItem) end_range=1;
+ else if (range->hItem2 == hItem) end_range=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)
+{
+ HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+ winTreeSelectRange(ih, hItemRoot, NULL, 0);
+}
+
+static void winTreeClearSelection(Ihandle* ih, HTREEITEM hItemExcept)
+{
+ winTreeSelectRange(ih, hItemExcept, hItemExcept, 1);
+}
+
+static int winTreeInvertSelectFunc(Ihandle* ih, HTREEITEM hItem, void* userdata)
+{
+ winTreeSelectItem(ih, hItem, -1);
+ (void)userdata;
+ return 1;
+}
+
+typedef struct _winTreeSelArray{
+ Iarray* markedArray;
+ char is_handle;
+ int id_control;
+}winTreeSelArray;
+
+static int winTreeSelectedArrayFunc(Ihandle* ih, HTREEITEM hItem, winTreeSelArray* selarray)
+{
+ selarray->id_control++;
+
+ if (winTreeIsItemSelected(ih, hItem))
+ {
+ if (selarray->is_handle)
+ {
+ HTREEITEM* hItemArrayData = (HTREEITEM*)iupArrayInc(selarray->markedArray);
+ int i = iupArrayCount(selarray->markedArray);
+ hItemArrayData[i-1] = hItem;
+ }
+ else
+ {
+ int* intArrayData = (int*)iupArrayInc(selarray->markedArray);
+ int i = iupArrayCount(selarray->markedArray);
+ intArrayData[i-1] = selarray->id_control;
+ }
+ }
+
+ return 1;
+}
+
+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);
+
+ return markedArray;
+}
+
+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);
+
+ return markedArray;
+}
+
+
+/*****************************************************************************/
+/* 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)
+{
+ TVITEM item;
+ TVINSERTSTRUCT tvins;
+ char* title = iupStrGetMemory(255);
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ item.pszText = title;
+ 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 */
+ {
+ /* 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 */
+ tvins.item = item;
+ tvins.hInsertAfter = hPosition;
+ tvins.hParent = hParent;
+
+ /* Add the node to the tree-view control */
+ return (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
+}
+
+static void winTreeCopyChildren(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int full_copy)
+{
+ HTREEITEM hChildSrc = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItemSrc);
+ HTREEITEM hNewItem = TVI_FIRST;
+ while (hChildSrc != NULL)
+ {
+ hNewItem = winTreeCopyItem(ih, hChildSrc, hItemDst, hNewItem, full_copy); /* Use the same order they where enumerated */
+
+ /* Recursively transfer all the items */
+ winTreeCopyChildren(ih, hChildSrc, hNewItem, full_copy);
+
+ /* Go to next sibling item */
+ hChildSrc = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hChildSrc);
+ }
+}
+
+/* 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)
+{
+ HTREEITEM hNewItem, hParent;
+ TVITEM item;
+ winTreeItemData* itemDataDst;
+
+ /* Get DST node attributes */
+ item.hItem = hItemDst;
+ item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemDataDst = (winTreeItemData*)item.lParam;
+
+ if (itemDataDst->kind == ITREE_BRANCH && (item.state & TVIS_EXPANDED))
+ {
+ /* copy as first child of expanded branch */
+ hParent = hItemDst;
+ hItemDst = TVI_FIRST;
+ }
+ else
+ {
+ /* 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);
+
+ winTreeCopyChildren(ih, hItemSrc, hNewItem, full_copy);
+
+ return hNewItem;
+}
+
+/*****************************************************************************/
+/* MANIPULATING IMAGES */
+/*****************************************************************************/
+static void winTreeUpdateImages(Ihandle* ih, HTREEITEM hItem, int mode)
+{
+ HTREEITEM hItemChild;
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ /* called when one of the default images is changed */
+
+ while(hItem != NULL)
+ {
+ /* Get node attributes */
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ if (item.state & TVIS_EXPANDED)
+ {
+ if (mode == ITREE_UPDATEIMAGE_EXPANDED)
+ {
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ item.iSelectedImage = item.iImage = (itemData->image_expanded!=-1)? itemData->image_expanded: (int)ih->data->def_image_expanded;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ }
+ }
+ else
+ {
+ if (mode == ITREE_UPDATEIMAGE_COLLAPSED)
+ {
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ item.iSelectedImage = item.iImage = (itemData->image!=-1)? itemData->image: (int)ih->data->def_image_collapsed;
+ 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
+ {
+ if (mode == ITREE_UPDATEIMAGE_LEAF)
+ {
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ item.iSelectedImage = item.iImage = (itemData->image!=-1)? itemData->image: (int)ih->data->def_image_leaf;
+ 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);
+ }
+}
+
+static int winTreeGetImageIndex(Ihandle* ih, const char* name)
+{
+ HIMAGELIST image_list;
+ int count, i;
+ Iarray* bmpArray;
+ HBITMAP *bmpArrayData;
+ HBITMAP bmp = iupImageGetImage(name, ih, 0);
+ if (!bmp)
+ return -1;
+
+ /* the array is used to avoi adding the same bitmap twice */
+ bmpArray = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY");
+ if (!bmpArray)
+ {
+ /* create the array if does not exist */
+ bmpArray = iupArrayCreate(50, sizeof(HBITMAP));
+ iupAttribSetStr(ih, "_IUPWIN_BMPARRAY", (char*)bmpArray);
+ }
+
+ bmpArrayData = iupArrayGetData(bmpArray);
+
+ image_list = (HIMAGELIST)SendMessage(ih->handle, TVM_GETIMAGELIST, TVSIL_NORMAL, 0);
+ if (!image_list)
+ {
+ int width, height;
+
+ /* must use this info, since image can be a driver image loaded from resources */
+ iupdrvImageGetInfo(bmp, &width, &height, NULL);
+
+ /* create the image list if does not exist */
+ image_list = ImageList_Create(width, height, ILC_COLOR32, 0, 50);
+ SendMessage(ih->handle, TVM_SETIMAGELIST, 0, (LPARAM)image_list);
+ }
+
+ /* check if that bitmap is already added to the list,
+ but we can not compare with the actual bitmap at the list since it is a copy */
+ count = ImageList_GetImageCount(image_list);
+ for (i = 0; i < count; i++)
+ {
+ if (bmpArrayData[i] == bmp)
+ return i;
+ }
+
+ bmpArrayData = iupArrayInc(bmpArray);
+ bmpArrayData[i] = bmp;
+ return ImageList_Add(image_list, bmp, NULL); /* the bmp is duplicated at the list */
+}
+
+
+/*****************************************************************************/
+/* CALLBACKS */
+/*****************************************************************************/
+
+static int winTreeCallBranchLeafCb(Ihandle* ih, HTREEITEM hItem)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ /* Get Children: branch or leaf */
+ item.mask = TVIF_HANDLE|TVIF_PARAM|TVIF_STATE;
+ item.hItem = hItem;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ if (item.state & TVIS_EXPANDED)
+ {
+ IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB");
+ if (cbBranchClose)
+ return cbBranchClose(ih, winTreeGetNodeId(ih, hItem));
+ }
+ else
+ {
+ IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB");
+ if (cbBranchOpen)
+ return cbBranchOpen(ih, winTreeGetNodeId(ih, hItem));
+ }
+ }
+ else
+ {
+ IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB");
+ if (cbExecuteLeaf)
+ return cbExecuteLeaf(ih, winTreeGetNodeId(ih, hItem));
+ }
+
+ return IUP_DEFAULT;
+}
+
+static void winTreeCallMultiSelectionCb(Ihandle* ih)
+{
+ IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB");
+ if(cbMulti)
+ {
+ Iarray* markedArray = winTreeGetSelectedArrayId(ih);
+ int* id_hitem = (int*)iupArrayGetData(markedArray);
+
+ cbMulti(ih, id_hitem, iupArrayCount(markedArray));
+
+ iupArrayDestroy(markedArray);
+ }
+ else
+ {
+ IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB");
+ if (cbSelec)
+ {
+ Iarray* markedArray = winTreeGetSelectedArrayId(ih);
+ int* id_hitem = (int*)iupArrayGetData(markedArray);
+ int i, count = iupArrayCount(markedArray);
+
+ for (i=0; i<count; i++)
+ cbSelec(ih, id_hitem[i], 1);
+
+ iupArrayDestroy(markedArray);
+ }
+ }
+}
+
+static void winTreeCallSelectionCb(Ihandle* ih, int status, HTREEITEM hItem)
+{
+ IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB");
+ if (cbSelec)
+ {
+ if (ih->data->mark_mode == ITREE_MARK_MULTIPLE && IupGetCallback(ih,"MULTISELECTION_CB"))
+ {
+ if ((GetKeyState(VK_SHIFT) & 0x8000))
+ return;
+ }
+
+ if (iupAttribGet(ih, "_IUPTREE_IGNORE_SELECTION_CB"))
+ return;
+
+ cbSelec(ih, winTreeGetNodeId(ih, hItem), status);
+ }
+}
+
+static int winTreeCallDragDropCb(Ihandle* ih, HTREEITEM hItemDrag, HTREEITEM hItemDrop, int *is_ctrl)
+{
+ IFniiii cbDragDrop = (IFniiii)IupGetCallback(ih, "DRAGDROP_CB");
+ int is_shift = 0;
+ if ((GetKeyState(VK_SHIFT) & 0x8000))
+ is_shift = 1;
+ if ((GetKeyState(VK_CONTROL) & 0x8000))
+ *is_ctrl = 1;
+ else
+ *is_ctrl = 0;
+
+ if (cbDragDrop)
+ {
+ int drag_id = winTreeGetNodeId(ih, hItemDrag);
+ int drop_id = winTreeGetNodeId(ih, hItemDrop);
+ return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl);
+ }
+
+ return IUP_CONTINUE; /* allow to move by default if callback not defined */
+}
+
+
+/*****************************************************************************/
+/* GET AND SET ATTRIBUTES */
+/*****************************************************************************/
+
+
+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);
+
+ return 1;
+}
+
+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);
+
+ return 1;
+}
+
+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);
+
+ return 1;
+}
+
+static int winTreeSetImageExpandedAttrib(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 | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+ itemData->image_expanded = (short)winTreeGetImageIndex(ih, value);
+
+ if (itemData->kind == ITREE_BRANCH && item.state & TVIS_EXPANDED)
+ {
+ if (itemData->image_expanded == -1)
+ item.iSelectedImage = item.iImage = (int)ih->data->def_image_expanded;
+ else
+ item.iSelectedImage = item.iImage = itemData->image_expanded;
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item);
+ }
+
+ return 1;
+}
+
+static int winTreeSetImageAttrib(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 | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+ itemData->image = (short)winTreeGetImageIndex(ih, value);
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ if (!(item.state & TVIS_EXPANDED))
+ {
+ if (itemData->image == -1)
+ item.iSelectedImage = item.iImage = (int)ih->data->def_image_collapsed;
+ else
+ item.iSelectedImage = item.iImage = itemData->image;
+
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item);
+ }
+ }
+ else
+ {
+ if (itemData->image == -1)
+ item.iSelectedImage = item.iImage = (int)ih->data->def_image_leaf;
+ else
+ item.iSelectedImage = item.iImage = itemData->image;
+
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item);
+ }
+
+ return 1;
+}
+
+static int winTreeSetTopItemAttrib(Ihandle* ih, const char* value)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, value);
+ if (hItem)
+ SendMessage(ih->handle, TVM_ENSUREVISIBLE, 0, (LPARAM)hItem);
+ return 0;
+}
+
+static int winTreeSetSpacingAttrib(Ihandle* ih, const char* value)
+{
+ if (!iupStrToInt(value, &ih->data->spacing))
+ ih->data->spacing = 1;
+
+ if(ih->data->spacing < 1)
+ ih->data->spacing = 1;
+
+ if (ih->handle)
+ {
+ int old_spacing = iupAttribGetInt(ih, "_IUPWIN_OLDSPACING");
+ int height = SendMessage(ih->handle, TVM_GETITEMHEIGHT, 0, 0);
+ height -= 2*old_spacing;
+ height += 2*ih->data->spacing;
+ SendMessage(ih->handle, TVM_SETITEMHEIGHT, height, 0);
+ iupAttribSetInt(ih, "_IUPWIN_OLDSPACING", ih->data->spacing);
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+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);
+ return 0;
+}
+
+static int winTreeSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ COLORREF cr = RGB(r,g,b);
+ SendMessage(ih->handle, TVM_SETBKCOLOR, 0, (LPARAM)cr);
+
+ /* update internal image cache */
+ iupTreeUpdateImages(ih);
+ }
+ return 0;
+}
+
+static char* winTreeGetBgColorAttrib(Ihandle* ih)
+{
+ COLORREF cr = (COLORREF)SendMessage(ih->handle, TVM_GETBKCOLOR, 0, 0);
+ if (cr == (COLORREF)-1)
+ return IupGetGlobal("TXTBGCOLOR");
+ else
+ {
+ char* str = iupStrGetMemory(20);
+ sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr));
+ return str;
+ }
+}
+
+static void winTreeSetRenameCaretPos(HWND hEdit, const char* value)
+{
+ int pos = 1;
+
+ if (iupStrToInt(value, &pos))
+ {
+ if (pos < 1) pos = 1;
+ pos--; /* IUP starts at 1 */
+
+ SendMessage(hEdit, EM_SETSEL, (WPARAM)pos, (LPARAM)pos);
+ }
+}
+
+static void winTreeSetRenameSelectionPos(HWND hEdit, const char* value)
+{
+ int start = 1, end = 1;
+
+ if (iupStrToIntInt(value, &start, &end, ':') != 2)
+ return;
+
+ if(start < 1 || end < 1)
+ return;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ SendMessage(hEdit, EM_SETSEL, (WPARAM)start, (LPARAM)end);
+}
+
+static char* winTreeGetTitle(Ihandle* ih, HTREEITEM hItem)
+{
+ TVITEM item;
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_TEXT;
+ item.pszText = iupStrGetMemory(255);
+ item.cchTextMax = 255;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ return item.pszText;
+}
+
+static char* winTreeGetTitleAttrib(Ihandle* ih, const char* name_id)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+ return winTreeGetTitle(ih, hItem);
+}
+
+static int winTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ TVITEM item;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_TEXT;
+ item.pszText = (char*)value;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item);
+ 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);
+ 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 iupwinFindHFont(itemData->hFont);
+}
+
+static int winTreeSetTitleFontAttrib(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;
+
+ if (value)
+ itemData->hFont = iupwinGetHFont(value);
+ else
+ itemData->hFont = NULL;
+
+ iupdrvDisplayUpdate(ih);
+
+ return 0;
+}
+
+static char* winTreeGetIndentationAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(255);
+ int indent = (int)SendMessage(ih->handle, TVM_GETINDENT, 0, 0);
+ sprintf(str, "%d", indent);
+ return str;
+}
+
+static int winTreeSetIndentationAttrib(Ihandle* ih, const char* value)
+{
+ int indent;
+ if (iupStrToInt(value, &indent))
+ SendMessage(ih->handle, TVM_SETINDENT, (WPARAM)indent, 0);
+ return 0;
+}
+
+static char* winTreeGetStateAttrib(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;
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ if (winTreeIsItemExpanded(ih, hItem))
+ return "EXPANDED";
+ else
+ return "COLLAPSED";
+ }
+
+ return NULL;
+}
+
+static int winTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ 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;
+ char* str;
+
+ if (!hItem)
+ return NULL;
+
+ while((hItemRoot != hItem) && (hItem != NULL))
+ {
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem);
+ depth++;
+ }
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", depth);
+ return str;
+}
+
+static int winTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ HTREEITEM hItemDst, hParent, hItemSrc;
+
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ hItemSrc = winTreeFindNodeFromString(ih, name_id);
+ if (!hItemSrc)
+ return 0;
+ hItemDst = winTreeFindNodeFromString(ih, value);
+ if (!hItemDst)
+ return 0;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ hParent = hItemDst;
+ while(hParent)
+ {
+ hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hParent);
+ if (hParent == hItemSrc)
+ 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);
+
+ return 0;
+}
+
+static int winTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ HTREEITEM hItemDst, hParent, hItemSrc;
+
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ hItemSrc = winTreeFindNodeFromString(ih, name_id);
+ if (!hItemSrc)
+ return 0;
+ hItemDst = winTreeFindNodeFromString(ih, value);
+ if (!hItemDst)
+ return 0;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ hParent = hItemDst;
+ while(hParent)
+ {
+ hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hParent);
+ if (hParent == hItemSrc)
+ return 0;
+ }
+
+ /* Copying the node and its children to the new position */
+ winTreeCopyNode(ih, hItemSrc, hItemDst, 1);
+
+ return 0;
+}
+
+static char* winTreeGetColorAttrib(Ihandle* ih, const char* name_id)
+{
+ unsigned char r, g, b;
+ char* str;
+ 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;
+
+ r = GetRValue(itemData->color);
+ g = GetGValue(itemData->color);
+ b = GetBValue(itemData->color);
+
+ str = iupStrGetMemory(12);
+ sprintf(str, "%d %d %d", r, g, b);
+ return str;
+}
+
+static int winTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ unsigned char r, g, b;
+ 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;
+
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ itemData->color = RGB(r,g,b);
+ iupdrvDisplayUpdate(ih);
+ }
+
+ return 0;
+}
+
+static int winTreeSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ COLORREF color = RGB(r,g,b);
+ SendMessage(ih->handle, TVM_SETTEXTCOLOR, 0, (LPARAM)color);
+ }
+ else
+ SendMessage(ih->handle, TVM_SETTEXTCOLOR, 0, (LPARAM)CLR_DEFAULT);
+
+ return 0;
+}
+
+static char* winTreeGetChildCountAttrib(Ihandle* ih, const char* name_id)
+{
+ int count;
+ char* str;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+
+ count = 0;
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ while(hItem != NULL)
+ {
+ count++;
+
+ /* Go to next sibling item */
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
+ }
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", count);
+ 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);
+ 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;
+
+ if(itemData->kind == ITREE_BRANCH)
+ return "BRANCH";
+ else
+ return "LEAF";
+}
+
+static char* winTreeGetParentAttrib(Ihandle* ih, const char* name_id)
+{
+ char* str;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem);
+ if (!hItem)
+ return NULL;
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", winTreeGetNodeId(ih, hItem));
+ return str;
+}
+
+static void winTreeDelNodeData(Ihandle* ih, HTREEITEM hItem)
+{
+ TVITEM item;
+ HTREEITEM hChildItem;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE|TVIF_PARAM;
+ if (SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item))
+ {
+ winTreeItemData* itemData = (winTreeItemData*)item.lParam;
+ if (itemData)
+ {
+ IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB");
+ if (cb) cb(ih, winTreeGetNodeId(ih, hItem), (char*)itemData->userdata);
+ free(itemData);
+ item.lParam = (LPARAM)NULL;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ }
+ }
+
+ hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ while (hChildItem)
+ {
+ winTreeDelNodeData(ih, hChildItem);
+ hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hChildItem);
+ }
+}
+
+static int winTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */
+ {
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+
+ /* the root node can't be deleted */
+ if(!hItem || hItem == hItemRoot)
+ return 0;
+
+ /* deleting the specified node (and it's children) */
+ winTreeDelNodeData(ih, hItem);
+ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItem);
+
+ return 0;
+ }
+ else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */
+ {
+ HTREEITEM hItem = winTreeFindNodeFromString(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 */
+ while (hChildItem)
+ {
+ winTreeDelNodeData(ih, hChildItem);
+ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hChildItem);
+ hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ }
+
+ 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);
+
+ /* Delete the array of marked nodes */
+ markedArray = winTreeGetSelectedArray(ih);
+ hItemArrayData = (HTREEITEM*)iupArrayGetData(markedArray);
+ count = iupArrayCount(markedArray);
+
+ for(i = 0; i < count; i++)
+ {
+ if (hItemArrayData[i] != hItemRoot) /* the root node can't be deleted */
+ {
+ winTreeDelNodeData(ih, hItemArrayData[i]);
+ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemArrayData[i]);
+ }
+ }
+
+ iupArrayDestroy(markedArray);
+
+ return 0;
+ }
+
+ return 0;
+}
+
+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));
+
+ SetFocus(ih->handle); /* the tree must have focus to activate the edit */
+ 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;
+}
+
+static char* winTreeGetMarkedAttrib(Ihandle* ih, const char* name_id)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+
+ if (winTreeIsItemSelected(ih, hItem))
+ return "YES";
+ else
+ return "NO";
+}
+
+static int winTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ winTreeSelectItem(ih, hItem, iupStrBoolean(value));
+ return 0;
+}
+
+static int winTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)hItem);
+
+ return 1;
+}
+
+static char* winTreeGetValueAttrib(Ihandle* ih)
+{
+ char* str;
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ if (!hItemFocus)
+ return "0"; /* default VALUE is root */
+
+ str = iupStrGetMemory(16);
+ sprintf(str, "%d", winTreeGetNodeId(ih, hItemFocus));
+ return str;
+}
+
+static int winTreeSetMarkAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->mark_mode==ITREE_MARK_SINGLE)
+ return 0;
+
+ if(iupStrEqualNoCase(value, "BLOCK"))
+ {
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ winTreeSelectRange(ih, (HTREEITEM)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"), hItemFocus, 0);
+ }
+ else if(iupStrEqualNoCase(value, "CLEARALL"))
+ winTreeClearSelection(ih, NULL);
+ 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);
+ else if(iupStrEqualPartial(value, "INVERT")) /* iupStrEqualPartial allows the use of "INVERTid" form */
+ {
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, &value[strlen("INVERT")]);
+ if (!hItem)
+ return 0;
+
+ winTreeSelectItem(ih, hItem, -1); /* toggle */
+ }
+ else
+ {
+ HTREEITEM hItem1, hItem2;
+
+ char str1[50], str2[50];
+ if (iupStrToStrStr(value, str1, str2, '-')!=2)
+ return 0;
+
+ hItem1 = winTreeFindNodeFromString(ih, str1);
+ if (!hItem1)
+ return 0;
+ hItem2 = winTreeFindNodeFromString(ih, str2);
+ if (!hItem2)
+ return 0;
+
+ winTreeSelectRange(ih, hItem1, hItem2, 0);
+ }
+
+ return 1;
+}
+
+static int winTreeSetValueAttrib(Ihandle* ih, const char* value)
+{
+ HTREEITEM hItem = NULL;
+ HTREEITEM hItemFocus;
+
+ if (winTreeSetMarkAttrib(ih, value))
+ return 0;
+
+ hItemFocus = winTreeGetFocusNode(ih);
+
+ if(iupStrEqualNoCase(value, "ROOT"))
+ 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);
+ else if(iupStrEqualNoCase(value, "PGUP"))
+ {
+ int i;
+ HTREEITEM hItemPrev = hItemFocus;
+ HTREEITEM hItemNext = hItemFocus;
+ for(i = 0; i < 10; i++)
+ {
+ hItemNext = hItemPrev;
+ hItemPrev = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemPrev);
+ if(hItemPrev == NULL)
+ {
+ hItemPrev = hItemNext;
+ break;
+ }
+ }
+
+ hItem = hItemPrev;
+ }
+ else if(iupStrEqualNoCase(value, "PGDN"))
+ {
+ int i;
+ HTREEITEM hItemPrev = hItemFocus;
+ HTREEITEM hItemNext = hItemFocus;
+
+ for(i = 0; i < 10; i++)
+ {
+ hItemPrev = hItemNext;
+ hItemNext = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemNext);
+ if(hItemNext == NULL)
+ {
+ hItemNext = hItemPrev;
+ break;
+ }
+ }
+
+ hItem = hItemNext;
+ }
+ else if(iupStrEqualNoCase(value, "NEXT"))
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemFocus);
+ else if(iupStrEqualNoCase(value, "PREVIOUS"))
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemFocus);
+ else
+ hItem = winTreeFindNodeFromString(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);
+ }
+ winTreeSetFocusNode(ih, hItem);
+ }
+
+ return 0;
+}
+
+void iupdrvTreeUpdateMarkMode(Ihandle *ih)
+{
+ /* does nothing, must handle single and multiple selection manually in Windows */
+ (void)ih;
+}
+
+/*********************************************************************************************************/
+
+
+static int winTreeEditProc(Ihandle* ih, HWND cbedit, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch (msg)
+ {
+ case WM_GETDLGCODE:
+ {
+ MSG* pMsg = (MSG*)lp;
+
+ if (pMsg && (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN))
+ {
+ if (pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_RETURN)
+ {
+ /* these keys are not processed if the return code is not this */
+ *result = DLGC_WANTALLKEYS;
+ return 1;
+ }
+ }
+ }
+ }
+
+ (void)wp;
+ (void)cbedit;
+ (void)ih;
+ return 0;
+}
+
+static LRESULT CALLBACK winTreeEditWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ int ret = 0;
+ LRESULT result = 0;
+ WNDPROC oldProc;
+ Ihandle *ih;
+
+ ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */
+
+ /* retrieve the control previous procedure for subclassing */
+ oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB");
+
+ ret = winTreeEditProc(ih, hwnd, msg, wp, lp, &result);
+
+ if (ret)
+ return result;
+ else
+ return CallWindowProc(oldProc, hwnd, msg, wp, lp);
+}
+
+static void winTreeDrag(Ihandle* ih, int x, int y)
+{
+ HTREEITEM hItemDrop;
+
+ 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);
+ }
+
+ if ((hItemDrop = winTreeFindNodePointed(ih)) != NULL)
+ {
+ if(dragImageList)
+ ImageList_DragShowNolock(FALSE);
+
+ SendMessage(ih->handle, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)hItemDrop);
+
+ /* store the drop item to be executed */
+ iupAttribSetStr(ih, "_IUPTREE_DROPITEM", (char*)hItemDrop);
+
+ if(dragImageList)
+ ImageList_DragShowNolock(TRUE);
+ }
+}
+
+static void winTreeDrop(Ihandle* ih)
+{
+ HTREEITEM hItemDrag = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM");
+ HTREEITEM hItemDrop = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DROPITEM");
+ HIMAGELIST dragImageList = (HIMAGELIST)iupAttribGet(ih, "_IUPTREE_DRAGIMAGELIST");
+ HTREEITEM hParent;
+ int is_ctrl;
+
+ if (dragImageList)
+ {
+ ImageList_DragLeave(ih->handle);
+ ImageList_EndDrag();
+ ImageList_Destroy(dragImageList);
+ iupAttribSetStr(ih, "_IUPTREE_DRAGIMAGELIST", NULL);
+ }
+
+ ReleaseCapture();
+ ShowCursor(TRUE);
+
+ /* Remove drop target highlighting */
+ SendMessage(ih->handle, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)NULL);
+
+ iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", NULL);
+ iupAttribSetStr(ih, "_IUPTREE_DROPITEM", NULL);
+
+ if (!hItemDrop || hItemDrag == hItemDrop)
+ return;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ hParent = hItemDrop;
+ while(hParent)
+ {
+ hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hParent);
+ if (hParent == hItemDrag)
+ return;
+ }
+
+ 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);
+ }
+
+ SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItemNew); /* set focus and selection */
+ }
+}
+
+static void winTreeExtendSelect(Ihandle* ih, int x, int y)
+{
+ HTREEITEM hItemFirstSel;
+ TVHITTESTINFO info;
+ HTREEITEM hItem;
+ info.pt.x = x;
+ info.pt.y = y;
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)&info);
+
+ if (!(info.flags & TVHT_ONITEM) || !hItem)
+ return;
+
+ 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);
+ }
+}
+
+static int winTreeMouseMultiSelect(Ihandle* ih, int x, int y)
+{
+ TVHITTESTINFO info;
+ HTREEITEM hItem;
+ info.pt.x = x;
+ info.pt.y = y;
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)&info);
+
+ if (!(info.flags & TVHT_ONITEM) || !hItem)
+ return 0;
+
+ if (GetKeyState(VK_CONTROL) & 0x8000) /* Control key is down */
+ {
+ /* Toggle selection state */
+ winTreeSelectItem(ih, hItem, -1);
+ iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItem);
+
+ winTreeCallSelectionCb(ih, winTreeIsItemSelected(ih, hItem), hItem);
+ winTreeSetFocusNode(ih, hItem);
+
+ return 1;
+ }
+ else if (GetKeyState(VK_SHIFT) & 0x8000) /* Shift key is down */
+ {
+ HTREEITEM 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);
+
+ winTreeCallMultiSelectionCb(ih);
+ winTreeSetFocusNode(ih, hItem);
+ return 1;
+ }
+ }
+
+ /* simple click */
+ winTreeClearSelection(ih, hItem);
+ iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItem);
+ iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1");
+
+ return 0;
+}
+
+static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch (msg)
+ {
+ case WM_CTLCOLOREDIT:
+ {
+ HWND hEdit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ if (hEdit)
+ {
+ winTreeItemData* itemData = (winTreeItemData*)iupAttribGet(ih, "_IUPWIN_EDIT_DATA");
+ HDC hDC = (HDC)wp;
+ COLORREF cr;
+
+ SetTextColor(hDC, itemData->color);
+
+ cr = (COLORREF)SendMessage(ih->handle, TVM_GETBKCOLOR, 0, 0);
+ SetBkColor(hDC, cr);
+ SetDCBrushColor(hDC, cr);
+ *result = (LRESULT)GetStockObject(DC_BRUSH);
+ return 1;
+ }
+
+ break;
+ }
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ {
+ /* ------------Comment from wxWidgets--------------------
+ the tree control greys out the selected item when it loses focus and
+ paints it as selected again when it regains it, but it won't do it
+ for the other items itself - help it */
+ if (ih->data->mark_mode == ITREE_MARK_MULTIPLE)
+ {
+ HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0);
+ RECT rect;
+
+ while(hItemChild != NULL)
+ {
+ *(HTREEITEM*)&rect = hItemChild;
+ if (SendMessage(ih->handle, TVM_GETITEMRECT, TRUE, (LPARAM)&rect))
+ InvalidateRect(ih->handle, &rect, FALSE);
+
+ /* Go to next visible item */
+ hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemChild);
+ }
+ }
+ break;
+ }
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ {
+ if (iupwinBaseProc(ih, msg, wp, lp, result)==1)
+ return 1;
+
+ if (wp == VK_RETURN)
+ {
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ if (winTreeCallBranchLeafCb(ih, hItemFocus) != IUP_IGNORE)
+ winTreeExpandItem(ih, hItemFocus, -1);
+
+ *result = 0;
+ return 1;
+ }
+ else if (wp == VK_F2)
+ {
+ winTreeSetRenameAttrib(ih, NULL);
+ *result = 0;
+ return 1;
+ }
+ else if (wp == VK_SPACE)
+ {
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ {
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ /* Toggle selection state */
+ winTreeSelectItem(ih, hItemFocus, -1);
+ }
+ }
+ else if (wp == VK_UP || wp == VK_DOWN)
+ {
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ if (wp == VK_UP)
+ hItemFocus = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemFocus);
+ else
+ hItemFocus = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemFocus);
+ if (!hItemFocus)
+ return 0;
+
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ {
+ /* Only move focus */
+ winTreeSetFocusNode(ih, hItemFocus);
+
+ *result = 0;
+ return 1;
+ }
+ else if (GetKeyState(VK_SHIFT) & 0x8000)
+ {
+ 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);
+
+ *result = 0;
+ return 1;
+ }
+ }
+
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE)
+ {
+ iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItemFocus);
+ winTreeClearSelection(ih, NULL);
+ /* normal processing will select the focus item */
+ }
+ }
+
+ return 0;
+ }
+ case WM_LBUTTONDOWN:
+ if (iupwinButtonDown(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE)
+ {
+ /* must set focus on left button down or the tree won't show its focus */
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ SetFocus(ih->handle);
+
+ if (winTreeMouseMultiSelect(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)))
+ {
+ *result = 0; /* abort the normal processing if we process multiple selection */
+ return 1;
+ }
+ }
+ break;
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ if (iupwinButtonDown(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ 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));
+ else if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT"))
+ winTreeExtendSelect(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp));
+
+ iupwinMouseMove(ih, msg, wp, lp);
+ break;
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ if (iupwinButtonUp(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+
+ if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT"))
+ {
+ iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", NULL);
+ if (iupAttribGet(ih, "_IUPTREE_LASTSELITEM"))
+ {
+ winTreeCallMultiSelectionCb(ih);
+ iupAttribSetStr(ih, "_IUPTREE_LASTSELITEM", NULL);
+ }
+ }
+
+ if (ih->data->show_dragdrop && (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM") != NULL)
+ winTreeDrop(ih);
+
+ break;
+ case WM_CHAR:
+ {
+ if (wp==VK_TAB) /* the keys have the same definitions as the chars */
+ {
+ *result = 0;
+ return 1; /* abort default processing to avoid beep */
+ }
+ break;
+ }
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+static COLORREF winTreeInvertColor(COLORREF color)
+{
+ return RGB(~GetRValue(color), ~GetGValue(color), ~GetBValue(color));
+}
+
+static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result)
+{
+ if (msg_info->code == TVN_ITEMCHANGINGA || msg_info->code == TVN_ITEMCHANGINGW) /* Vista Only */
+ {
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE)
+ {
+ NMTVITEMCHANGE* info = (NMTVITEMCHANGE*)msg_info;
+ HTREEITEM hItem = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_ALLOW_CHANGE");
+ if (hItem && hItem != info->hItem) /* Workaround for Vista SetFocus */
+ {
+ *result = TRUE; /* prevent the change */
+ return 1;
+ }
+ }
+ }
+ 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 */
+ }
+ else if(msg_info->code == TVN_BEGINLABELEDIT)
+ {
+ char* value;
+ HWND hEdit;
+ NMTVDISPINFO* info = (NMTVDISPINFO*)msg_info;
+
+ if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT"))
+ {
+ *result = TRUE; /* prevent the change */
+ return 1;
+ }
+
+ hEdit = (HWND)SendMessage(ih->handle, TVM_GETEDITCONTROL, 0, 0);
+
+ /* save the edit box. */
+ iupwinHandleAdd(ih, hEdit);
+ iupAttribSetStr(ih, "_IUPWIN_EDITBOX", (char*)hEdit);
+
+ /* subclass the edit box. */
+ IupSetCallback(ih, "_IUPWIN_EDITOLDPROC_CB", (Icallback)GetWindowLongPtr(hEdit, GWLP_WNDPROC));
+ SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR)winTreeEditWinProc);
+
+ value = iupAttribGetStr(ih, "RENAMECARET");
+ if (value)
+ winTreeSetRenameCaretPos(hEdit, value);
+
+ value = iupAttribGetStr(ih, "RENAMESELECTION");
+ if (value)
+ winTreeSetRenameSelectionPos(hEdit, value);
+
+ {
+ winTreeItemData* itemData;
+ TVITEM item;
+ item.hItem = info->item.hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+ iupAttribSetStr(ih, "_IUPWIN_EDIT_DATA", (char*)itemData);
+
+ if (itemData->hFont)
+ SendMessage(hEdit, WM_SETFONT, (WPARAM)itemData->hFont, MAKELPARAM(TRUE,0));
+ }
+ }
+ else if(msg_info->code == TVN_ENDLABELEDIT)
+ {
+ 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;
+ }
+ }
+
+ *result = TRUE;
+ return 1;
+ }
+ }
+ else if(msg_info->code == TVN_BEGINDRAG)
+ {
+ if (ih->data->show_dragdrop)
+ {
+ 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)
+ {
+ 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);
+ }
+
+ ShowCursor(FALSE);
+ SetCapture(ih->handle); /* drag only inside the tree */
+ }
+ }
+ else if(msg_info->code == NM_DBLCLK)
+ {
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ /* Get Children: branch or leaf */
+ item.mask = TVIF_HANDLE|TVIF_PARAM;
+ item.hItem = hItemFocus;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (itemData->kind == ITREE_LEAF)
+ {
+ IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB");
+ if(cbExecuteLeaf)
+ cbExecuteLeaf(ih, winTreeGetNodeId(ih, hItemFocus));
+ }
+ }
+ else if(msg_info->code == TVN_ITEMEXPANDING)
+ {
+ /* mouse click by user: click on the "+" sign or double click on the selected node */
+ NMTREEVIEW* tree_info = (NMTREEVIEW*)msg_info;
+ HTREEITEM hItem = tree_info->itemNew.hItem;
+
+ if (winTreeCallBranchLeafCb(ih, hItem) != IUP_IGNORE)
+ {
+ TVITEM item;
+ winTreeItemData* itemData = (winTreeItemData*)tree_info->itemNew.lParam;
+
+ if (tree_info->action == TVE_EXPAND)
+ item.iSelectedImage = item.iImage = (itemData->image_expanded!=-1)? itemData->image_expanded: (int)ih->data->def_image_expanded;
+ else
+ 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);
+ }
+ else
+ {
+ *result = TRUE; /* prevent the change */
+ return 1;
+ }
+ }
+ else if(msg_info->code == NM_RCLICK)
+ {
+ HTREEITEM hItem = winTreeFindNodePointed(ih);
+ IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB");
+ if (cbRightClick)
+ cbRightClick(ih, winTreeGetNodeId(ih, hItem));
+ }
+ else if (msg_info->code == NM_CUSTOMDRAW)
+ {
+ NMTVCUSTOMDRAW *customdraw = (NMTVCUSTOMDRAW*)msg_info;
+
+ if (customdraw->nmcd.dwDrawStage == CDDS_PREPAINT)
+ {
+ *result = CDRF_NOTIFYPOSTPAINT|CDRF_NOTIFYITEMDRAW;
+ return 1;
+ }
+
+ if (customdraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
+ {
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = (HTREEITEM)customdraw->nmcd.dwItemSpec;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (winTreeIsItemSelected(ih, hItem))
+ customdraw->clrText = winTreeInvertColor(itemData->color);
+ else
+ customdraw->clrText = itemData->color;
+
+ *result = CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT;
+
+ if (itemData->hFont)
+ {
+ SelectObject(customdraw->nmcd.hdc, itemData->hFont);
+ *result |= CDRF_NEWFONT;
+ }
+
+ return 1;
+ }
+ }
+
+ return 0; /* allow the default processsing */
+}
+
+static int winTreeConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ TVHITTESTINFO info;
+ HTREEITEM hItem;
+ info.pt.x = x;
+ info.pt.y = y;
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)&info);
+ if (hItem)
+ return winTreeGetNodeId(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;
+
+ /* can be set only on the Tree View creation */
+
+ if (!ih->data->show_dragdrop)
+ dwStyle |= TVS_DISABLEDRAGDROP;
+
+ if (ih->data->show_rename)
+ dwStyle |= TVS_EDITLABELS;
+
+ if (!iupAttribGetBoolean(ih, "HIDELINES"))
+ dwStyle |= TVS_HASLINES;
+
+ if (!iupAttribGetBoolean(ih, "HIDEBUTTONS"))
+ dwStyle |= TVS_HASBUTTONS;
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (!iupwinCreateWindowEx(ih, WC_TREEVIEW, 0, dwStyle))
+ return IUP_ERROR;
+
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTreeProc);
+ IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTreeWmNotify);
+
+ /* Force background update before setting the images */
+ {
+ char* value = iupAttribGet(ih, "BGCOLOR");
+ if (value)
+ {
+ winTreeSetBgColorAttrib(ih, value);
+ iupAttribSetStr(ih, "BGCOLOR", NULL);
+ }
+ else if (iupwinGetSystemMajorVersion()<6) /* force background in XP because of the editbox background */
+ winTreeSetBgColorAttrib(ih, IupGetGlobal("TXTBGCOLOR"));
+ }
+
+ /* Initialize the default images */
+ ih->data->def_image_leaf = (void*)winTreeGetImageIndex(ih, "IMGLEAF");
+ ih->data->def_image_collapsed = (void*)winTreeGetImageIndex(ih, "IMGCOLLAPSED");
+ ih->data->def_image_expanded = (void*)winTreeGetImageIndex(ih, "IMGEXPANDED");
+
+ /* Add the Root Node */
+ winTreeAddRootNode(ih);
+
+ /* configure for DRAG&DROP of files */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winTreeConvertXYToPos);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTreeInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winTreeMapMethod;
+ ic->UnMap = winTreeUnMapMethod;
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", winTreeGetBgColorAttrib, winTreeSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winTreeSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT);
+
+ /* 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);
+
+ /* IupTree Attributes - IMAGES */
+ iupClassRegisterAttributeId(ic, "IMAGE", NULL, winTreeSetImageAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "IMAGEEXPANDED", NULL, winTreeSetImageExpandedAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "IMAGELEAF", NULL, winTreeSetImageLeafAttrib, IUPAF_SAMEASSYSTEM, "IMGLEAF", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEBRANCHCOLLAPSED", NULL, winTreeSetImageBranchCollapsedAttrib, IUPAF_SAMEASSYSTEM, "IMGCOLLAPSED", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEBRANCHEXPANDED", NULL, winTreeSetImageBranchExpandedAttrib, IUPAF_SAMEASSYSTEM, "IMGEXPANDED", IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - NODES */
+ iupClassRegisterAttributeId(ic, "STATE", winTreeGetStateAttrib, winTreeSetStateAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "DEPTH", winTreeGetDepthAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "KIND", winTreeGetKindAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "PARENT", winTreeGetParentAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ 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);
+
+ /* IupTree Attributes - MARKS */
+ iupClassRegisterAttributeId(ic, "MARKED", winTreeGetMarkedAttrib, winTreeSetMarkedAttrib, IUPAF_NO_INHERIT);
+ 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, "VALUE", winTreeGetValueAttrib, winTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - ACTION */
+ iupClassRegisterAttributeId(ic, "DELNODE", NULL, winTreeSetDelNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ 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);
+}
diff --git a/iup/src/win/iupwin_val.c b/iup/src/win/iupwin_val.c
new file mode 100755
index 0000000..706c612
--- /dev/null
+++ b/iup/src/win/iupwin_val.c
@@ -0,0 +1,315 @@
+/** \file
+ * \brief Valuator Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_val.h"
+#include "iup_drv.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+
+
+#ifndef SHRT_MAX
+#define SHRT_MAX 32767
+#endif
+
+void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h)
+{
+ int ticks_size = 0;
+ if (iupAttribGetInt(ih, "SHOWTICKS"))
+ {
+ char* tickspos = iupAttribGetStr(ih, "TICKSPOS");
+ if(iupStrEqualNoCase(tickspos, "BOTH"))
+ ticks_size = 2*8;
+ else
+ ticks_size = 8;
+ }
+
+ if (ih->data->type == IVAL_HORIZONTAL)
+ {
+ *w = 35;
+ *h = 30+ticks_size;
+ }
+ else
+ {
+ *w = 30+ticks_size;
+ *h = 35;
+ }
+}
+
+static int winValSetStepAttrib(Ihandle* ih, const char* value)
+{
+ int linesize;
+ ih->data->step = atof(value);
+ linesize = (int)(ih->data->step*SHRT_MAX);
+ SendMessage(ih->handle, TBM_SETLINESIZE, 0, linesize);
+ return 0; /* do not store value in hash table */
+}
+
+static int winValSetPageStepAttrib(Ihandle* ih, const char* value)
+{
+ int pagesize;
+ ih->data->pagestep = atof(value);
+ pagesize = (int)(ih->data->pagestep*SHRT_MAX);
+ SendMessage(ih->handle, TBM_SETPAGESIZE, 0, pagesize);
+ return 0; /* do not store value in hash table */
+}
+
+static int winValSetShowTicksAttrib(Ihandle* ih, const char* value)
+{
+ int tick_freq, show_ticks;
+
+ if (!ih->data->show_ticks) /* can only set if already not zero */
+ return 0;
+
+ show_ticks = atoi(value);
+ if (show_ticks<2) show_ticks=2;
+ ih->data->show_ticks = show_ticks;
+
+ /* Defines the interval frequency for tick marks */
+ tick_freq = SHRT_MAX/(show_ticks-1);
+ SendMessage(ih->handle, TBM_SETTICFREQ, tick_freq, 0);
+ return 0;
+}
+
+static int winValSetValueAttrib(Ihandle* ih, const char* value)
+{
+ int ival;
+
+ ih->data->val = atof(value);
+ iupValCropValue(ih);
+
+ ival = (int)(((ih->data->val-ih->data->vmin)/(ih->data->vmax - ih->data->vmin))*SHRT_MAX);
+ if (ih->data->inverted)
+ ival = SHRT_MAX-ival;
+
+ SendMessage(ih->handle, TBM_SETPOS, TRUE, ival);
+ return 0; /* do not store value in hash table */
+}
+
+
+/*********************************************************************************************/
+
+
+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;
+ int ival;
+ IFn cb;
+
+ ival = (int)SendMessage(ih->handle, TBM_GETPOS, 0, 0);
+ if (ih->data->inverted)
+ ival = SHRT_MAX-ival;
+
+ ih->data->val = (((double)ival/(double)SHRT_MAX)*(ih->data->vmax - ih->data->vmin)) + ih->data->vmin;
+ iupValCropValue(ih);
+
+ cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB");
+ if (cb)
+ {
+ if (ih->data->val == old_val)
+ return 0;
+
+ cb(ih);
+ }
+ else
+ {
+ IFnd cb_old = NULL;
+ switch (msg)
+ {
+ case TB_BOTTOM:
+ case TB_TOP:
+ case TB_LINEDOWN:
+ case TB_LINEUP:
+ case TB_PAGEDOWN:
+ case TB_PAGEUP:
+ {
+ cb_old = (IFnd) IupGetCallback(ih, "BUTTON_PRESS_CB");
+ break;
+ }
+ case TB_THUMBPOSITION:
+ {
+ cb_old = (IFnd) IupGetCallback(ih, "BUTTON_RELEASE_CB");
+ break;
+ }
+ case TB_THUMBTRACK:
+ {
+ cb_old = (IFnd) IupGetCallback(ih, "MOUSEMOVE_CB");
+ break;
+ }
+ }
+ if (cb_old)
+ cb_old(ih, ih->data->val);
+ }
+
+ return 0; /* not used */
+}
+
+static void winValIncPageValue(Ihandle *ih, int dir)
+{
+ int pagesize, ival;
+ pagesize = (int)(ih->data->pagestep*SHRT_MAX);
+
+ ival = (int)SendMessage(ih->handle, TBM_GETPOS, 0, 0);
+ ival += dir*pagesize;
+ if (ival < 0) ival = 0;
+ if (ival > SHRT_MAX) ival = SHRT_MAX;
+ SendMessage(ih->handle, TBM_SETPOS, TRUE, ival);
+
+ winValCustomScroll(ih, 0);
+}
+
+static int winValProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ (void)lp;
+
+ switch (msg)
+ {
+ case WM_ERASEBKGND:
+ {
+ RECT rect;
+ HDC hDC = (HDC)wp;
+ GetClientRect(ih->handle, &rect);
+ iupwinDrawParentBackground(ih, hDC, &rect);
+ /* return non zero value */
+ *result = 1;
+ return 1;
+ }
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ {
+ if (iupwinBaseProc(ih, msg, wp, lp, result)==1)
+ return 1;
+
+ if (GetKeyState(VK_CONTROL) & 0x8000) /* handle Ctrl+Arrows */
+ {
+ if (wp == VK_UP || wp == VK_LEFT)
+ {
+ winValIncPageValue(ih, -1);
+ *result = 0;
+ return 1;
+ }
+ if (wp == VK_RIGHT || wp == VK_DOWN)
+ {
+ winValIncPageValue(ih, 1);
+ *result = 0;
+ return 1;
+ }
+ }
+ return 0;
+ }
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+
+/*********************************************************************************************/
+
+
+static int winValMapMethod(Ihandle* ih)
+{
+ DWORD dwStyle = WS_CHILD | TBS_AUTOTICKS;
+ int show_ticks;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ /* Track bar Orientation */
+ if (ih->data->type == IVAL_HORIZONTAL)
+ dwStyle |= TBS_HORZ;
+ else
+ dwStyle |= TBS_VERT;
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ /* Track bar Ticks */
+ show_ticks = iupAttribGetInt(ih, "SHOWTICKS");
+ if (!show_ticks)
+ {
+ dwStyle |= TBS_NOTICKS; /* No show_ticks */
+ }
+ else
+ {
+ char* tickspos;
+
+ if (show_ticks<2) show_ticks=2;
+ ih->data->show_ticks = show_ticks; /* non zero value, can be changed later, but not to zero */
+
+ /* Defines the position of tick marks */
+ tickspos = iupAttribGetStr(ih, "TICKSPOS");
+ if(iupStrEqualNoCase(tickspos, "BOTH"))
+ dwStyle |= TBS_BOTH;
+ else if(iupStrEqualNoCase(tickspos, "REVERSE"))
+ dwStyle |= TBS_BOTTOM; /* same as TBS_RIGHT */
+ else /* NORMAL */
+ dwStyle |= TBS_TOP; /* same as TBS_LEFT */
+ }
+
+ if (!iupwinCreateWindowEx(ih, TRACKBAR_CLASS, 0, dwStyle))
+ return IUP_ERROR;
+
+ /* Process Keyboard */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winValProc);
+
+ /* Process Val Scroll commands */
+ IupSetCallback(ih, "_IUPWIN_CUSTOMSCROLL_CB", (Icallback)winValCustomScroll);
+
+ /* Process background color */
+ IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winValCtlColor);
+
+ /* configure the native range */
+ SendMessage(ih->handle, TBM_SETRANGEMIN, FALSE, 0);
+ SendMessage(ih->handle, TBM_SETRANGEMAX, FALSE, SHRT_MAX);
+
+ if (ih->data->inverted)
+ SendMessage(ih->handle, TBM_SETPOS, FALSE, SHRT_MAX); /* default initial position is at MIN */
+
+ return IUP_NOERROR;
+}
+
+void iupdrvValInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winValMapMethod;
+
+ /* IupVal only */
+ iupClassRegisterAttribute(ic, "VALUE", iupValGetValueAttrib, winValSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWTICKS", iupValGetShowTicksAttrib, winValSetShowTicksAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "PAGESTEP", iupValGetPageStepAttrib, winValSetPageStepAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ 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);
+}
diff --git a/iup/src/win/iupwindows_help.c b/iup/src/win/iupwindows_help.c
new file mode 100755
index 0000000..f3a06b6
--- /dev/null
+++ b/iup/src/win/iupwindows_help.c
@@ -0,0 +1,32 @@
+/** \file
+ * \brief Windows Driver IupHelp
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <windows.h>
+#include <shellapi.h>
+
+#include "iup.h"
+
+int IupHelp(const char* url)
+{
+ int err = (int)ShellExecute(GetDesktopWindow(), "open", url, NULL, NULL, SW_SHOWNORMAL);
+ if (err <= 32)
+ {
+ switch (err)
+ {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ return -2; /* File not found */
+ break;
+ default:
+ return -1; /* Generic error */
+ break;
+ }
+ }
+ return 1;
+}
diff --git a/iup/src/win/iupwindows_info.c b/iup/src/win/iupwindows_info.c
new file mode 100755
index 0000000..982c980
--- /dev/null
+++ b/iup/src/win/iupwindows_info.c
@@ -0,0 +1,212 @@
+/** \file
+ * \brief Windows System Information
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This module should depend only on IUP core headers
+ and Windows system headers. */
+
+#include <windows.h>
+
+#include "iup_str.h"
+#include "iup_drvinfo.h"
+
+
+int iupdrvMakeDirectory(const char* name)
+{
+ if (CreateDirectory(name, NULL))
+ return 1;
+ else
+ return 0;
+}
+
+int iupdrvIsFile(const char* name)
+{
+ DWORD attrib = GetFileAttributes(name);
+ if (attrib == INVALID_FILE_ATTRIBUTES)
+ return 0;
+ if (attrib & FILE_ATTRIBUTE_DIRECTORY)
+ return 0;
+ return 1;
+}
+
+int iupdrvIsDirectory(const char* name)
+{
+ DWORD attrib = GetFileAttributes(name);
+ if (attrib == INVALID_FILE_ATTRIBUTES)
+ return 0;
+ if (attrib & FILE_ATTRIBUTE_DIRECTORY)
+ return 1;
+ return 0;
+}
+
+char* iupdrvGetCurrentDirectory(void)
+{
+ char* cur_dir;
+ int len = GetCurrentDirectory(0, NULL);
+ if (len == 0) return NULL;
+
+ cur_dir = malloc(len+2);
+ GetCurrentDirectory(len+1, cur_dir);
+ cur_dir[len] = '\\';
+ cur_dir[len+1] = 0;
+ return cur_dir;
+}
+
+int iupdrvSetCurrentDirectory(const char* dir)
+{
+ return SetCurrentDirectory(dir);
+}
+
+int iupdrvGetWindowDecor(void* wnd, int *border, int *caption)
+{
+ WINDOWINFO wi;
+ wi.cbSize = sizeof(WINDOWINFO);
+ GetWindowInfo((HWND)wnd, &wi);
+
+ *border = wi.cxWindowBorders;
+
+ if (wi.rcClient.bottom == wi.rcClient.top)
+ *caption = wi.rcClient.bottom - wi.cyWindowBorders;
+ else
+ {
+ /* caption = window height - top border - client height */
+ *caption = (wi.rcWindow.bottom-wi.rcWindow.top) - 2*wi.cyWindowBorders - (wi.rcClient.bottom-wi.rcClient.top);
+ }
+
+ return 1;
+}
+
+void iupdrvGetScreenSize(int *width, int *height)
+{
+ RECT area;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &area, 0);
+ *width = (int)(area.right - area.left);
+ *height = (int)(area.bottom - area.top);
+}
+
+void iupdrvGetFullSize(int *width, int *height)
+{
+ RECT rect;
+ GetWindowRect(GetDesktopWindow(), &rect);
+ *width = rect.right - rect.left;
+ *height = rect.bottom - rect.top;
+}
+
+int iupdrvGetScreenDepth(void)
+{
+ int bpp;
+ HDC hDCDisplay = GetDC(NULL);
+ bpp = GetDeviceCaps(hDCDisplay, BITSPIXEL);
+ ReleaseDC(NULL, hDCDisplay);
+ return bpp;
+}
+
+void iupdrvGetCursorPos(int *x, int *y)
+{
+ POINT CursorPoint;
+ GetCursorPos(&CursorPoint);
+ *x = (int)CursorPoint.x;
+ *y = (int)CursorPoint.y;
+}
+
+void iupdrvGetKeyState(char* key)
+{
+ if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
+ key[0] = 'S';
+ else
+ key[0] = ' ';
+ if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
+ key[1] = 'C';
+ else
+ key[1] = ' ';
+ if (GetAsyncKeyState(VK_MENU) & 0x8000)
+ key[2] = 'A';
+ else
+ key[2] = ' ';
+ if ((GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000))
+ key[3] = 'Y';
+ else
+ key[3] = ' ';
+
+ key[4] = 0;
+}
+
+char *iupdrvGetSystemName(void)
+{
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osvi);
+
+ if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ {
+ if (osvi.dwMajorVersion <= 4)
+ return "WinNT";
+
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
+ return "Win2K";
+
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion > 0)
+ return "WinXP";
+
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
+ return "Vista";
+
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion > 0)
+ return "Win7";
+ }
+
+ return "Windows";
+}
+
+char *iupdrvGetSystemVersion(void)
+{
+ char *str = iupStrGetMemory(256);
+ OSVERSIONINFOEX osvi;
+ SYSTEM_INFO si;
+
+ ZeroMemory(&si, sizeof(SYSTEM_INFO));
+ GetSystemInfo(&si);
+
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ GetVersionEx((OSVERSIONINFO*)&osvi);
+
+ sprintf(str, "%d.%d.%d", (int)osvi.dwMajorVersion, (int)osvi.dwMinorVersion, (int)osvi.dwBuildNumber);
+
+ /* Display service pack (if any). */
+ if (osvi.szCSDVersion && osvi.szCSDVersion[0]!=0)
+ {
+ strcat(str, " ");
+ strcat(str, osvi.szCSDVersion);
+ }
+
+ if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
+ strcat(str, " (IA64)");
+ else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+ strcat(str, " (x64)");
+ else
+ strcat(str, " (x86)");
+
+ return str;
+}
+
+char *iupdrvGetComputerName(void)
+{
+ DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
+ char* str = iupStrGetMemory(size);
+ GetComputerName((LPTSTR)str, &size);
+ return str;
+}
+
+char *iupdrvGetUserName(void)
+{
+ DWORD size = 256;
+ char* str = iupStrGetMemory(size);
+ GetUserName((LPTSTR)str, &size);
+ return (char*)str;
+}
diff --git a/iup/src/win/iupwindows_main.c b/iup/src/win/iupwindows_main.c
new file mode 100755
index 0000000..ea7e2ae
--- /dev/null
+++ b/iup/src/win/iupwindows_main.c
@@ -0,0 +1,66 @@
+/** \file
+ * \brief Windows Driver WinMain
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdlib.h> /* declaration of __argc and __argv */
+
+#include "iup.h"
+
+
+#ifdef __WATCOMC__ /* force Watcom to link this module, called from IupOpen */
+void iupwinMainDummy(void)
+{
+ return;
+}
+#else
+extern int main(int, char **);
+#endif
+
+/* save this handle in DllMain only, use to load resources from the DLL. */
+HINSTANCE iupwin_dll_hinstance = 0;
+
+#ifdef IUP_DLL
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ (void)fdwReason;
+ (void)lpvReserved;
+
+ iupwin_dll_hinstance = hinstDLL;
+
+ return TRUE;
+}
+#else
+/* this module is always linked in the makefile,
+ But it must not define WinMain if building the DLL */
+int PASCAL WinMain (HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int ncmdshow)
+{
+ (void)hinst; /* NOT used */
+ (void)hprev;
+ (void)cmdline;
+ (void)ncmdshow;
+
+ /* WinMain is NOT called for Console applications */
+
+#ifdef __WATCOMC__
+ {
+ extern int _argc;
+ extern char** _argv;
+ return IupMain(_argc, _argv);
+ }
+#else
+ {
+ /* this seems to work for all the compilers we tested, except Watcom compilers */
+ /* These are declared in <stdlib.h>, except for Cygwin. */
+#ifdef __GNUC__
+ extern int __argc;
+ extern char** __argv;
+#endif
+ return main(__argc, __argv);
+ }
+#endif
+}
+#endif