diff options
Diffstat (limited to 'iup/src')
115 files changed, 6496 insertions, 3363 deletions
diff --git a/iup/src/Makefile b/iup/src/Makefile index 028047f..e666555 100755 --- a/iup/src/Makefile +++ b/iup/src/Makefile @@ -1,9 +1,12 @@ -.PHONY: do_all iup iupgtk -do_all: iup iupgtk +.PHONY: do_all iup iupgtk iupmot +do_all: iup iup: - @$(MAKE) --no-print-directory -f ../tecmake_compact.mak + @$(MAKE) --no-print-directory -f ../tecmake.mak iupgtk: - @$(MAKE) --no-print-directory -f ../tecmake_compact.mak USE_GTK=Yes + @$(MAKE) --no-print-directory -f ../tecmake.mak USE_GTK=Yes + +iupmot: + @$(MAKE) --no-print-directory -f ../tecmake.mak USE_MOTIF=Yes diff --git a/iup/src/config.mak b/iup/src/config.mak index e857643..82b8452 100755 --- a/iup/src/config.mak +++ b/iup/src/config.mak @@ -2,9 +2,31 @@ PROJNAME = iup LIBNAME = iup OPT = YES -#ifdef DBG +ifdef GTK_DEFAULT + ifdef USE_MOTIF + # Build Motif version in Linux,Darwin,FreeBSD + LIBNAME = iupmot + else + ifeq ($(findstring Win, $(TEC_SYSNAME)), ) + # Force definition if not in Windows + USE_GTK = Yes + endif + endif +else + ifdef USE_GTK + # Build GTK version in IRIX,SunOS,AIX,Win32 + LIBNAME = iupgtk + else + ifeq ($(findstring Win, $(TEC_SYSNAME)), ) + # Force definition if not in Windows + USE_MOTIF = Yes + endif + endif +endif + +ifdef DBG DEFINES += IUP_ASSERT -#endif +endif INCLUDES = ../include . @@ -17,19 +39,14 @@ SRC = iup_array.c iup_callback.c iup_dlglist.c iup_attrib.c iup_focus.c iup_font iup_user.c iup_button.c iup_radio.c iup_toggle.c iup_progressbar.c iup_text.c iup_val.c \ iup_box.c iup_hbox.c iup_vbox.c iup_cbox.c iup_class.c iup_classbase.c iup_maskmatch.c \ iup_mask.c iup_maskparse.c iup_tabs.c iup_spin.c iup_list.c iup_getparam.c \ - iup_sbox.c iup_normalizer.c iup_tree.c + iup_sbox.c iup_normalizer.c iup_tree.c iup_split.c ifdef USE_GTK - ifndef GTK_DEFAULT - # Build GTK version in IRIX,SunOS,AIX,Win32 - LIBNAME := iupgtk - endif - DEFINES += GTK_DISABLE_DEPRECATED INCLUDES += gtk SRC += gtk/iupgtk_common.c gtk/iupgtk_focus.c gtk/iupgtk_font.c gtk/iupgtk_clipboard.c \ gtk/iupgtk_globalattrib.c gtk/iupgtk_key.c gtk/iupgtk_tips.c \ - gtk/iupgtk_loop.c gtk/iupgtk_open.c gtk/iupgtk_messagedlg.c \ + gtk/iupgtk_loop.c gtk/iupgtk_open.c gtk/iupgtk_messagedlg.c gtk/iupgtk_draw.c \ gtk/iupgtk_dialog.c gtk/iupgtk_timer.c gtk/iupgtk_image.c gtk/iupgtk_label.c \ gtk/iupgtk_colordlg.c gtk/iupgtk_fontdlg.c gtk/iupgtk_filedlg.c \ gtk/iupgtk_button.c gtk/iupgtk_toggle.c gtk/iupgtk_progressbar.c \ @@ -40,7 +57,11 @@ ifdef USE_GTK DEFINES += _WIN32_WINNT=0x0500 _WIN32_IE=0x0500 WINVER=0x0500 NOTREEVIEW SRC += win/iupwindows_main.c win/iupwindows_help.c win/iupwindows_info.c else - SRC += gtk/iupgtk_help.c mot/iupunix_info.c + ifdef GTK_MAC + SRC += gtk/iupmac_help.c gtk/iupmac_info.c + else + SRC += gtk/iupgtk_help.c mot/iupunix_info.c + endif endif ifdef USE_HILDON @@ -49,42 +70,35 @@ ifdef USE_GTK LIBS += hildon-1 endif else - ifneq ($(findstring Win, $(TEC_SYSNAME)), ) - - SRC += win/iupwin_common.c win/iupwin_brush.c win/iupwin_focus.c win/iupwin_font.c \ - win/iupwin_globalattrib.c win/iupwin_handle.c win/iupwin_key.c \ - win/iupwin_loop.c win/iupwin_open.c win/iupwin_tips.c win/iupwin_info.c \ - win/iupwin_dialog.c win/iupwin_messagedlg.c win/iupwin_timer.c \ - win/iupwin_image.c win/iupwin_label.c win/iupwin_canvas.c win/iupwin_frame.c \ - win/iupwin_colordlg.c win/iupwin_fontdlg.c win/iupwin_filedlg.c \ - win/iupwin_button.c win/iupwin_draw.c win/iupwin_toggle.c win/iupwin_clipboard.c \ - win/iupwin_progressbar.c win/iupwin_text.c win/iupwin_val.c \ - win/iupwin_tabs.c win/iupwin_menu.c win/iupwin_list.c win/iupwin_tree.c - - SRC += win/iupwindows_main.c win/iupwindows_help.c win/iupwindows_info.c - - INCLUDES += win - DEFINES += _WIN32_WINNT=0x0500 _WIN32_IE=0x0500 WINVER=0x0500 NOTREEVIEW - else - ifdef GTK_DEFAULT - # Build Motif version in Linux,Darwin,FreeBSD - LIBNAME := iupmot - endif - - SRC += mot/iupmot_common.c mot/iupmot_color.c mot/iupmot_focus.c mot/iupmot_font.c \ - mot/iupmot_key.c mot/iupmot_loop.c mot/iupmot_open.c mot/iupmot_tips.c \ - mot/iupmot_globalattrib.c mot/iupmot_dialog.c mot/iupmot_messagedlg.c \ - mot/iupmot_timer.c mot/iupmot_image.c mot/iupmot_label.c mot/iupmot_canvas.c \ - mot/iupmot_colordlg.c mot/iupmot_fontdlg.c mot/iupmot_filedlg.c mot/iupmot_frame.c \ - mot/iupmot_button.c mot/iupmot_toggle.c mot/iupmot_progressbar.c mot/iupmot_clipboard.c \ - mot/iupmot_text.c mot/iupmot_val.c mot/iupmot_tabs.c mot/iupmot_menu.c \ - mot/iupmot_list.c mot/iupmot_tree.c - - SRC += mot/iupunix_help.c mot/iupunix_info.c - - INCLUDES += mot - USE_MOTIF=Yes - endif +ifdef USE_MOTIF + SRC += mot/iupmot_common.c mot/iupmot_color.c mot/iupmot_focus.c mot/iupmot_font.c \ + mot/iupmot_key.c mot/iupmot_loop.c mot/iupmot_open.c mot/iupmot_tips.c \ + mot/iupmot_globalattrib.c mot/iupmot_dialog.c mot/iupmot_messagedlg.c mot/iupmot_draw.c \ + mot/iupmot_timer.c mot/iupmot_image.c mot/iupmot_label.c mot/iupmot_canvas.c \ + mot/iupmot_colordlg.c mot/iupmot_fontdlg.c mot/iupmot_filedlg.c mot/iupmot_frame.c \ + mot/iupmot_button.c mot/iupmot_toggle.c mot/iupmot_progressbar.c mot/iupmot_clipboard.c \ + mot/iupmot_text.c mot/iupmot_val.c mot/iupmot_tabs.c mot/iupmot_menu.c \ + mot/iupmot_list.c mot/iupmot_tree.c + + SRC += mot/iupunix_help.c mot/iupunix_info.c + + INCLUDES += mot +else + SRC += win/iupwin_common.c win/iupwin_brush.c win/iupwin_focus.c win/iupwin_font.c \ + win/iupwin_globalattrib.c win/iupwin_handle.c win/iupwin_key.c \ + win/iupwin_loop.c win/iupwin_open.c win/iupwin_tips.c win/iupwin_info.c \ + win/iupwin_dialog.c win/iupwin_messagedlg.c win/iupwin_timer.c \ + win/iupwin_image.c win/iupwin_label.c win/iupwin_canvas.c win/iupwin_frame.c \ + win/iupwin_colordlg.c win/iupwin_fontdlg.c win/iupwin_filedlg.c \ + win/iupwin_button.c win/iupwin_draw.c win/iupwin_toggle.c win/iupwin_clipboard.c \ + win/iupwin_progressbar.c win/iupwin_text.c win/iupwin_val.c \ + win/iupwin_tabs.c win/iupwin_menu.c win/iupwin_list.c win/iupwin_tree.c + + SRC += win/iupwindows_main.c win/iupwindows_help.c win/iupwindows_info.c + + INCLUDES += win + DEFINES += _WIN32_WINNT=0x0500 _WIN32_IE=0x0500 WINVER=0x0500 NOTREEVIEW +endif endif ifeq "$(TEC_SYSNAME)" "SunOS" @@ -113,6 +127,6 @@ ifeq "$(TEC_UNAME)" "dll" endif ifeq "$(TEC_UNAME)" "owc1" - # Necessary or IUP will not work in Open Watcom + # Necessary or IUP 3 will not work in Open Watcom DBG=Yes endif diff --git a/iup/src/gtk/iupgtk_button.c b/iup/src/gtk/iupgtk_button.c index 18be87c..f8474ae 100755 --- a/iup/src/gtk/iupgtk_button.c +++ b/iup/src/gtk/iupgtk_button.c @@ -150,8 +150,10 @@ static int gtkButtonSetPaddingAttrib(Ihandle* ih, const char* value) gtk_alignment_set_padding(alignment, ih->data->vert_padding, ih->data->vert_padding, ih->data->horiz_padding, ih->data->horiz_padding); } + return 0; } - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } #ifdef WIN32 @@ -366,12 +368,12 @@ static int gtkButtonMapMethod(Ihandle* ih) ih->data->type = IUP_BUTTON_IMAGE; value = iupAttribGet(ih, "TITLE"); - if (value) + if (value && *value!=0) { GtkSettings* settings = gtk_widget_get_settings(ih->handle); g_object_set(settings, "gtk-button-images", (int)TRUE, NULL); - gtk_button_set_label((GtkButton*)ih->handle, value); + gtk_button_set_label((GtkButton*)ih->handle, iupgtkStrConvertToUTF8(value)); ih->data->type |= IUP_BUTTON_TEXT; #if GTK_CHECK_VERSION(2, 10, 0) @@ -397,7 +399,7 @@ static int gtkButtonMapMethod(Ihandle* ih) #endif } else - gtk_button_set_label((GtkButton*)ih->handle, title); + gtk_button_set_label((GtkButton*)ih->handle, iupgtkStrConvertToUTF8(title)); ih->data->type = IUP_BUTTON_TEXT; } diff --git a/iup/src/gtk/iupgtk_canvas.c b/iup/src/gtk/iupgtk_canvas.c index daae4ad..3af48a4 100755 --- a/iup/src/gtk/iupgtk_canvas.c +++ b/iup/src/gtk/iupgtk_canvas.c @@ -537,8 +537,8 @@ static int gtkCanvasMapMethod(Ihandle* ih) /* To receive mouse events on a drawing area, you will need to enable them. */ gtk_widget_add_events(ih->handle, GDK_EXPOSURE_MASK| - GDK_POINTER_MOTION_MASK|GDK_BUTTON_MOTION_MASK| - GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK| + GDK_POINTER_MOTION_MASK|GDK_POINTER_MOTION_HINT_MASK| + GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|GDK_BUTTON_MOTION_MASK| GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK| GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK| GDK_FOCUS_CHANGE_MASK|GDK_STRUCTURE_MASK); @@ -611,14 +611,15 @@ void iupdrvCanvasInitClass(Iclass* ic) iupClassRegisterAttribute(ic, "YAUTOHIDE", NULL, gtkCanvasSetYAutoHideAttrib, "YES", NULL, IUPAF_DEFAULT); /* force new default value */ iupClassRegisterAttribute(ic, "DRAWABLE", gtkCanvasGetDrawableAttrib, NULL, NULL, NULL, IUPAF_NO_STRING); - //iupClassRegisterAttribute(ic, "CD_GDK", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); /* IupCanvas Windows or X only */ -#ifdef WIN32 - iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); -#else - iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); - iupClassRegisterAttribute(ic, "XDISPLAY", (IattribGetFunc)iupdrvGetDisplay, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); +#ifndef GTK_MAC + #ifdef WIN32 + iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); + #else + iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "XDISPLAY", (IattribGetFunc)iupdrvGetDisplay, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + #endif #endif } diff --git a/iup/src/gtk/iupgtk_common.c b/iup/src/gtk/iupgtk_common.c index 40368f2..d84c1c8 100755 --- a/iup/src/gtk/iupgtk_common.c +++ b/iup/src/gtk/iupgtk_common.c @@ -91,13 +91,13 @@ void iupdrvBaseUnMapMethod(Ihandle* ih) gtk_widget_destroy(widget); /* To match the call to gtk_*****_new */ } -void iupdrvDisplayUpdate(Ihandle *ih) +void iupdrvPostRedraw(Ihandle *ih) { /* Post a REDRAW */ gtk_widget_queue_draw(ih->handle); } -void iupdrvDisplayRedraw(Ihandle *ih) +void iupdrvRedrawNow(Ihandle *ih) { GdkWindow* window = ih->handle->window; /* Post a REDRAW */ @@ -202,7 +202,11 @@ void iupdrvSetVisible(Ihandle* ih, int visible) int iupdrvIsVisible(Ihandle* ih) { +#if GTK_CHECK_VERSION(2, 18, 0) + if (gtk_widget_get_visible(ih->handle)) +#else if (GTK_WIDGET_VISIBLE(ih->handle)) +#endif { /* if marked as visible, since we use gtk_widget_hide and NOT gtk_widget_hide_all must check its parents. */ @@ -211,7 +215,11 @@ int iupdrvIsVisible(Ihandle* ih) { if (parent->iclass->nativetype != IUP_TYPEVOID) { +#if GTK_CHECK_VERSION(2, 18, 0) + if (!gtk_widget_get_visible(parent->handle)) +#else if (!GTK_WIDGET_VISIBLE(parent->handle)) +#endif return 0; } @@ -225,7 +233,11 @@ int iupdrvIsVisible(Ihandle* ih) int iupdrvIsActive(Ihandle *ih) { - return (GTK_WIDGET_IS_SENSITIVE(ih->handle)); +#if GTK_CHECK_VERSION(2, 18, 0) + return gtk_widget_is_sensitive(ih->handle); +#else + return GTK_WIDGET_IS_SENSITIVE(ih->handle); +#endif } void iupdrvSetActive(Ihandle* ih, int enable) @@ -424,9 +436,11 @@ static GdkCursor* gtkGetCursor(Ihandle* ih, const char* name) { "RESIZE_N", GDK_TOP_SIDE}, { "RESIZE_S", GDK_BOTTOM_SIDE}, { "RESIZE_NS", GDK_SB_V_DOUBLE_ARROW}, + { "SPLITTER_HORIZ", GDK_SB_V_DOUBLE_ARROW}, { "RESIZE_W", GDK_LEFT_SIDE}, { "RESIZE_E", GDK_RIGHT_SIDE}, { "RESIZE_WE", GDK_SB_H_DOUBLE_ARROW}, + { "SPLITTER_VERT", GDK_SB_H_DOUBLE_ARROW}, { "RESIZE_NE", GDK_TOP_RIGHT_CORNER}, { "RESIZE_SE", GDK_BOTTOM_RIGHT_CORNER}, { "RESIZE_NW", GDK_TOP_LEFT_CORNER}, @@ -571,18 +585,24 @@ void iupdrvDrawFocusRect(Ihandle* ih, void* _gc, int x, int y, int w, int h) { GdkWindow* window = ih->handle->window; GtkStyle *style = gtk_widget_get_style(ih->handle); +#if GTK_CHECK_VERSION(2, 18, 0) + GtkStateType state = gtk_widget_get_state(ih->handle); +#else + GtkStateType state = GTK_WIDGET_STATE(ih->handle); +#endif + gtk_paint_focus(style, window, state, NULL, ih->handle, NULL, x, y, w, h); (void)_gc; - - gtk_paint_focus(style, window, GTK_WIDGET_STATE(ih->handle), NULL, ih->handle, NULL, x, y, w, h); } void iupdrvBaseRegisterCommonAttrib(Iclass* ic) { +#ifndef GTK_MAC #ifdef WIN32 iupClassRegisterAttribute(ic, "HFONT", iupgtkGetFontIdAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); #else iupClassRegisterAttribute(ic, "XFONTID", iupgtkGetFontIdAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); #endif +#endif iupClassRegisterAttribute(ic, "PANGOFONTDESC", iupgtkGetPangoFontDescAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); } @@ -789,7 +809,17 @@ char* iupgtkStrConvertFromFilename(const char* str) /* From Filename to IUP */ gboolean iupgtkMotionNotifyEvent(GtkWidget *widget, GdkEventMotion *evt, Ihandle *ih) { - IFniis cb = (IFniis)IupGetCallback(ih,"MOTION_CB"); + IFniis cb; + + if (evt->is_hint) + { + int x, y; + gdk_window_get_pointer(widget->window, &x, &y, NULL); + evt->x = x; + evt->y = y; + } + + cb = (IFniis)IupGetCallback(ih,"MOTION_CB"); if (cb) { char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; @@ -818,6 +848,23 @@ gboolean iupgtkButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih) iupgtkButtonKeySetStatus(evt->state, evt->button, status, doubleclick); + if (doubleclick) + { + /* Must compensate the fact that in GTK there is an extra button press event + when occours a double click, we compensate that completing the event + with a button release before the double click. */ + + status[5] = ' '; /* clear double click */ + + ret = cb(ih, b, 0, (int)evt->x, (int)evt->y, status); /* release */ + if (ret==IUP_CLOSE) + IupExitLoop(); + else if (ret==IUP_IGNORE) + return TRUE; + + status[5] = 'D'; /* restore double click */ + } + ret = cb(ih, b, press, (int)evt->x, (int)evt->y, status); if (ret==IUP_CLOSE) IupExitLoop(); diff --git a/iup/src/gtk/iupgtk_dialog.c b/iup/src/gtk/iupgtk_dialog.c index 46c0ce1..ff0d8f2 100755 --- a/iup/src/gtk/iupgtk_dialog.c +++ b/iup/src/gtk/iupgtk_dialog.c @@ -120,12 +120,13 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu static int native_border = 0; static int native_caption = 0; - int has_caption = iupAttribGetBoolean(ih, "MAXBOX") || - iupAttribGetBoolean(ih, "MINBOX") || - iupAttribGetBoolean(ih, "MENUBOX") || - IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ + int has_titlebar = iupAttribGetBoolean(ih, "RESIZE") || /* GTK and Motif only */ + iupAttribGetBoolean(ih, "MAXBOX") || + iupAttribGetBoolean(ih, "MINBOX") || + iupAttribGetBoolean(ih, "MENUBOX") || + IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ - int has_border = has_caption || + int has_border = has_titlebar || iupAttribGetBoolean(ih, "RESIZE") || iupAttribGetBoolean(ih, "BORDER"); @@ -147,7 +148,7 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu *border = win_border; *caption = 0; - if (has_caption) + if (has_titlebar) *caption = win_caption; if (!native_border && *border) @@ -171,7 +172,7 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu } *caption = 0; - if (has_caption) + if (has_titlebar) { if (native_caption) *caption = native_caption; @@ -429,6 +430,7 @@ static int gtkDialogMapMethod(Ihandle* ih) int functions = 0; InativeHandle* parent; GtkWidget* fixed; + int has_titlebar = 0; #ifdef HILDON if (iupAttribGetBoolean(ih, "HILDONWINDOW")) @@ -494,33 +496,41 @@ static int gtkDialogMapMethod(Ihandle* ih) iupAttribSetStr(ih, "MINBOX", "NO"); } - if (IupGetAttribute(ih, "TITLE")) { /* must use IupGetAttribute to check from the native implementation */ - functions |= GDK_FUNC_MOVE; - decorations |= GDK_DECOR_TITLE; - } - - if (iupAttribGetBoolean(ih, "MENUBOX")) { + if (iupAttribGet(ih, "TITLE")) + has_titlebar = 1; + if (iupAttribGetBoolean(ih, "MENUBOX")) + { functions |= GDK_FUNC_CLOSE; decorations |= GDK_DECOR_MENU; + has_titlebar = 1; } - - if (iupAttribGetBoolean(ih, "MINBOX")) { + if (iupAttribGetBoolean(ih, "MINBOX")) + { functions |= GDK_FUNC_MINIMIZE; decorations |= GDK_DECOR_MINIMIZE; + has_titlebar = 1; } - - if (iupAttribGetBoolean(ih, "MAXBOX")) { + if (iupAttribGetBoolean(ih, "MAXBOX")) + { functions |= GDK_FUNC_MAXIMIZE; decorations |= GDK_DECOR_MAXIMIZE; + has_titlebar = 1; } - - if (iupAttribGetBoolean(ih, "RESIZE")) { + if (iupAttribGetBoolean(ih, "RESIZE")) + { functions |= GDK_FUNC_RESIZE; decorations |= GDK_DECOR_RESIZEH; - } - if (iupAttribGetBoolean(ih, "BORDER")) - decorations |= GDK_DECOR_BORDER; + decorations |= GDK_DECOR_BORDER; /* has_border */ + } + if (has_titlebar) + { + functions |= GDK_FUNC_MOVE; + decorations |= GDK_DECOR_TITLE; + gtk_window_set_title((GtkWindow*)ih->handle, ""); + } + if (iupAttribGetBoolean(ih, "BORDER") || has_titlebar) + decorations |= GDK_DECOR_BORDER; /* has_border */ if (decorations == 0) gtk_window_set_decorated((GtkWindow*)ih->handle, FALSE); @@ -980,11 +990,12 @@ void iupdrvDialogInitClass(Iclass* ic) iupClassRegisterCallback(ic, "TRAYCLICK_CB", "iii"); /* Driver Dependent Attribute functions */ - -#ifdef WIN32 - iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); -#else - iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); +#ifndef GTK_MAC + #ifdef WIN32 + iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); + #else + iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); + #endif #endif /* Visual */ diff --git a/iup/src/gtk/iupgtk_draw.c b/iup/src/gtk/iupgtk_draw.c new file mode 100644 index 0000000..4390c66 --- /dev/null +++ b/iup/src/gtk/iupgtk_draw.c @@ -0,0 +1,161 @@ +/** \file + * \brief Draw Functions + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> + +#include <gtk/gtk.h> + +#include "iup.h" + +#include "iup_attrib.h" +#include "iup_class.h" +#include "iup_str.h" +#include "iup_object.h" +#include "iup_image.h" +#include "iup_draw.h" + +#include "iupgtk_drv.h" + + +struct _IdrawCanvas{ + Ihandle* ih; + int w, h; + + GdkDrawable* wnd; + GdkPixmap* pixmap; + GdkGC *gc, *pixmap_gc; +}; + +IdrawCanvas* iupDrawCreateCanvas(Ihandle* ih) +{ + IdrawCanvas* dc = calloc(1, sizeof(IdrawCanvas)); + + dc->wnd = ih->handle->window; + dc->gc = gdk_gc_new(dc->wnd); + + gdk_drawable_get_size(dc->wnd, &dc->w, &dc->h); + + dc->pixmap = gdk_pixmap_new(dc->wnd, dc->w, dc->h, gdk_drawable_get_depth(dc->wnd)); + dc->pixmap_gc = gdk_gc_new(dc->pixmap); + + return dc; +} + +void iupDrawKillCanvas(IdrawCanvas* dc) +{ + g_object_unref(dc->pixmap_gc); + g_object_unref(dc->pixmap); + g_object_unref(dc->gc); + + free(dc); +} + +void iupDrawUpdateSize(IdrawCanvas* dc) +{ + int w, h; + gdk_drawable_get_size(dc->wnd, &w, &h); + + if (w != dc->w || h != dc->h) + { + g_object_unref(dc->pixmap_gc); + g_object_unref(dc->pixmap); + + dc->pixmap = gdk_pixmap_new(dc->wnd, dc->w, dc->h, gdk_drawable_get_depth(dc->wnd)); + dc->pixmap_gc = gdk_gc_new(dc->pixmap); + } +} + +void iupDrawFlush(IdrawCanvas* dc) +{ + gdk_draw_drawable(dc->wnd, dc->gc, dc->pixmap, 0, 0, 0, 0, dc->w, dc->h); +} + +void iupDrawGetSize(IdrawCanvas* dc, int *w, int *h) +{ + if (w) *w = dc->w; + if (h) *h = dc->h; +} + +void iupDrawParentBackground(IdrawCanvas* dc) +{ + unsigned char r=0, g=0, b=0; + char* color = iupBaseNativeParentGetBgColorAttrib(dc->ih); + iupStrToRGB(color, &r, &g, &b); + iupDrawRectangle(dc, 0, 0, dc->w-1, dc->h-1, r, g, b, 1); +} + +void iupDrawRectangle(IdrawCanvas* dc, int x1, int y1, int x2, int y2, unsigned char r, unsigned char g, unsigned char b, int filled) +{ + GdkColor color; + iupgdkColorSet(&color, r, g, b); + gdk_gc_set_rgb_fg_color(dc->pixmap_gc, &color); + gdk_draw_rectangle(dc->pixmap, dc->pixmap_gc, filled, x1, y1, x2-x1+1, y2-y1+1); +} + +void iupDrawLine(IdrawCanvas* dc, int x1, int y1, int x2, int y2, unsigned char r, unsigned char g, unsigned char b) +{ + GdkColor color; + iupgdkColorSet(&color, r, g, b); + gdk_gc_set_rgb_fg_color(dc->pixmap_gc, &color); + gdk_draw_line(dc->pixmap, dc->pixmap_gc, x1, y1, x2, y2); +} + +void iupDrawArc(IdrawCanvas* dc, int x1, int y1, int x2, int y2, double a1, double a2, unsigned char r, unsigned char g, unsigned char b, int filled) +{ + GdkColor color; + iupgdkColorSet(&color, r, g, b); + gdk_gc_set_rgb_fg_color(dc->pixmap_gc, &color); + gdk_draw_arc(dc->pixmap, dc->pixmap_gc, filled, x1, y1, x2-x1+1, y2-y1+1, iupROUND(a1*64), iupROUND((a2 - a1)*64)); +} + +void iupDrawPolygon(IdrawCanvas* dc, int* points, int count, unsigned char r, unsigned char g, unsigned char b, int filled) +{ + GdkColor color; + iupgdkColorSet(&color, r, g, b); + gdk_gc_set_rgb_fg_color(dc->pixmap_gc, &color); + gdk_draw_polygon(dc->pixmap, dc->pixmap_gc, filled, (GdkPoint*)points, count); +} + +void iupDrawSetClipRect(IdrawCanvas* dc, int x1, int y1, int x2, int y2) +{ + GdkRectangle rect; + rect.x = x1; + rect.y = y1; + rect.width = x2-x1+1; + rect.height = y2-y1+1; + gdk_gc_set_clip_rectangle(dc->pixmap_gc, &rect); +} + +void iupDrawResetClip(IdrawCanvas* dc) +{ + gdk_gc_set_clip_region(dc->pixmap_gc, NULL); +} + +void iupDrawText(IdrawCanvas* dc, const char* text, int len, int x, int y, unsigned char r, unsigned char g, unsigned char b) +{ + PangoLayout* fontlayout = (PangoLayout*)IupGetAttribute(dc->ih, "PANGOLAYOUT"); + GdkColor color; + iupgdkColorSet(&color, r, g, b); + gdk_gc_set_rgb_fg_color(dc->pixmap_gc, &color); + pango_layout_set_text(fontlayout, iupgtkStrConvertToUTF8(text), len); + gdk_draw_layout(dc->pixmap, dc->pixmap_gc, x, y, fontlayout); +} + +void iupDrawImage(IdrawCanvas* dc, const char* name, int make_inactive, int x, int y) +{ + int img_w, img_h, bpp; + GdkPixbuf* pixbuf = iupImageGetImage(name, dc->ih, make_inactive); + if (!pixbuf) + return; + + /* must use this info, since image can be a driver image loaded from resources */ + iupdrvImageGetInfo(pixbuf, &img_w, &img_h, &bpp); + + gdk_draw_pixbuf(dc->pixmap, dc->pixmap_gc, pixbuf, 0, 0, x, y, img_w, img_h, GDK_RGB_DITHER_NORMAL, 0, 0); +} diff --git a/iup/src/gtk/iupgtk_drv.h b/iup/src/gtk/iupgtk_drv.h index ade2a4a..bf567d6 100755 --- a/iup/src/gtk/iupgtk_drv.h +++ b/iup/src/gtk/iupgtk_drv.h @@ -59,8 +59,8 @@ void iupgtkFontUpdateObjectPangoLayout(Ihandle* ih, gpointer object); /* There are PANGO_SCALE Pango units in one device unit. For an output backend where a device unit is a pixel, a size value of 10 * PANGO_SCALE gives 10 pixels. */ -#define IUPGTK_PANGOUNITS2PIXELS(_x) (((_x) + PANGO_SCALE/2) / PANGO_SCALE) -#define IUPGTK_PIXELS2PANGOUNITS(_x) ((_x) * PANGO_SCALE) +#define iupGTK_PANGOUNITS2PIXELS(_x) (((_x) + PANGO_SCALE/2) / PANGO_SCALE) +#define iupGTK_PIXELS2PANGOUNITS(_x) ((_x) * PANGO_SCALE) /* open */ diff --git a/iup/src/gtk/iupgtk_filedlg.c b/iup/src/gtk/iupgtk_filedlg.c index 5426910..a326c72 100755 --- a/iup/src/gtk/iupgtk_filedlg.c +++ b/iup/src/gtk/iupgtk_filedlg.c @@ -77,6 +77,8 @@ static void gtkFileDlgGetMultipleFiles(Ihandle* ih, GSList* list) cur_len = iupArrayCount(names_array); all_names = iupArrayAdd(names_array, dir_len+1); memcpy(all_names+cur_len, filename, dir_len); + all_names[cur_len+dir_len] = '0'; + iupAttribStoreStr(ih, "DIRECTORY", all_names); all_names[cur_len+dir_len] = '|'; dir_len++; /* skip separator */ @@ -101,10 +103,14 @@ static void gtkFileDlgGetMultipleFiles(Ihandle* ih, GSList* list) iupArrayDestroy(names_array); } -#ifdef WIN32 -#include <gdk/gdkwin32.h> +#ifdef GTK_MAC + #include <gdk/gdk.h> #else -#include <gdk/gdkx.h> + #ifdef WIN32 + #include <gdk/gdkwin32.h> + #else + #include <gdk/gdkx.h> + #endif #endif static void gtkFileDlgUpdatePreviewGLCanvas(Ihandle* ih) @@ -112,10 +118,12 @@ static void gtkFileDlgUpdatePreviewGLCanvas(Ihandle* ih) Ihandle* glcanvas = IupGetAttributeHandle(ih, "PREVIEWGLCANVAS"); if (glcanvas) { -#ifdef WIN32 - iupAttribSetStr(glcanvas, "HWND", iupAttribGet(ih, "HWND")); -#else - iupAttribSetStr(glcanvas, "XWINDOW", iupAttribGet(ih, "XWINDOW")); +#ifndef GTK_MAC + #ifdef WIN32 + iupAttribSetStr(glcanvas, "HWND", iupAttribGet(ih, "HWND")); + #else + iupAttribSetStr(glcanvas, "XWINDOW", iupAttribGet(ih, "XWINDOW")); + #endif #endif glcanvas->iclass->Map(glcanvas); } @@ -126,12 +134,15 @@ static void gtkFileDlgPreviewRealize(GtkWidget *widget, Ihandle *ih) iupAttribSetStr(ih, "PREVIEWDC", iupgtkGetNativeGraphicsContext(widget)); iupAttribSetStr(ih, "WID", (char*)widget); -#ifdef WIN32 - iupAttribSetStr(ih, "HWND", (char*)GDK_WINDOW_HWND(widget->window)); -#else - iupAttribSetStr(ih, "XWINDOW", (char*)GDK_WINDOW_XID(widget->window)); - iupAttribSetStr(ih, "XDISPLAY", (char*)iupdrvGetDisplay()); +#ifndef GTK_MAC + #ifdef WIN32 + iupAttribSetStr(ih, "HWND", (char*)GDK_WINDOW_HWND(widget->window)); + #else + iupAttribSetStr(ih, "XWINDOW", (char*)GDK_WINDOW_XID(widget->window)); + iupAttribSetStr(ih, "XDISPLAY", (char*)iupdrvGetDisplay()); + #endif #endif + gtkFileDlgUpdatePreviewGLCanvas(ih); } @@ -174,11 +185,11 @@ static void gtkFileDlgUpdatePreview(GtkFileChooser *file_chooser, Ihandle* ih) { char *filename = gtk_file_chooser_get_preview_filename(file_chooser); + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); if (iupdrvIsFile(filename)) - { - IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); cb(ih, iupgtkStrConvertFromFilename(filename), "SELECT"); - } + else + cb(ih, iupgtkStrConvertFromFilename(filename), "OTHER"); g_free (filename); @@ -469,6 +480,13 @@ static int gtkFileDlgPopup(Ihandle* ih, int x, int y) char* filename = (char*)file_list->data; iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(filename)); g_free(filename); + + /* store the DIRECTORY */ + { + char* dir = iupStrFileGetPath(iupAttribGet(ih, "VALUE")); + iupAttribStoreStr(ih, "DIRECTORY", dir); + free(dir); + } } g_slist_free(file_list); @@ -481,6 +499,14 @@ static int gtkFileDlgPopup(Ihandle* ih, int x, int y) iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(filename)); file_exist = iupdrvIsFile(filename); dir_exist = iupdrvIsDirectory(filename); + + if (file_exist) + { + char* dir = iupStrFileGetPath(filename); + iupAttribStoreStr(ih, "DIRECTORY", dir); + free(dir); + } + g_free(filename); } @@ -507,8 +533,11 @@ static int gtkFileDlgPopup(Ihandle* ih, int x, int y) { /* GtkFileChooser does not change the current directory */ char* dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog)); - if (dir) iupdrvSetCurrentDirectory(dir); - g_free(dir); + if (dir) + { + iupdrvSetCurrentDirectory(dir); + g_free(dir); + } } } else diff --git a/iup/src/gtk/iupgtk_font.c b/iup/src/gtk/iupgtk_font.c index f7ff348..1139f62 100755 --- a/iup/src/gtk/iupgtk_font.c +++ b/iup/src/gtk/iupgtk_font.c @@ -132,9 +132,9 @@ static IgtkFont* gtkFindFont(const char *standardfont) metrics = pango_context_get_metrics(gtk_fonts_context, fontdesc, pango_context_get_language(gtk_fonts_context)); fonts[i].charheight = pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics); - fonts[i].charheight = IUPGTK_PANGOUNITS2PIXELS(fonts[i].charheight); + fonts[i].charheight = iupGTK_PANGOUNITS2PIXELS(fonts[i].charheight); fonts[i].charwidth = pango_font_metrics_get_approximate_char_width(metrics); - fonts[i].charwidth = IUPGTK_PANGOUNITS2PIXELS(fonts[i].charwidth); + fonts[i].charwidth = iupGTK_PANGOUNITS2PIXELS(fonts[i].charwidth); pango_font_metrics_unref(metrics); gtkFontUpdate(&(fonts[i])); diff --git a/iup/src/gtk/iupgtk_fontdlg.c b/iup/src/gtk/iupgtk_fontdlg.c index 5769cbc..dca0232 100755 --- a/iup/src/gtk/iupgtk_fontdlg.c +++ b/iup/src/gtk/iupgtk_fontdlg.c @@ -24,7 +24,7 @@ static int gtkFontDlgPopup(Ihandle* ih, int x, int y) InativeHandle* parent = iupDialogGetNativeParent(ih); GtkFontSelectionDialog* dialog; int response; - char* preview_text; + char* preview_text, *standardfont; iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ iupAttribSetInt(ih, "_IUPDLG_Y", y); @@ -36,7 +36,10 @@ static int gtkFontDlgPopup(Ihandle* ih, int x, int y) if (parent) gtk_window_set_transient_for((GtkWindow*)dialog, (GtkWindow*)parent); - gtk_font_selection_dialog_set_font_name(dialog, iupAttribGet(ih, "VALUE")); + standardfont = iupAttribGet(ih, "VALUE"); + if (!standardfont) + standardfont = IupGetGlobal("DEFAULTFONT"); + gtk_font_selection_dialog_set_font_name(dialog, standardfont); preview_text = iupAttribGet(ih, "PREVIEWTEXT"); if (preview_text) diff --git a/iup/src/gtk/iupgtk_frame.c b/iup/src/gtk/iupgtk_frame.c index 022c6c7..25595be 100755 --- a/iup/src/gtk/iupgtk_frame.c +++ b/iup/src/gtk/iupgtk_frame.c @@ -41,8 +41,11 @@ static char* gtkFrameGetTitleAttrib(Ihandle* ih) static int gtkFrameSetTitleAttrib(Ihandle* ih, const char* value) { - GtkFrame* frame = (GtkFrame*)ih->handle; - gtk_frame_set_label(frame, iupgtkStrConvertToUTF8(value)); + if (iupAttribGetStr(ih, "_IUPFRAME_HAS_TITLE")) + { + GtkFrame* frame = (GtkFrame*)ih->handle; + gtk_frame_set_label(frame, iupgtkStrConvertToUTF8(value)); + } return 0; } @@ -57,7 +60,11 @@ static int gtkFrameSetBgColorAttrib(Ihandle* ih, const char* value) if (label) iupgtkBaseSetBgColor(label, r, g, b); - iupgtkBaseSetBgColor(ih->handle, r, g, b); + if (iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) + { + GtkWidget* fixed = gtk_bin_get_child((GtkBin*)ih->handle); + iupgtkBaseSetBgColor(fixed, r, g, b); + } return 1; } @@ -120,10 +127,19 @@ static int gtkFrameMapMethod(Ihandle* ih) gtk_frame_set_shadow_type((GtkFrame*)ih->handle, GTK_SHADOW_IN); else gtk_frame_set_shadow_type((GtkFrame*)ih->handle, GTK_SHADOW_ETCHED_IN); + + if (iupAttribGet(ih, "BGCOLOR")) + iupAttribSetStr(ih, "_IUPFRAME_HAS_BGCOLOR", "1"); } /* the container that will receive the child element. */ fixed = gtk_fixed_new(); + if (iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) +#if GTK_CHECK_VERSION(2, 18, 0) + gtk_widget_set_has_window(fixed, TRUE); +#else + gtk_fixed_set_has_window((GtkFixed*)fixed, TRUE); +#endif gtk_container_add((GtkContainer*)ih->handle, fixed); gtk_widget_show(fixed); diff --git a/iup/src/gtk/iupgtk_key.c b/iup/src/gtk/iupgtk_key.c index 5aec919..ed485a7 100755 --- a/iup/src/gtk/iupgtk_key.c +++ b/iup/src/gtk/iupgtk_key.c @@ -316,9 +316,9 @@ gboolean iupgtkKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) if (code == 0) return FALSE; - /* Avoid duplicate calls if a child of the dialog contains the focus. - GTK will call the callback for the child and for the dialog */ - if (ih->iclass->nativetype == IUP_TYPEDIALOG && ih != IupGetFocus()) + /* Avoid duplicate calls if a child of a native container contains the focus. + GTK will call the callback for the child and for the container. */ + if (ih->iclass->childtype != IUP_CHILDNONE && ih != IupGetFocus()) return FALSE; result = iupKeyCallKeyCb(ih, code); @@ -390,33 +390,33 @@ gboolean iupgtkKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) void iupgtkButtonKeySetStatus(guint state, unsigned int but, char* status, int doubleclick) { if (state & GDK_SHIFT_MASK) - iupKEYSETSHIFT(status); + iupKEY_SETSHIFT(status); if (state & GDK_CONTROL_MASK) - iupKEYSETCONTROL(status); + iupKEY_SETCONTROL(status); if ((state & GDK_BUTTON1_MASK) || but==1) - iupKEYSETBUTTON1(status); + iupKEY_SETBUTTON1(status); if ((state & GDK_BUTTON2_MASK) || but==2) - iupKEYSETBUTTON2(status); + iupKEY_SETBUTTON2(status); if ((state & GDK_BUTTON3_MASK) || but==3) - iupKEYSETBUTTON3(status); + iupKEY_SETBUTTON3(status); if ((state & GDK_BUTTON4_MASK) || but==4) - iupKEYSETBUTTON4(status); + iupKEY_SETBUTTON4(status); if ((state & GDK_BUTTON5_MASK) || but==5) - iupKEYSETBUTTON5(status); + iupKEY_SETBUTTON5(status); if (state & GDK_MOD1_MASK || state & GDK_MOD5_MASK) /* Alt */ - iupKEYSETALT(status); + iupKEY_SETALT(status); if (state & GDK_MOD4_MASK) /* Apple/Win */ - iupKEYSETSYS(status); + iupKEY_SETSYS(status); if (doubleclick) - iupKEYSETDOUBLE(status); + iupKEY_SETDOUBLE(status); } diff --git a/iup/src/gtk/iupgtk_label.c b/iup/src/gtk/iupgtk_label.c index 49d5c6d..f95f576 100755 --- a/iup/src/gtk/iupgtk_label.c +++ b/iup/src/gtk/iupgtk_label.c @@ -133,8 +133,10 @@ static int gtkLabelSetPaddingAttrib(Ihandle* ih, const char* value) { GtkMisc* misc = (GtkMisc*)ih->handle; gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding); + return 0; } - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } static char* gtkLabelGetPangoLayoutAttrib(Ihandle* ih) diff --git a/iup/src/gtk/iupgtk_list.c b/iup/src/gtk/iupgtk_list.c index 80f6cce..48fa88e 100755 --- a/iup/src/gtk/iupgtk_list.c +++ b/iup/src/gtk/iupgtk_list.c @@ -113,6 +113,8 @@ void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value) GtkTreeIter iter; gtk_list_store_insert(GTK_LIST_STORE(model), &iter, pos); gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, iupgtkStrConvertToUTF8(value), -1); + + iupListUpdateOldValue(ih, pos, 0); } void iupdrvListRemoveItem(Ihandle* ih, int pos) @@ -127,14 +129,24 @@ void iupdrvListRemoveItem(Ihandle* ih, int pos) int curpos = gtk_combo_box_get_active((GtkComboBox*)ih->handle); if (pos == curpos) { - if (curpos > 0) curpos--; - else curpos++; + if (curpos > 0) + curpos--; + else + { + curpos=1; + if (iupdrvListGetCount(ih)==1) + curpos = -1; /* remove the selection */ + } + g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkListComboBoxChanged), ih); gtk_combo_box_set_active((GtkComboBox*)ih->handle, curpos); + g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkListComboBoxChanged), ih); } } gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + + iupListUpdateOldValue(ih, pos, 1); } } @@ -177,7 +189,7 @@ static int gtkListSetStandardFontAttrib(Ihandle* ih, const char* value) static char* gtkListGetIdValueAttrib(Ihandle* ih, const char* name_id) { int pos = iupListGetPos(ih, name_id); - if (pos != -1) + if (pos >= 0) { GtkTreeIter iter; GtkTreeModel* model = gtkListGetModel(ih); @@ -349,7 +361,7 @@ static int gtkListSetValueAttrib(Ihandle* ih, const char* value) GtkTreeModel *model = gtkListGetModel(ih); g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkListComboBoxChanged), ih); if (iupStrToInt(value, &pos)==1 && - (pos>0 && pos<gtk_tree_model_iter_n_children(model, NULL))) + (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); @@ -788,9 +800,10 @@ static int gtkListSetNCAttrib(Ihandle* ih, const char* value) { GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); gtk_entry_set_max_length(entry, ih->data->nc); + return 0; } - - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } static int gtkListSetClipboardAttrib(Ihandle *ih, const char *value) @@ -1364,9 +1377,9 @@ static int gtkListMapMethod(Ihandle* ih) if (!ih->data->has_editbox && ih->data->is_multiple) { gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); -#if GTK_CHECK_VERSION(2, 10, 0) + #if GTK_CHECK_VERSION(2, 10, 0) gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(ih->handle), TRUE); -#endif + #endif } else gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); diff --git a/iup/src/gtk/iupgtk_loop.c b/iup/src/gtk/iupgtk_loop.c index e349a45..704923e 100755 --- a/iup/src/gtk/iupgtk_loop.c +++ b/iup/src/gtk/iupgtk_loop.c @@ -69,6 +69,13 @@ int IupMainLoop(void) return IUP_NOERROR; } +int IupLoopStepWait(void) +{ + if (gtk_main_iteration_do(TRUE)) + return IUP_CLOSE; + return IUP_DEFAULT; +} + int IupLoopStep(void) { if (gtk_main_iteration_do(FALSE)) diff --git a/iup/src/gtk/iupgtk_menu.c b/iup/src/gtk/iupgtk_menu.c index c12fbea..772f4cf 100755 --- a/iup/src/gtk/iupgtk_menu.c +++ b/iup/src/gtk/iupgtk_menu.c @@ -245,11 +245,19 @@ static int gtkMenuMapMethod(Ihandle* ih) return IUP_NOERROR; } +static void gtkMenuUnMapMethod(Ihandle* ih) +{ + if (iupMenuIsMenuBar(ih)) + ih->parent = NULL; + + iupdrvBaseUnMapMethod(ih); +} + void iupdrvMenuInitClass(Iclass* ic) { /* Driver Dependent Class functions */ ic->Map = gtkMenuMapMethod; - ic->UnMap = iupdrvBaseUnMapMethod; + ic->UnMap = gtkMenuUnMapMethod; /* Used by iupdrvMenuGetMenuBarSize */ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, NULL, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_DEFAULT); /* use inheritance to retrieve standard fonts */ @@ -337,15 +345,10 @@ static int gtkItemSetValueAttrib(Ihandle* ih, const char* value) static char* gtkItemGetValueAttrib(Ihandle* ih) { - if (GTK_IS_CHECK_MENU_ITEM(ih->handle)) - { - if (gtk_check_menu_item_get_active((GtkCheckMenuItem*)ih->handle)) - return "ON"; - else - return "OFF"; - } + if (GTK_IS_CHECK_MENU_ITEM(ih->handle) && gtk_check_menu_item_get_active((GtkCheckMenuItem*)ih->handle)) + return "ON"; else - return NULL; + return "OFF"; } static int gtkItemMapMethod(Ihandle* ih) diff --git a/iup/src/gtk/iupgtk_open.c b/iup/src/gtk/iupgtk_open.c index 66e46e8..962f760 100755 --- a/iup/src/gtk/iupgtk_open.c +++ b/iup/src/gtk/iupgtk_open.c @@ -20,7 +20,52 @@ #include "iupgtk_drv.h" +#ifdef GTK_MAC +#include <gdk/gdk.h> +char* iupgtkGetNativeWindowHandle(Ihandle* ih) +{ + GdkWindow* window = ih->handle->window; + if (window) + return (char*)window; + else + return NULL; +} + +void* iupgtkGetNativeGraphicsContext(GtkWidget* widget) +{ + return (void*)gdk_gc_new((GdkDrawable*)widget->window); +} + +void iupgtkReleaseNativeGraphicsContext(GtkWidget* widget, void* gc) +{ + g_object_unref(gc); + (void)widget; +} + +void* iupdrvGetDisplay(void) +{ + GdkDisplay* display = gdk_display_get_default(); + return display; +} + +void iupgtkPushVisualAndColormap(void* visual, void* colormap) +{ + GdkColormap* gdk_colormap; + GdkVisual *gdk_visual = gdk_visual_get_best(); + + gdk_colormap = gdk_colormap_new(gdk_visual, FALSE); + + gtk_widget_push_colormap(gdk_colormap); + + /* gtk_widget_push_visual is now deprecated */ +} + +static void gtkSetDrvGlobalAttrib(void) +{ +} + +#else #ifdef WIN32 /******************************** WIN32 ************************************/ #include <gdk/gdkwin32.h> @@ -115,6 +160,8 @@ static void gtkSetDrvGlobalAttrib(void) #endif +#endif + static void gtkSetGlobalColorAttrib(const char* name, GdkColor *color) { iupGlobalSetDefaultColorAttrib(name, (int)iupCOLOR16TO8(color->red), diff --git a/iup/src/gtk/iupgtk_tabs.c b/iup/src/gtk/iupgtk_tabs.c index 8029826..6b5aa66 100755 --- a/iup/src/gtk/iupgtk_tabs.c +++ b/iup/src/gtk/iupgtk_tabs.c @@ -76,13 +76,13 @@ static void gtkTabsUpdatePageBgColor(Ihandle* ih, unsigned char r, unsigned char for (child = ih->firstchild; child; child = child->brother) { - GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); - if (tab_page) + GtkWidget* tab_container = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (tab_container) { GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL"); if (tab_label) iupgtkBaseSetBgColor(tab_label, r, g, b); - iupgtkBaseSetBgColor(tab_page, r, g, b); + iupgtkBaseSetBgColor(tab_container, r, g, b); } } } @@ -121,15 +121,18 @@ static int gtkTabsSetPaddingAttrib(Ihandle* ih, const char* value) iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); if (ih->handle) + { gtkTabsUpdatePagePadding(ih); - return 0; + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ } static void gtkTabsUpdateTabType(Ihandle* ih) { - GtkNotebook* tab_page = (GtkNotebook*)ih->handle; int iup2gtk[4] = {GTK_POS_TOP, GTK_POS_BOTTOM, GTK_POS_LEFT, GTK_POS_RIGHT}; - gtk_notebook_set_tab_pos(tab_page, iup2gtk[ih->data->type]); + gtk_notebook_set_tab_pos((GtkNotebook*)ih->handle, iup2gtk[ih->data->type]); } static int gtkTabsSetTabTypeAttrib(Ihandle* ih, const char* value) @@ -144,7 +147,7 @@ static int gtkTabsSetTabTypeAttrib(Ihandle* ih, const char* value) ih->data->type = ITABS_TOP; if (ih->handle) - gtkTabsUpdateTabType(ih); + gtkTabsUpdateTabType(ih); /* for this to work must be updated in map */ return 0; } @@ -171,7 +174,7 @@ static int gtkTabsSetTabTitleAttrib(Ihandle* ih, const char* name_id, const char GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL"); if (tab_label) { - GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); + GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_PAGE"); gtk_label_set_text((GtkLabel*)tab_label, iupgtkStrConvertToUTF8(value)); gtk_notebook_set_menu_label_text((GtkNotebook*)ih->handle, tab_page, gtk_label_get_text((GtkLabel*)tab_label)); } @@ -238,8 +241,10 @@ void gtkTabSwitchPage(GtkNotebook* notebook, GtkNotebookPage *page, int pos, Iha IFnnn cb; Ihandle* child = IupGetChild(ih, pos); Ihandle* prev_child = IupGetChild(ih, iupdrvTabsGetCurrentTab(ih)); - IupSetAttribute(child, "VISIBLE", "YES"); - IupSetAttribute(prev_child, "VISIBLE", "NO"); + GtkWidget* tab_container = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); + GtkWidget* prev_tab_container = (GtkWidget*)iupAttribGet(prev_child, "_IUPTAB_CONTAINER"); + if (tab_container) gtk_widget_show(tab_container); + if (prev_tab_container) gtk_widget_hide(prev_tab_container); if (iupAttribGet(ih, "_IUPGTK_IGNORE_CHANGE")) return; @@ -263,7 +268,7 @@ static void gtkTabsChildAddedMethod(Ihandle* ih, Ihandle* child) if (ih->handle) { - GtkWidget* tab_page; + GtkWidget *tab_page, *tab_container; GtkWidget *tab_label = NULL, *tab_image = NULL; char *tabtitle, *tabimage; int pos; @@ -271,9 +276,13 @@ static void gtkTabsChildAddedMethod(Ihandle* ih, Ihandle* child) pos = IupGetChildPos(ih, child); - tab_page = gtk_fixed_new(); + tab_page = gtk_vbox_new(FALSE, 0); gtk_widget_show(tab_page); + tab_container = gtk_fixed_new(); + gtk_widget_show(tab_container); + gtk_container_add((GtkContainer*)tab_page, tab_container); + tabtitle = iupAttribGet(child, "TABTITLE"); if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos); tabimage = iupAttribGet(child, "TABIMAGE"); @@ -327,9 +336,10 @@ static void gtkTabsChildAddedMethod(Ihandle* ih, Ihandle* child) iupAttribSetStr(child, "_IUPGTK_TABIMAGE", (char*)tab_image); /* store it even if its NULL */ iupAttribSetStr(child, "_IUPGTK_TABLABEL", (char*)tab_label); - iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)tab_page); + iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)tab_container); + iupAttribSetStr(child, "_IUPTAB_PAGE", (char*)tab_page); iupStrToRGB(IupGetAttribute(ih, "BGCOLOR"), &r, &g, &b); - iupgtkBaseSetBgColor(tab_page, r, g, b); + iupgtkBaseSetBgColor(tab_container, r, g, b); if (tabtitle) { @@ -354,10 +364,8 @@ static void gtkTabsChildAddedMethod(Ihandle* ih, Ihandle* child) iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", NULL); - if (pos == iupdrvTabsGetCurrentTab(ih)) - IupSetAttribute(child, "VISIBLE", "YES"); - else - IupSetAttribute(child, "VISIBLE", "NO"); + if (pos != iupdrvTabsGetCurrentTab(ih)) + gtk_widget_hide(tab_container); } } @@ -365,10 +373,11 @@ static void gtkTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) { if (ih->handle) { - GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); + GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_PAGE"); if (tab_page) { int pos = gtk_notebook_page_num((GtkNotebook*)ih->handle, tab_page); + iupTabsTestRemoveTab(ih, pos); iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", "1"); gtk_notebook_remove_page((GtkNotebook*)ih->handle, pos); @@ -377,6 +386,7 @@ static void gtkTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) iupAttribSetStr(child, "_IUPGTK_TABIMAGE", NULL); iupAttribSetStr(child, "_IUPGTK_TABLABEL", NULL); iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL); + iupAttribSetStr(child, "_IUPTAB_PAGE", NULL); } } } @@ -440,5 +450,5 @@ void iupdrvTabsInitClass(Iclass* ic) iupClassRegisterAttribute(ic, "TABORIENTATION", iupTabsGetTabOrientationAttrib, gtkTabsSetTabOrientationAttrib, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "TABTITLE", NULL, gtkTabsSetTabTitleAttrib, IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, gtkTabsSetTabImageAttrib, IUPAF_NO_INHERIT); - iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, gtkTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, gtkTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); } diff --git a/iup/src/gtk/iupgtk_text.c b/iup/src/gtk/iupgtk_text.c index 4c2906a..d0909d7 100755 --- a/iup/src/gtk/iupgtk_text.c +++ b/iup/src/gtk/iupgtk_text.c @@ -101,7 +101,7 @@ static void gtkTextParseParagraphFormat(Ihandle* formattag, GtkTextTag* tag) align = PANGO_TAB_LEFT; free(str); - pango_tab_array_set_tab(tabs, i, align, IUPGTK_PIXELS2PANGOUNITS(pos)); + pango_tab_array_set_tab(tabs, i, align, iupGTK_PIXELS2PANGOUNITS(pos)); i++; if (i == 32) break; } @@ -171,7 +171,7 @@ static void gtkTextParseCharacterFormat(Ihandle* formattag, GtkTextTag* tag) else iupStrToInt(format, &val); - val = IUPGTK_PIXELS2PANGOUNITS(val); + val = iupGTK_PIXELS2PANGOUNITS(val); g_object_set(G_OBJECT(tag), "rise", val, NULL); } @@ -214,7 +214,7 @@ static void gtkTextParseCharacterFormat(Ihandle* formattag, GtkTextTag* tag) { if (val < 0) /* in pixels */ { - val = IUPGTK_PIXELS2PANGOUNITS(-val); + val = iupGTK_PIXELS2PANGOUNITS(-val); g_object_set(G_OBJECT(tag), "size", val, NULL); } else /* in points */ @@ -387,8 +387,8 @@ static int gtkTextConvertXYToPos(Ihandle* ih, int x, int y) /* transform to Layout coordinates */ gtk_entry_get_layout_offsets(GTK_ENTRY(ih->handle), &off_x, &off_y); - x = IUPGTK_PIXELS2PANGOUNITS(x - off_x); - y = IUPGTK_PIXELS2PANGOUNITS(y - off_y); + x = iupGTK_PIXELS2PANGOUNITS(x - off_x); + y = iupGTK_PIXELS2PANGOUNITS(y - off_y); pango_layout_xy_to_index(gtk_entry_get_layout(GTK_ENTRY(ih->handle)), x, y, &pos, &trailing); return pos; @@ -851,7 +851,7 @@ static char* gtkTextGetValueAttrib(Ihandle* ih) static int gtkTextSetInsertAttrib(Ihandle* ih, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; if (!value) return 0; @@ -875,7 +875,8 @@ static int gtkTextSetInsertAttrib(Ihandle* ih, const char* value) static int gtkTextSetAppendAttrib(Ihandle* ih, const char* value) { - if (!ih->handle) /* do not store the action before map */ + gint pos; + if (!ih->handle) /* do not do the action before map */ return 0; /* disable callbacks */ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); @@ -884,13 +885,18 @@ static int gtkTextSetAppendAttrib(Ihandle* ih, const char* value) GtkTextIter iter; GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); gtk_text_buffer_get_end_iter(buffer, &iter); - if (ih->data->append_newline) + pos = gtk_text_buffer_get_char_count(buffer); + if (ih->data->append_newline && pos!=0) gtk_text_buffer_insert(buffer, &iter, "\n", 1); gtk_text_buffer_insert(buffer, &iter, iupgtkStrConvertToUTF8(value), -1); } else { - gint pos = strlen(gtk_entry_get_text(GTK_ENTRY(ih->handle)))+1; +#if GTK_CHECK_VERSION(2, 14, 0) + pos = gtk_entry_get_text_length(GTK_ENTRY(ih->handle))+1; +#else + pos = strlen(gtk_entry_get_text(GTK_ENTRY(ih->handle)))+1; +#endif gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &pos); } iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); @@ -946,8 +952,10 @@ static int gtkTextSetPaddingAttrib(Ihandle* ih, const char* value) gtk_entry_set_inner_border(GTK_ENTRY(ih->handle), &border); #endif } + return 0; } - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } static int gtkTextSetNCAttrib(Ihandle* ih, const char* value) @@ -955,10 +963,14 @@ static int gtkTextSetNCAttrib(Ihandle* ih, const char* value) if (!iupStrToInt(value, &ih->data->nc)) ih->data->nc = INT_MAX; - if (!ih->data->is_multiline && ih->handle) - gtk_entry_set_max_length(GTK_ENTRY(ih->handle), ih->data->nc); - - return 0; + if (ih->handle) + { + if (!ih->data->is_multiline) + gtk_entry_set_max_length(GTK_ENTRY(ih->handle), ih->data->nc); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ } static int gtkTextSetClipboardAttrib(Ihandle *ih, const char *value) diff --git a/iup/src/gtk/iupgtk_toggle.c b/iup/src/gtk/iupgtk_toggle.c index 8ff7df5..040beda 100755 --- a/iup/src/gtk/iupgtk_toggle.c +++ b/iup/src/gtk/iupgtk_toggle.c @@ -213,8 +213,10 @@ static int gtkToggleSetPaddingAttrib(Ihandle* ih, const char* value) GtkButton* button = (GtkButton*)ih->handle; GtkMisc* misc = (GtkMisc*)gtk_button_get_image(button); gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding); + return 0; } - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } static int gtkToggleSetFgColorAttrib(Ihandle* ih, const char* value) diff --git a/iup/src/gtk/iupgtk_tree.c b/iup/src/gtk/iupgtk_tree.c index d408f27..9595ada 100755 --- a/iup/src/gtk/iupgtk_tree.c +++ b/iup/src/gtk/iupgtk_tree.c @@ -31,33 +31,50 @@ #include "iup_drvinfo.h" #include "iupgtk_drv.h" + +/* IMPORTANT: + + GtkTreeStore uses the "user_data" field of the GtkTreeIter + to store the node pointer that is position independent. + So we use it as a reference to the node in the cache, just like in Motif and Windows. + + BUT if GTK change its implementation this must be changed also. See "gtk_tree_store.c". + + ABOUT SELECTIONS: + + From the GTK documentation on GtkTreeSelection + + "Additionally, you cannot change the selection of a row on the model + that is not currently displayed by the view without expanding its parents first." +*/ + enum { - IUPGTK_TREE_IMAGE, + IUPGTK_TREE_IMAGE, /* "pixbuf", "pixbuf-expander-closed" */ IUPGTK_TREE_HAS_IMAGE, - IUPGTK_TREE_IMAGE_EXPANDED, + IUPGTK_TREE_IMAGE_EXPANDED, /* "pixbuf-expander-open" */ IUPGTK_TREE_HAS_IMAGE_EXPANDED, - IUPGTK_TREE_TITLE, - IUPGTK_TREE_KIND, - IUPGTK_TREE_COLOR, - IUPGTK_TREE_FONT, - IUPGTK_TREE_USERDATA + IUPGTK_TREE_TITLE, /* "text" */ + IUPGTK_TREE_KIND, /* "is-expander" */ + IUPGTK_TREE_COLOR, /* "foreground-gdk" */ + IUPGTK_TREE_FONT, /* "font-desc" */ + IUPGTK_TREE_SELECT, + IUPGTK_TREE_LAST_DATA /* used as a count */ }; -static GtkTreeIter gtkTreeInvalidIter = {0,0,0,0}; +static void gtkTreeRebuildNodeCache(Ihandle* ih, int id, GtkTreeIter iterItem); /*****************************************************************************/ /* COPYING ITEMS (Branches and its children) */ /*****************************************************************************/ /* Insert the copied item in a new location. Returns the new item. */ -static void gtkTreeCopyItem(GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeIter* iterParent, int position, GtkTreeIter *iterNewItem, int full_copy) +static void gtkTreeCopyItem(Ihandle* ih, GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeIter* iterParent, int position, GtkTreeIter *iterNewItem) { GtkTreeStore* store = GTK_TREE_STORE(model); int kind; char* title; gboolean has_image, has_image_expanded; PangoFontDescription* font; - void* userdata; GdkColor *color; GdkPixbuf* image, *image_expanded; @@ -69,9 +86,10 @@ static void gtkTreeCopyItem(GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeI IUPGTK_TREE_KIND, &kind, IUPGTK_TREE_COLOR, &color, IUPGTK_TREE_FONT, &font, - IUPGTK_TREE_USERDATA, &userdata, -1); + /* Add the new node */ + ih->data->node_count++; if (position == 2) gtk_tree_store_append(store, iterNewItem, iterParent); else if (position == 1) /* copy as first child of expanded branch */ @@ -79,9 +97,6 @@ static void gtkTreeCopyItem(GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeI else /* copy as next brother of item or collapsed branch */ gtk_tree_store_insert_after(store, iterNewItem, NULL, iterParent); /* iterParent is sibling of the new item */ - if (full_copy) /* during a full copy the userdata reference is not copied */ - userdata = NULL; - gtk_tree_store_set(store, iterNewItem, IUPGTK_TREE_IMAGE, image, IUPGTK_TREE_HAS_IMAGE, has_image, IUPGTK_TREE_IMAGE_EXPANDED, image_expanded, @@ -90,21 +105,21 @@ static void gtkTreeCopyItem(GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeI IUPGTK_TREE_KIND, kind, IUPGTK_TREE_COLOR, color, IUPGTK_TREE_FONT, font, - IUPGTK_TREE_USERDATA, userdata, + IUPGTK_TREE_SELECT, 0, -1); } -static void gtkTreeCopyChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, int full_copy) +static void gtkTreeCopyChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst) { GtkTreeIter iterChildSrc; int hasItem = gtk_tree_model_iter_children(model, &iterChildSrc, iterItemSrc); /* get the firstchild */ while(hasItem) { GtkTreeIter iterNewItem; - gtkTreeCopyItem(model, &iterChildSrc, iterItemDst, 2, &iterNewItem, full_copy); /* append always */ + gtkTreeCopyItem(ih, model, &iterChildSrc, iterItemDst, 2, &iterNewItem); /* append always */ /* Recursively transfer all the items */ - gtkTreeCopyChildren(ih, model, &iterChildSrc, &iterNewItem, full_copy); + gtkTreeCopyChildren(ih, model, &iterChildSrc, &iterNewItem); /* Go to next sibling item */ hasItem = gtk_tree_model_iter_next(model, &iterChildSrc); @@ -112,9 +127,17 @@ static void gtkTreeCopyChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *i } /* Copies all items in a branch to a new location. Returns the new branch node. */ -static void gtkTreeCopyNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, GtkTreeIter* iterNewItem, int full_copy) +static void gtkTreeCopyMoveNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, GtkTreeIter* iterNewItem, int is_copy) { int kind, position = 0; /* insert after iterItemDst */ + int id_new, count, id_src, id_dst; + + int old_count = ih->data->node_count; + + id_src = iupTreeFindNodeId(ih, iterItemSrc); + id_dst = iupTreeFindNodeId(ih, iterItemDst); + id_new = id_dst+1; /* contains the position for a copy operation */ + gtk_tree_model_get(model, iterItemDst, IUPGTK_TREE_KIND, &kind, -1); if (kind == ITREE_BRANCH) @@ -122,346 +145,311 @@ static void gtkTreeCopyNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterI GtkTreePath* path = gtk_tree_model_get_path(model, iterItemDst); if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) position = 1; /* insert as first child of iterItemDst */ + else + { + int child_count = iupdrvTreeTotalChildCount(ih, iterItemDst); + id_new += child_count; + } gtk_tree_path_free(path); } - gtkTreeCopyItem(model, iterItemSrc, iterItemDst, position, iterNewItem, full_copy); + /* move to the same place does nothing */ + if (!is_copy && id_new == id_src) + { + iterNewItem->stamp = 0; + return; + } - gtkTreeCopyChildren(ih, model, iterItemSrc, iterNewItem, full_copy); -} + gtkTreeCopyItem(ih, model, iterItemSrc, iterItemDst, position, iterNewItem); -/*****************************************************************************/ -/* FINDING ITEMS */ -/*****************************************************************************/ + gtkTreeCopyChildren(ih, model, iterItemSrc, iterNewItem); -static void gtkTreeInvertAllNodeMarking(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter* iterItem) -{ - GtkTreeIter iterChild; - int hasItem = TRUE; + count = ih->data->node_count - old_count; + iupTreeCopyMoveCache(ih, id_src, id_new, count, is_copy); - while(hasItem) + if (!is_copy) { - if(gtk_tree_selection_iter_is_selected(selection, iterItem)) - gtk_tree_selection_unselect_iter(selection, iterItem); - else - gtk_tree_selection_select_iter(selection, iterItem); + /* Deleting the node of its old position */ + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + gtk_tree_store_remove(GTK_TREE_STORE(model), iterItemSrc); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); - /* Check whether we have child items */ - if(gtk_tree_model_iter_has_child(model, iterItem)) - { - gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ - gtkTreeInvertAllNodeMarking(ih, model, selection, &iterChild); - } + /* restore count, because we remove src */ + ih->data->node_count = old_count; - /* Go to next sibling item */ - hasItem = gtk_tree_model_iter_next(model, iterItem); + /* compensate position for a move */ + if (id_new > id_src) + id_new -= count; } + + gtkTreeRebuildNodeCache(ih, id_new, *iterNewItem); } -static GtkTreeIter gtkTreeFindVisibleNodeId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode) +/*****************************************************************************/ +/* FINDING ITEMS */ +/*****************************************************************************/ + +static void gtkTreeIterInit(Ihandle* ih, GtkTreeIter* iterItem, InodeHandle* node_handle) { - GtkTreeIter iterChild; - GtkTreePath* path; - int hasItem = TRUE; + iterItem->stamp = ih->data->stamp; + iterItem->user_data = node_handle; + iterItem->user_data2 = NULL; + iterItem->user_data3 = NULL; +} - while(hasItem) - { - /* ID control to traverse items */ - ih->data->id_control++; /* not the real id since it counts only the visible ones */ +static int gtkTreeIsNodeSelected(GtkTreeModel* model, GtkTreeIter *iterItem) +{ + gboolean selected = 0; + gtk_tree_model_get(model, iterItem, IUPGTK_TREE_SELECT, &selected, -1); + return selected; +} - /* StateID founded! */ - if(iterItem.user_data == iterNode.user_data) - return iterItem; +static void gtkTreeSelectNodeRaw(GtkTreeModel* model, GtkTreeIter *iterItem, int select) +{ + /* Cannot change the selection of a row on the model that is not currently displayed. + So we store the selection state here. And update the actual state when the node becames visible. */ + gtk_tree_store_set(GTK_TREE_STORE(model), iterItem, IUPGTK_TREE_SELECT, select, -1); +} - path = gtk_tree_model_get_path(model, &iterItem); +static void gtkTreeSelectNode(GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter *iterItem, int select) +{ + if (select == -1) + select = !gtkTreeIsNodeSelected(model, iterItem); /* toggle */ - /* Check whether we have child items and it is expanded (visible) */ - if (gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) - { - gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ - iterChild = gtkTreeFindVisibleNodeId(ih, model, iterChild, iterNode); + gtkTreeSelectNodeRaw(model, iterItem, select); - /* StateID founded! */ - if(iterChild.user_data) - { - gtk_tree_path_free(path); - return iterChild; - } - } + if (select) + gtk_tree_selection_select_iter(selection, iterItem); + else + gtk_tree_selection_unselect_iter(selection, iterItem); +} - gtk_tree_path_free(path); - /* Go to next sibling item */ - hasItem = gtk_tree_model_iter_next(model, &iterItem); +static void gtkTreeSelectAll(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, int selected) +{ + int i; + GtkTreeIter iterItem; + + for (i = 0; i < ih->data->node_count; i++) + { + gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); + gtkTreeSelectNodeRaw(model, &iterItem, selected); } - return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ + if (selected) + gtk_tree_selection_select_all(selection); + else + gtk_tree_selection_unselect_all(selection); } -static GtkTreeIter gtkTreeFindVisibleNodeFromId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem) +static void gtkTreeInvertAllNodeMarking(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection) { - GtkTreeIter iterChild; - GtkTreePath* path; - int hasItem = TRUE; + int i; + GtkTreeIter iterItem; - while(hasItem) + for (i = 0; i < ih->data->node_count; i++) { - /* ID control to traverse items */ - ih->data->id_control--; /* not the real id since it counts only the visible ones */ + gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); + gtkTreeSelectNode(model, selection, &iterItem, -1); + } +} - /* StateID founded! */ - if(ih->data->id_control < 0) - return iterItem; +static void gtkTreeSelectRange(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter *iterItem1, GtkTreeIter *iterItem2, int clear) +{ + int i; + int id1 = iupTreeFindNodeId(ih, iterItem1->user_data); + int id2 = iupTreeFindNodeId(ih, iterItem2->user_data); + GtkTreeIter iterItem; - path = gtk_tree_model_get_path(model, &iterItem); + if (id1 > id2) + { + int tmp = id1; + id1 = id2; + id2 = tmp; + } - /* Check whether we have child items and it is expanded (visible) */ - if(gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + for (i = 0; i < ih->data->node_count; i++) + { + gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); + if (i < id1 || i > id2) { - gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ - iterChild = gtkTreeFindVisibleNodeFromId(ih, model, iterChild); - - /* StateID founded! */ - if(ih->data->id_control < 0) - { - gtk_tree_path_free(path); - return iterChild; - } + if (clear) + gtkTreeSelectNode(model, selection, &iterItem, 0); } - - gtk_tree_path_free(path); - /* Go to next sibling item */ - hasItem = gtk_tree_model_iter_next(model, &iterItem); + else + gtkTreeSelectNode(model, selection, &iterItem, 1); } - - return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ } -static GtkTreeIter gtkTreeGetLastVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem) +static int gtkTreeIsNodeVisible(Ihandle* ih, GtkTreeModel* model, InodeHandle* node_handle, InodeHandle* *nodeLastParent) { - GtkTreeIter iterChild, iterPrev = gtkTreeInvalidIter; - GtkTreePath* path = gtk_tree_model_get_path(model, &iterItem); - - /* Check whether we have child items and it is expanded (visible) */ - if(gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) - { - int hasItem = TRUE; - gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + GtkTreeIter iterItem, iterParent; + GtkTreePath* path; + int is_visible; - while(hasItem) - { - iterPrev = iterChild; + gtkTreeIterInit(ih, &iterItem, node_handle); - /* Go to next sibling item */ - hasItem = gtk_tree_model_iter_next(model, &iterChild); - } + if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem) || + iterParent.user_data == *nodeLastParent) + return 1; - iterItem = gtkTreeGetLastVisibleNode(ih, model, iterPrev); - } + path = gtk_tree_model_get_path(model, &iterParent); + is_visible = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); gtk_tree_path_free(path); - return iterItem; + if (!is_visible) + return 0; + + /* save last parent */ + *nodeLastParent = iterParent.user_data; + return 1; } -static GtkTreeIter gtkTreeFindNodeID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode) +static void gtkTreeGetLastVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem) { - GtkTreeIter iterChild; - int hasItem = TRUE; + int i; + InodeHandle* nodeLastParent = NULL; - while(hasItem) + for (i = ih->data->node_count-1; i >= 0; i--) { - /* ID control to traverse items */ - ih->data->id_control++; - - /* StateID founded! */ - if (iterItem.user_data == iterNode.user_data) - return iterItem; - - /* Check whether we have child items */ - if (gtk_tree_model_iter_has_child(model, &iterItem)) + if (gtkTreeIsNodeVisible(ih, model, ih->data->node_cache[i].node_handle, &nodeLastParent)) { - gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ - iterChild = gtkTreeFindNodeID(ih, model, iterChild, iterNode); - - /* StateID founded! */ - if(iterChild.user_data) - return iterChild; + gtkTreeIterInit(ih, iterItem, ih->data->node_cache[i].node_handle); + return; } - - /* Go to next sibling item */ - hasItem = gtk_tree_model_iter_next(model, &iterItem); } - return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ + gtkTreeIterInit(ih, iterItem, ih->data->node_cache[0].node_handle); /* root is always visible */ } -static int gtkTreeGetNodeId(Ihandle* ih, GtkTreeIter iterItem) +static void gtkTreeGetNextVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, int count) { - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - GtkTreeIter iterRoot; - gtk_tree_model_get_iter_first(model, &iterRoot); - - ih->data->id_control = -1; - iterItem = gtkTreeFindNodeID(ih, model, iterRoot, iterItem); - if (iterItem.user_data) - return ih->data->id_control; - else - return -1; -} + int i, id; + InodeHandle* nodeLastParent = NULL; -static GtkTreeIter gtkTreeFindUserData(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, void* userdata) -{ - GtkTreeIter iterChild; - int hasItem = TRUE; - void* node_userdata; + id = iupTreeFindNodeId(ih, iterItem->user_data); + id += count; - while(hasItem) + for (i = id; i < ih->data->node_count; i++) { - /* ID control to traverse items */ - ih->data->id_control++; + if (gtkTreeIsNodeVisible(ih, model, ih->data->node_cache[i].node_handle, &nodeLastParent)) + { + gtkTreeIterInit(ih, iterItem, ih->data->node_cache[i].node_handle); + return; + } + } - gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &node_userdata, -1); + gtkTreeIterInit(ih, iterItem, ih->data->node_cache[0].node_handle); /* root is always visible */ +} - /* userdata founded! */ - if (node_userdata == userdata) - return iterItem; +static void gtkTreeGetPreviousVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, int count) +{ + int i, id; + InodeHandle* nodeLastParent = NULL; - /* Check whether we have child items */ - if (gtk_tree_model_iter_has_child(model, &iterItem)) - { - gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ - iterChild = gtkTreeFindUserData(ih, model, iterChild, userdata); + id = iupTreeFindNodeId(ih, iterItem->user_data); + id -= count; - /* userdata founded! */ - if (iterChild.user_data) - return iterChild; + for (i = id; i >= 0; i--) + { + if (gtkTreeIsNodeVisible(ih, model, ih->data->node_cache[i].node_handle, &nodeLastParent)) + { + gtkTreeIterInit(ih, iterItem, ih->data->node_cache[i].node_handle); + return; } - - /* Go to next sibling item */ - hasItem = gtk_tree_model_iter_next(model, &iterItem); } - return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ + gtkTreeGetLastVisibleNode(ih, model, iterItem); } -static int gtkTreeGetUserDataId(Ihandle* ih, GtkTreeModel* model, void* userdata) +static int gtkTreeFindNodeId(Ihandle* ih, GtkTreeIter* iterItem) { - GtkTreeIter iterRoot, iterItem; - gtk_tree_model_get_iter_first(model, &iterRoot); - - ih->data->id_control = -1; - iterItem = gtkTreeFindUserData(ih, model, iterRoot, userdata); - if (iterItem.user_data) - return ih->data->id_control; - else - return -1; + return iupTreeFindNodeId(ih, iterItem->user_data); } -static void gtkTreeCallNodeRemovedRec(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, IFnis cb) +static void gtkTreeCallNodeRemovedRec(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, IFns cb, int *id) { GtkTreeIter iterChild; - int hasItem = TRUE; - void* node_userdata; + int hasItem; + int old_id = *id; + /* Check whether we have child items */ + /* remove from children first */ + hasItem = gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ while(hasItem) { - /* ID control to traverse items */ - ih->data->id_control++; - - gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &node_userdata, -1); - - cb(ih, ih->data->id_control, (char*)node_userdata); - - /* Check whether we have child items */ - if (gtk_tree_model_iter_has_child(model, &iterItem)) - { - gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ - gtkTreeCallNodeRemovedRec(ih, model, iterChild, cb); - } + /* go recursive to children */ + gtkTreeCallNodeRemovedRec(ih, model, &iterChild, cb, id); /* Go to next sibling item */ - hasItem = gtk_tree_model_iter_next(model, &iterItem); + hasItem = gtk_tree_model_iter_next(model, &iterChild); } + + /* actually do it for the node */ + ih->data->node_count--; + (*id)++; + + cb(ih, (char*)ih->data->node_cache[old_id].userdata); } static void gtkTreeCallNodeRemoved(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem) { - IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB"); + int old_count = ih->data->node_count; + int id = iupTreeFindNodeId(ih, iterItem->user_data); + int old_id = id; + + IFns cb = (IFns)IupGetCallback(ih, "NODEREMOVED_CB"); if (cb) + gtkTreeCallNodeRemovedRec(ih, model, iterItem, cb, &id); + else { - ih->data->id_control = gtkTreeGetNodeId(ih, *iterItem)-1; - gtkTreeCallNodeRemovedRec(ih, model, *iterItem, cb); + int removed_count = iupdrvTreeTotalChildCount(ih, iterItem->user_data)+1; + ih->data->node_count -= removed_count; } + + iupTreeDelFromCache(ih, old_id, old_count-ih->data->node_count); } -static gboolean gtkTreeFindNodeFromID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, int *id) +static void gtkTreeCallNodeRemovedAll(Ihandle* ih) { - GtkTreeIter iterChild; - int hasItem = TRUE; + IFns cb = (IFns)IupGetCallback(ih, "NODEREMOVED_CB"); + int i, old_count = ih->data->node_count; - while(hasItem) + if (cb) { - /* ID control to traverse items */ - (*id)--; - - /* StateID founded! */ - if (*id < 0) - return TRUE; - - /* Check whether we have child items */ - if (gtk_tree_model_iter_has_child(model, iterItem)) + for (i = 0; i < ih->data->node_count; i++) { - gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ - - if (gtkTreeFindNodeFromID(ih, model, &iterChild, id)) - { - *iterItem = iterChild; - return TRUE; - } + cb(ih, (char*)ih->data->node_cache[i].userdata); } - - /* Go to next sibling item */ - hasItem = gtk_tree_model_iter_next(model, iterItem); } - return FALSE; + ih->data->node_count = 0; + + iupTreeDelFromCache(ih, 0, old_count); } -static gboolean gtkTreeFindNodeFromString(Ihandle* ih, GtkTreeModel* model, const char* name_id, GtkTreeIter *iterItem) +static gboolean gtkTreeFindNodeFromString(Ihandle* ih, const char* name_id, GtkTreeIter *iterItem) { - if (name_id[0]) - { - int id; - if (iupStrToInt(name_id, &id)) - { - gtk_tree_model_get_iter_first(model, iterItem); - return gtkTreeFindNodeFromID(ih, model, iterItem, &id); - } - } - else - { - GtkTreePath* path = NULL; - gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); - if (path) - { - gtk_tree_model_get_iter(model, iterItem, path); - gtk_tree_path_free(path); - return TRUE; - } - } - return FALSE; + InodeHandle* node_handle = iupTreeGetNodeFromString(ih, name_id); + if (!node_handle) + return FALSE; + + gtkTreeIterInit(ih, iterItem, node_handle); + return TRUE; } /*****************************************************************************/ /* MANIPULATING IMAGES */ /*****************************************************************************/ -static void gtkTreeUpdateImages(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, int mode) +static void gtkTreeUpdateImages(Ihandle* ih, int mode) { - GtkTreeIter iterChild; - int hasItem = TRUE; - int kind; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + int i, kind; - while(hasItem) + for (i=0; i<ih->data->node_count; i++) { + gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); if (kind == ITREE_BRANCH) @@ -480,14 +468,6 @@ static void gtkTreeUpdateImages(Ihandle* ih, GtkTreeModel* model, GtkTreeIter it if (!has_image) gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, -1); } - - if (gtk_tree_model_iter_has_child(model, &iterItem)) - { - - /* Recursively traverse child items */ - gtk_tree_model_iter_children(model, &iterChild, &iterItem); - gtkTreeUpdateImages(ih, model, iterChild, mode); - } } else { @@ -499,9 +479,6 @@ static void gtkTreeUpdateImages(Ihandle* ih, GtkTreeModel* model, GtkTreeIter it gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, -1); } } - - /* Go to next sibling item */ - hasItem = gtk_tree_model_iter_next(model, &iterItem); } } @@ -536,26 +513,49 @@ void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* t GtkTreeIter iterPrev, iterNewItem, iterParent; GtkTreePath* path; GdkColor color = {0L,0,0,0}; - int kindPrev; - - if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterPrev)) - return; + int kindPrev = -1; - gtk_tree_model_get(GTK_TREE_MODEL(store), &iterPrev, IUPGTK_TREE_KIND, &kindPrev, -1); + if (!gtkTreeFindNodeFromString(ih, name_id, &iterPrev)) + { + /* check if the root was really specified */ + int id = 0; + if (!iupStrToInt(name_id, &id) || id != -1) + return; + } + else + gtk_tree_model_get(GTK_TREE_MODEL(store), &iterPrev, IUPGTK_TREE_KIND, &kindPrev, -1); - if (kindPrev == ITREE_BRANCH && add) - gtk_tree_store_insert(store, &iterNewItem, &iterPrev, 0); /* iterPrev is parent of the new item (firstchild of it) */ + if (kindPrev != -1) + { + /* Add the new node */ + if (kindPrev == ITREE_BRANCH && add) + gtk_tree_store_insert(store, &iterNewItem, &iterPrev, 0); /* iterPrev is parent of the new item (firstchild of it) */ + else + gtk_tree_store_insert_after(store, &iterNewItem, NULL, &iterPrev); /* iterPrev is sibling of the new item */ + iupTreeAddToCache(ih, add, kindPrev, iterPrev.user_data, iterNewItem.user_data); + } else - gtk_tree_store_insert_after(store, &iterNewItem, NULL, &iterPrev); /* iterPrev is sibling of the new item */ + { + gtk_tree_store_append(store, &iterNewItem, NULL); /* root node */ + iupTreeAddToCache(ih, 0, 0, NULL, iterNewItem.user_data); + + /* store the stamp for the tree */ + ih->data->stamp = iterNewItem.stamp; + } iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color); + if (!title) + title = ""; + /* set the attributes of the new node */ gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_HAS_IMAGE, FALSE, IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, IUPGTK_TREE_TITLE, iupgtkStrConvertToUTF8(title), IUPGTK_TREE_KIND, kind, - IUPGTK_TREE_COLOR, &color, -1); + IUPGTK_TREE_COLOR, &color, + IUPGTK_TREE_SELECT, 0, + -1); if (kind == ITREE_LEAF) gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, -1); @@ -563,56 +563,113 @@ void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* t gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, -1); - if (kindPrev == ITREE_BRANCH && add) - iterParent = iterPrev; - else - gtk_tree_model_iter_parent(GTK_TREE_MODEL(store), &iterParent, &iterNewItem); + if (kindPrev != -1) + { + if (kindPrev == ITREE_BRANCH && add) + iterParent = iterPrev; + else if (!gtk_tree_model_iter_parent(GTK_TREE_MODEL(store), &iterParent, &iterNewItem)) + return; - /* If this is the first child of the parent, then handle the ADDEXPANDED attribute */ - if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), &iterParent) == 1) + /* If this is the first child of the parent, then handle the ADDEXPANDED attribute */ + if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), &iterParent) == 1) + { + path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterParent); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", "1"); + if (ih->data->add_expanded) + gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE); + else + gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", NULL); + gtk_tree_path_free(path); + } + } + else { - int depth; - path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterParent); - depth = gtk_tree_path_get_depth(path)-1; - if (ih->data->add_expanded || depth==0) /* if this is the first child of the root, expand always */ + if (ih->data->node_count == 1) { - iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB", "1"); - gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE); + /* MarkStart node */ + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)iterNewItem.user_data); + + /* Set the default VALUE */ + path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterNewItem); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); + gtk_tree_path_free(path); } - else - gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); - gtk_tree_path_free(path); } } -static void gtkTreeAddRootNode(Ihandle* ih) + +/*****************************************************************************/ +/* AUXILIAR FUNCTIONS */ +/*****************************************************************************/ + + +static void gtkTreeChildRebuildCacheRec(Ihandle* ih, GtkTreeModel *model, GtkTreeIter *iterItem, int *id) { - GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); - GtkTreePath* path; - GtkTreeIter iterRoot; - GdkColor color = {0L,0,0,0}; + GtkTreeIter iterChild; + int hasItem = gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ + while(hasItem) + { + (*id)++; + ih->data->node_cache[*id].node_handle = iterChild.user_data; - iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color); + /* go recursive to children */ + gtkTreeChildRebuildCacheRec(ih, model, &iterChild, id); + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterChild); + } +} - gtk_tree_store_append(store, &iterRoot, NULL); /* root node */ - gtk_tree_store_set(store, &iterRoot, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, - IUPGTK_TREE_HAS_IMAGE, FALSE, - IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, - IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, - IUPGTK_TREE_KIND, ITREE_BRANCH, - IUPGTK_TREE_COLOR, &color, -1); +static void gtkTreeRebuildNodeCache(Ihandle* ih, int id, GtkTreeIter iterItem) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + ih->data->node_cache[id].node_handle = iterItem.user_data; + gtkTreeChildRebuildCacheRec(ih, model, &iterItem, &id); +} + +static void gtkTreeChildCountRec(GtkTreeModel *model, GtkTreeIter *iterItem, int *count) +{ + GtkTreeIter iterChild; + int hasItem = gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ + while(hasItem) + { + (*count)++; - path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterRoot); - /* MarkStart node */ - iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)path); + /* go recursive to children */ + gtkTreeChildCountRec(model, &iterChild, count); - /* Set the default VALUE */ - gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterChild); + } +} + +int iupdrvTreeTotalChildCount(Ihandle* ih, InodeHandle* node_handle) +{ + int count = 0; + GtkTreeIter iterItem; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtkTreeIterInit(ih, &iterItem, node_handle); + gtkTreeChildCountRec(model, &iterItem, &count); + return count; +} + +InodeHandle* iupdrvTreeGetFocusNode(Ihandle* ih) +{ + GtkTreePath* path = NULL; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); + if (path) + { + GtkTreeIter iterItem; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_model_get_iter(model, &iterItem, path); + gtk_tree_path_free(path); + return iterItem.user_data; + } + + return NULL; } -/*****************************************************************************/ -/* AUXILIAR FUNCTIONS */ -/*****************************************************************************/ static void gtkTreeOpenCloseEvent(Ihandle* ih) { GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); @@ -620,7 +677,7 @@ static void gtkTreeOpenCloseEvent(Ihandle* ih) GtkTreePath* path; int kind; - if (!gtkTreeFindNodeFromString(ih, model, "", &iterItem)) + if (!gtkTreeFindNodeFromString(ih, "", &iterItem)) return; path = gtk_tree_model_get_path(model, &iterItem); @@ -637,27 +694,22 @@ static void gtkTreeOpenCloseEvent(Ihandle* ih) } } -static gboolean gtkTreeSelected_Foreach_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list) +typedef struct _gtkTreeSelectMinMax { - GtkTreeRowReference *rowref; - - rowref = gtk_tree_row_reference_new(model, path); - *rowref_list = g_list_append(*rowref_list, rowref); + Ihandle* ih; + int id1, id2; +} gtkTreeSelectMinMax; - (void)iter; - return FALSE; /* do not stop walking the store, call us with next row */ -} - -static gboolean gtkTreeSelected_Iter_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list) +static gboolean gtkTreeSelected_Foreach_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iterItem, gtkTreeSelectMinMax *minmax) { - GtkTreeRowReference *rowref; - GtkTreeIter iterParent; - if (!gtk_tree_model_iter_parent(model, &iterParent, iter)) /* the root node can't be deleted */ - return FALSE; /* do not stop walking the store, call us with next row */ - - rowref = gtk_tree_row_reference_new(model, path); - *rowref_list = g_list_append(*rowref_list, rowref); + int id = iupTreeFindNodeId(minmax->ih, iterItem->user_data); + if (id < minmax->id1) + minmax->id1 = id; + if (id > minmax->id2) + minmax->id2 = id; + (void)model; + (void)path; return FALSE; /* do not stop walking the store, call us with next row */ } @@ -672,45 +724,48 @@ static void gtkTreeCallMultiSelectionCb(Ihandle* ih) { GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); - GtkTreeIter iterRoot; - GList *rr_list = NULL; - GList *node; - int* id_rowItem; - int count_selected_rows, i = 0; + GtkTreeIter iterItem; + int i = 0, countItems; + gtkTreeSelectMinMax minmax; - gtk_tree_model_get_iter_first(model, &iterRoot); + minmax.ih = ih; + minmax.id1 = ih->data->node_count; + minmax.id2 = -1; - gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Foreach_Func, &rr_list); - count_selected_rows = g_list_length(rr_list); - id_rowItem = malloc(sizeof(int) * count_selected_rows); + gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Foreach_Func, &minmax); + if (minmax.id2 == -1) + return; - for(node = rr_list; node != NULL; node = node->next) + /* interactive selection of several nodes will NOT select hidden nodes, + so make sure that they are selected. */ + for(i = minmax.id1; i <= minmax.id2; i++) { - GtkTreePath* path = gtk_tree_row_reference_get_path(node->data); - if (path) - { - GtkTreeIter iterItem; - gtk_tree_model_get_iter(model, &iterItem, path); - - id_rowItem[i] = gtkTreeGetNodeId(ih, iterItem); - i++; - - gtk_tree_path_free(path); - } + gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); + if (!gtkTreeIsNodeSelected(model, &iterItem)) + gtkTreeSelectNodeRaw(model, &iterItem, 1); } - g_list_foreach(rr_list, (GFunc) gtk_tree_row_reference_free, NULL); - g_list_free(rr_list); + /* if last selected item is a branch, then select its children */ + iupTreeSelectLastCollapsedBranch(ih, &(minmax.id2)); + + countItems = minmax.id2-minmax.id1+1; if (cbMulti) - cbMulti(ih, id_rowItem, count_selected_rows); - else { - for (i=0; i<count_selected_rows; i++) - cbSelec(ih, id_rowItem[i], 1); - } + int* id_rowItem = malloc(sizeof(int) * countItems); + + for(i = 0; i < countItems; i++) + id_rowItem[i] = minmax.id1+i; - free(id_rowItem); + cbMulti(ih, id_rowItem, countItems); + + free(id_rowItem); + } + else if (cbSelec) + { + for (i=0; i<countItems; i++) + cbSelec(ih, minmax.id1+i, 1); + } } } @@ -747,14 +802,22 @@ 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; + int kind; - if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), value, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, value, &iterItem)) return 0; path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterItem); - if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1); + if (kind == ITREE_LEAF) + gtk_tree_view_expand_to_path(GTK_TREE_VIEW(ih->handle), path); + else + { + int expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); gtk_tree_view_expand_to_path(GTK_TREE_VIEW(ih->handle), path); + if (!expanded) gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); + } gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE, 0, 0); /* scroll to visible */ @@ -788,34 +851,23 @@ static int gtkTreeSetExpandAllAttrib(Ihandle* ih, const char* value) if (iupStrBoolean(value)) gtk_tree_view_expand_all(GTK_TREE_VIEW(ih->handle)); else - { - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - GtkTreeIter iterRoot; - GtkTreePath* pathRoot; - gtk_tree_view_collapse_all(GTK_TREE_VIEW(ih->handle)); - /* The root node is always expanded */ - gtk_tree_model_get_iter_first(model, &iterRoot); - pathRoot = gtk_tree_model_get_path(model, &iterRoot); - gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), pathRoot, FALSE); - gtk_tree_path_free(pathRoot); - } - return 0; } static char* gtkTreeGetDepthAttrib(Ihandle* ih, const char* name_id) { - char* depth; + char* str; GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return NULL; - depth = iupStrGetMemory(10); - sprintf(depth, "%d", gtk_tree_store_iter_depth(store, &iterItem)); - return depth; + str = iupStrGetMemory(10); + sprintf(str, "%d", gtk_tree_store_iter_depth(store, &iterItem)); + return str; } static int gtkTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value) @@ -824,14 +876,14 @@ static int gtkTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char GtkTreeIter iterItemSrc, iterItemDst, iterNewItem; GtkTreeIter iterParent, iterNextParent; - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItemSrc)) return 0; - if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst)) + if (!gtkTreeFindNodeFromString(ih, value, &iterItemDst)) return 0; /* If Drag item is an ancestor of Drop item then return */ @@ -843,12 +895,8 @@ static int gtkTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char iterParent = iterNextParent; } - /* Copying the node and its children to the new position */ - gtkTreeCopyNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 0); /* not a full copy, preserve user data */ - - /* Deleting the node of its old position */ - /* do not delete the user data, we copy the references in CopyNode */ - gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItemSrc); + /* Move the node and its children to the new position */ + gtkTreeCopyMoveNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 0); return 0; } @@ -859,14 +907,14 @@ static int gtkTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char GtkTreeIter iterItemSrc, iterItemDst, iterNewItem; GtkTreeIter iterParent, iterNextParent; - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItemSrc)) return 0; - if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst)) + if (!gtkTreeFindNodeFromString(ih, value, &iterItemDst)) return 0; /* If Drag item is an ancestor of Drop item then return */ @@ -878,8 +926,8 @@ static int gtkTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char iterParent = iterNextParent; } - /* Copying the node and its children to the new position */ - gtkTreeCopyNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 1); + /* Copy the node and its children to the new position */ + gtkTreeCopyMoveNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 1); return 0; } @@ -891,7 +939,7 @@ static char* gtkTreeGetColorAttrib(Ihandle* ih, const char* name_id) GtkTreeIter iterItem; GdkColor *color; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return NULL; gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_COLOR, &color, -1); @@ -912,7 +960,7 @@ static int gtkTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* v GdkColor color; unsigned char r, g, b; - if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return 0; if (!iupStrToRGB(value, &r, &g, &b)) @@ -931,14 +979,14 @@ static char* gtkTreeGetParentAttrib(Ihandle* ih, const char* name_id) GtkTreeIter iterParent; char* str; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return NULL; if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem)) return NULL; str = iupStrGetMemory(10); - sprintf(str, "%d", gtkTreeGetNodeId(ih, iterParent)); + sprintf(str, "%d", gtkTreeFindNodeId(ih, &iterParent)); return str; } @@ -948,7 +996,7 @@ static char* gtkTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) GtkTreeIter iterItem; char* str; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return NULL; str = iupStrGetMemory(10); @@ -956,40 +1004,13 @@ static char* gtkTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) return str; } -static int gtkTreeCount(GtkTreeModel* model, GtkTreeIter iterBranch) -{ - GtkTreeIter iterChild; - int count = 0; - int hasItem = gtk_tree_model_iter_children(model, &iterChild, &iterBranch); /* get the firstchild */ - count++; - while(hasItem) - { - count += gtkTreeCount(model, iterChild); - - /* Go to next sibling item */ - hasItem = gtk_tree_model_iter_next(model, &iterChild); - } - - return count; -} - -static char* gtkTreeGetCountAttrib(Ihandle* ih) -{ - GtkTreeIter iterRoot; - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - char* str = iupStrGetMemory(10); - gtk_tree_model_get_iter_first(model, &iterRoot); - sprintf(str, "%d", gtkTreeCount(model, iterRoot)); - return str; -} - static char* gtkTreeGetKindAttrib(Ihandle* ih, const char* name_id) { GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); GtkTreeIter iterItem; int kind; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return NULL; gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); @@ -1005,7 +1026,7 @@ static char* gtkTreeGetStateAttrib(Ihandle* ih, const char* name_id) GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return NULL; if (gtk_tree_model_iter_has_child(model, &iterItem)) @@ -1028,13 +1049,20 @@ static int gtkTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* v GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); GtkTreeIter iterItem; GtkTreePath* path; + int kind; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return 0; - path = gtk_tree_model_get_path(model, &iterItem); - gtkTreeExpandItem(ih, path, iupStrEqualNoCase(value, "EXPANDED")); - gtk_tree_path_free(path); + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); + if (kind == ITREE_BRANCH) + { + path = gtk_tree_model_get_path(model, &iterItem); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", "1"); + gtkTreeExpandItem(ih, path, iupStrEqualNoCase(value, "EXPANDED")); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", NULL); + gtk_tree_path_free(path); + } return 0; } @@ -1050,7 +1078,7 @@ static char* gtkTreeGetTitleAttrib(Ihandle* ih, const char* name_id) { GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return NULL; return gtkTreeGetTitle(model, iterItem); } @@ -1059,8 +1087,10 @@ static int gtkTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* v { GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return 0; + if (!value) + value = ""; gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_TITLE, iupgtkStrConvertToUTF8(value), -1); return 0; } @@ -1070,7 +1100,7 @@ static int gtkTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const cha PangoFontDescription* fontdesc = NULL; GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return 0; if (value) fontdesc = iupgtkGetPangoFontDesc(value); @@ -1083,49 +1113,12 @@ static char* gtkTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) PangoFontDescription* fontdesc; GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return NULL; gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_FONT, &fontdesc, -1); return pango_font_description_to_string(fontdesc); } -static char* gtkTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id) -{ - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - int id; - char* str = (char*)(name_id+1); /* skip ':' */ - void* userdata = NULL; - if (sscanf(str, "%p", &userdata)!=1) - return NULL; - id = gtkTreeGetUserDataId(ih, model, userdata); - if (id == -1) - return NULL; - str = iupStrGetMemory(16); - sprintf(str, "%d", id); - return str; -} - -static char* gtkTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) -{ - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - GtkTreeIter iterItem; - char* userdata; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) - return NULL; - gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &userdata, -1); - return userdata; -} - -static int gtkTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) -{ - GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); - GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) - return 0; - gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_USERDATA, value, -1); - return 0; -} - static char* gtkTreeGetValueAttrib(Ihandle* ih) { GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); @@ -1140,67 +1133,117 @@ static char* gtkTreeGetValueAttrib(Ihandle* ih) gtk_tree_path_free(path); str = iupStrGetMemory(16); - sprintf(str, "%d", gtkTreeGetNodeId(ih, iterItem)); + sprintf(str, "%d", gtkTreeFindNodeId(ih, &iterItem)); return str; } - return "0"; /* default VALUE is root */ + if (ih->data->node_count) + return "0"; /* default VALUE is root */ + else + return "-1"; +} + +static char* gtkTreeGetMarkedNodesAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(ih->data->node_count+1); + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + int i; + + for (i=0; i<ih->data->node_count; i++) + { + gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); + if (gtkTreeIsNodeSelected(model, &iterItem)) + str[i] = '+'; + else + str[i] = '-'; + } + + str[ih->data->node_count] = 0; + return str; +} + +static int gtkTreeSetMarkedNodesAttrib(Ihandle* ih, const char* value) +{ + int count, i; + GtkTreeModel* model; + GtkTreeIter iterItem; + GtkTreeSelection* selection; + + if (ih->data->mark_mode==ITREE_MARK_SINGLE || !value) + return 0; + + count = strlen(value); + if (count > ih->data->node_count) + count = ih->data->node_count; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + + for (i=0; i<count; i++) + { + gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); + if (value[i] == '+') + gtkTreeSelectNode(model, selection, &iterItem, 1); + else + gtkTreeSelectNode(model, selection, &iterItem, 0); + } + + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + + return 0; } static int gtkTreeSetMarkAttrib(Ihandle* ih, const char* value) { GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); - GtkTreeIter iterRoot; if (ih->data->mark_mode==ITREE_MARK_SINGLE) return 0; - gtk_tree_model_get_iter_first(model, &iterRoot); - if(iupStrEqualNoCase(value, "BLOCK")) { + GtkTreeIter iterItem1, iterItem2; GtkTreePath* pathFocus; gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); - gtk_tree_selection_select_range(selection, (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"), pathFocus); + gtk_tree_model_get_iter(model, &iterItem1, pathFocus); gtk_tree_path_free(pathFocus); + + gtkTreeIterInit(ih, &iterItem2, iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE")); + + gtkTreeSelectRange(ih, model, selection, &iterItem1, &iterItem2, 0); } else if(iupStrEqualNoCase(value, "CLEARALL")) - gtk_tree_selection_unselect_all(selection); + gtkTreeSelectAll(ih, model, selection, 0); else if(iupStrEqualNoCase(value, "MARKALL")) - gtk_tree_selection_select_all(selection); + gtkTreeSelectAll(ih, model, selection, 1); else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */ - gtkTreeInvertAllNodeMarking(ih, model, selection, &iterRoot); + gtkTreeInvertAllNodeMarking(ih, model, selection); else if(iupStrEqualPartial(value, "INVERT")) { /* iupStrEqualPartial allows the use of "INVERTid" form */ GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, model, &value[strlen("INVERT")], &iterItem)) + if (!gtkTreeFindNodeFromString(ih, &value[strlen("INVERT")], &iterItem)) return 0; - if(gtk_tree_selection_iter_is_selected(selection, &iterItem)) - gtk_tree_selection_unselect_iter(selection, &iterItem); - else - gtk_tree_selection_select_iter(selection, &iterItem); + gtkTreeSelectNode(model, selection, &iterItem, -1); /* toggle */ } else { - GtkTreePath *path1, *path2; GtkTreeIter iterItem1, iterItem2; char str1[50], str2[50]; if (iupStrToStrStr(value, str1, str2, '-')!=2) return 0; - if (!gtkTreeFindNodeFromString(ih, model, str1, &iterItem1)) + if (!gtkTreeFindNodeFromString(ih, str1, &iterItem1)) return 0; - if (!gtkTreeFindNodeFromString(ih, model, str2, &iterItem2)) + if (!gtkTreeFindNodeFromString(ih, str2, &iterItem2)) return 0; - path1 = gtk_tree_model_get_path(model, &iterItem1); - path2 = gtk_tree_model_get_path(model, &iterItem2); - gtk_tree_selection_select_range(selection, path1, path2); - gtk_tree_path_free(path1); - gtk_tree_path_free(path2); + gtkTreeSelectRange(ih, model, selection, &iterItem1, &iterItem2, 0); } return 1; @@ -1210,148 +1253,112 @@ static int gtkTreeSetValueAttrib(Ihandle* ih, const char* value) { GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); - GtkTreeIter iterRoot, iterItem; + GtkTreeIter iterItem; GtkTreePath* path; + int kind; if (gtkTreeSetMarkAttrib(ih, value)) return 0; - gtk_tree_model_get_iter_first(model, &iterRoot); - - if (iupStrEqualNoCase(value, "ROOT")) - iterItem = iterRoot; + if (iupStrEqualNoCase(value, "ROOT") || iupStrEqualNoCase(value, "FIRST")) + gtk_tree_model_get_iter_first(model, &iterItem); else if(iupStrEqualNoCase(value, "LAST")) - iterItem = gtkTreeGetLastVisibleNode(ih, model, iterRoot); + gtkTreeGetLastVisibleNode(ih, model, &iterItem); else if(iupStrEqualNoCase(value, "PGUP")) { - GtkTreeIter iterPrev; - GtkTreePath* pathFocus; gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); - gtk_tree_model_get_iter(model, &iterPrev, pathFocus); + gtk_tree_model_get_iter(model, &iterItem, pathFocus); gtk_tree_path_free(pathFocus); - ih->data->id_control = -1; - gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterPrev); - ih->data->id_control -= 10; /* less 10 visible nodes */ - - if(ih->data->id_control < 0) - ih->data->id_control = 0; /* Begin of tree = Root id */ - - iterItem = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); + gtkTreeGetPreviousVisibleNode(ih, model, &iterItem, 10); } else if(iupStrEqualNoCase(value, "PGDN")) { - GtkTreeIter iterNext; - GtkTreePath* pathFocus; gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); - gtk_tree_model_get_iter(model, &iterNext, pathFocus); + gtk_tree_model_get_iter(model, &iterItem, pathFocus); gtk_tree_path_free(pathFocus); - ih->data->id_control = -1; - gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterNext); - ih->data->id_control += 10; /* more 10 visible nodes */ - - iterNext = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); - - if (ih->data->id_control >= 0) - iterNext = gtkTreeGetLastVisibleNode(ih, model, iterRoot); - - iterItem = iterNext; + gtkTreeGetNextVisibleNode(ih, model, &iterItem, 10); } else if(iupStrEqualNoCase(value, "NEXT")) { - GtkTreeIter iterNext; - GtkTreePath* pathFocus; gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); - gtk_tree_model_get_iter(model, &iterNext, pathFocus); + gtk_tree_model_get_iter(model, &iterItem, pathFocus); gtk_tree_path_free(pathFocus); - ih->data->id_control = -1; - gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterNext); - ih->data->id_control++; /* more 1 visible node */ - - iterNext = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); - - if (ih->data->id_control >= 0) - iterNext = gtkTreeGetLastVisibleNode(ih, model, iterRoot); - - iterItem = iterNext; + gtkTreeGetNextVisibleNode(ih, model, &iterItem, 1); } else if(iupStrEqualNoCase(value, "PREVIOUS")) { - GtkTreeIter iterPrev; - GtkTreePath* pathFocus; gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); - gtk_tree_model_get_iter(model, &iterPrev, pathFocus); + gtk_tree_model_get_iter(model, &iterItem, pathFocus); gtk_tree_path_free(pathFocus); - ih->data->id_control = -1; - gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterPrev); - ih->data->id_control--; /* less 1 visible node */ - - if (ih->data->id_control < 0) - ih->data->id_control = 0; - - iterItem = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); - if (!iterItem.user_data) - return 0; + gtkTreeGetPreviousVisibleNode(ih, model, &iterItem, 1); } else { - if (!gtkTreeFindNodeFromString(ih, model, value, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, value, &iterItem)) return 0; } /* select */ if (ih->data->mark_mode==ITREE_MARK_SINGLE) { - iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", "1"); - gtk_tree_selection_select_iter(selection, &iterItem); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + gtkTreeSelectNode(model, selection, &iterItem, 1); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); } path = gtk_tree_model_get_path(model, &iterItem); + + /* make it visible */ + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); + if (kind == ITREE_LEAF) + gtk_tree_view_expand_to_path(GTK_TREE_VIEW(ih->handle), path); + else + { + int expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); + gtk_tree_view_expand_to_path(GTK_TREE_VIEW(ih->handle), path); + if (!expanded) gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); + } + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE, 0, 0); /* scroll to visible */ + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); /* set focus */ + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + gtk_tree_path_free(path); - iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", gtkTreeGetNodeId(ih, iterItem)); + iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", gtkTreeFindNodeId(ih, &iterItem)); return 0; } static int gtkTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) { - GtkTreePath *pathMarkStart, *pathMarkStartPrev; - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return 0; - pathMarkStart = gtk_tree_model_get_path(model, &iterItem); - - pathMarkStartPrev = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"); - if (pathMarkStartPrev) - gtk_tree_path_free(pathMarkStartPrev); - - iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)pathMarkStart); + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)iterItem.user_data); return 1; } static char* gtkTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) { - GtkTreeSelection* selection; - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeModel* model; GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return 0; - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); - if (gtk_tree_selection_iter_is_selected(selection, &iterItem)) + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + if (gtkTreeIsNodeSelected(model, &iterItem)) return "YES"; else return "NO"; @@ -1359,87 +1366,99 @@ static char* gtkTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) static int gtkTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value) { + GtkTreeModel* model; GtkTreeSelection* selection; - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return 0; - iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", "1"); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); if (iupStrBoolean(value)) - gtk_tree_selection_select_iter(selection, &iterItem); + gtkTreeSelectNode(model, selection, &iterItem, 1); else - gtk_tree_selection_unselect_iter(selection, &iterItem); + gtkTreeSelectNode(model, selection, &iterItem, 0); + + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); return 0; } static int gtkTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; - if (iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */ + if (iupStrEqualNoCase(value, "ALL")) { GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - GtkTreeIter iterItem; - GtkTreeIter iterParent; + gtkTreeCallNodeRemovedAll(ih); - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) - return 0; + /* deleting the reference node (and it's children) */ + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + gtk_tree_store_clear(GTK_TREE_STORE(model)); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + return 0; + } + if (iupStrEqualNoCase(value, "SELECTED")) /* selected here means the reference node */ + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; - if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem)) /* the root node can't be deleted */ + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return 0; gtkTreeCallNodeRemoved(ih, model, &iterItem); - /* deleting the specified node (and it's children) */ + /* deleting the reference node (and it's children) */ + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); } - else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */ + else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the reference node */ { GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); GtkTreeIter iterItem, iterChild; int hasChildren; - if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return 0; hasChildren = gtk_tree_model_iter_children(model, &iterChild, &iterItem); - /* deleting the selected node's children */ + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + + /* deleting the reference node children */ while(hasChildren) { gtkTreeCallNodeRemoved(ih, model, &iterChild); hasChildren = gtk_tree_store_remove(GTK_TREE_STORE(model), &iterChild); } + + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); } else if(iupStrEqualNoCase(value, "MARKED")) /* Delete the array of marked nodes */ { + int i; GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); - GList *rr_list = NULL; - GList *node; + GtkTreeIter iterItem; - gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Iter_Func, &rr_list); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); - for(node = rr_list; node != NULL; node = node->next) + for(i = 1; i < ih->data->node_count; /* increment only if not removed */) { - GtkTreePath* path = gtk_tree_row_reference_get_path(node->data); - if (path) + gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); + if (gtkTreeIsNodeSelected(model, &iterItem)) { - GtkTreeIter iterItem; - if (gtk_tree_model_get_iter(model, &iterItem, path)) - { - gtkTreeCallNodeRemoved(ih, model, &iterItem); - gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem); - } - gtk_tree_path_free(path); + gtkTreeCallNodeRemoved(ih, model, &iterItem); + gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem); } - gtk_tree_row_reference_free(node->data); + else + i++; } - g_list_free(rr_list); + + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); } return 0; @@ -1450,36 +1469,11 @@ static int gtkTreeSetRenameAttrib(Ihandle* ih, const char* value) if (ih->data->show_rename) { GtkTreePath* path; - IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); GtkTreeViewColumn *focus_column; - gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, &focus_column); - - if (cbShowRename) - { - GtkTreeIter iterItem; - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - gtk_tree_model_get_iter(model, &iterItem, path); - cbShowRename(ih, gtkTreeGetNodeId(ih, iterItem)); - } - gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, focus_column, TRUE); gtk_tree_path_free(path); } - else - { - IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB"); - if (cbRenameNode) - { - GtkTreePath* path; - GtkTreeIter iterItem; - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); - gtk_tree_model_get_iter(model, &iterItem, path); - gtk_tree_path_free(path); - cbRenameNode(ih, gtkTreeGetNodeId(ih, iterItem), gtkTreeGetTitle(model, iterItem)); - } - } (void)value; return 0; @@ -1491,7 +1485,7 @@ static int gtkTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); GdkPixbuf* pixExpand = iupImageGetImage(value, ih, 0); GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return 0; gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1); @@ -1514,7 +1508,7 @@ static int gtkTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* v GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); GdkPixbuf* pixImage = iupImageGetImage(value, ih, 0); GtkTreeIter iterItem; - if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + if (!gtkTreeFindNodeFromString(ih, name_id, &iterItem)) return 0; if (pixImage) @@ -1539,42 +1533,30 @@ static int gtkTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* v static int gtkTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) { - GtkTreeIter iterRoot; - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ih->data->def_image_expanded = iupImageGetImage(value, ih, 0); - gtk_tree_model_get_iter_first(model, &iterRoot); - - /* Update all images, starting at root node */ - gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_EXPANDED); + /* Update all images */ + gtkTreeUpdateImages(ih, ITREE_UPDATEIMAGE_EXPANDED); return 1; } static int gtkTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) { - GtkTreeIter iterRoot; - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ih->data->def_image_collapsed = iupImageGetImage(value, ih, 0); - gtk_tree_model_get_iter_first(model, &iterRoot); - - /* Update all images, starting at root node */ - gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_COLLAPSED); + /* Update all images */ + gtkTreeUpdateImages(ih, ITREE_UPDATEIMAGE_COLLAPSED); return 1; } static int gtkTreeSetImageLeafAttrib(Ihandle* ih, const char* value) { - GtkTreeIter iterRoot; - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); ih->data->def_image_leaf = iupImageGetImage(value, ih, 0); - gtk_tree_model_get_iter_first(model, &iterRoot); - - /* Update all images, starting at root node */ - gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_LEAF); + /* Update all images */ + gtkTreeUpdateImages(ih, ITREE_UPDATEIMAGE_LEAF); return 1; } @@ -1655,6 +1637,7 @@ void iupdrvTreeUpdateMarkMode(Ihandle *ih) if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && !ih->data->show_dragdrop) { #if GTK_CHECK_VERSION(2, 10, 0) + if (iupAttribGetInt(ih, "RUBBERBAND")) gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(ih->handle), TRUE); #endif } @@ -1704,6 +1687,19 @@ static void gtkTreeCellTextEditingStarted(GtkCellRenderer *cell, GtkCellEditable PangoFontDescription* fontdesc = NULL; GdkColor *color = NULL; GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + IFni cbShowRename; + + gtk_tree_model_get_iter_from_string(model, &iterItem, path_string); + + cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); + if (cbShowRename && cbShowRename(ih, gtkTreeFindNodeId(ih, &iterItem))==IUP_IGNORE) + { + /* TODO: non of these worked: + gtk_cell_renderer_stop_editing(cell, TRUE); + gtk_cell_editable_editing_done(editable); */ + gtk_editable_set_editable(GTK_EDITABLE(editable), FALSE); + return; + } value = iupAttribGetStr(ih, "RENAMECARET"); if (value) @@ -1713,7 +1709,6 @@ static void gtkTreeCellTextEditingStarted(GtkCellRenderer *cell, GtkCellEditable if (value) gtkTreeSetRenameSelectionPos(editable, value); - gtk_tree_model_get_iter_from_string(model, &iterItem, path_string); gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_FONT, &fontdesc, -1); if (fontdesc) gtk_widget_modify_font(GTK_WIDGET(editable), fontdesc); @@ -1732,7 +1727,7 @@ static void gtkTreeCellTextEdited(GtkCellRendererText *cell, gchar *path_string, IFnis cbRename; if (!new_text) - return; + new_text = ""; model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); if (!gtk_tree_model_get_iter_from_string(model, &iterItem, path_string)) @@ -1741,7 +1736,7 @@ static void gtkTreeCellTextEdited(GtkCellRendererText *cell, gchar *path_string, cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); if (cbRename) { - if (cbRename(ih, gtkTreeGetNodeId(ih, iterItem), iupgtkStrConvertFromUTF8(new_text)) == IUP_IGNORE) + if (cbRename(ih, gtkTreeFindNodeId(ih, &iterItem), iupgtkStrConvertFromUTF8(new_text)) == IUP_IGNORE) return; } @@ -1766,8 +1761,8 @@ static int gtkTreeCallDragDropCb(Ihandle* ih, GtkTreeIter *iterDrag, GtkTreeIter if (cbDragDrop) { - int drag_id = gtkTreeGetNodeId(ih, *iterDrag); - int drop_id = gtkTreeGetNodeId(ih, *iterDrop); + int drag_id = gtkTreeFindNodeId(ih, iterDrag); + int drop_id = gtkTreeFindNodeId(ih, iterDrop); return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl); } @@ -1804,22 +1799,17 @@ static void gtkTreeDragDataReceived(GtkWidget *widget, GdkDragContext *context, { GtkTreeIter iterNewItem; - /* Copy the dragged item to the new position. */ - gtkTreeCopyNode(ih, model, &iterDrag, &iterDrop, &iterNewItem, is_ctrl); - - if (!is_ctrl) - { - /* do not delete the user data, we copy the references in CopyNode */ - gtk_tree_store_remove(GTK_TREE_STORE(model), &iterDrag); - } + /* Copy or move the dragged item to the new position. */ + gtkTreeCopyMoveNode(ih, model, &iterDrag, &iterDrop, &iterNewItem, is_ctrl); /* set focus and selection */ + if (iterNewItem.stamp) { GtkTreePath *pathNew; GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); pathNew = gtk_tree_model_get_path(model, &iterNewItem); - gtk_tree_selection_select_path(selection, pathNew); + gtkTreeSelectNode(model, selection, &iterNewItem, 1); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), pathNew, NULL, FALSE, 0, 0); gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), pathNew, NULL, FALSE); @@ -1927,10 +1917,24 @@ static void gtkTreeDragBegin(GtkWidget *widget, GdkDragContext *context, Ihandle (void)widget; } +static gboolean gtkTreeSelectionFunc(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean selected, Ihandle* ih) +{ + GtkTreeIter iterItem; + gtk_tree_model_get_iter(model, &iterItem, path); + gtkTreeSelectNodeRaw(model, &iterItem, !selected); + (void)ih; + (void)selection; + return TRUE; +} + static void gtkTreeSelectionChanged(GtkTreeSelection* selection, Ihandle* ih) { IFnii cbSelec; int is_ctrl = 0; + (void)selection; + + if (iupAttribGet(ih, "_IUPTREE_IGNORE_SELECTION_CB")) + return; if (ih->data->mark_mode == ITREE_MARK_MULTIPLE) { @@ -1953,25 +1957,17 @@ static void gtkTreeSelectionChanged(GtkTreeSelection* selection, Ihandle* ih) if (cbSelec) { int curpos = -1, is_selected = 0; + GtkTreeIter iterFocus; + GtkTreePath* pathFocus; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - if (iupAttribGet(ih, "_IUP_IGNORE_SELECTION")) - { - iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", NULL); - return; - } - + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + if (pathFocus) { - GtkTreeIter iterFocus; - GtkTreePath* pathFocus; - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); - gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); - if (pathFocus) - { - gtk_tree_model_get_iter(model, &iterFocus, pathFocus); - gtk_tree_path_free(pathFocus); - curpos = gtkTreeGetNodeId(ih, iterFocus); - is_selected = gtk_tree_selection_iter_is_selected(selection, &iterFocus); - } + gtk_tree_model_get_iter(model, &iterFocus, pathFocus); + gtk_tree_path_free(pathFocus); + curpos = gtkTreeFindNodeId(ih, &iterFocus); + is_selected = gtkTreeIsNodeSelected(model, &iterFocus); } if (curpos == -1) @@ -1993,18 +1989,52 @@ static void gtkTreeSelectionChanged(GtkTreeSelection* selection, Ihandle* ih) } } +static void gtkTreeUpdateSelectionChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter *iterItem) +{ + int expanded; + GtkTreeIter iterChild; + int hasItem = gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ + while(hasItem) + { + if (gtkTreeIsNodeSelected(model, &iterChild)) + gtk_tree_selection_select_iter(selection, &iterChild); + + expanded = 0; + if (gtk_tree_model_iter_has_child(model, &iterChild)) + { + GtkTreePath* path = gtk_tree_model_get_path(model, &iterChild); + expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); + gtk_tree_path_free(path); + } + + /* Recursive only if expanded */ + if (expanded) + gtkTreeUpdateSelectionChildren(ih, model, selection, &iterChild); + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterChild); + } +} + +static void gtkTreeRowExpanded(GtkTreeView* tree_view, GtkTreeIter *iterItem, GtkTreePath *path, Ihandle* ih) +{ + GtkTreeSelection* selection = gtk_tree_view_get_selection(tree_view); + GtkTreeModel* model = gtk_tree_view_get_model(tree_view); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + gtkTreeUpdateSelectionChildren(ih, model, selection, iterItem); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + (void)path; +} + static gboolean gtkTreeTestExpandRow(GtkTreeView* tree_view, GtkTreeIter *iterItem, GtkTreePath *path, Ihandle* ih) { IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB"); if (cbBranchOpen) { - if (iupAttribGet(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB")) - { - iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB", NULL); + if (iupAttribGet(ih, "_IUPTREE_IGNORE_BRANCH_CB")) return FALSE; - } - if (cbBranchOpen(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE) + if (cbBranchOpen(ih, gtkTreeFindNodeId(ih, iterItem)) == IUP_IGNORE) return TRUE; /* prevent the change */ } @@ -2018,7 +2048,10 @@ static gboolean gtkTreeTestCollapseRow(GtkTreeView* tree_view, GtkTreeIter *iter IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); if (cbBranchClose) { - if (cbBranchClose(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE) + if (iupAttribGet(ih, "_IUPTREE_IGNORE_BRANCH_CB")) + return FALSE; + + if (cbBranchClose(ih, gtkTreeFindNodeId(ih, iterItem)) == IUP_IGNORE) return TRUE; } @@ -2042,7 +2075,7 @@ static void gtkTreeRowActived(GtkTreeView* tree_view, GtkTreePath *path, GtkTree /* just to leaf nodes */ if(gtk_tree_model_iter_has_child(model, &iterItem) == 0 && kind == ITREE_LEAF) - cbExecuteLeaf(ih, gtkTreeGetNodeId(ih, iterItem)); + cbExecuteLeaf(ih, gtkTreeFindNodeId(ih, &iterItem)); (void)column; (void)tree_view; @@ -2057,11 +2090,57 @@ static int gtkTreeConvertXYToPos(Ihandle* ih, int x, int y) GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); gtk_tree_model_get_iter(model, &iterItem, path); gtk_tree_path_free (path); - return gtkTreeGetNodeId(ih, iterItem); + return gtkTreeFindNodeId(ih, &iterItem); } return -1; } +static Iarray* gtkTreeGetSelectedArrayId(Ihandle* ih) +{ + Iarray* selarray = iupArrayCreate(1, sizeof(int)); + int i; + GtkTreeIter iterItem; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + + for (i = 0; i < ih->data->node_count; i++) + { + gtkTreeIterInit(ih, &iterItem, ih->data->node_cache[i].node_handle); + if (gtkTreeIsNodeSelected(model, &iterItem)) + { + int* id_hitem = (int*)iupArrayInc(selarray); + int j = iupArrayCount(selarray); + id_hitem[j-1] = i; + } + } + + return selarray; +} + +static void gtkTreeCallMultiUnSelectionCb(Ihandle* ih) +{ + IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTIUNSELECTION_CB"); + IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbSelec || cbMulti) + { + Iarray* markedArray = gtkTreeGetSelectedArrayId(ih); + int* id_hitem = (int*)iupArrayGetData(markedArray); + int i, count = iupArrayCount(markedArray); + + if (count > 1) + { + if (cbMulti) + cbMulti(ih, id_hitem, iupArrayCount(markedArray)); + else + { + for (i=0; i<count; i++) + cbSelec(ih, id_hitem[i], 0); + } + } + + iupArrayDestroy(markedArray); + } +} + static gboolean gtkTreeButtonEvent(GtkWidget *treeview, GdkEventButton *evt, Ihandle* ih) { if (iupgtkButtonEvent(treeview, evt, ih) == TRUE) @@ -2097,6 +2176,18 @@ static gboolean gtkTreeButtonEvent(GtkWidget *treeview, GdkEventButton *evt, Iha gtk_tree_path_free(path); } } + 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)) + { + gtkTreeCallMultiUnSelectionCb(ih); + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1"); + } + } else if (evt->type == GDK_BUTTON_RELEASE && evt->button == 1) /* left single release */ { if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & GDK_SHIFT_MASK)) @@ -2109,16 +2200,7 @@ static gboolean gtkTreeButtonEvent(GtkWidget *treeview, GdkEventButton *evt, Iha iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "2"); } } - else if (evt->type == GDK_BUTTON_PRESS && evt->button == 1) /* left single press */ - { - iupAttribSetInt(ih, "_IUPTREE_DRAG_X", (int)evt->x); - iupAttribSetInt(ih, "_IUPTREE_DRAG_Y", (int)evt->y); - if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && - !(evt->state & GDK_SHIFT_MASK) && !(evt->state & GDK_CONTROL_MASK)) - iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1"); - } - return FALSE; } @@ -2159,29 +2241,14 @@ static void gtkTreeEnableDragDrop(Ihandle* ih) { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 } }; - if (iupAttribGetBoolean(ih, "AUTODRAGDROP")) - { - gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW(ih->handle), - GDK_BUTTON1_MASK, - row_targets, - G_N_ELEMENTS(row_targets), - GDK_ACTION_MOVE|GDK_ACTION_COPY); - gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW(ih->handle), - row_targets, - G_N_ELEMENTS(row_targets), - GDK_ACTION_MOVE|GDK_ACTION_COPY); - } - else - { - gtk_drag_source_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); - gtk_drag_dest_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); + gtk_drag_source_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); + gtk_drag_dest_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); - g_signal_connect(G_OBJECT(ih->handle), "drag-begin", G_CALLBACK(gtkTreeDragBegin), ih); - g_signal_connect(G_OBJECT(ih->handle), "drag-motion", G_CALLBACK(gtkTreeDragMotion), ih); - g_signal_connect(G_OBJECT(ih->handle), "drag-leave", G_CALLBACK(gtkTreeDragLeave), NULL); - g_signal_connect(G_OBJECT(ih->handle), "drag-drop", G_CALLBACK(gtkTreeDragDrop), ih); - g_signal_connect(G_OBJECT(ih->handle), "drag-data-received", G_CALLBACK(gtkTreeDragDataReceived), ih); - } + g_signal_connect(G_OBJECT(ih->handle), "drag-begin", G_CALLBACK(gtkTreeDragBegin), ih); + g_signal_connect(G_OBJECT(ih->handle), "drag-motion", G_CALLBACK(gtkTreeDragMotion), ih); + g_signal_connect(G_OBJECT(ih->handle), "drag-leave", G_CALLBACK(gtkTreeDragLeave), NULL); + g_signal_connect(G_OBJECT(ih->handle), "drag-drop", G_CALLBACK(gtkTreeDragDrop), ih); + g_signal_connect(G_OBJECT(ih->handle), "drag-data-received", G_CALLBACK(gtkTreeDragDataReceived), ih); } /*****************************************************************************/ @@ -2194,8 +2261,16 @@ static int gtkTreeMapMethod(Ihandle* ih) GtkTreeSelection* selection; GtkTreeViewColumn *column; - store = gtk_tree_store_new(9, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, - G_TYPE_STRING, G_TYPE_INT, GDK_TYPE_COLOR, PANGO_TYPE_FONT_DESCRIPTION, G_TYPE_POINTER); + store = gtk_tree_store_new(IUPGTK_TREE_LAST_DATA, + GDK_TYPE_PIXBUF, /* IUPGTK_TREE_IMAGE */ + G_TYPE_BOOLEAN, /* IUPGTK_TREE_HAS_IMAGE */ + GDK_TYPE_PIXBUF, /* IUPGTK_TREE_IMAGE_EXPANDED */ + G_TYPE_BOOLEAN, /* IUPGTK_TREE_HAS_IMAGE_EXPANDED */ + G_TYPE_STRING, /* IUPGTK_TREE_TITLE */ + G_TYPE_INT, /* IUPGTK_TREE_KIND */ + GDK_TYPE_COLOR, /* IUPGTK_TREE_COLOR */ + PANGO_TYPE_FONT_DESCRIPTION, /* IUPGTK_TREE_FONT */ + G_TYPE_BOOLEAN); /* IUPGTK_TREE_SELECT */ ih->handle = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); @@ -2262,8 +2337,9 @@ static int gtkTreeMapMethod(Ihandle* ih) gtk_scrolled_window_set_policy(scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); - gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); + gtk_tree_selection_set_select_function(selection, (GtkTreeSelectionFunc)gtkTreeSelectionFunc, ih, NULL); + gtk_tree_view_set_reorderable(GTK_TREE_VIEW(ih->handle), FALSE); /* callbacks */ @@ -2279,6 +2355,7 @@ static int gtkTreeMapMethod(Ihandle* ih) g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "row-expanded", G_CALLBACK(gtkTreeRowExpanded), ih); g_signal_connect(G_OBJECT(ih->handle), "test-expand-row", G_CALLBACK(gtkTreeTestExpandRow), ih); g_signal_connect(G_OBJECT(ih->handle), "test-collapse-row", G_CALLBACK(gtkTreeTestCollapseRow), ih); g_signal_connect(G_OBJECT(ih->handle), "row-activated", G_CALLBACK(gtkTreeRowActived), ih); @@ -2301,7 +2378,8 @@ static int gtkTreeMapMethod(Ihandle* ih) ih->data->def_image_collapsed = iupImageGetImage("IMGCOLLAPSED", ih, 0); ih->data->def_image_expanded = iupImageGetImage("IMGEXPANDED", ih, 0); - gtkTreeAddRootNode(ih); + if (iupAttribGetInt(ih, "ADDROOT")) + iupdrvTreeAddNode(ih, "-1", ITREE_BRANCH, "", 0); /* configure for DRAG&DROP of files */ if (IupGetCallback(ih, "DROPFILES_CB")) @@ -2309,13 +2387,23 @@ static int gtkTreeMapMethod(Ihandle* ih) IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkTreeConvertXYToPos); + iupdrvTreeUpdateMarkMode(ih); + return IUP_NOERROR; } +static void gtkTreeUnMapMethod(Ihandle* ih) +{ + ih->data->node_count = 0; + + iupdrvBaseUnMapMethod(ih); +} + void iupdrvTreeInitClass(Iclass* ic) { /* Driver Dependent Class functions */ ic->Map = gtkTreeMapMethod; + ic->UnMap = gtkTreeUnMapMethod; /* Visual */ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTreeSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); @@ -2324,7 +2412,6 @@ void iupdrvTreeInitClass(Iclass* ic) /* IupTree Attributes - GENERAL */ iupClassRegisterAttribute(ic, "EXPANDALL", NULL, gtkTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "INDENTATION", gtkTreeGetIndentationAttrib, gtkTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT); - iupClassRegisterAttribute(ic, "COUNT", gtkTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, gtkTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); iupClassRegisterAttribute(ic, "TOPITEM", NULL, gtkTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); @@ -2345,7 +2432,6 @@ void iupdrvTreeInitClass(Iclass* ic) iupClassRegisterAttributeId(ic, "COLOR", gtkTreeGetColorAttrib, gtkTreeSetColorAttrib, IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "NAME", gtkTreeGetTitleAttrib, gtkTreeSetTitleAttrib, IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "TITLE", gtkTreeGetTitleAttrib, gtkTreeSetTitleAttrib, IUPAF_NO_INHERIT); - iupClassRegisterAttributeId(ic, "USERDATA", gtkTreeGetUserDataAttrib, gtkTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "CHILDCOUNT", gtkTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "TITLEFONT", gtkTreeGetTitleFontAttrib, gtkTreeSetTitleFontAttrib, IUPAF_NO_INHERIT); @@ -2355,6 +2441,7 @@ void iupdrvTreeInitClass(Iclass* ic) iupClassRegisterAttribute (ic, "MARK", NULL, gtkTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute (ic, "STARTING", NULL, gtkTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); iupClassRegisterAttribute (ic, "MARKSTART", NULL, gtkTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARKEDNODES", gtkTreeGetMarkedNodesAttrib, gtkTreeSetMarkedNodesAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); iupClassRegisterAttribute (ic, "VALUE", gtkTreeGetValueAttrib, gtkTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); @@ -2363,7 +2450,7 @@ void iupdrvTreeInitClass(Iclass* ic) iupClassRegisterAttribute(ic, "RENAME", NULL, gtkTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "MOVENODE", NULL, gtkTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "COPYNODE", NULL, gtkTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); - iupClassRegisterAttributeId(ic, "FINDUSERDATA", gtkTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); - iupClassRegisterAttribute (ic, "AUTODRAGDROP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT); + /* IupTree Attributes - GTK Only */ + iupClassRegisterAttribute (ic, "RUBBERBAND", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); } diff --git a/iup/src/gtk/iupmac_help.c b/iup/src/gtk/iupmac_help.c new file mode 100644 index 0000000..fa8d0af --- /dev/null +++ b/iup/src/gtk/iupmac_help.c @@ -0,0 +1,46 @@ +/** \file + * \brief MAC 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, "Snow Leopard") || + iupStrEqualNoCase(system, "Leopard") || + iupStrEqualNoCase(system, "Tiger") || + iupStrEqualNoCase(system, "Panther")) + browser = "safari"; + else if (iupStrEqualNoCase(system, "Jaguar") || + iupStrEqualNoCase(system, "Puma") || + iupStrEqualNoCase(system, "Cheetah")) + browser = "iexplore"; + else /* MacOS */ + browser = "netscape"; + } + + cmd = (char*)malloc(sizeof(char)*(strlen(url)+strlen(browser)+3)); + sprintf(cmd, "open -a %s %s &", browser, url); + ret = system(cmd); + free(cmd); + if (ret == -1) + return -1; + return 1; +} diff --git a/iup/src/gtk/iupmac_info.c b/iup/src/gtk/iupmac_info.c new file mode 100644 index 0000000..a040bad --- /dev/null +++ b/iup/src/gtk/iupmac_info.c @@ -0,0 +1,358 @@ +/** \file + * \brief MAC OS System Information + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* This module should depend only on IUP core headers and + Mac OS Carbon system headers. */ + +#include <Carbon/Carbon.h> + +#include <sys/utsname.h> +#include <unistd.h> +#include <limits.h> +#include <errno.h> +#include <sys/stat.h> + +#include <gtk/gtk.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" + +#define IUP_MAC_ERROR -1 + +/****************************************** + ** These are NOT working as expected. So we kept the posix versions. *** + +static void iupMacStrToUniChar(const char* buffer, UniChar* outBuf, long length, long* outLen) +{ + CFStringRef stringRef = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8); + + CFStringGetCharacters (stringRef, CFRangeMake(0, CFStringGetLength(stringRef)), outBuf); + *outLen = (long) CFStringGetLength (stringRef); + + CFRelease(stringRef); +} + +int iupdrvMakeDirectory(const char* name) +{ + FSRef refParent, refNew; + UniChar nameDir; + long lenDir; + + if(FSFindFolder(kUserDomain, kCurrentUserFolderType, kDontCreateFolder, &refParent) != noErr) + return 0; + + iupMacStrToUniChar(name, &nameDir, strlen(name), &lenDir); + + if(FSMakeFSRefUnicode(&refParent, lenDir, &nameDir, kTextEncodingUnknown, &refNew) != fnfErr) // fnfErr => Directory does not exists + return 0; + + if(FSCreateDirectoryUnicode(&refParent, lenDir, &nameDir, kFSCatInfoNone, NULL, &refNew, NULL, NULL) != noErr) + return 0; + + return 1; +} + +char* iupdrvGetCurrentDirectory(void) +{ + FSRef refDir; + FSVolumeRefNum vRefNum; + long dirID; + size_t size = 256; + char *buffer = (char *)malloc(size); + + if(HGetVol(NULL, &vRefNum, &dirID) != noErr) // Deprecated in Mac OS X v10.4 + return 0; + + if(FSMakeFSRef(vRefNum, dirID, NULL, &refDir) != noErr) // Deprecated in Mac OS X v10.5 + return 0; + + FSRefMakePath (&refDir, (UInt8*)buffer, size); + + return buffer; +} + +int iupdrvSetCurrentDirectory(const char* dir) +{ + FSRef refDir; + FSCatalogInfo catalogInfo; + int isDirectory; + + if(FSPathMakeRef((const UInt8*)dir, &refDir, &isDirectory) != noErr) + return 0; + + if (!isDirectory) + return 0; + + if(FSGetCatalogInfo(refDir, kFSCatInfoVolume + kFSCatInfoNodeID, &catalogInfo, NULL, NULL, NULL) != noErr) + return 0; + + if(HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID) != noErr) // Deprecated in Mac OS X v10.4 + return 0; + + return 1; +} + +char* iupdrvGetCurrentDirectory(void) +{ + char* path = iupStrGetMemory(256); + CFBundleRef mainBundle = CFBundleGetMainBundle(); + CFURLRef curDir = CFBundleCopyBundleURL(mainBundle); + CFStringRef cfStringRef = CFURLCopyFileSystemPath(curDir, kCFURLPOSIXPathStyle); + + CFStringGetCString(cfStringRef, path, 256, kCFStringEncodingUTF8); + + return path; +} +*********************************************/ + +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; +} + +static int iMacIsFolder(const char* name) +{ + FSRef refName; + Boolean isFolder; + + if(FSPathMakeRef((const UInt8*)name, &refName, &isFolder) != noErr) + return IUP_MAC_ERROR; + + return isFolder; +} + +int iupdrvIsFile(const char* name) +{ + int isDir = iMacIsFolder(name); + + if((isDir != IUP_MAC_ERROR) && !isDir) + return 1; + + return 0; +} + +int iupdrvIsDirectory(const char* name) +{ + int isDir = iMacIsFolder(name); + + if((isDir != IUP_MAC_ERROR) && isDir) + 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) +{ + Rect rect; + CGRect cg; + int minX, minY; + + CGDirectDisplayID mainDisplayID = CGMainDisplayID(); + GDHandle hGDev; + DMGetGDeviceByDisplayID((DisplayIDType)mainDisplayID, &hGDev, false); + + GetAvailableWindowPositioningBounds(hGDev, &rect); + + cg = CGRectMake(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); + + minX = (int)CGRectGetMinX(cg); + minY = (int)CGRectGetMinY(cg); + + if (minX >= 0 && minY >= 0 && (minY >= minX)) + { + *border = minX; + *caption = minY - *border; + + return 1; + } + + *border = 0; + *caption = 0; + + return 0; +} + +void iupdrvGetScreenSize(int *width, int *height) +{ + int w_size = CGDisplayPixelsWide(kCGDirectMainDisplay); + int h_size = CGDisplayPixelsHigh(kCGDirectMainDisplay); + + *width = w_size; + *height = h_size; +} + +void iupdrvGetFullSize(int *width, int *height) +{ + CGRect rect; + + rect = CGDisplayBounds(kCGDirectMainDisplay); + + *width = (int)CGRectGetWidth(rect); + *height = (int)CGRectGetHeight(rect); +} + +int iupdrvGetScreenDepth(void) +{ + return CGDisplayBitsPerPixel(kCGDirectMainDisplay); /* Deprecated in Mac OS X v10.6 */ +} + +void iupdrvGetCursorPos(int *x, int *y) +{ + Point pnt; + CGPoint point; + + GetMouse(&pnt); + point = CGPointMake(pnt.h, pnt.v); + + *x = (int)point.x; + *y = (int)point.y; +} + +void iupdrvGetKeyState(char* key) +{ + if (GetCurrentEventKeyModifiers() & shiftKey) + key[0] = 'S'; + else + key[0] = ' '; + + if (GetCurrentEventKeyModifiers() & controlKey) + key[1] = 'C'; + else + key[1] = ' '; + + if (GetCurrentEventKeyModifiers() & optionKey) + key[2] = 'A'; + else + key[2] = ' '; + + if (GetCurrentEventKeyModifiers() & cmdKey) + key[3] = 'Y'; + else + key[3] = ' '; + + key[4] = 0; +} + +char *iupdrvGetSystemName(void) +{ + long systemVersion; + + if (Gestalt(gestaltSystemVersion, &systemVersion) == noErr) + { + if (systemVersion >= 0x1060) + return "Snow Leopard"; + else if (systemVersion >= 0x1050) + return "Leopard"; + else if (systemVersion >= 0x1040) + return "Tiger"; + else if (systemVersion >= 0x1030) + return "Panther"; + else if (systemVersion >= 0x1020) + return "Jaguar"; + else if (systemVersion >= 0x1010) + return "Puma"; + else if (systemVersion >= 0x1010) + return "Cheetah"; + } + + return "MacOS"; +} + +char *iupdrvGetSystemVersion(void) +{ + char* str = iupStrGetMemory(70); + long systemVersion, versionMajor, versionMinor, versionBugFix, systemArchitecture; + + if (Gestalt(gestaltSystemVersion, &systemVersion) != noErr) + { + printf("Unable to obtain system version\n"); + return NULL; + } + + if (systemVersion < 0x1040) + { + /* Major, Minor, Bug fix */ + sprintf(str, "%ld.%ld.%ld", ((systemVersion & 0xF000) >> 12) * 10 + ((systemVersion & 0x0F00) >> 8), + ((systemVersion & 0x00F0) >> 4), (systemVersion & 0x000F)); + } + else /* MAC_OS_X_VERSION_10_4 or later */ + { + Gestalt(gestaltSystemVersionMajor, &versionMajor); + Gestalt(gestaltSystemVersionMinor, &versionMinor); + Gestalt(gestaltSystemVersionBugFix, &versionBugFix); + + sprintf(str, "%ld.%ld.%ld", versionMajor, versionMinor, versionBugFix); + } + + if(Gestalt(gestaltSysArchitecture, &systemArchitecture) == noErr) + { + if (systemArchitecture == gestalt68k) + sprintf(str, "%s %s", str, "(Motorola 68k)"); + else if (systemArchitecture == gestaltPowerPC) + sprintf(str, "%s %s", str, "(Power PC)"); + else /* gestaltIntel */ + sprintf(str, "%s %s", str, "(Intel)"); + } + + return str; +} + +char *iupdrvGetComputerName(void) +{ + char* str = iupStrGetMemory(50); + CFStringRef computerName = CSCopyMachineName(); + CFStringGetCString(computerName, str, 50, kCFStringEncodingUTF8); + return str; +} + +char *iupdrvGetUserName(void) +{ + char* str = iupStrGetMemory(50); + CFStringRef userName = CSCopyUserName(TRUE); /* TRUE = login name FALSE = user name */ + CFStringGetCString(userName, str, 50, kCFStringEncodingUTF8); + return str; +} diff --git a/iup/src/iup.c b/iup/src/iup.c index df4bf34..d103af5 100755 --- a/iup/src/iup.c +++ b/iup/src/iup.c @@ -36,8 +36,10 @@ * \subsection com File Comments (at start) * - Check an existant file for example. * - * \subsection inc Include Defines - * - __IUPXXX_H (same file name, upper case, "__" preffix and replace "." by "_") + * \subsection def Defines + * - __IUPXXX_H (for include file, same file name, upper case, "__" preffix and replace "." by "_") + * - IUP_XXX (for enumerations) + * - iupXXX (for macros, complement with Function Names rules) * * \subsection doc Documentation * - In the header, using Doxygen commands. @@ -58,7 +60,7 @@ #include "iup.h" /* This appears only here to avoid changing the iup.h header fo bug fixes */ -#define IUP_VERSION_FIX " RC3" +#define IUP_VERSION_FIX "" #define IUP_VERSION_FIX_NUMBER 0 const char iup_ident[] = diff --git a/iup/src/iup.def b/iup/src/iup.def index d0dcfbd..56e7225 100755 --- a/iup/src/iup.def +++ b/iup/src/iup.def @@ -27,6 +27,8 @@ IupGetFunction IupGetGlobal IupGetHandle IupGetInt +IupGetInt2 +IupGetIntInt IupGetLanguage IupGetName IupHbox @@ -40,6 +42,7 @@ IupListDialog IupLoad IupLoadBuffer IupLoopStep +IupLoopStepWait IupMainLoop IupMap IupMapFont @@ -68,6 +71,7 @@ IupShowXY IupStoreAttribute IupStoreGlobal IupSubmenu +IupSplit IupText IupToggle IupUnMapFont @@ -135,6 +139,7 @@ IupTextConvertLinColToPos IupTextConvertPosToLinCol IupUpdateChildren IupTreeSetAttribute +IupTreeSetAttributeHandle IupTreeStoreAttribute IupTreeGetAttribute IupTreeGetInt @@ -175,8 +180,8 @@ iupdrvFontGetStringWidth iupdrvFontGetMultiLineStringSize iupdrvFontGetCharSize iupdrvDrawFocusRect -iupdrvDisplayUpdate -iupdrvDisplayRedraw +iupdrvPostRedraw +iupdrvRedrawNow iupdrvBaseUnMapMethod iupdrvBaseSetZorderAttrib iupdrvBaseSetTipVisibleAttrib @@ -351,3 +356,17 @@ iupArrayCreate iupArrayCount iupArrayAdd iupSaveImageAsText +iupDrawCreateCanvas +iupDrawKillCanvas +iupDrawFlush +iupDrawGetSize +iupDrawParentBackground +iupDrawRectangle +iupDrawLine +iupDrawArc +iupDrawPolygon +iupDrawResetClip +iupDrawSetClipRect +iupDrawText +iupDrawUpdateSize +iupDrawImage diff --git a/iup/src/iup_attrib.c b/iup/src/iup_attrib.c index 2bbb80a..bf9576e 100755 --- a/iup/src/iup_attrib.c +++ b/iup/src/iup_attrib.c @@ -63,7 +63,7 @@ char* IupGetAttributes(Ihandle *ih) name = iupTableFirst(ih->attrib); while (name) { - if (!iupAttribIsInternal(name)) + if (!iupATTRIB_ISINTERNAL(name)) { if (buffer[0] != 0) strcat(buffer,","); @@ -115,6 +115,14 @@ void iupAttribUpdateFromParent(Ihandle* ih) } } +static int iAttribIsInherit(Ihandle* ih, const char* name) +{ + int inherit; + char *def_value; + iupClassObjectGetAttributeInfo(ih, name, &def_value, &inherit); + return inherit; +} + static void iAttribNotifyChildren(Ihandle *ih, const char* name, const char *value) { int inherit; @@ -123,17 +131,36 @@ static void iAttribNotifyChildren(Ihandle *ih, const char* name, const char *val { if (!iupTableGet(child->attrib, name)) { - /* set on the class */ - iupClassObjectSetAttribute(child, name, value, &inherit); + /* set only if an inheritable attribute at the child */ + if (iAttribIsInherit(child, name)) + { + /* set on the class */ + iupClassObjectSetAttribute(child, name, value, &inherit); - if (inherit) /* inherit can be different for the child */ iAttribNotifyChildren(child, name, value); + } } child = child->brother; } } +void iupAttribUpdateChildren(Ihandle* ih) +{ + char *name = iupTableFirst(ih->attrib); + while (name) + { + if (!iupATTRIB_ISINTERNAL(name) && iAttribIsInherit(ih, name)) + { + /* retrieve from the table */ + char* value = iupTableGet(ih->attrib, name); + iAttribNotifyChildren(ih, name, value); + } + + name = iupTableNext(ih->attrib); + } +} + void iupAttribUpdate(Ihandle* ih) { char** name_array; @@ -159,7 +186,7 @@ void iupAttribUpdate(Ihandle* ih) for (i = 0; i < count; i++) { name = name_array[i]; - if (!iupAttribIsInternal(name)) + if (!iupATTRIB_ISINTERNAL(name)) { /* retrieve from the table */ value = iupTableGet(ih->attrib, name); @@ -196,7 +223,7 @@ void IupSetAttribute(Ihandle *ih, const char* name, const char *value) if (!iupObjectCheck(ih)) return; - if (iupAttribIsInternal(name)) + if (iupATTRIB_ISINTERNAL(name)) iupAttribSetStr(ih, name, value); else { @@ -225,7 +252,7 @@ void IupStoreAttribute(Ihandle *ih, const char* name, const char *value) if (!iupObjectCheck(ih)) return; - if (iupAttribIsInternal(name)) + if (iupATTRIB_ISINTERNAL(name)) iupAttribStoreStr(ih, name, value); else { @@ -257,7 +284,7 @@ char* IupGetAttribute(Ihandle *ih, const char* name) if (!value) value = iupAttribGet(ih, name); - if (!value && !iupAttribIsInternal(name)) + if (!value && !iupATTRIB_ISINTERNAL(name)) { if (inherit) { @@ -346,6 +373,16 @@ void iupAttribSetHandleName(Ihandle *ih) IupSetHandle(str_name, ih); } +char* iupAttribGetHandleName(Ihandle *ih) +{ + char str_name[100]; + sprintf(str_name, "_IUP_NAME(%p)", ih); + if (IupGetHandle(str_name)==ih) + return iupStrGetMemoryCopy(str_name); + else + return NULL; +} + void IupSetAttributeHandle(Ihandle *ih, const char* name, Ihandle *ih_named) { int inherit; @@ -426,7 +463,7 @@ void iupAttribSetInt(Ihandle *ih, const char* name, int num) void iupAttribSetFloat(Ihandle *ih, const char* name, float num) { - iupAttribSetStrf(ih, name, "%f", (double)num); + iupAttribSetStrf(ih, name, "%g", (double)num); } int iupAttribGetBoolean(Ihandle* ih, const char* name) @@ -479,7 +516,7 @@ char* iupAttribGetStr(Ihandle* ih, const char* name) value = iupTableGet(ih->attrib, name); - if (!value && !iupAttribIsInternal(name)) + if (!value && !iupATTRIB_ISINTERNAL(name)) { int inherit; char *def_value; @@ -555,6 +592,15 @@ static void iAttribCapture(char* env_buffer, char* dlm) env_buffer[i-1]='\0'; /* discard delimiter */ } +static void iAttribSkipComment(void) +{ + int c; + do + { + c = *env_str; ++env_str; + } while ((c > 0) && (c != '\n')); +} + static int iAttribToken(char* env_buffer) { for (;;) @@ -565,6 +611,11 @@ static int iAttribToken(char* env_buffer) case 0: return IUPLEX_TK_END; + case '#': /* Skip comment */ + case '%': /* Skip comment */ + iAttribSkipComment(); + continue; + case ' ': /* ignore whitespace */ case '\t': case '\n': @@ -609,7 +660,7 @@ static void iAttribParse(Ihandle *ih, const char* str) { switch (iAttribToken(env_buffer)) { - case IUPLEX_TK_END: /* procedimento igual ao IUPLEX_TK_COMMA */ + case IUPLEX_TK_END: /* same as IUPLEX_TK_COMMA */ end = 1; case IUPLEX_TK_COMMA: if (name) diff --git a/iup/src/iup_attrib.h b/iup/src/iup_attrib.h index 993dd3c..8593d6e 100755 --- a/iup/src/iup_attrib.h +++ b/iup/src/iup_attrib.h @@ -28,7 +28,7 @@ extern "C" { /** Returns true if the attribute name if in the internal format "_IUP...". * \ingroup attrib */ -#define iupAttribIsInternal(_name) ((_name[0] == '_' && _name[1] == 'I' && _name[2] == 'U' && _name[3] == 'P')? 1: 0) +#define iupATTRIB_ISINTERNAL(_name) ((_name[0] == '_' && _name[1] == 'I' && _name[2] == 'U' && _name[3] == 'P')? 1: 0) /** Returns true if the attribute name is a known pointer. * \ingroup attrib */ @@ -102,16 +102,23 @@ float iupAttribGetFloat(Ihandle* ih, const char* name); * \ingroup attrib */ void iupAttribSetHandleName(Ihandle *ih); +/** Returns the internal name if set. + * \ingroup attrib */ +char* iupAttribGetHandleName(Ihandle *ih); + /* For all attributes in the evironment, call the class SetAttribute only. - * Called only after the element is mapped. */ + * Called only after the element is mapped, but before the children are mapped. */ void iupAttribUpdate(Ihandle* ih); /* For all registered inherited attributes, checks the parent tree and * call the class SetAttribute if the attribute is defined. - * Called only after the element is mapped. */ + * Called only after the element is mapped, but before the children are mapped. */ void iupAttribUpdateFromParent(Ihandle* ih); +/* For all attributes in the evironment, call the class SetAttribute only for the children. + * Called only after the element is mapped, and after the children are mapped. */ +void iupAttribUpdateChildren(Ihandle* ih); /* Other functions declared in <iup.h> and implemented here. diff --git a/iup/src/iup_box.c b/iup/src/iup_box.c index 54e56d9..111cab4 100755 --- a/iup/src/iup_box.c +++ b/iup/src/iup_box.c @@ -172,9 +172,9 @@ static int iBoxSetCMarginAttrib(Ihandle* ih, const char* value) iupdrvFontGetCharSize(ih, &charwidth, &charheight); iupStrToIntInt(value, &cmargin_x, &cmargin_y, 'x'); if (cmargin_x!=-1) - ih->data->margin_x = iupHEIGHT2RASTER(cmargin_x, charheight); + ih->data->margin_x = iupWIDTH2RASTER(cmargin_x, charwidth); if (cmargin_y!=-1) - ih->data->margin_x = iupWIDTH2RASTER(cmargin_y, charwidth); + ih->data->margin_y = iupHEIGHT2RASTER(cmargin_y, charheight); return 0; } @@ -227,8 +227,12 @@ Iclass* iupBoxClassBase(void) /* boxes only */ iupClassRegisterAttribute(ic, "GAP", iBoxGetGapAttrib, iBoxSetGapAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED); iupClassRegisterAttribute(ic, "CGAP", iBoxGetCGapAttrib, iBoxSetCGapAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "NGAP", iBoxGetGapAttrib, iBoxSetGapAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NCGAP", iBoxGetCGapAttrib, iBoxSetCGapAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "MARGIN", iBoxGetMarginAttrib, iBoxSetMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); iupClassRegisterAttribute(ic, "CMARGIN", iBoxGetCMarginAttrib, iBoxSetCMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "NMARGIN", iBoxGetMarginAttrib, iBoxSetMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NCMARGIN", iBoxGetCMarginAttrib, iBoxSetCMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "EXPANDCHILDREN", iBoxGetExpandChildrenAttrib, iBoxSetExpandChildrenAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "HOMOGENEOUS", iBoxGetHomogeneousAttrib, iBoxSetHomogeneousAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); diff --git a/iup/src/iup_button.c b/iup/src/iup_button.c index 7719663..56befe2 100755 --- a/iup/src/iup_button.c +++ b/iup/src/iup_button.c @@ -100,8 +100,9 @@ static void iButtonComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *ex char* value = iupAttribGet(ih, "IMAGE"); if (value) { + char* title = iupAttribGet(ih, "TITLE"); type = IUP_BUTTON_IMAGE; - if (iupAttribGet(ih, "TITLE")) + if (title && *title!=0) type |= IUP_BUTTON_TEXT; } else diff --git a/iup/src/iup_canvas.c b/iup/src/iup_canvas.c index 5eda988..46fefd9 100755 --- a/iup/src/iup_canvas.c +++ b/iup/src/iup_canvas.c @@ -55,14 +55,14 @@ void iupCanvasCalcScrollRealPos(double min, double max, double *pos, char* iupCanvasGetPosXAttrib(Ihandle* ih) { char* str = iupStrGetMemory(20); - sprintf(str, "%f", ih->data->posx); + sprintf(str, "%g", ih->data->posx); return str; } char* iupCanvasGetPosYAttrib(Ihandle* ih) { char* str = iupStrGetMemory(20); - sprintf(str, "%f", ih->data->posy); + sprintf(str, "%g", ih->data->posy); return str; } diff --git a/iup/src/iup_classattrib.c b/iup/src/iup_classattrib.c index df8f873..3ac780c 100755 --- a/iup/src/iup_classattrib.c +++ b/iup/src/iup_classattrib.c @@ -55,7 +55,7 @@ static const char* iClassFindId(const char* name) { if (*name >= '0' && *name <= '9') return name; - if (*name == '*' || *name == ':') + if (*name == '*' || *name == ':' || *name == '-') return name; name++; @@ -94,7 +94,6 @@ int iupClassObjectSetAttribute(Ihandle* ih, const char* name, const char * value const char* name_id = iClassFindId(name); if (name_id) { - IattribFunc* afunc; const char* partial_name = iClassCutNameId(name, name_id); if (!partial_name) partial_name = "IDVALUE"; /* pure numbers are used as attributes in IupList and IupMatrix, @@ -474,8 +473,12 @@ void iupClassObjectEnsureDefaultAttributes(Ihandle* ih) (afunc->call_global_default && iupGlobalDefaultColorChanged(afunc->default_value))) { if ((!ih->handle && (afunc->flags & IUPAF_NOT_MAPPED)) || - (ih->handle && !(afunc->flags & IUPAF_NOT_MAPPED) && !iupAttribGet(ih, name))) - afunc->set(ih, iClassGetDefaultValue(afunc)); + (ih->handle && !(afunc->flags & IUPAF_NOT_MAPPED))) + { + char* value = iupAttribGet(ih, name); + if (!value) /* if set will be updated later */ + afunc->set(ih, iClassGetDefaultValue(afunc)); + } } } diff --git a/iup/src/iup_classbase.c b/iup/src/iup_classbase.c index 9cb9e63..03a98d1 100755 --- a/iup/src/iup_classbase.c +++ b/iup/src/iup_classbase.c @@ -164,8 +164,7 @@ static char* iBaseGetPositionAttrib(Ihandle* ih) static int iBaseSetPositionAttrib(Ihandle* ih, const char* value) { - if (ih->is_floating) - iupStrToIntInt(value, &ih->x, &ih->y, ','); + iupStrToIntInt(value, &ih->x, &ih->y, ','); return 0; } @@ -211,7 +210,7 @@ char* iupBaseGetVisibleAttrib(Ihandle* ih) int iupBaseSetVisibleAttrib(Ihandle* ih, const char* value) { iupdrvSetVisible(ih, iupStrBoolean(value)); - return 0; + return 1; /* must be 1 to mark when set at the element */ } char* iupBaseNativeParentGetBgColorAttrib(Ihandle* ih) @@ -410,15 +409,19 @@ void iupBaseRegisterCommonAttrib(Iclass* ic) iupClassRegisterAttribute(ic, "FLOATING", iBaseGetFloatingAttrib, iBaseSetFloatingAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "EXPAND", iBaseGetExpandAttrib, iBaseSetExpandAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "NORMALIZERGROUP", NULL, iBaseSetNormalizerGroupAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "EXPANDWEIGTH", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* make sure everyone has the correct default value */ - iupClassRegisterAttribute(ic, "VISIBLE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); iupClassRegisterAttribute(ic, "ACTIVE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); if (ic->is_interactive) iupClassRegisterAttribute(ic, "CANFOCUS", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); else iupClassRegisterAttribute(ic, "CANFOCUS", NULL, NULL, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NO_INHERIT); + /* if not native container, must set at children, + native container will automatically hide its children. */ + iupClassRegisterAttribute(ic, "VISIBLE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); /* let the attribute to be propagated to children */ + iupClassRegisterAttribute(ic, "SIZE", iupBaseGetSizeAttrib, iupBaseSetSizeAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, iupBaseSetRasterSizeAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "CHARSIZE", iupBaseGetCharSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); @@ -439,7 +442,7 @@ void iupBaseRegisterCommonAttrib(Iclass* ic) void iupBaseRegisterVisualAttrib(Iclass* ic) { - iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, iupBaseSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); /* VISIBLE inheritance comes from the native system */ + iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, iupBaseSetVisibleAttrib, "YES", "NO", IUPAF_DEFAULT); iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); iupClassRegisterAttribute(ic, "ZORDER", NULL, iupdrvBaseSetZorderAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); diff --git a/iup/src/iup_dialog.c b/iup/src/iup_dialog.c index d70e12c..1aaf095 100755 --- a/iup/src/iup_dialog.c +++ b/iup/src/iup_dialog.c @@ -220,11 +220,19 @@ static void iDialogDestroyMethod(Ihandle* ih) iupDlgListRemove(ih); } +static int iDialogSetMenuAttrib(Ihandle* ih, const char* value); + static void iDialogComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) { int decorwidth, decorheight; Ihandle* child = ih->firstchild; + /* if does not have a menu, but the attribute is defined, + try to update the menu before retrieving the decoration. */ + char* value = iupAttribGet(ih, "MENU"); + if (!ih->data->menu && value) + iDialogSetMenuAttrib(ih, value); + iupDialogGetDecorSize(ih, &decorwidth, &decorheight); *w = decorwidth; *h = decorheight; @@ -278,20 +286,22 @@ static void iDialogAfterShow(Ihandle* ih) { Ihandle* old_focus; IFni show_cb; + int show_state; /* process all pending messages */ IupFlush(); old_focus = IupGetFocus(); + show_state = ih->data->show_state; show_cb = (IFni)IupGetCallback(ih, "SHOW_CB"); - if (show_cb && show_cb(ih, ih->data->show_state) == IUP_CLOSE) + if (show_cb && show_cb(ih, show_state) == IUP_CLOSE) { IupExitLoop(); return; } - if (ih->data->show_state == IUP_SHOW) + if (show_state == IUP_SHOW) { if (show_cb) IupFlush(); /* again to update focus */ @@ -718,7 +728,8 @@ Iclass* iupDialogGetClass(void) iupBaseRegisterVisualAttrib(ic); /* Overwrite Visual */ - iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, iDialogSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NO_INHERIT); /* the only case where VISIBLE default is NO */ + /* the only case where VISIBLE default is NO, and must not be propagated to the dialog children */ + iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, iDialogSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NO_INHERIT); /* IupDialog only */ iupClassRegisterAttribute(ic, "MENU", NULL, iDialogSetMenuAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); diff --git a/iup/src/iup_draw.h b/iup/src/iup_draw.h new file mode 100644 index 0000000..b4d08e3 --- /dev/null +++ b/iup/src/iup_draw.h @@ -0,0 +1,98 @@ +/** \file + * \brief Simple Draw API. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_DRAW_H +#define __IUP_DRAW_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** \defgroup draw Simple Draw API + * \par + * See \ref iup_draw.h + * \ingroup util */ + + + +struct _IdrawCanvas; +typedef struct _IdrawCanvas IdrawCanvas; + + +/** Creates a draw canvas based on an IupCanvas. + * This will create an image for offscreen drawing. + * \ingroup draw */ +IdrawCanvas* iupDrawCreateCanvas(Ihandle* ih); + +/** Destroys the IdrawCanvas. + * \ingroup draw */ +void iupDrawKillCanvas(IdrawCanvas* dc); + +/** Draws the ofscreen image on the screen. + * \ingroup draw */ +void iupDrawFlush(IdrawCanvas* dc); + +/** Rebuild the offscreen image if the canvas size has changed. + * Automatically done in iupDrawCreateCanvas. + * \ingroup draw */ +void iupDrawUpdateSize(IdrawCanvas* dc); + +/** Returns the canvas size available for drawing. + * \ingroup draw */ +void iupDrawGetSize(IdrawCanvas* dc, int *w, int *h); + +/** Draws the parent background. + * \ingroup draw */ +void iupDrawParentBackground(IdrawCanvas* dc); + +/** Draws a line. + * \ingroup draw */ +void iupDrawLine(IdrawCanvas* dc, int x1, int y1, int x2, int y2, unsigned char r, unsigned char g, unsigned char b); + +/** Draws a filled/hollow rectangle. + * \ingroup draw */ +void iupDrawRectangle(IdrawCanvas* dc, int x1, int y1, int x2, int y2, unsigned char r, unsigned char g, unsigned char b, int filled); + +/** Draws a filled/hollow arc. + * \ingroup draw */ +void iupDrawArc(IdrawCanvas* dc, int x1, int y1, int x2, int y2, double a1, double a2, unsigned char r, unsigned char g, unsigned char b, int filled); + +/** Draws a filled/hollow polygon. + * points are arranged xyxyxy... + * \ingroup draw */ +void iupDrawPolygon(IdrawCanvas* dc, int* points, int count, unsigned char r, unsigned char g, unsigned char b, int filled); + +/** Draws a text. + * x,y is at left,top corner of the text. + * \ingroup draw */ +void iupDrawText(IdrawCanvas* dc, const char* text, int len, int x, int y, unsigned char r, unsigned char g, unsigned char b); + +/** Draws an image. + * x,y is at left,top corner of the image. + * \ingroup draw */ +void iupDrawImage(IdrawCanvas* dc, const char* name, int make_inactive, int x, int y); + +/** Sets a rectangle clipping area. + * \ingroup draw */ +void iupDrawSetClipRect(IdrawCanvas* dc, int x1, int y1, int x2, int y2); + +/** Removes clipping. + * \ingroup draw */ +void iupDrawResetClip(IdrawCanvas* dc); + +/* +TO DO: +- check position and size of primitives +*/ + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/iup/src/iup_drv.h b/iup/src/iup_drv.h index 5cdb8e7..1071347 100755 --- a/iup/src/iup_drv.h +++ b/iup/src/iup_drv.h @@ -60,11 +60,11 @@ void iupdrvSetActive(Ihandle* ih, int enable); /** Post a redraw of a control. * \ingroup drv */ -void iupdrvDisplayUpdate(Ihandle *ih); +void iupdrvPostRedraw(Ihandle *ih); /** Force a redraw of a control. * \ingroup drv */ -void iupdrvDisplayRedraw(Ihandle *ih); +void iupdrvRedrawNow(Ihandle *ih); /** Reparent the native control. * \ingroup drv */ diff --git a/iup/src/iup_focus.c b/iup/src/iup_focus.c index be54b75..fc0579c 100755 --- a/iup/src/iup_focus.c +++ b/iup/src/iup_focus.c @@ -220,15 +220,25 @@ void iupFocusPrevious(Ihandle *ih) /* local variables */ static Ihandle* iup_current_focus = NULL; +Ihandle* IupGetFocus(void) +{ + return iup_current_focus; +} + +void iupSetCurrentFocus(Ihandle *ih) +{ + iup_current_focus = ih; +} + Ihandle *IupSetFocus(Ihandle *ih) { - Ihandle* old_focus = iup_current_focus; + Ihandle* old_focus = IupGetFocus(); iupASSERT(iupObjectCheck(ih)); if (!iupObjectCheck(ih)) return old_focus; - /* iup_current_focus is NOT set here, + /* Current focus is NOT set here, only in the iupCallGetFocusCb */ if (iupFocusCanAccept(ih)) @@ -237,16 +247,11 @@ Ihandle *IupSetFocus(Ihandle *ih) return old_focus; } -Ihandle *IupGetFocus(void) -{ - return iup_current_focus; -} - void iupCallGetFocusCb(Ihandle *ih) { Icallback cb; - if (ih == iup_current_focus) /* avoid duplicate messages */ + if (ih == IupGetFocus()) /* avoid duplicate messages */ return; cb = (Icallback)IupGetCallback(ih, "GETFOCUS_CB"); @@ -258,14 +263,14 @@ void iupCallGetFocusCb(Ihandle *ih) if (cb2) cb2(ih, 1); } - iup_current_focus = ih; + iupSetCurrentFocus(ih); } void iupCallKillFocusCb(Ihandle *ih) { Icallback cb; - if (ih != iup_current_focus) /* avoid duplicate messages */ + if (ih != IupGetFocus()) /* avoid duplicate messages */ return; cb = IupGetCallback(ih, "KILLFOCUS_CB"); @@ -277,5 +282,5 @@ void iupCallKillFocusCb(Ihandle *ih) if (cb2) cb2(ih, 0); } - iup_current_focus = NULL; + iupSetCurrentFocus(NULL); } diff --git a/iup/src/iup_focus.h b/iup/src/iup_focus.h index 239e233..9fb4e58 100755 --- a/iup/src/iup_focus.h +++ b/iup/src/iup_focus.h @@ -39,6 +39,7 @@ Ihandle* iupFocusNextInteractive(Ihandle *ih); void iupFocusNext(Ihandle *ih); void iupFocusPrevious(Ihandle *ih); +void iupSetCurrentFocus(Ihandle *ih); /* Other functions declared in <iup.h> and implemented here. IupPreviousField diff --git a/iup/src/iup_getparam.c b/iup/src/iup_getparam.c index 1418aa5..7fd6a94 100755 --- a/iup/src/iup_getparam.c +++ b/iup/src/iup_getparam.c @@ -45,6 +45,14 @@ static int iParamButtonCancel_CB(Ihandle* self) return IUP_CLOSE; } +static int iParamButtonHelp_CB(Ihandle* self) +{ + Ihandle* dlg = IupGetDialog(self); + Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB"); + if (cb) cb(dlg, -4, (void*)iupAttribGet(dlg, "USER_DATA")); + return IUP_DEFAULT; +} + static int iParamToggleAction_CB(Ihandle *self, int v) { Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM"); @@ -288,7 +296,7 @@ static int iParamColorButton_CB(Ihandle *self, int button, int pressed) IupPopup(dlg, IUP_CENTER, IUP_CENTER); - if (IupGetInt(dlg, "STATUS") != -1) + if (IupGetInt(dlg, "STATUS")==1) { char* value = IupGetAttribute(dlg, "VALUE"); IupSetAttribute(textbox, "VALUE", value); @@ -381,11 +389,13 @@ static int iParamSpinInt_CB(Ihandle *self, int pos) static Ihandle* iParamCreateBox(Ihandle* param) { Ihandle *box, *ctrl = NULL, *label; - char *type; + char *type = iupAttribGet(param, "TYPE"); + + if (iupStrEqual(type, "BUTTONNAMES")) + return NULL; label = IupLabel(iupAttribGet(param, "TITLE")); - type = iupAttribGet(param, "TYPE"); if (iupStrEqual(type, "SEPARATOR")) { box = IupHbox(label, NULL); @@ -563,7 +573,7 @@ static Ihandle* iParamCreateBox(Ihandle* param) float step = iupAttribGetFloat(param, "STEP"); float val = iupAttribGetFloat(param, "VALUE"); if (step == 0) step = (max-min)/20.0f; - IupSetfAttribute(ctrl, "MASKFLOAT", "%f:%f", (double)min, (double)max); + IupSetfAttribute(ctrl, "MASKFLOAT", "%g:%g", (double)min, (double)max); /* here spin is always [0-spinmax] converted to [min-max] */ @@ -584,7 +594,7 @@ static Ihandle* iParamCreateBox(Ihandle* param) if (min == 0) IupSetAttribute(ctrl, "MASK", IUP_MASK_UFLOAT); else - IupSetfAttribute(ctrl, "MASKFLOAT", "%f:%f", (double)min, (double)1.0e10); + IupSetfAttribute(ctrl, "MASKFLOAT", "%g:%g", (double)min, (double)1.0e10); IupAppend(box, ctrl); } else @@ -620,6 +630,7 @@ static Ihandle* iParamCreateBox(Ihandle* param) } IupSetfAttribute(ctrl, "SPINMAX", "%d", max); IupSetfAttribute(ctrl, "SPINMIN", "%d", min); + IupSetfAttribute(ctrl, "MASKINT", "%d:%d", min, max); } else if (iupAttribGetInt(param, "PARTIAL")) { @@ -696,7 +707,7 @@ static Ihandle* iParamCreateBox(Ihandle* param) static Ihandle* IupParamDlgP(Ihandle** params) { - Ihandle *dlg, *button_ok, *button_cancel, + Ihandle *dlg, *button_ok, *button_cancel, *button_help=NULL, *dlg_box, *button_box, *param_box; int i, lbl_width, p, expand; @@ -713,7 +724,23 @@ static Ihandle* IupParamDlgP(Ihandle** params) i = 0; expand = 0; while (params[i] != NULL) { - IupAppend(param_box, iParamCreateBox(params[i])); + Ihandle* box = iParamCreateBox(params[i]); + if (box) + IupAppend(param_box, box); + else /* buttonnames */ + { + char* value = iupAttribGet(params[i], "_IUPGP_OK"); + if (value && *value) IupSetAttribute(button_ok, "TITLE", value); + value = iupAttribGet(params[i], "_IUPGP_CANCEL"); + if (value && *value) IupSetAttribute(button_cancel, "TITLE", value); + value = iupAttribGet(params[i], "_IUPGP_HELP"); + if (value && *value) + { + button_help = IupButton(value, NULL); + IupSetAttribute(button_help, "PADDING", "20x0"); + IupSetCallback(button_help, "ACTION", (Icallback)iParamButtonHelp_CB); + } + } if (IupGetInt(params[i], "EXPAND")) expand = 1; @@ -725,6 +752,7 @@ static Ihandle* IupParamDlgP(Ihandle** params) IupFill(), button_ok, button_cancel, + button_help, NULL); IupSetAttribute(button_box,"MARGIN","0x0"); IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL"); @@ -926,6 +954,23 @@ static void iParamSetFileOptions(char* extra, Ihandle* param) iupAttribStoreStr(param, "_IUPGP_NOOVERWRITEPROMPT", nooverwriteprompt); } +static void iParamSetButtonNames(char* extra, Ihandle* param) +{ + char *ok, *cancel, *help; + int count; + + if (!extra) + return; + + ok = iParamGetNextStrItem(extra, ',', &count); extra += count; + cancel = iParamGetNextStrItem(extra, ',', &count); extra += count; + help = iParamGetNextStrItem(extra, ',', &count); extra += count; + + iupAttribStoreStr(param, "_IUPGP_OK", ok); + iupAttribStoreStr(param, "_IUPGP_CANCEL", cancel); + iupAttribStoreStr(param, "_IUPGP_HELP", help); +} + static void iParamSetListItems(char* extra, Ihandle* param) { int d = 1, count; @@ -1082,6 +1127,12 @@ static Ihandle *IupParamf(const char* format, int *line_size) iupAttribSetStr(param, "TYPE", "SEPARATOR"); iupAttribSetStr(param, "DATA_TYPE", "-1"); /* NONE */ break; + case 'u': + iupAttribSetStr(param, "TYPE", "BUTTONNAMES"); + iupAttribSetStr(param, "DATA_TYPE", "-1"); /* NONE */ + extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count; + iParamSetButtonNames(extra, param); + break; default: return NULL; } @@ -1099,7 +1150,7 @@ static Ihandle *IupParamf(const char* format, int *line_size) int iupGetParamCount(const char *format, int *param_extra) { - int param_count = 0, sep = 0; + int param_count = 0, extra = 0; const char* s = format; *param_extra = 0; @@ -1107,14 +1158,20 @@ int iupGetParamCount(const char *format, int *param_extra) { if (*s == '%' && *(s+1) == 't') /* do not count separator lines */ { - sep = 1; + extra = 1; + (*param_extra)++; + } + + if (*s == '%' && *(s+1) == 'u') /* do not count button names lines */ + { + extra = 1; (*param_extra)++; } if (*s == '\n') { - if (sep) - sep = 0; + if (extra) + extra = 0; else param_count++; } @@ -1154,21 +1211,21 @@ int IupGetParamv(const char* title, Iparamcb action, void* user_data, const char return 0; data_type = IupGetInt(params[i], "DATA_TYPE"); - if (data_type == 1) - { - int *data_int = (int*)(param_data[p]); - if (!data_int) return 0; - iupAttribSetStrf(params[i], "VALUE", "%d", *data_int); - p++; - } - else if (data_type == 2) + if (data_type == 2) /* float */ { float *data_float = (float*)(param_data[p]); if (!data_float) return 0; iupAttribSetStrf(params[i], "VALUE", "%g", *data_float); p++; } - else if (data_type == 0) + else if (data_type == 1) /* integer */ + { + int *data_int = (int*)(param_data[p]); + if (!data_int) return 0; + iupAttribSetStrf(params[i], "VALUE", "%d", *data_int); + p++; + } + else if (data_type == 0) /* string */ { char *data_str = (char*)(param_data[p]); if (!data_str) return 0; diff --git a/iup/src/iup_globalattrib.c b/iup/src/iup_globalattrib.c index 00586fb..d1a2584 100755 --- a/iup/src/iup_globalattrib.c +++ b/iup/src/iup_globalattrib.c @@ -129,12 +129,14 @@ int iupGlobalIsPointer(const char* name) static struct { const char *name; } ptr_table[] = { -#ifdef WIN32 +#ifndef GTK_MAC + #ifdef WIN32 {"HINSTANCE"}, -#else + #else {"XDISPLAY"}, {"XSCREEN"}, {"APPSHELL"}, + #endif #endif }; #define PTR_TABLE_SIZE ((sizeof ptr_table)/(sizeof ptr_table[0])) diff --git a/iup/src/iup_hbox.c b/iup/src/iup_hbox.c index e790636..a8a93a3 100755 --- a/iup/src/iup_hbox.c +++ b/iup/src/iup_hbox.c @@ -213,6 +213,13 @@ static void iHboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) else { int empty = (child->expand & IUP_EXPAND_W1)? empty_w1: ((child->expand & IUP_EXPAND_W0)? empty_w0: 0); + char* weigth_str = iupAttribGet(child, "EXPANDWEIGTH"); + if (weigth_str) + { + float weigth; + if (iupStrToFloat(weigth_str, &weigth)) + empty = iupROUND(empty * weigth); + } iupBaseSetCurrentSize(child, child->naturalwidth+empty, client_height, shrink); } diff --git a/iup/src/iup_key.h b/iup/src/iup_key.h index 37d6c9d..9b30bc4 100755 --- a/iup/src/iup_key.h +++ b/iup/src/iup_key.h @@ -51,16 +51,16 @@ void iupKeyInit(void); #define IUPKEY_STATUS_SIZE 11 /* 10 chars + null */ #define IUPKEY_STATUS_INIT " " /* 10 spaces */ -#define iupKEYSETSHIFT(_s) (_s[0]='S') -#define iupKEYSETCONTROL(_s) (_s[1]='C') -#define iupKEYSETBUTTON1(_s) (_s[2]='1') -#define iupKEYSETBUTTON2(_s) (_s[3]='2') -#define iupKEYSETBUTTON3(_s) (_s[4]='3') -#define iupKEYSETDOUBLE(_s) (_s[5]='D') -#define iupKEYSETALT(_s) (_s[6]='A') -#define iupKEYSETSYS(_s) (_s[7]='Y') -#define iupKEYSETBUTTON4(_s) (_s[8]='4') -#define iupKEYSETBUTTON5(_s) (_s[9]='5') +#define iupKEY_SETSHIFT(_s) (_s[0]='S') +#define iupKEY_SETCONTROL(_s) (_s[1]='C') +#define iupKEY_SETBUTTON1(_s) (_s[2]='1') +#define iupKEY_SETBUTTON2(_s) (_s[3]='2') +#define iupKEY_SETBUTTON3(_s) (_s[4]='3') +#define iupKEY_SETDOUBLE(_s) (_s[5]='D') +#define iupKEY_SETALT(_s) (_s[6]='A') +#define iupKEY_SETSYS(_s) (_s[7]='Y') +#define iupKEY_SETBUTTON4(_s) (_s[8]='4') +#define iupKEY_SETBUTTON5(_s) (_s[9]='5') #ifdef __cplusplus diff --git a/iup/src/iup_layout.c b/iup/src/iup_layout.c index b96293c..0ccd496 100755 --- a/iup/src/iup_layout.c +++ b/iup/src/iup_layout.c @@ -43,7 +43,7 @@ static void iLayoutDisplayUpdateChildren(Ihandle *ih) iLayoutDisplayUpdateChildren(child); if (child->handle && child->iclass->nativetype != IUP_TYPEVOID) - iupdrvDisplayUpdate(child); + iupdrvPostRedraw(child); } } @@ -54,7 +54,7 @@ void IupUpdate(Ihandle* ih) return; if (ih->handle && ih->iclass->nativetype != IUP_TYPEVOID) - iupdrvDisplayUpdate(ih); + iupdrvPostRedraw(ih); } void IupUpdateChildren(Ihandle* ih) @@ -74,7 +74,7 @@ static void iLayoutDisplayRedrawChildren(Ihandle *ih) iLayoutDisplayRedrawChildren(child); if (child->handle && child->iclass->nativetype != IUP_TYPEVOID) - iupdrvDisplayRedraw(child); + iupdrvRedrawNow(child); } } @@ -85,7 +85,7 @@ void IupRedraw(Ihandle* ih, int children) return; if (ih->handle && ih->iclass->nativetype != IUP_TYPEVOID) - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); if (children) iLayoutDisplayRedrawChildren(ih); @@ -136,7 +136,7 @@ void iupLayoutCompute(Ihandle* ih) iupBaseSetPosition(ih, 0, 0); } -static void iLayoutSetMinMaxSize(Ihandle* ih, int *w, int *h) +void iupLayoutSetMinMaxSize(Ihandle* ih, int *w, int *h) { if (ih->has_minsize) { @@ -163,7 +163,8 @@ void iupBaseComputeNaturalSize(Ihandle* ih) ih->naturalwidth = ih->userwidth; ih->naturalheight = ih->userheight; - if (ih->iclass->childtype!=IUP_CHILDNONE || ih->iclass->nativetype == IUP_TYPEDIALOG) + if (ih->iclass->childtype!=IUP_CHILDNONE || + ih->iclass->nativetype == IUP_TYPEDIALOG) /* pre-defined dialogs can restrict the number of children */ { int w=0, h=0, children_expand; @@ -190,7 +191,7 @@ void iupBaseComputeNaturalSize(Ihandle* ih) ih->naturalheight = iupMAX(ih->naturalheight, h); /* crop the natural size */ - iLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight)); + iupLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight)); } } else @@ -198,15 +199,15 @@ void iupBaseComputeNaturalSize(Ihandle* ih) /* for non-container only compute if user size is not defined */ if (ih->naturalwidth <= 0 || ih->naturalheight <= 0) { - int w=0, h=0; - iupClassObjectComputeNaturalSize(ih, &w, &h, NULL); + int w=0, h=0, children_expand; + iupClassObjectComputeNaturalSize(ih, &w, &h, &children_expand); if (ih->naturalwidth <= 0) ih->naturalwidth = w; if (ih->naturalheight <= 0) ih->naturalheight = h; } /* crop the natural size */ - iLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight)); + iupLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight)); } } @@ -259,7 +260,7 @@ void iupBaseSetCurrentSize(Ihandle* ih, int w, int h, int shrink) /* crop the current size if expanded */ if (ih->expand & IUP_EXPAND_WIDTH || ih->expand & IUP_EXPAND_HEIGHT) - iLayoutSetMinMaxSize(ih, &(ih->currentwidth), &(ih->currentheight)); + iupLayoutSetMinMaxSize(ih, &(ih->currentwidth), &(ih->currentheight)); } } diff --git a/iup/src/iup_layout.h b/iup/src/iup_layout.h index a2a0c29..775e5a2 100755 --- a/iup/src/iup_layout.h +++ b/iup/src/iup_layout.h @@ -16,6 +16,8 @@ extern "C" { void iupLayoutCompute(Ihandle* ih); /* can be called before map */ void iupLayoutUpdate(Ihandle* ih); /* called only after map */ +void iupLayoutSetMinMaxSize(Ihandle* ih, int *w, int *h); + /* Other functions declared in <iup.h> and implemented here. IupRefresh */ diff --git a/iup/src/iup_ledlex.c b/iup/src/iup_ledlex.c index 3283a43..5cf8640 100755 --- a/iup/src/iup_ledlex.c +++ b/iup/src/iup_ledlex.c @@ -35,7 +35,7 @@ static struct /* lexical variables */ static int iLexGetChar (void); static int iLexToken(int *erro); static int iLexCapture (char* dlm); -static int iLexSkip (char* dlm); +static void iLexSkipComment (void); static int iLexCaptureAttr (void); int iupLexStart(const char* filename, int is_file) /* initialize lexical analysis */ @@ -186,9 +186,9 @@ static int iLexToken(int *erro) case ']': return IUPLEX_TK_ENDATTR; - case '#': /* iLexSkip comment */ - case '%': /* iLexSkip comment */ - iLexSkip ("\n\r"); + case '#': /* Skip comment */ + case '%': /* Skip comment */ + iLexSkipComment(); continue; case ' ': /* ignore whitespace */ @@ -276,14 +276,13 @@ static int iLexCaptureAttr (void) return c; /* return delimiter */ } -static int iLexSkip (char* dlm) +static void iLexSkipComment (void) { int c; do { - c = iLexGetChar (); - } while ((c > 0) && !strchr (dlm,c)); - return c; /* return delimiter */ + c = iLexGetChar(); + } while ((c > 0) && (c != '\n')); } static int iLexGetChar (void) diff --git a/iup/src/iup_list.c b/iup/src/iup_list.c index 5965665..1077d98 100755 --- a/iup/src/iup_list.c +++ b/iup/src/iup_list.c @@ -53,6 +53,37 @@ static void iListCallActionCallback(Ihandle* ih, IFnsii cb, int pos, int state) IupExitLoop(); } +void iupListUpdateOldValue(Ihandle* ih, int pos, int removed) +{ + if (!ih->data->has_editbox) + { + char* old_value = iupAttribGet(ih, "_IUPLIST_OLDVALUE"); + if (old_value) + { + int old_pos = atoi(old_value)-1; /* was in IUP reference, starting at 1 */ + if (ih->data->is_dropdown || !ih->data->is_multiple) + { + if (old_pos >= pos) + { + if (removed && old_pos == pos) + { + /* when the current item is removed nothing remains selected */ + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + } + else + iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", removed? old_pos-1: old_pos+1); + } + } + else + { + /* multiple selection on a non drop-down list. */ + char* value = IupGetAttribute(ih, "VALUE"); + iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value); + } + } + } +} + void iupListSingleCallActionCallback(Ihandle* ih, IFnsii cb, int pos) { char* old_str = iupAttribGet(ih, "_IUPLIST_OLDVALUE"); @@ -77,7 +108,7 @@ void iupListMultipleCallActionCallback(Ihandle* ih, IFnsii cb, IFns multi_cb, in char* old_str = iupAttribGet(ih, "_IUPLIST_OLDVALUE"); int old_count = old_str? strlen(old_str): 0; - char* str = iupStrGetMemory(count+1); + char* str = malloc(count+1); memset(str, '-', count); str[count]=0; for (i=0; i<sel_count; i++) @@ -92,6 +123,7 @@ void iupListMultipleCallActionCallback(Ihandle* ih, IFnsii cb, IFns multi_cb, in if (multi_cb) { int unchanged = 1; + for (i=0; i<count && old_str; i++) { if (str[i] == old_str[i]) @@ -101,7 +133,10 @@ void iupListMultipleCallActionCallback(Ihandle* ih, IFnsii cb, IFns multi_cb, in } if (old_str && unchanged) + { + free(str); return; + } if (multi_cb(ih, str) == IUP_CLOSE) IupExitLoop(); @@ -133,6 +168,7 @@ void iupListMultipleCallActionCallback(Ihandle* ih, IFnsii cb, IFns multi_cb, in } iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", str); + free(str); } int iupListGetPos(Ihandle* ih, const char* name_id) @@ -145,7 +181,8 @@ int iupListGetPos(Ihandle* ih, const char* name_id) pos--; /* IUP items start at 1 */ if (pos < 0) return -1; - if (pos > count-1) return -1; + if (pos == count) return -2; + if (pos > count) return -1; return pos; } @@ -217,7 +254,10 @@ int iupListSetIdValueAttrib(Ihandle* ih, const char* name_id, const char* value) if (pos >= 0 && pos <= count-1) { if (pos == 0) + { iupdrvListRemoveAllItems(ih); + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + } else { int i = pos; @@ -245,7 +285,7 @@ int iupListSetIdValueAttrib(Ihandle* ih, const char* name_id, const char* value) static int iListSetAppendItemAttrib(Ihandle* ih, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; if (value) iupdrvListAppendItem(ih, value); @@ -254,27 +294,32 @@ static int iListSetAppendItemAttrib(Ihandle* ih, const char* value) static int iListSetInsertItemAttrib(Ihandle* ih, const char* name_id, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; if (value) { int pos = iupListGetPos(ih, name_id); - if (pos!=-1) + if (pos >= 0) iupdrvListInsertItem(ih, pos, value); + else if (pos == -2) + iupdrvListAppendItem(ih, value); } return 0; } static int iListSetRemoveItemAttrib(Ihandle* ih, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; if (!value) + { iupdrvListRemoveAllItems(ih); + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + } else { int pos = iupListGetPos(ih, value); - if (pos!=-1) + if (pos >= 0) iupdrvListRemoveItem(ih, pos); } return 0; diff --git a/iup/src/iup_list.h b/iup/src/iup_list.h index 045116b..05fe9f8 100755 --- a/iup/src/iup_list.h +++ b/iup/src/iup_list.h @@ -30,6 +30,7 @@ char* iupListGetNCAttrib(Ihandle* ih); char* iupListGetPaddingAttrib(Ihandle* ih); char* iupListGetSpacingAttrib(Ihandle* ih); void iupListSingleCallDblClickCallback(Ihandle* ih, IFnis cb, int pos); +void iupListUpdateOldValue(Ihandle* ih, int pos, int removed); struct _IcontrolData { diff --git a/iup/src/iup_names.c b/iup/src/iup_names.c index 9ec01a6..18ca3ef 100755 --- a/iup/src/iup_names.c +++ b/iup/src/iup_names.c @@ -14,11 +14,41 @@ #include "iup_object.h" #include "iup_class.h" #include "iup_assert.h" +#include "iup_attrib.h" #include "iup_str.h" static Itable *inames_strtable = NULL; /* table indexed by name containing Ihandle* address */ -static Itable *inames_ihtable = NULL; /* table indexed by Ihandle* address containing names */ + +void iupNamesInit(void) +{ + inames_strtable = iupTableCreate(IUPTABLE_STRINGINDEXED); +} + +void iupNamesFinish(void) +{ + iupTableDestroy(inames_strtable); + inames_strtable = NULL; +} + +static Ihandle* iNameGetTopParent(Ihandle* ih) +{ + Ihandle* parent = ih; + while (parent->parent) + parent = parent->parent; + return parent; +} + +static int iNameCheckArray(Ihandle** ih_array, int count, Ihandle* ih) +{ + int i; + for (i = 0; i < count; i++) + { + if (ih_array[i] == ih) + return 0; + } + return 1; +} void iupNamesDestroyHandles(void) { @@ -37,10 +67,14 @@ void iupNamesDestroyHandles(void) while (name) { ih = (Ihandle*)iupTableGetCurr(inames_strtable); - if (iupObjectCheck(ih)) + if (iupObjectCheck(ih)) /* here must be a handle */ { - ih_array[i] = ih; - i++; + ih = iNameGetTopParent(ih); + if (iNameCheckArray(ih_array, i, ih)) + { + ih_array[i] = ih; + i++; + } } name = iupTableNext(inames_strtable); } @@ -48,44 +82,28 @@ void iupNamesDestroyHandles(void) count = i; for (i = 0; i < count; i++) { - if (iupObjectCheck(ih_array[i])) + if (iupObjectCheck(ih_array[i])) /* here must be a handle */ IupDestroy(ih_array[i]); } free(ih_array); } -void iupNamesInit(void) -{ - inames_strtable = iupTableCreate(IUPTABLE_STRINGINDEXED); - inames_ihtable = iupTableCreate(IUPTABLE_POINTERINDEXED); -} - -void iupNamesFinish(void) -{ - iupTableDestroy(inames_strtable); - inames_strtable = NULL; - - iupTableDestroy(inames_ihtable); - inames_ihtable = NULL; -} - -void iupRemoveAllNames(Ihandle* ih) +void iupRemoveNames(Ihandle* ih) { char *name; - Ihandle *cur_ih; - name = iupTableFirst(inames_strtable); - while (name) - { - cur_ih = (Ihandle*)iupTableGetCurr(inames_strtable); - if (iupObjectCheck(cur_ih) && cur_ih == ih) - iupTableRemoveCurr(inames_strtable); + /* clear the cache */ + name = iupAttribGet(ih, "_IUP_LASTHANDLENAME"); + if (name) + iupTableRemove(inames_strtable, name); - name = iupTableNext(inames_strtable); - } + /* check for an internal name */ + name = iupAttribGetHandleName(ih); + if (name) + iupTableRemove(inames_strtable, name); - iupTableRemove(inames_ihtable, (char*)ih); + /* Do NOT search for other names */ } Ihandle *IupGetHandle(const char *name) @@ -104,22 +122,24 @@ Ihandle* IupSetHandle(const char *name, Ihandle *ih) return NULL; old_ih = iupTableGet(inames_strtable, name); + if (ih != NULL) { iupTableSet(inames_strtable, name, ih, IUPTABLE_POINTER); - iupTableSet(inames_ihtable, (char*)ih, (char*)name, IUPTABLE_STRING); /* keep only the last name set */ + + /* save the name in the cache if it is a valid handle */ + if (iupObjectCheck(ih)) + iupAttribStoreStr(ih, "_IUP_LASTHANDLENAME", name); } else { - ih = iupTableGet(inames_strtable, name); iupTableRemove(inames_strtable, name); - if (ih) - { - char* cur_name = iupTableGet(inames_ihtable, (char*)ih); - if (iupStrEqualNoCase(cur_name, name)) - iupTableRemove(inames_ihtable, (char*)ih); - } + + /* clear the name from the cache if it is a valid handle */ + if (iupObjectCheck(old_ih)) + iupAttribSetStr(old_ih, "_IUP_LASTHANDLENAME", NULL); } + return old_ih; } @@ -151,7 +171,8 @@ static int iNamesCountDialogs(void) while (name) { Ihandle* dlg = (Ihandle*)iupTableGetCurr(inames_strtable); - if (iupObjectCheck(dlg) && dlg->iclass->nativetype == IUP_TYPEDIALOG) + if (iupObjectCheck(dlg) && /* here must be a handle */ + dlg->iclass->nativetype == IUP_TYPEDIALOG) i++; name = iupTableNext(inames_strtable); @@ -171,7 +192,8 @@ int IupGetAllDialogs(char** names, int n) while (name) { Ihandle* dlg = (Ihandle*)iupTableGetCurr(inames_strtable); - if (iupObjectCheck(dlg) && dlg->iclass->nativetype == IUP_TYPEDIALOG) + if (iupObjectCheck(dlg) && /* here must be a handle */ + dlg->iclass->nativetype == IUP_TYPEDIALOG) { names[i] = name; i++; @@ -186,8 +208,32 @@ int IupGetAllDialogs(char** names, int n) char* IupGetName(Ihandle* ih) { - iupASSERT(iupObjectCheck(ih)); - if (!iupObjectCheck(ih)) + char *name; + if (!ih) /* no iupASSERT needed here */ return NULL; - return iupTableGet(inames_ihtable, (char*)ih); + + if (iupObjectCheck(ih)) + { + /* check the cache first, but must be a handle */ + name = iupAttribGet(ih, "_IUP_LASTHANDLENAME"); + if (name) + return name; + } + + /* check for an internal name */ + name = iupAttribGetHandleName(ih); + if (name) + return name; + + /* search for the name */ + name = iupTableFirst(inames_strtable); + while (name) + { + if ((Ihandle*)iupTableGetCurr(inames_strtable) == ih) + return name; + + name = iupTableNext(inames_strtable); + } + + return NULL; } diff --git a/iup/src/iup_names.h b/iup/src/iup_names.h index 9d3adc7..d652594 100755 --- a/iup/src/iup_names.h +++ b/iup/src/iup_names.h @@ -17,7 +17,7 @@ void iupNamesFinish(void); void iupNamesDestroyHandles(void); /* called from IupDestroy */ -void iupRemoveAllNames(Ihandle* ih); +void iupRemoveNames(Ihandle* ih); /* Other functions declared in <iup.h> and implemented here. IupGetName diff --git a/iup/src/iup_object.c b/iup/src/iup_object.c index 7f4ce23..f0d5dc9 100755 --- a/iup/src/iup_object.c +++ b/iup/src/iup_object.c @@ -148,6 +148,8 @@ Ihandle* IupCreate(const char *name) void IupDestroy(Ihandle *ih) { + Icallback cb; + iupASSERT(iupObjectCheck(ih)); if (!iupObjectCheck(ih)) return; @@ -156,6 +158,9 @@ void IupDestroy(Ihandle *ih) if (ih->iclass->nativetype == IUP_TYPEDIALOG) IupHide(ih); + cb = IupGetCallback(ih, "DESTROY_CB"); + if (cb) cb(ih); + /* Destroy all its children. Just need to remove the first child, IupDetach will update firstchild. */ @@ -165,6 +170,9 @@ void IupDestroy(Ihandle *ih) /* unmap if mapped and remove from its parent child list */ IupDetach(ih); + /* removes names associated with the element */ + iupRemoveNames(ih); + /* destroy the element */ iupClassObjectDestroy(ih); @@ -172,9 +180,6 @@ void IupDestroy(Ihandle *ih) if (ih->data) free(ih->data); - /* removes all the names associated with the element */ - iupRemoveAllNames(ih); - /* destroy the base handle structure */ iHandleDestroy(ih); } diff --git a/iup/src/iup_object.h b/iup/src/iup_object.h index 6f6b668..a69edc0 100755 --- a/iup/src/iup_object.h +++ b/iup/src/iup_object.h @@ -113,6 +113,7 @@ Ihandle* iupObjectCreate(Iclass* ic, void** params); void** iupObjectGetParamList(void* first, va_list arglist); /** Checks if the handle is still valid based on the signature. + * But if the handle was destroyed still can access invalid memory. * \ingroup object */ int iupObjectCheck(Ihandle* ih); diff --git a/iup/src/iup_open.c b/iup/src/iup_open.c index e02561e..bce5c5c 100755 --- a/iup/src/iup_open.c +++ b/iup/src/iup_open.c @@ -101,8 +101,8 @@ void IupClose(void) iupdrvSetIdleFunction(NULL); /* stop any idle */ - iupDlgListDestroyAll(); /* destroy all dialogs */ - iupNamesDestroyHandles(); /* destroy everything else that have names */ + iupDlgListDestroyAll(); /* destroy all dialogs and their children */ + iupNamesDestroyHandles(); /* destroy everything that do not belong to a dialog */ iupImageStockFinish(); /* release stock images hash table and the images */ iupRegisterFinish(); /* release native classes */ diff --git a/iup/src/iup_register.c b/iup/src/iup_register.c index 4c58038..2e9954a 100755 --- a/iup/src/iup_register.c +++ b/iup/src/iup_register.c @@ -99,6 +99,7 @@ void iupRegisterInternalClasses(void) iupRegisterClass(iupCboxGetClass()); iupRegisterClass(iupSboxGetClass()); iupRegisterClass(iupNormalizerGetClass()); + iupRegisterClass(iupSplitGetClass()); iupRegisterClass(iupMenuGetClass()); iupRegisterClass(iupItemGetClass()); diff --git a/iup/src/iup_sbox.c b/iup/src/iup_sbox.c index 5a71d33..9998481 100755 --- a/iup/src/iup_sbox.c +++ b/iup/src/iup_sbox.c @@ -57,6 +57,7 @@ static void iSboxSaveDimension(Ihandle* ih, int w, int h) { ih->data->w = w; ih->data->h = h; + iupLayoutSetMinMaxSize(ih, &(ih->data->w), &(ih->data->h)); } static void iSboxAddDecorOffset(Ihandle* ih, int *x, int *y) diff --git a/iup/src/iup_show.c b/iup/src/iup_show.c index 9ea1408..b42975e 100755 --- a/iup/src/iup_show.c +++ b/iup/src/iup_show.c @@ -53,35 +53,6 @@ void IupUnmap(Ihandle *ih) ih->handle = NULL; } -static char* iShowGetVisible(Ihandle* ih) -{ - char* value = iupAttribGet(ih, "VISIBLE"); /* Check on the element first */ - while (!value) - { - ih = ih->parent; /* iheritance here independs on the attribute */ - if (!ih) - return NULL; - - value = iupAttribGet(ih, "VISIBLE"); - - /* only recursive up to the native parent */ - if (ih->iclass->nativetype != IUP_TYPEVOID) - return value; /* can be NULL */ - } - - return value; -} - -static void iShowUpdateVisible(Ihandle* ih) -{ - int inherit; - /* although default is VISIBLE=YES, - when mapped the element is still hidden. - So we must manually update the visible state. */ - char* value = iShowGetVisible(ih); - iupClassObjectSetAttribute(ih, "VISIBLE", value, &inherit); -} - int IupMap(Ihandle* ih) { iupASSERT(iupObjectCheck(ih)); @@ -108,7 +79,7 @@ int IupMap(Ihandle* ih) return IUP_ERROR; } - /* update FONT, must be the before several others */ + /* update FONT, must be the before several others, so we do it here */ if (ih->iclass->nativetype != IUP_TYPEVOID && ih->iclass->nativetype != IUP_TYPEIMAGE && ih->iclass->nativetype != IUP_TYPEMENU) @@ -117,18 +88,13 @@ int IupMap(Ihandle* ih) /* ensure attributes default values, at this time only the ones that need to be set after map */ iupClassObjectEnsureDefaultAttributes(ih); - /* check visible state if not a dialog */ - if (ih->iclass->nativetype == IUP_TYPECANVAS || - ih->iclass->nativetype == IUP_TYPECONTROL) - iShowUpdateVisible(ih); - - /* updates the defined attributes in the native system. */ + /* updates the defined attributes from the hash table to the native system. */ iupAttribUpdate(ih); - /* updates attributes defined in the parent tree */ + /* updates inheritable attributes defined in the parent tree */ iupAttribUpdateFromParent(ih); - /* map children */ + /* map children independent from childtype */ { Ihandle* child = ih->firstchild; while (child) @@ -140,6 +106,10 @@ int IupMap(Ihandle* ih) } } + /* updates the defined attributes from the hash table to the native system. */ + if (ih->iclass->childtype!=IUP_CHILDNONE) + iupAttribUpdateChildren(ih); + /* moves and resizes the elements to reflect the layout computation */ /* if the dialog is visible will be reflected in the user interface */ if (ih->iclass->nativetype == IUP_TYPEDIALOG) diff --git a/iup/src/iup_spin.c b/iup/src/iup_spin.c index 6fadab4..514703f 100755 --- a/iup/src/iup_spin.c +++ b/iup/src/iup_spin.c @@ -175,7 +175,7 @@ static int iSpinCreateMethod(Ihandle* ih, void** params) static int iSpinboxCreateMethod(Ihandle* ih, void** params) { - Ihandle *spin, *ctrl; + Ihandle *spin; if (!params || !(params[0])) return IUP_ERROR; @@ -184,8 +184,7 @@ static int iSpinboxCreateMethod(Ihandle* ih, void** params) IupSetAttribute(ih, "MARGIN", "0x0"); IupSetAttribute(ih, "ALIGNMENT", "ACENTER"); - ctrl = (Ihandle*)(params[0]); - iupChildTreeAppend(ih, ctrl); + /* IupText is already a child of Spinbox because of the IupHbox Create method */ spin = IupSpin(); iupChildTreeAppend(ih, spin); @@ -249,7 +248,7 @@ Iclass* iupSpinboxGetClass(void) ic->name = "spinbox"; ic->format = "h"; /* one Ihandle */ ic->nativetype = IUP_TYPEVOID; - ic->childtype = IUP_CHILDNONE; + ic->childtype = IUP_CHILD_ONE; /* fake value to define it as a container */ ic->is_interactive = 0; iupClassRegisterCallback(ic, "SPIN_CB", "i"); @@ -267,7 +266,7 @@ Iclass* iupSpinGetClass(void) ic->name = "spin"; ic->format = NULL; /* no parameters */ ic->nativetype = IUP_TYPEVOID; - ic->childtype = IUP_CHILDNONE; + ic->childtype = IUP_CHILD_ONE; /* fake value to define it as a container */ ic->is_interactive = 0; /* Class functions */ diff --git a/iup/src/iup_split.c b/iup/src/iup_split.c new file mode 100644 index 0000000..1829142 --- /dev/null +++ b/iup/src/iup_split.c @@ -0,0 +1,780 @@ +/** \file + * \brief iupsplit 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" +#include "iup_draw.h" + + +enum { ISPLIT_VERT, ISPLIT_HORIZ }; + +struct _IcontrolData +{ + /* aux */ + int is_holding; + int start_pos, start_bar, start_size; + + /* attributes */ + int layoutdrag, autohide, showgrip, barsize; + int direction; /* one of the types: ISPLIT_VERT, ISPLIT_HORIZ */ + int val; /* split value: 0-1000, default 500 */ +}; + +static int iSplitGetWidth1(Ihandle* ih) +{ + int width1 = ((ih->currentwidth-ih->data->barsize)*ih->data->val)/1000; + if (width1 < 0) width1 = 0; + return width1; +} + +static int iSplitGetHeight1(Ihandle* ih) +{ + int height1 = ((ih->currentheight-ih->data->barsize)*ih->data->val)/1000; + if (height1 < 0) height1 = 0; + return height1; +} + +static void iSplitSetBarPosition(Ihandle* ih, int cur_x, int cur_y, int update) +{ + if (ih->data->direction == ISPLIT_VERT) + { + ih->firstchild->x = ih->data->start_bar + (cur_x - ih->data->start_pos); + if (ih->firstchild->x < ih->x) + ih->firstchild->x = ih->x; + if (ih->firstchild->x > ih->x+ih->currentwidth) + ih->firstchild->x = ih->x+ih->currentwidth; + } + else /* ISPLIT_HORIZ */ + { + ih->firstchild->y = ih->data->start_bar + (cur_y - ih->data->start_pos); + if (ih->firstchild->y < ih->y) + ih->firstchild->y = ih->y; + if (ih->firstchild->y > ih->y+ih->currentheight) + ih->firstchild->y = ih->y+ih->currentheight; + } + + if (update) + { + IupSetAttribute(ih->firstchild, "ZORDER", "TOP"); + iupClassObjectLayoutUpdate(ih->firstchild); + } +} + +static void iSplitShowHide(Ihandle* child, int hide) +{ + if (hide) + { + IupSetAttribute(child, "FLOATING", "YES"); + IupSetAttribute(child, "VISIBLE", "NO"); + } + else if (!IupGetInt(child, "VISIBLE")) + { + IupSetAttribute(child, "FLOATING", "NO"); + IupSetAttribute(child, "VISIBLE", "YES"); + } +} + +static void iSplitAutoHideXY(Ihandle* ih) +{ + if (ih->data->direction == ISPLIT_VERT) + { + Ihandle *child1 = ih->firstchild->brother; + if (child1) + { + Ihandle *child2 = child1->brother; + + iSplitShowHide(child1, ih->firstchild->x < ih->x+ih->data->barsize); + + if (child2) + iSplitShowHide(child2, ih->firstchild->x > ih->x+ih->currentwidth-ih->data->barsize); + } + } + else /* ISPLIT_HORIZ */ + { + Ihandle *child1 = ih->firstchild->brother; + if (child1) + { + Ihandle *child2 = child1->brother; + + iSplitShowHide(child1, ih->firstchild->y < ih->y+ih->data->barsize); + + if (child2) + iSplitShowHide(child2, ih->firstchild->y > ih->y+ih->currentheight-ih->data->barsize); + } + } +} + +static void iSplitAutoHideVal(Ihandle* ih) +{ + Ihandle *child1 = ih->firstchild->brother; + if (child1) + { + int tol; + Ihandle *child2 = child1->brother; + + if (ih->data->direction == ISPLIT_VERT) + { + if (ih->currentwidth <= ih->data->barsize) + return; + + tol = (1000*ih->data->barsize)/ih->currentwidth; + } + else + { + if (ih->currentheight <= ih->data->barsize) + return; + + tol = (1000*ih->data->barsize)/ih->currentheight; + } + + iSplitShowHide(child1, ih->data->val<tol); + + if (child2) + iSplitShowHide(child2, ih->data->val > 1000-tol); + } +} + + +/*****************************************************************************\ +|* Callbacks of canvas bar *| +\*****************************************************************************/ + + +static int iSplitAction_CB(Ihandle* bar) +{ + Ihandle* ih = bar->parent; + IdrawCanvas* dc = iupDrawCreateCanvas(bar); + + iupDrawParentBackground(dc); + + if (ih->data->showgrip) + { + int i, w, h, x, y, count; + unsigned char r = 160, g = 160, b = 160, bg_r, bg_g, bg_b; + iupDrawGetSize(dc, &w, &h); + + iupStrToRGB(IupGetAttribute(ih, "COLOR"), &r, &g, &b); + if (r+g+b > 3*190) + { bg_r = 100; bg_g = 100; bg_b = 100; } + else + { bg_r = 255; bg_g = 255; bg_b = 255; } + + if (ih->data->direction == ISPLIT_VERT) + { + x = ih->data->barsize/2-1; + y = 2; + count = (h-2)/5; + } + else + { + x = 2; + y = ih->data->barsize/2-1; + count = (w-2)/5; + } + + for (i = 0; i < count; i++) + { + iupDrawRectangle(dc, x+1, y+1, x+2, y+2, bg_r, bg_g, bg_b, 1); + iupDrawRectangle(dc, x, y, x+1, y+1, r, g, b, 1); + if (ih->data->direction == ISPLIT_VERT) + y += 5; + else + x += 5; + } + } + + iupDrawFlush(dc); + + iupDrawKillCanvas(dc); + + return IUP_DEFAULT; +} + +static int iSplitMotion_CB(Ihandle* bar, int x, int y, char *status) +{ + Ihandle* ih = bar->parent; + + if (ih->data->is_holding) + { + if (iup_isbutton1(status)) + { + int cur_x, cur_y; + + iupStrToIntInt(IupGetGlobal("CURSORPOS"), &cur_x, &cur_y, 'x'); + + if (ih->data->direction == ISPLIT_VERT) + { + int width1 = iSplitGetWidth1(ih); + width1 = ih->data->start_size + (cur_x - ih->data->start_pos); + ih->data->val = (width1*1000)/(ih->currentwidth-ih->data->barsize); + } + else + { + int height1 = iSplitGetHeight1(ih); + height1 = ih->data->start_size + (cur_y - ih->data->start_pos); + ih->data->val = (height1*1000)/(ih->currentheight-ih->data->barsize); + } + + if (ih->data->val < 0) ih->data->val = 0; + if (ih->data->val > 1000) ih->data->val = 1000; + + if (ih->data->layoutdrag) + { + if (ih->data->autohide) + { + iSplitSetBarPosition(ih, cur_x, cur_y, 0); + iSplitAutoHideXY(ih); + } + + IupRefresh(ih); /* may affect all the elements in the dialog */ + } + else + iSplitSetBarPosition(ih, cur_x, cur_y, 1); + } + else + ih->data->is_holding = 0; + } + + (void)x; + (void)y; + return IUP_DEFAULT; +} + +static int iSplitButton_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->is_holding && pressed) + { + int cur_x, cur_y; + + ih->data->is_holding = 1; + + iupStrToIntInt(IupGetGlobal("CURSORPOS"), &cur_x, &cur_y, 'x'); + + /* Save the cursor position and size */ + if (ih->data->direction == ISPLIT_VERT) + { + ih->data->start_bar = ih->firstchild->x; + ih->data->start_pos = cur_x; + ih->data->start_size = iSplitGetWidth1(ih); + } + else + { + ih->data->start_bar = ih->firstchild->y; + ih->data->start_pos = cur_y; + ih->data->start_size = iSplitGetHeight1(ih); + } + } + else if (ih->data->is_holding && !pressed) + { + ih->data->is_holding = 0; + + if (!ih->data->layoutdrag) + { + if (ih->data->autohide) + { + int cur_x, cur_y; + iupStrToIntInt(IupGetGlobal("CURSORPOS"), &cur_x, &cur_y, 'x'); + iSplitSetBarPosition(ih, cur_x, cur_y, 0); + iSplitAutoHideXY(ih); + } + + IupRefresh(ih); /* may affect all the elements in the dialog */ + } + } + + (void)x; + (void)y; + (void)status; + return IUP_DEFAULT; +} + +static int iSplitFocus_CB(Ihandle* bar, int focus) +{ + Ihandle* ih = bar->parent; + + if (!ih || focus) /* use only kill focus */ + return IUP_DEFAULT; + + if (ih->data->is_holding) + ih->data->is_holding = 0; + + return IUP_DEFAULT; +} + + +/*****************************************************************************\ +|* Attributes *| +\*****************************************************************************/ + + +static char* iSplitGetClientSize1Attrib(Ihandle* ih) +{ + int width, height; + char* str = iupStrGetMemory(20); + + if (ih->data->direction == ISPLIT_VERT) + { + width = iSplitGetWidth1(ih); + height = ih->currentheight; + } + else /* ISPLIT_HORIZ */ + { + height = iSplitGetHeight1(ih); + width = ih->currentwidth; + } + + sprintf(str, "%dx%d", width, height); + return str; +} + +static char* iSplitGetClientSize2Attrib(Ihandle* ih) +{ + int width, height; + char* str = iupStrGetMemory(20); + + if (ih->data->direction == ISPLIT_VERT) + { + int width1 = iSplitGetWidth1(ih); + + width = (ih->currentwidth-ih->data->barsize)-width1; + if (width < 0) width = 0; + + height = ih->currentheight; + } + else /* ISPLIT_HORIZ */ + { + int height1 = iSplitGetHeight1(ih); + + height = (ih->currentheight-ih->data->barsize)-height1; + if (height < 0) height = 0; + + width = ih->currentwidth; + } + + sprintf(str, "%dx%d", width, height); + return str; +} + +static int iSplitSetColorAttrib(Ihandle* ih, const char* value) +{ + (void)value; + iupdrvPostRedraw(ih); + return 1; /* store value in hash table */ +} + +static int iSplitSetDirectionAttrib(Ihandle* ih, const char* value) +{ + if (ih->handle) /* only before map */ + return 0; + + if (iupStrEqual(value, "HORIZONTAL")) + ih->data->direction = ISPLIT_HORIZ; + else /* Default = VERTICAL */ + ih->data->direction = ISPLIT_VERT; + + if (ih->data->direction == ISPLIT_VERT) + IupSetAttribute(ih->firstchild, "CURSOR", "SPLITTER_VERT"); + else + IupSetAttribute(ih->firstchild, "CURSOR", "SPLITTER_HORIZ"); + + return 0; /* do not store value in hash table */ +} + +static int iSplitSetValueAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + ih->data->val = -1; + + if (ih->data->autohide) + iSplitAutoHideVal(ih); + + if (ih->handle) + IupRefresh(ih); /* may affect all the elements in the dialog */ + } + else + { + int val; + if (iupStrToInt(value, &val)) + { + ih->data->val = val; + + if (ih->data->autohide) + iSplitAutoHideVal(ih); + + if (ih->handle) + IupRefresh(ih); /* may affect all the elements in the dialog */ + } + } + + return 0; /* do not store value in hash table */ +} + +static char* iSplitGetValueAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(30); + sprintf(str, "%d", ih->data->val); + return str; +} + +static int iSplitSetBarSizeAttrib(Ihandle* ih, const char* value) +{ + if (iupStrToInt(value, &ih->data->barsize)) + { + if (ih->data->autohide) + iSplitAutoHideVal(ih); + + if (ih->handle) + IupRefresh(ih); /* may affect all the elements in the dialog */ + } + return 0; /* do not store value in hash table */ +} + +static char* iSplitGetBarSizeAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(30); + sprintf(str, "%d", ih->data->barsize); + return str; +} + +static int iSplitSetLayoutDragAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + ih->data->layoutdrag = 1; + else + ih->data->layoutdrag = 0; + + return 0; /* do not store value in hash table */ +} + +static char* iSplitGetLayoutDragAttrib(Ihandle* ih) +{ + if (ih->data->layoutdrag) + return "YES"; + else + return "NO"; +} + +static int iSplitSetShowGripAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + ih->data->showgrip = 1; + else + { + ih->data->showgrip = 0; + + if (ih->data->barsize == 5) + iSplitSetBarSizeAttrib(ih, "3"); + } + + return 0; /* do not store value in hash table */ +} + +static char* iSplitGetShowGripAttrib(Ihandle* ih) +{ + if (ih->data->showgrip) + return "YES"; + else + return "NO"; +} + +static int iSplitSetAutoHideAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + { + ih->data->autohide = 1; + iSplitAutoHideVal(ih); + } + else + { + Ihandle *child1 = ih->firstchild->brother; + if (child1) + { + Ihandle *child2 = child1->brother; + iSplitShowHide(child1, 0); + if (child2) + iSplitShowHide(child2, 0); + } + + ih->data->autohide = 0; + } + + return 0; /* do not store value in hash table */ +} + +static char* iSplitGetAutoHideAttrib(Ihandle* ih) +{ + if (ih->data->autohide) + return "YES"; + else + return "NO"; +} + + +/*****************************************************************************\ +|* Methods *| +\*****************************************************************************/ + + +static void iSplitComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int natural_w = 0, + natural_h = 0; + Ihandle *child1, *child2 = NULL; + child1 = ih->firstchild->brother; + if (child1) + child2 = child1->brother; + + /* always has at least one child, the bar, not necessary to compute its natural size */ + if (ih->data->direction == ISPLIT_VERT) + natural_w += ih->data->barsize; + else + natural_h += ih->data->barsize; + + if (child1) + { + /* update child natural size first */ + iupBaseComputeNaturalSize(child1); + + if (ih->data->direction == ISPLIT_VERT) + { + natural_w += child1->naturalwidth; + natural_h = iupMAX(natural_h, child1->naturalheight); + } + else + { + natural_w = iupMAX(natural_w, child1->naturalwidth); + natural_h += child1->naturalheight; + } + + *expand = child1->expand; + + if (child2) + { + /* update child natural size first */ + iupBaseComputeNaturalSize(child2); + + if (ih->data->direction == ISPLIT_VERT) + { + natural_w += child2->naturalwidth; + natural_h = iupMAX(natural_h, child2->naturalheight); + } + else + { + natural_w = iupMAX(natural_w, child2->naturalwidth); + natural_h += child2->naturalheight; + } + + *expand |= child2->expand; + } + } + + if (ih->data->val == -1) + { + if (child1) + { + if (ih->data->direction == ISPLIT_VERT) + ih->data->val = (child1->naturalwidth*1000)/(natural_w-ih->data->barsize); + else + ih->data->val = (child1->naturalheight*1000)/(natural_h-ih->data->barsize); + + if (ih->data->val < 0) ih->data->val = 0; + if (ih->data->val > 1000) ih->data->val = 1000; + } + else + ih->data->val = 0; + } + + *w = natural_w; + *h = natural_h; +} + +static void iSplitSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) +{ + Ihandle *child1, *child2 = NULL; + child1 = ih->firstchild->brother; + if (child1) + child2 = child1->brother; + + if (ih->data->direction == ISPLIT_VERT) + { + int width2 = 0; + + if (child1) + { + int width1 = iSplitGetWidth1(ih); + iupBaseSetCurrentSize(child1, width1, ih->currentheight, shrink); + + width2 = (ih->currentwidth-ih->data->barsize)-width1; + if (width2 < 0) width2 = 0; + } + + /* bar */ + ih->firstchild->currentwidth = ih->data->barsize; + ih->firstchild->currentheight = ih->currentheight; + + if (child2) + iupBaseSetCurrentSize(child2, width2, ih->currentheight, shrink); + } + else /* ISPLIT_HORIZ */ + { + int height2 = 0; + + if (child1) + { + int height1 = iSplitGetHeight1(ih); + iupBaseSetCurrentSize(child1, ih->currentwidth, height1, shrink); + + height2 = (ih->currentheight-ih->data->barsize)-height1; + if (height2 < 0) height2 = 0; + } + + /* bar */ + ih->firstchild->currentwidth = ih->currentwidth; + ih->firstchild->currentheight = ih->data->barsize; + + if (child2) + iupBaseSetCurrentSize(child2, ih->currentwidth, height2, shrink); + } +} + +static void iSplitSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + Ihandle *child1, *child2 = NULL; + child1 = ih->firstchild->brother; + if (child1) + child2 = child1->brother; + + if (ih->data->direction == ISPLIT_VERT) + { + if (child1) + iupBaseSetPosition(child1, x, y); + x += iSplitGetWidth1(ih); + + /* bar */ + iupBaseSetPosition(ih->firstchild, x, y); + x += ih->data->barsize; + + if (child2) + iupBaseSetPosition(child2, x, y); + } + else /* ISPLIT_HORIZ */ + { + if (child1) + iupBaseSetPosition(child1, x, y); + y += iSplitGetHeight1(ih); + + /* bar */ + iupBaseSetPosition(ih->firstchild, x, y); + y += ih->data->barsize; + + if (child2) + iupBaseSetPosition(child2, x, y); + } +} + +static int iSplitCreateMethod(Ihandle* ih, void** params) +{ + Ihandle* bar; + + ih->data = iupALLOCCTRLDATA(); + + ih->data->direction = ISPLIT_VERT; + ih->data->val = -1; + ih->data->layoutdrag = 1; + ih->data->autohide = 0; + ih->data->barsize = 5; + ih->data->showgrip = 1; + + bar = IupCanvas(NULL); + iupChildTreeAppend(ih, bar); /* bar will always be the firstchild */ + + IupSetAttribute(bar, "CANFOCUS", "NO"); + IupSetAttribute(bar, "BORDER", "NO"); + IupSetAttribute(bar, "EXPAND", "NO"); + IupSetAttribute(bar, "CURSOR", "SPLITTER_VERT"); + + /* Setting callbacks */ + IupSetCallback(bar, "BUTTON_CB", (Icallback) iSplitButton_CB); + IupSetCallback(bar, "FOCUS_CB", (Icallback) iSplitFocus_CB); + IupSetCallback(bar, "MOTION_CB", (Icallback) iSplitMotion_CB); + IupSetCallback(bar, "ACTION", (Icallback) iSplitAction_CB); + + if (params) + { + Ihandle** iparams = (Ihandle**)params; + if (iparams[0]) IupAppend(ih, iparams[0]); + if (iparams[1]) IupAppend(ih, iparams[1]); + } + + return IUP_NOERROR; +} + +Iclass* iupSplitGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "split"; + ic->format = "HH"; /* two optional ihandle */ + ic->nativetype = IUP_TYPEVOID; + ic->childtype = IUP_CHILDMANY; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iSplitCreateMethod; + ic->Map = iupBaseTypeVoidMapMethod; + + ic->ComputeNaturalSize = iSplitComputeNaturalSizeMethod; + ic->SetChildrenCurrentSize = iSplitSetChildrenCurrentSizeMethod; + ic->SetChildrenPosition = iSplitSetChildrenPositionMethod; + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Base Container */ + iupClassRegisterAttribute(ic, "CLIENTSIZE1", iSplitGetClientSize1Attrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CLIENTSIZE2", iSplitGetClientSize2Attrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* IupSplit only */ + iupClassRegisterAttribute(ic, "COLOR", NULL, iSplitSetColorAttrib, IUPAF_SAMEASSYSTEM, "160 160 160", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DIRECTION", NULL, iSplitSetDirectionAttrib, IUPAF_SAMEASSYSTEM, "VERTICAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", iSplitGetValueAttrib, iSplitSetValueAttrib, IUPAF_SAMEASSYSTEM, "500", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "LAYOUTDRAG", iSplitGetLayoutDragAttrib, iSplitSetLayoutDragAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWGRIP", iSplitGetShowGripAttrib, iSplitSetShowGripAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AUTOHIDE", iSplitGetAutoHideAttrib, iSplitSetAutoHideAttrib, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "BARSIZE", iSplitGetBarSizeAttrib, iSplitSetBarSizeAttrib, IUPAF_SAMEASSYSTEM, "5", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} + +Ihandle* IupSplit(Ihandle* child1, Ihandle* child2) +{ + void *params[3]; + params[0] = (void*)child1; + params[1] = (void*)child2; + params[2] = NULL; + return IupCreatev("split", params); +} diff --git a/iup/src/iup_stdcontrols.h b/iup/src/iup_stdcontrols.h index 11499ae..0f3deb9 100755 --- a/iup/src/iup_stdcontrols.h +++ b/iup/src/iup_stdcontrols.h @@ -46,6 +46,7 @@ Iclass* iupZboxGetClass(void); Iclass* iupCboxGetClass(void); Iclass* iupSboxGetClass(void); Iclass* iupNormalizerGetClass(void); +Iclass* iupSplitGetClass(void); Iclass* iupTimerGetClass(void); Iclass* iupImageGetClass(void); diff --git a/iup/src/iup_str.c b/iup/src/iup_str.c index 68976f1..5f5b85d 100755 --- a/iup/src/iup_str.c +++ b/iup/src/iup_str.c @@ -147,8 +147,9 @@ char *iupStrCopyUntil(char **str, int c) return NULL; p_str=strchr(*str,c); - if (!p_str) return NULL; - + if (!p_str) + return NULL; + else { int i; int sl=(int)(p_str - (*str)); @@ -160,10 +161,10 @@ char *iupStrCopyUntil(char **str, int c) new_str[i] = (*str)[i]; new_str[sl] = 0; - } - *str = p_str+1; - return new_str; + *str = p_str+1; + return new_str; + } } char *iupStrCopyUntilNoCase(char **str, int c) @@ -174,11 +175,12 @@ char *iupStrCopyUntilNoCase(char **str, int c) p_str=strchr(*str,c); /* usually the lower case is enough */ if (!p_str && isalpha(c)) - { p_str=strchr(*str, toupper(c)); /* but check also for upper case */ - if (!p_str) return NULL; - } + /* if both fail, then abort */ + if (!p_str) + return NULL; + else { int i; int sl=(int)(p_str - (*str)); @@ -190,10 +192,10 @@ char *iupStrCopyUntilNoCase(char **str, int c) new_str[i] = (*str)[i]; new_str[sl] = 0; - } - *str = p_str+1; - return new_str; + *str = p_str+1; + return new_str; + } } char *iupStrGetMemory(int size) diff --git a/iup/src/iup_table.c b/iup/src/iup_table.c index 9e97ff5..a873191 100755 --- a/iup/src/iup_table.c +++ b/iup/src/iup_table.c @@ -19,12 +19,12 @@ /* Adjust these parameters for optimal performance and memory usage */ static const unsigned int itable_maxTableSizeIndex = 8; static const unsigned int itable_hashTableSize[] = { 31, 101, 401, 1601, 4001, 8009, 16001, 32003, 64007 }; -static const float itable_resizeLimit = 2; +static const unsigned int itable_resizeLimit = 2; static const unsigned int itable_itemGrow = 5; /* Iteration context. */ -typedef struct ItableContext +typedef struct _ItableContext { unsigned int entryIndex; /* index at the Itable::entries array */ unsigned int itemIndex; /* index at the ItableEntry::items array */ @@ -41,7 +41,7 @@ typedef struct ItableContext * this is simply the pointer (in this case keyIndex * and keyStr are equal). */ -typedef struct ItableKey +typedef struct _ItableKey { unsigned long keyIndex; /* the secondary hash number */ const char *keyStr; @@ -52,11 +52,11 @@ ItableKey; * Such an item is stored in the item list of * an entry. */ -typedef struct ItableItem +typedef struct _ItableItem { Itable_Types itemType; - ItableKey key; - void *value; + ItableKey key; + void* value; } ItableItem; @@ -67,29 +67,28 @@ ItableItem; * in nextItemIndex. * size is the current size of the items array. */ -typedef struct ItableEntry +typedef struct _ItableEntry { unsigned int nextItemIndex; - unsigned int size; - ItableItem *items; + unsigned int itemsSize; + ItableItem* items; } ItableEntry; /* A hash table. - * indexType is the type of the index. * entries is an array of entries. Select an * entry by its index. * size is the number of entries in the hash table... */ -struct Itable +struct _Itable { - unsigned int size; - unsigned int numberOfEntries; - unsigned int tableSizeIndex; /* index into itable_hashTableSize array */ - Itable_IndexTypes indexType; - ItableEntry *entries; - ItableContext context; + unsigned int entriesSize; + unsigned int numberOfEntries; + unsigned int tableSizeIndex; /* index into itable_hashTableSize array */ + Itable_IndexTypes indexType; /* type of the index: string or pointer. */ + ItableEntry *entries; + ItableContext context; }; @@ -121,8 +120,7 @@ Itable *iupTableCreate(Itable_IndexTypes indexType) Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSizeIndex) { - Itable *it = (Itable *)malloc(sizeof(struct Itable)); - + Itable *it = (Itable *)malloc(sizeof(Itable)); iupASSERT(it!=NULL); if (!it) return 0; @@ -130,12 +128,12 @@ Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSiz if (initialSizeIndex > itable_maxTableSizeIndex) initialSizeIndex = itable_maxTableSizeIndex; - it->size = itable_hashTableSize[initialSizeIndex]; + it->entriesSize = itable_hashTableSize[initialSizeIndex]; it->tableSizeIndex = initialSizeIndex; it->numberOfEntries = 0; it->indexType = indexType; - it->entries = (ItableEntry *)malloc(it->size * sizeof(ItableEntry)); + it->entries = (ItableEntry *)malloc(it->entriesSize * sizeof(ItableEntry)); iupASSERT(it->entries!=NULL); if (!it->entries) { @@ -143,7 +141,7 @@ Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSiz return 0; } - memset(it->entries, 0, it->size * sizeof(ItableEntry)); + memset(it->entries, 0, it->entriesSize * sizeof(ItableEntry)); it->context.entryIndex = (unsigned int)-1; it->context.itemIndex = (unsigned int)-1; @@ -158,16 +156,19 @@ void iupTableClear(Itable *it) if (!it) return; - for (i = 0; i < it->size; i++) + for (i = 0; i < it->entriesSize; i++) { ItableEntry *entry = &(it->entries[i]); if (entry->items) + { iTableFreeItemArray(it->indexType, entry->nextItemIndex, entry->items); + entry->items = NULL; + } } it->numberOfEntries = 0; - memset(it->entries, 0, it->size * sizeof(ItableEntry)); + memset(it->entries, 0, it->entriesSize * sizeof(ItableEntry)); it->context.entryIndex = (unsigned int)-1; it->context.itemIndex = (unsigned int)-1; @@ -185,7 +186,10 @@ void iupTableDestroy(Itable *it) iupTableClear(it); if (it->entries) + { free(it->entries); + it->entries = NULL; + } free(it); } @@ -288,17 +292,23 @@ static void iTableRemoveItem(Itable *it, ItableEntry *entry, unsigned int itemIn item = &(entry->items[itemIndex]); if (it->indexType == IUPTABLE_STRINGINDEXED) + { free((void *)item->key.keyStr); + item->key.keyStr = NULL; + } if (item->itemType == IUPTABLE_STRING) + { free(item->value); + item->value = NULL; + } - /* order the remaining items */ + /* re-order the remaining items */ for (i = itemIndex; i < entry->nextItemIndex-1; i++) entry->items[i] = entry->items[i+1]; - /* clear the non used item */ - memset(entry->items + entry->nextItemIndex, 0, sizeof (ItableItem)); + /* clear the released item */ + memset(entry->items + entry->nextItemIndex-1, 0, sizeof (ItableItem)); entry->nextItemIndex--; it->numberOfEntries--; @@ -398,7 +408,7 @@ char *iupTableFirst(Itable *it) it->context.itemIndex = (unsigned int)-1; /* find the first used entry */ - for (entryIndex = 0; entryIndex < it->size; entryIndex++) + for (entryIndex = 0; entryIndex < it->entriesSize; entryIndex++) { if (it->entries[entryIndex].nextItemIndex > 0) { @@ -430,7 +440,7 @@ char *iupTableNext(Itable *it) else { /* find the next used entry */ - for (entryIndex = it->context.entryIndex+1; entryIndex < it->size; entryIndex++) + for (entryIndex = it->context.entryIndex+1; entryIndex < it->entriesSize; entryIndex++) { if (it->entries[entryIndex].nextItemIndex > 0) { @@ -471,7 +481,7 @@ char *iupTableRemoveCurr(Itable *it) else { /* find the next used entry */ - for (entryIndex = it->context.entryIndex+1; entryIndex < it->size; entryIndex++) + for (entryIndex = it->context.entryIndex+1; entryIndex < it->entriesSize; entryIndex++) { if (it->entries[entryIndex].nextItemIndex > 0) { @@ -498,6 +508,8 @@ static void iTableFreeItemArray(Itable_IndexTypes indexType, unsigned int nextFr { unsigned int i; + /* Used only in iupTableClear */ + iupASSERT(items!=NULL); if (!items) return; @@ -505,13 +517,19 @@ static void iTableFreeItemArray(Itable_IndexTypes indexType, unsigned int nextFr if (indexType == IUPTABLE_STRINGINDEXED) { for (i = 0; i < nextFreeIndex; i++) + { free((void *)(items[i].key.keyStr)); + items[i].key.keyStr = NULL; + } } for (i = 0; i < nextFreeIndex; i++) { if (items[i].itemType == IUPTABLE_STRING) + { free(items[i].value); + items[i].value = NULL; + } } free(items); @@ -545,7 +563,7 @@ static unsigned int iTableGetEntryIndex(Itable *it, const char *key, unsigned lo *keyIndex = (unsigned long)key; /* this could NOT be dependent from table size */ } - return (unsigned int)((*keyIndex) % it->size); + return (unsigned int)((*keyIndex) % it->entriesSize); } #ifdef DEBUGTABLE @@ -603,25 +621,24 @@ static unsigned int iTableFindItem(Itable *it, const char *key, ItableEntry **en static void iTableUpdateArraySize(ItableEntry *entry) { - if (entry->nextItemIndex >= entry->size) + if (entry->nextItemIndex >= entry->itemsSize) { /* we have to expand the item array */ unsigned int newSize; - newSize = entry->size + itable_itemGrow; + newSize = entry->itemsSize + itable_itemGrow; entry->items = (ItableItem *)realloc(entry->items, newSize * sizeof(ItableItem)); iupASSERT(entry->items!=NULL); if (!entry->items) return; - memset(entry->items + entry->size, 0, itable_itemGrow * sizeof(ItableItem)); + memset(entry->items + entry->itemsSize, 0, itable_itemGrow * sizeof(ItableItem)); - entry->size = newSize; + entry->itemsSize = newSize; } } - static void iTableAdd(Itable *it, ItableKey *key, void *value, Itable_Types itemType) { unsigned int entryIndex; @@ -657,7 +674,7 @@ static unsigned int iTableResize(Itable *it) /* check if we do not need to resize the hash table */ if (it->numberOfEntries == 0 || it->tableSizeIndex >= itable_maxTableSizeIndex || - it->size / it->numberOfEntries >= itable_resizeLimit) + it->entriesSize / it->numberOfEntries >= itable_resizeLimit) return 0; /* create a new hash table and copy the contents of @@ -666,7 +683,7 @@ static unsigned int iTableResize(Itable *it) newSizeIndex = it->tableSizeIndex + 1; newTable = iupTableCreateSized(it->indexType, newSizeIndex); - for (entryIndex = 0; entryIndex < it->size; entryIndex++) + for (entryIndex = 0; entryIndex < it->entriesSize; entryIndex++) { entry = &(it->entries[entryIndex]); @@ -680,12 +697,13 @@ static unsigned int iTableResize(Itable *it) } free(entry->items); + entry->items = NULL; } } free(it->entries); - it->size = newTable->size; + it->entriesSize = newTable->entriesSize; it->tableSizeIndex = newTable->tableSizeIndex; it->numberOfEntries = newTable->numberOfEntries; it->entries = newTable->entries; @@ -712,11 +730,11 @@ static void iTableShowStatistics(Itable *it) return; } - nofSlots = it->size; + nofSlots = it->entriesSize; nofKeys = it->numberOfEntries; optimalNofKeysPerSlot = (double)nofKeys / (double)nofSlots; - for (entryIndex = 0; entryIndex < it->size; entryIndex++) + for (entryIndex = 0; entryIndex < it->entriesSize; entryIndex++) { ItableEntry *entry = &(it->entries[entryIndex]); diff --git a/iup/src/iup_table.h b/iup/src/iup_table.h index 5222160..f2ff2c7 100755 --- a/iup/src/iup_table.h +++ b/iup/src/iup_table.h @@ -42,8 +42,8 @@ typedef enum _Itable_Types typedef void (*Ifunc)(void); -struct Itable; -typedef struct Itable Itable; +struct _Itable; +typedef struct _Itable Itable; /** Creates a hash table with an initial default size. @@ -63,7 +63,7 @@ Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSiz /** Destroys the Itable. * Calls \ref iupTableClear. * \ingroup table */ -void iupTableDestroy(Itable *n); +void iupTableDestroy(Itable *it); /** Removes all items in the table. * This function does also free the memory of strings contained in the table!!!! @@ -76,33 +76,33 @@ int iupTableCount(Itable *it); /** Store an element in the table. * \ingroup table */ -void iupTableSet(Itable *n, const char *key, void *value, Itable_Types itemType); +void iupTableSet(Itable *it, const char *key, void *value, Itable_Types itemType); /** Store a function pointer in the table. * Type is set to IUPTABLE_FUNCPOINTER. * \ingroup table */ -void iupTableSetFunc(Itable *n, const char *key, Ifunc func); +void iupTableSetFunc(Itable *it, const char *key, Ifunc func); /** Retrieves an element from the table. * Returns NULL if not found. * \ingroup table */ -void *iupTableGet(Itable *n, const char *key); +void *iupTableGet(Itable *it, const char *key); /** Retrieves a function pointer from the table. * If not a function or not found returns NULL. * value always contains the element pointer. * \ingroup table */ -Ifunc iupTableGetFunc(Itable *n, const char *key, void **value); +Ifunc iupTableGetFunc(Itable *it, const char *key, void **value); /** Retrieves an element from the table and its type. * \ingroup table */ -void *iupTableGetTyped(Itable *n, const char *key, Itable_Types *itemType); +void *iupTableGetTyped(Itable *it, const char *key, Itable_Types *itemType); /** Removes the entry at the specified key from the * hash table and frees the memory used by it if * it is a string... * \ingroup table */ -void iupTableRemove(Itable *n, const char *key); +void iupTableRemove(Itable *it, const char *key); /** Key iteration function. Returns a key. * To iterate over all keys call iupTableFirst at the first diff --git a/iup/src/iup_tabs.c b/iup/src/iup_tabs.c index 77b2cf5..2907371 100755 --- a/iup/src/iup_tabs.c +++ b/iup/src/iup_tabs.c @@ -307,6 +307,25 @@ static char* iTabsGetClientSizeAttrib(Ihandle* ih) return str; } +void iupTabsTestRemoveTab(Ihandle* ih, int pos) +{ + int cur_pos = iupdrvTabsGetCurrentTab(ih); + if (cur_pos == pos) + { + if (cur_pos == 0) + { + Ihandle* child = IupGetChild(ih, 1); + if (!child) /* not found child, means only one child, do nothing */ + return; + + cur_pos = 1; + } + else + cur_pos--; + + iupdrvTabsSetCurrentTab(ih, cur_pos); + } +} /* ------------------------------------------------------------------------- */ /* TABS - Methods */ diff --git a/iup/src/iup_tabs.h b/iup/src/iup_tabs.h index 7f5df2e..fd0edf4 100755 --- a/iup/src/iup_tabs.h +++ b/iup/src/iup_tabs.h @@ -16,6 +16,7 @@ char* iupTabsGetTabOrientationAttrib(Ihandle* ih); char* iupTabsGetTabTypeAttrib(Ihandle* ih); char* iupTabsAttribGetStrId(Ihandle* ih, const char* name, int pos); char* iupTabsGetPaddingAttrib(Ihandle* ih); +void iupTabsTestRemoveTab(Ihandle* ih, int pos); int iupdrvTabsExtraDecor(Ihandle* ih); int iupdrvTabsGetLineCountAttrib(Ihandle* ih); diff --git a/iup/src/iup_tree.c b/iup/src/iup_tree.c index c06e573..b5344f5 100755 --- a/iup/src/iup_tree.c +++ b/iup/src/iup_tree.c @@ -200,6 +200,240 @@ void iupTreeUpdateImages(Ihandle *ih) iupClassObjectSetAttribute(ih, "IMAGEBRANCHEXPANDED", value, &inherit); } +void iupTreeSelectLastCollapsedBranch(Ihandle* ih, int *last_id) +{ + /* if last selected item is a branch, then select its children */ + if (iupStrEqual(IupTreeGetAttribute(ih, "KIND", *last_id), "BRANCH") && + iupStrEqual(IupTreeGetAttribute(ih, "STATE", *last_id), "COLLAPSED")) + { + int childcount = IupTreeGetInt(ih, "CHILDCOUNT", *last_id); + if (childcount > 0) + { + int start = *last_id + 1; + int end = *last_id + childcount; + IupSetfAttribute(ih, "MARK", "%d-%d", start, end); + *last_id = *last_id + childcount; + } + } +} + +int iupTreeForEach(Ihandle* ih, iupTreeNodeFunc func, void* userdata) +{ + int i; + for (i = 0; i < ih->data->node_count; i++) + { + if (!func(ih, ih->data->node_cache[i].node_handle, i, userdata)) + return 0; + } + + return 1; +} + +int iupTreeFindNodeId(Ihandle* ih, InodeHandle* node_handle) +{ + /* Unoptimized version: + int i; + for (i = 0; i < ih->data->node_count; i++) + { + if (ih->data->node_cache[i].node_handle == node_handle) + return i; + } + */ + InodeData *node_cache = ih->data->node_cache; + while(node_cache->node_handle != node_handle && + node_cache->node_handle != NULL) /* the cache always have zeros at the end */ + node_cache++; + + if (node_cache->node_handle != NULL) + return node_cache - ih->data->node_cache; + else + return -1; +} + +static int iTreeFindUserDataId(Ihandle* ih, void* userdata) +{ + /* Unoptimized version: + int i; + for (i = 0; i < ih->data->node_count; i++) + { + if (ih->data->node_cache[i].node_handle == node_handle) + return i; + } + */ + InodeData *node_cache = ih->data->node_cache; + while(node_cache->userdata != userdata && + node_cache->node_handle != NULL) /* the cache always have zeros at the end */ + node_cache++; + + if (node_cache->node_handle != NULL) + return node_cache - ih->data->node_cache; + else + return -1; +} + +static int iTreeGetIdFromString(const char* name_id) +{ + if (name_id && name_id[0]) + { + int id = -1; + iupStrToInt(name_id, &id); + return id; + } + else + return -2; +} + +InodeHandle* iupTreeGetNode(Ihandle* ih, int id) +{ + if (id >= 0 && id < ih->data->node_count) + return ih->data->node_cache[id].node_handle; + else if (id == -2) + return iupdrvTreeGetFocusNode(ih); + else + return NULL; +} + +InodeHandle* iupTreeGetNodeFromString(Ihandle* ih, const char* name_id) +{ + return iupTreeGetNode(ih, iTreeGetIdFromString(name_id)); +} + +static void iTreeAddToCache(Ihandle* ih, int id, InodeHandle* node_handle) +{ + iupASSERT(id >= 0 && id < ih->data->node_count); + if (id < 0 || id >= ih->data->node_count) + return; + + /* node_count here already contains the final count */ + + if (id == ih->data->node_count-1) + ih->data->node_cache[id].node_handle = node_handle; + else + { + /* open space for the new id */ + int remain_count = ih->data->node_count-id; + memmove(ih->data->node_cache+id+1, ih->data->node_cache+id, remain_count*sizeof(InodeData)); + ih->data->node_cache[id].node_handle = node_handle; + } + + ih->data->node_cache[id].userdata = NULL; +} + +static void iTreeIncCacheMem(Ihandle* ih) +{ + /* node_count here already contains the final count */ + + if (ih->data->node_count+10 > ih->data->node_cache_max) + { + int old_node_cache_max = ih->data->node_cache_max; + ih->data->node_cache_max += 20; + ih->data->node_cache = realloc(ih->data->node_cache, ih->data->node_cache_max*sizeof(InodeData)); + memset(ih->data->node_cache+old_node_cache_max, 0, 20*sizeof(InodeData)); + } +} + +void iupTreeAddToCache(Ihandle* ih, int add, int kindPrev, InodeHandle* prevNode, InodeHandle* node_handle) +{ + int new_id = 0; + + ih->data->node_count++; + + /* node_count here already contains the final count */ + iTreeIncCacheMem(ih); + + if (prevNode) + { + if (add || kindPrev == ITREE_LEAF) + { + /* ADD implies always that id=prev_id+1 */ + /* INSERT after a leaf implies always that new_id=prev_id+1 */ + int prev_id = iupTreeFindNodeId(ih, prevNode); + new_id = prev_id+1; + } + else + { + /* INSERT after a branch implies always that new_id=prev_id+1+child_count */ + int prev_id = iupTreeFindNodeId(ih, prevNode); + int child_count = iupdrvTreeTotalChildCount(ih, prevNode); + new_id = prev_id+1+child_count; + } + } + + iTreeAddToCache(ih, new_id, node_handle); + iupAttribSetInt(ih, "LASTADDNODE", new_id); +} + +void iupTreeDelFromCache(Ihandle* ih, int id, int count) +{ + int remain_count; + + /* id can be the last node, actually==node_count becase node_count is already updated */ + iupASSERT(id >= 0 && id <= ih->data->node_count); + if (id < 0 || id > ih->data->node_count) + return; + + /* node_count here already contains the final count */ + + /* remove id+count */ + remain_count = ih->data->node_count-id; + memmove(ih->data->node_cache+id, ih->data->node_cache+id+count, remain_count*sizeof(InodeData)); + + /* clear the remaining space */ + memset(ih->data->node_cache+ih->data->node_count, 0, count*sizeof(InodeData)); +} + +void iupTreeCopyMoveCache(Ihandle* ih, int id_src, int id_dst, int count, int is_copy) +{ + int remain_count; + + iupASSERT(id_src >= 0 && id_src < ih->data->node_count); + if (id_src < 0 || id_src >= ih->data->node_count) + return; + + iupASSERT(id_dst >= 0 && id_dst < ih->data->node_count); + if (id_dst < 0 || id_dst >= ih->data->node_count) + return; + + iupASSERT(id_dst < id_src || id_dst > id_src+count); + if (id_dst >= id_src && id_dst <= id_src+count) + return; + + /* id_dst here points to the final position for a copy operation */ + + /* node_count here contains the final count for a copy operation */ + iTreeIncCacheMem(ih); + + /* add space for new nodes */ + remain_count = ih->data->node_count - (id_dst + count); + memmove(ih->data->node_cache+id_dst+count, ih->data->node_cache+id_dst, remain_count*sizeof(InodeData)); + + /* compensate because we add space for new nodes */ + if (id_src > id_dst) + id_src += count; + + if (is_copy) + { + /* during a copy, the userdata is not reused, so clear it */ + memset(ih->data->node_cache+id_dst, 0, count*sizeof(InodeData)); + } + else /* move = copy + delete */ + { + /* copy userdata from src to dst */ + memcpy(ih->data->node_cache+id_dst, ih->data->node_cache+id_src, count*sizeof(InodeData)); + + /* remove the src */ + remain_count = ih->data->node_count - (id_src + count); + memmove(ih->data->node_cache+id_src, ih->data->node_cache+id_src+count, remain_count*sizeof(InodeData)); + + /* clear the remaining space */ + memset(ih->data->node_cache+ih->data->node_count-count, 0, count*sizeof(InodeData)); + } +} + + +/*************************************************************************/ + + char* iupTreeGetSpacingAttrib(Ihandle* ih) { char *str = iupStrGetMemory(50); @@ -221,8 +455,10 @@ static int iTreeSetMarkModeAttrib(Ihandle* ih, const char* value) ih->data->mark_mode = ITREE_MARK_MULTIPLE; else ih->data->mark_mode = ITREE_MARK_SINGLE; + if (ih->handle) - iupdrvTreeUpdateMarkMode(ih); + iupdrvTreeUpdateMarkMode(ih); /* for this to work, must update during map */ + return 0; } @@ -290,7 +526,7 @@ static int iTreeSetShowDragDropAttrib(Ihandle* ih, const char* value) static int iTreeSetAddLeafAttrib(Ihandle* ih, const char* name_id, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; iupdrvTreeAddNode(ih, name_id, ITREE_LEAF, value, 1); return 0; @@ -298,7 +534,7 @@ static int iTreeSetAddLeafAttrib(Ihandle* ih, const char* name_id, const char* v static int iTreeSetAddBranchAttrib(Ihandle* ih, const char* name_id, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; iupdrvTreeAddNode(ih, name_id, ITREE_BRANCH, value, 1); return 0; @@ -306,7 +542,7 @@ static int iTreeSetAddBranchAttrib(Ihandle* ih, const char* name_id, const char* static int iTreeSetInsertLeafAttrib(Ihandle* ih, const char* name_id, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; iupdrvTreeAddNode(ih, name_id, ITREE_LEAF, value, 0); return 0; @@ -314,7 +550,7 @@ static int iTreeSetInsertLeafAttrib(Ihandle* ih, const char* name_id, const char static int iTreeSetInsertBranchAttrib(Ihandle* ih, const char* name_id, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; iupdrvTreeAddNode(ih, name_id, ITREE_BRANCH, value, 0); return 0; @@ -338,6 +574,74 @@ static int iTreeSetAddExpandedAttrib(Ihandle* ih, const char* value) return 0; } +static char* iTreeGetCountAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(10); + sprintf(str, "%d", ih->data->node_count); + return str; +} + +static char* iTreeGetTotalChildCountAttrib(Ihandle* ih, const char* name_id) +{ + char* str; + InodeHandle* node_handle = iupTreeGetNodeFromString(ih, name_id); + if (!node_handle) + return NULL; + + str = iupStrGetMemory(10); + sprintf(str, "%d", iupdrvTreeTotalChildCount(ih, node_handle)); + return str; +} + + +static char* iTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id) +{ + int id; + char* str = (char*)(name_id+1); /* skip ':' */ + void* userdata = NULL; + if (sscanf(str, "%p", &userdata)!=1) + return NULL; + id = iTreeFindUserDataId(ih, userdata); + if (id == -1) + return NULL; + str = iupStrGetMemory(16); + sprintf(str, "%d", id); + return str; +} + +static char* iTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) +{ + int id = iTreeGetIdFromString(name_id); + if (id >= 0 && id < ih->data->node_count) + return ih->data->node_cache[id].userdata; + else if (id == -2) + { + InodeHandle* node_handle = iupdrvTreeGetFocusNode(ih); + id = iupTreeFindNodeId(ih, node_handle); + if (id >= 0 && id < ih->data->node_count) + return ih->data->node_cache[id].userdata; + } + return NULL; +} + +static int iTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int id = iTreeGetIdFromString(name_id); + if (id >= 0 && id < ih->data->node_count) + ih->data->node_cache[id].userdata = (void*)value; + else if (id == -2) + { + InodeHandle* node_handle = iupdrvTreeGetFocusNode(ih); + id = iupTreeFindNodeId(ih, node_handle); + if (id >= 0 && id < ih->data->node_count) + ih->data->node_cache[id].userdata = (void*)value; + } + return 0; +} + + +/*************************************************************************/ + static int iTreeCreateMethod(Ihandle* ih, void **params) { (void)params; @@ -348,10 +652,20 @@ static int iTreeCreateMethod(Ihandle* ih, void **params) IupSetAttribute(ih, "EXPAND", "YES"); ih->data->add_expanded = 1; + ih->data->node_cache_max = 20; + ih->data->node_cache = calloc(ih->data->node_cache_max, sizeof(InodeData)); return IUP_NOERROR; } +static void iTreeDestroyMethod(Ihandle* ih) +{ + if (ih->data->node_cache) + free(ih->data->node_cache); +} + +/*************************************************************************/ + Ihandle* IupTree(void) { return IupCreate("tree"); @@ -371,15 +685,15 @@ Iclass* iupTreeGetClass(void) /* Class functions */ ic->Create = iTreeCreateMethod; ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; - ic->UnMap = iupdrvBaseUnMapMethod; + ic->Destroy = iTreeDestroyMethod; /* Callbacks */ iupClassRegisterCallback(ic, "SELECTION_CB", "ii"); iupClassRegisterCallback(ic, "MULTISELECTION_CB", "Ii"); + iupClassRegisterCallback(ic, "MULTIUNSELECTION_CB", "Ii"); iupClassRegisterCallback(ic, "BRANCHOPEN_CB", "i"); iupClassRegisterCallback(ic, "BRANCHCLOSE_CB", "i"); iupClassRegisterCallback(ic, "EXECUTELEAF_CB", "i"); - iupClassRegisterCallback(ic, "RENAMENODE_CB", "is"); iupClassRegisterCallback(ic, "SHOWRENAME_CB", "i"); iupClassRegisterCallback(ic, "RENAME_CB", "is"); iupClassRegisterCallback(ic, "DRAGDROP_CB", "iiii"); @@ -392,9 +706,12 @@ Iclass* iupTreeGetClass(void) iupBaseRegisterVisualAttrib(ic); /* IupTree Attributes - GENERAL */ - iupClassRegisterAttribute(ic, "SHOWDRAGDROP", iTreeGetShowDragDropAttrib, iTreeSetShowDragDropAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); - iupClassRegisterAttribute(ic, "SHOWRENAME", iTreeGetShowRenameAttrib, iTreeSetShowRenameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); - iupClassRegisterAttribute(ic, "ADDEXPANDED", iTreeGetAddExpandedAttrib, iTreeSetAddExpandedAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWDRAGDROP", iTreeGetShowDragDropAttrib, iTreeSetShowDragDropAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWRENAME", iTreeGetShowRenameAttrib, iTreeSetShowRenameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ADDEXPANDED", iTreeGetAddExpandedAttrib, iTreeSetAddExpandedAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "COUNT", iTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "LASTADDNODE", NULL, NULL, IUPAF_SAMEASSYSTEM, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ADDROOT", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); /* IupTree Attributes - MARKS */ iupClassRegisterAttribute(ic, "CTRL", NULL, iTreeSetCtrlAttrib, NULL, NULL, IUPAF_NOT_MAPPED); @@ -406,6 +723,11 @@ Iclass* iupTreeGetClass(void) iupClassRegisterAttributeId(ic, "ADDBRANCH", NULL, iTreeSetAddBranchAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "INSERTLEAF", NULL, iTreeSetInsertLeafAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "INSERTBRANCH", NULL, iTreeSetInsertBranchAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + /* IupTree Attributes - NODES */ + iupClassRegisterAttributeId(ic, "TOTALCHILDCOUNT", iTreeGetTotalChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "FINDUSERDATA", iTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "USERDATA", iTreeGetUserDataAttrib, iTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); /* Default node images */ iTreeInitializeImages(); @@ -415,18 +737,23 @@ Iclass* iupTreeGetClass(void) return ic; } - /********************************************************************************************/ - -void IupTreeSetAttribute(Ihandle* ih, const char* a, int id, char* v) +void IupTreeSetAttribute(Ihandle* ih, const char* a, int id, const char* v) { char* attr = iupStrGetMemory(50); sprintf(attr, "%s%d", a, id); IupSetAttribute(ih, attr, v); } -void IupTreeStoreAttribute(Ihandle* ih, const char* a, int id, char* v) +void IupTreeSetAttributeHandle(Ihandle* ih, const char* a, int id, Ihandle* ih_named) +{ + char* attr = iupStrGetMemory(50); + sprintf(attr, "%s%d", a, id); + IupSetAttributeHandle(ih, attr, ih_named); +} + +void IupTreeStoreAttribute(Ihandle* ih, const char* a, int id, const char* v) { char* attr = iupStrGetMemory(50); sprintf(attr, "%s%d", a, id); @@ -454,7 +781,7 @@ float IupTreeGetFloat(Ihandle* ih, const char* a, int id) return IupGetFloat(ih, attr); } -void IupTreeSetfAttribute(Ihandle* ih, const char* a, int id, char* f, ...) +void IupTreeSetfAttribute(Ihandle* ih, const char* a, int id, const char* f, ...) { static char v[SHRT_MAX]; char* attr = iupStrGetMemory(50); @@ -466,34 +793,40 @@ void IupTreeSetfAttribute(Ihandle* ih, const char* a, int id, char* f, ...) IupStoreAttribute(ih, attr, v); } - /************************************************************************************/ - int IupTreeSetUserId(Ihandle* ih, int id, void* userdata) { - char attr[30]; - sprintf(attr,"USERDATA%d",id); - IupSetAttribute(ih, attr, userdata); - return IupGetAttribute(ih, attr)? 1: 0; + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return 0; + + if (id >= 0 && id < ih->data->node_count) + { + ih->data->node_cache[id].userdata = userdata; + return 1; + } + + return 0; } int IupTreeGetId(Ihandle* ih, void *userdata) { - int id = -1; - char* value; - char attr[30]; - sprintf(attr,"FINDUSERDATA:%p",userdata); - value = IupGetAttribute(ih, attr); - if (!value) return -1; + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return -1; - iupStrToInt(value, &id); - return id; + return iTreeFindUserDataId(ih, userdata); } void* IupTreeGetUserId(Ihandle* ih, int id) { - char attr[30]; - sprintf(attr,"USERDATA%d",id); - return IupGetAttribute(ih, attr); + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + if (id >= 0 && id < ih->data->node_count) + return ih->data->node_cache[id].userdata; + + return NULL; } diff --git a/iup/src/iup_tree.h b/iup/src/iup_tree.h index f96a698..44acc83 100755 --- a/iup/src/iup_tree.h +++ b/iup/src/iup_tree.h @@ -29,6 +29,36 @@ void iupdrvTreeUpdateMarkMode(Ihandle *ih); char* iupTreeGetSpacingAttrib(Ihandle* ih); +#if defined(GTK_MAJOR_VERSION) +typedef void InodeHandle; +#elif defined(XmVERSION) +typedef struct _WidgetRec InodeHandle; +#elif defined(WINVER) +typedef struct _TREEITEM InodeHandle; +#else +typedef struct _InodeData InodeHandle; +#endif + +typedef struct _InodeData +{ + InodeHandle* node_handle; + void* userdata; +} InodeData; + +typedef int (*iupTreeNodeFunc)(Ihandle* ih, InodeHandle* node_handle, int id, void* userdata); +int iupTreeForEach(Ihandle* ih, iupTreeNodeFunc func, void* userdata); +InodeHandle* iupTreeGetNode(Ihandle* ih, int id); +InodeHandle* iupTreeGetNodeFromString(Ihandle* ih, const char* name_id); +int iupTreeFindNodeId(Ihandle* ih, InodeHandle* node_handle); + +InodeHandle* iupdrvTreeGetFocusNode(Ihandle* ih); +int iupdrvTreeTotalChildCount(Ihandle* ih, InodeHandle* node_handle); +void iupTreeSelectLastCollapsedBranch(Ihandle* ih, int *last_id); + +void iupTreeDelFromCache(Ihandle* ih, int id, int count); +void iupTreeAddToCache(Ihandle* ih, int add, int kindPrev, InodeHandle* prevNode, InodeHandle* node_handle); +void iupTreeCopyMoveCache(Ihandle* ih, int id_src, int id_dst, int count, int is_copy); + /* Structure of the tree */ struct _IcontrolData { @@ -36,6 +66,7 @@ struct _IcontrolData add_expanded, show_dragdrop, show_rename, + stamp, /* GTK only */ spacing; void* def_image_leaf; /* Default image leaf */ @@ -44,9 +75,10 @@ struct _IcontrolData void* def_image_leaf_mask; /* Motif Only */ void* def_image_collapsed_mask; - void* def_image_expanded_mask; + void* def_image_expanded_mask; - int id_control; /* auxiliary variable for computing or finding the id of a node */ + InodeData *node_cache; + int node_cache_max, node_count; }; diff --git a/iup/src/iup_vbox.c b/iup/src/iup_vbox.c index f71aa51..23e8e3a 100755 --- a/iup/src/iup_vbox.c +++ b/iup/src/iup_vbox.c @@ -215,6 +215,13 @@ static void iVboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) else { int empty = (child->expand & IUP_EXPAND_H1)? empty_h1: ((child->expand & IUP_EXPAND_H0)? empty_h0: 0); + char* weigth_str = iupAttribGet(child, "EXPANDWEIGTH"); + if (weigth_str) + { + float weigth; + if (iupStrToFloat(weigth_str, &weigth)) + empty = iupROUND(empty * weigth); + } iupBaseSetCurrentSize(child, client_width, child->naturalheight+empty, shrink); } diff --git a/iup/src/iup_zbox.c b/iup/src/iup_zbox.c index 3f79892..dd4a0e4 100755 --- a/iup/src/iup_zbox.c +++ b/iup/src/iup_zbox.c @@ -210,7 +210,7 @@ static int iZboxSetVisibleAttrib(Ihandle* ih, const char* value) { if (iupObjectCheck(ih->data->value_handle)) IupSetAttribute(ih->data->value_handle, "VISIBLE", (char*)value); - return 0; + return 1; /* must be 1 to mark when set at the element */ } static void iZboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) @@ -368,8 +368,8 @@ Iclass* iupZboxGetClass(void) iupClassRegisterAttribute(ic, "VALUEPOS", iZboxGetValuePosAttrib, iZboxSetValuePosAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "VALUE_HANDLE", NULL, iZboxSetValueHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); - /* Intercept VISIBLE since ZBOX works showing and hidding its children */ - iupClassRegisterAttribute(ic, "VISIBLE", NULL, iZboxSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + /* Intercept VISIBLE since ZBOX works by showing and hidding its children */ + iupClassRegisterAttribute(ic, "VISIBLE", NULL, iZboxSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED); return ic; } diff --git a/iup/src/make_uname b/iup/src/make_uname index 7fec9f8..6542234 100755 --- a/iup/src/make_uname +++ b/iup/src/make_uname @@ -1,4 +1,4 @@ #This builds all the libraries of the folder for 1 uname -tecmake $1 $2 $3 $4 $5 $6 $7 +tecmake USE_MOTIF=Yes $1 $2 $3 $4 $5 $6 $7 tecmake USE_GTK=Yes $1 $2 $3 $4 $5 $6 $7 diff --git a/iup/src/mot/iupmot_button.c b/iup/src/mot/iupmot_button.c index 2d93588..f6e383f 100755 --- a/iup/src/mot/iupmot_button.c +++ b/iup/src/mot/iupmot_button.c @@ -112,8 +112,10 @@ static int motButtonSetPaddingAttrib(Ihandle* ih, const char* value) { XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, XmNmarginWidth, ih->data->horiz_padding, NULL); + return 0; } - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } static int motButtonSetBgColorAttrib(Ihandle* ih, const char* value) @@ -189,43 +191,43 @@ static int motButtonMapMethod(Ihandle* ih) if (value) { ih->data->type = IUP_BUTTON_IMAGE; - iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP); + iupMOT_SETARG(args, num_args, XmNlabelType, XmPIXMAP); } else { ih->data->type = IUP_BUTTON_TEXT; - iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); + iupMOT_SETARG(args, num_args, XmNlabelType, XmSTRING); } /* Core */ - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ /* Label */ - iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ - iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ - iupmotSetArg(args, num_args, XmNmarginWidth, 0); - iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ - iupmotSetArg(args, num_args, XmNmarginLeft, 0); - iupmotSetArg(args, num_args, XmNmarginBottom, 0); - iupmotSetArg(args, num_args, XmNmarginRight, 0); + iupMOT_SETARG(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ + iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNmarginTop, 0); /* no extra margins */ + iupMOT_SETARG(args, num_args, XmNmarginLeft, 0); + iupMOT_SETARG(args, num_args, XmNmarginBottom, 0); + iupMOT_SETARG(args, num_args, XmNmarginRight, 0); /* PushButton */ - iupmotSetArg(args, num_args, XmNfillOnArm, False); + iupMOT_SETARG(args, num_args, XmNfillOnArm, False); /* Primitive */ if (iupAttribGetBoolean(ih, "FOCUSONCLICK")) { if (iupAttribGetBoolean(ih, "CANFOCUS")) - iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); else - iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); } else - iupmotSetArg(args, num_args, XmNtraversalOn, False); - iupmotSetArg(args, num_args, XmNhighlightThickness, 2); - iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); + iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); ih->handle = XtCreateManagedWidget( iupDialogGetChildIdStr(ih), /* child identifier */ diff --git a/iup/src/mot/iupmot_canvas.c b/iup/src/mot/iupmot_canvas.c index 7777cf3..299bbcd 100755 --- a/iup/src/mot/iupmot_canvas.c +++ b/iup/src/mot/iupmot_canvas.c @@ -434,6 +434,10 @@ static void motCanvasLayoutUpdateMethod(Ihandle *ih) XtVaGetValues(sb_win, XmNborderWidth, &border, NULL); + /* avoid abort in X */ + if (ih->currentwidth <= 2*border) ih->currentwidth = 2*border+1; + if (ih->currentheight <= 2*border) ih->currentheight = 2*border+1; + XtVaSetValues(sb_win, XmNx, (XtArgVal)ih->x, XmNy, (XtArgVal)ih->y, @@ -458,19 +462,19 @@ static int motCanvasMapMethod(Ihandle* ih) /* Create the scrolled window */ /******************************/ - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); - iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); - iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and draw area */ - iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); + iupMOT_SETARG(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupMOT_SETARG(args, num_args, XmNspacing, 0); /* no space between scrollbars and draw area */ + iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); if (iupAttribGetBoolean(ih, "BORDER")) { - iupmotSetArg(args, num_args, XmNborderWidth, 1); - iupmotSetArg(args, num_args, XmNborderColor, iupmotColorGetPixelStr("0 0 0")); + iupMOT_SETARG(args, num_args, XmNborderWidth, 1); + iupMOT_SETARG(args, num_args, XmNborderColor, iupmotColorGetPixelStr("0 0 0")); } else - iupmotSetArg(args, num_args, XmNborderWidth, 0); + iupMOT_SETARG(args, num_args, XmNborderWidth, 0); sb_win = XtCreateManagedWidget( iupDialogGetChildIdStr(ih), /* child identifier */ @@ -488,36 +492,36 @@ static int motCanvasMapMethod(Ihandle* ih) /****************************/ num_args = 0; - iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ - iupmotSetArg(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ - iupmotSetArg(args, num_args, XmNshadowThickness, 0); - iupmotSetArg(args, num_args, XmNresizePolicy, XmRESIZE_NONE); /* no automatic resize of children */ + iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ + iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); + iupMOT_SETARG(args, num_args, XmNresizePolicy, XmRESIZE_NONE); /* no automatic resize of children */ if (ih->iclass->is_interactive) { - iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); /* include in navigation */ + iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); /* include in navigation */ if (iupAttribGetBoolean(ih, "CANFOCUS")) - iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); else - iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); } else { - iupmotSetArg(args, num_args, XmNnavigationType, XmNONE); - iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNnavigationType, XmNONE); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); } - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ visual = IupGetAttribute(ih, "VISUAL"); /* defined by the OpenGL Canvas or NULL */ if (visual) { Colormap colormap = (Colormap)iupAttribGet(ih, "COLORMAP"); if (colormap) - iupmotSetArg(args, num_args, XmNcolormap,colormap); + iupMOT_SETARG(args, num_args, XmNcolormap,colormap); iupmotDialogSetVisual(ih, visual); } diff --git a/iup/src/mot/iupmot_common.c b/iup/src/mot/iupmot_common.c index 7b3f8b7..286e075 100755 --- a/iup/src/mot/iupmot_common.c +++ b/iup/src/mot/iupmot_common.c @@ -167,6 +167,10 @@ void iupdrvBaseLayoutUpdateMethod(Ihandle *ih) Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); if (!widget) widget = ih->handle; + /* avoid abort in X */ + if (ih->currentwidth == 0) ih->currentwidth = 1; + if (ih->currentheight == 0) ih->currentheight = 1; + XtVaSetValues(widget, XmNx, (XtArgVal)ih->x, XmNy, (XtArgVal)ih->y, @@ -184,7 +188,7 @@ void iupdrvBaseUnMapMethod(Ihandle* ih) XtDestroyWidget(widget); /* To match the call to XtCreateManagedWidget */ } -void iupdrvDisplayUpdate(Ihandle *ih) +void iupdrvPostRedraw(Ihandle *ih) { XExposeEvent evt; Dimension w, h; @@ -209,12 +213,12 @@ void iupdrvDisplayUpdate(Ihandle *ih) XSendEvent(iupmot_display, XtWindow(ih->handle), False, ExposureMask, (XEvent*)&evt); } -void iupdrvDisplayRedraw(Ihandle *ih) +void iupdrvRedrawNow(Ihandle *ih) { Widget w; /* POST a Redraw */ - iupdrvDisplayUpdate(ih); + iupdrvPostRedraw(ih); /* if this element has an inner native parent (like IupTabs), then redraw that native parent if different from the element. */ @@ -223,7 +227,7 @@ void iupdrvDisplayRedraw(Ihandle *ih) { Widget handle = ih->handle; ih->handle = w; - iupdrvDisplayUpdate(ih); + iupdrvPostRedraw(ih); ih->handle = handle; } @@ -276,10 +280,11 @@ int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value) { if (iupdrvIsVisible(ih)) { + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); if (iupStrEqualNoCase(value, "TOP")) - XRaiseWindow(iupmot_display, XtWindow(ih->handle)); + XRaiseWindow(iupmot_display, XtWindow(widget)); else - XLowerWindow(iupmot_display, XtWindow(ih->handle)); + XLowerWindow(iupmot_display, XtWindow(widget)); } return 0; @@ -455,9 +460,11 @@ static Cursor motGetCursor(Ihandle* ih, const char* name) { "RESIZE_N", XC_top_side}, { "RESIZE_S", XC_bottom_side}, { "RESIZE_NS", XC_sb_v_double_arrow}, + { "SPLITTER_HORIZ", XC_sb_v_double_arrow}, { "RESIZE_W", XC_left_side}, { "RESIZE_E", XC_right_side}, { "RESIZE_WE", XC_sb_h_double_arrow}, + { "SPLITTER_VERT", XC_sb_h_double_arrow}, { "RESIZE_NE", XC_top_right_corner}, { "RESIZE_SE", XC_bottom_right_corner}, { "RESIZE_NW", XC_top_left_corner}, diff --git a/iup/src/mot/iupmot_dialog.c b/iup/src/mot/iupmot_dialog.c index 4eeb834..7a27d74 100755 --- a/iup/src/mot/iupmot_dialog.c +++ b/iup/src/mot/iupmot_dialog.c @@ -134,12 +134,13 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu static int native_border = 0; static int native_caption = 0; - int has_caption = iupAttribGetBoolean(ih, "MAXBOX") || - iupAttribGetBoolean(ih, "MINBOX") || - iupAttribGetBoolean(ih, "MENUBOX") || - IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ + int has_titlebar = iupAttribGetBoolean(ih, "RESIZE") || /* GTK and Motif only */ + iupAttribGetBoolean(ih, "MAXBOX") || + iupAttribGetBoolean(ih, "MINBOX") || + iupAttribGetBoolean(ih, "MENUBOX") || + IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ - int has_border = has_caption || + int has_border = has_titlebar || iupAttribGetBoolean(ih, "RESIZE") || iupAttribGetBoolean(ih, "BORDER"); @@ -155,7 +156,7 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu *border = win_border; *caption = 0; - if (has_caption) + if (has_titlebar) *caption = win_caption; if (!native_border && *border) @@ -181,7 +182,7 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu } *caption = 0; - if (has_caption) + if (has_titlebar) { if (native_caption) *caption = native_caption; @@ -853,6 +854,7 @@ static int motDialogMapMethod(Ihandle* ih) InativeHandle* parent; int mwm_decor = 0; int num_args = 0; + int has_titlebar = 0; Arg args[20]; if (iupAttribGetBoolean(ih, "DIALOGFRAME")) @@ -867,32 +869,46 @@ static int motDialogMapMethod(Ihandle* ih) /****************************/ if (iupAttribGet(ih, "TITLE")) - mwm_decor |= MWM_DECOR_TITLE; + has_titlebar = 1; if (iupAttribGetBoolean(ih, "MENUBOX")) - mwm_decor |= MWM_DECOR_MENU; + { + mwm_decor |= MWM_DECOR_MENU; + has_titlebar = 1; + } if (iupAttribGetBoolean(ih, "MINBOX")) - mwm_decor |= MWM_DECOR_MINIMIZE; + { + mwm_decor |= MWM_DECOR_MINIMIZE; + has_titlebar = 1; + } if (iupAttribGetBoolean(ih, "MAXBOX")) - mwm_decor |= MWM_DECOR_MAXIMIZE; + { + mwm_decor |= MWM_DECOR_MAXIMIZE; + has_titlebar = 1; + } if (iupAttribGetBoolean(ih, "RESIZE")) - mwm_decor |= MWM_DECOR_RESIZEH; - if (iupAttribGetBoolean(ih, "BORDER")) - mwm_decor |= MWM_DECOR_BORDER; - - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* so XtRealizeWidget will not show the dialog */ - iupmotSetArg(args, num_args, XmNdeleteResponse, XmDO_NOTHING); - iupmotSetArg(args, num_args, XmNallowShellResize, True); /* Used so the BulletinBoard can control the shell size */ - iupmotSetArg(args, num_args, XmNtitle, ""); - iupmotSetArg(args, num_args, XmNvisual, iupmot_visual); + { + mwm_decor |= MWM_DECOR_RESIZEH; + mwm_decor |= MWM_DECOR_BORDER; /* has_border */ + } + if (has_titlebar) + mwm_decor |= MWM_DECOR_TITLE; + if (iupAttribGetBoolean(ih, "BORDER") || has_titlebar) + mwm_decor |= MWM_DECOR_BORDER; /* has_border */ + + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* so XtRealizeWidget will not show the dialog */ + iupMOT_SETARG(args, num_args, XmNdeleteResponse, XmDO_NOTHING); + iupMOT_SETARG(args, num_args, XmNallowShellResize, True); /* Used so the BulletinBoard can control the shell size */ + iupMOT_SETARG(args, num_args, XmNtitle, ""); + iupMOT_SETARG(args, num_args, XmNvisual, iupmot_visual); if (iupmotColorMap()) - iupmotSetArg(args, num_args, XmNcolormap, iupmotColorMap()); + iupMOT_SETARG(args, num_args, XmNcolormap, iupmotColorMap()); if (mwm_decor != 0x7E) - iupmotSetArg(args, num_args, XmNmwmDecorations, mwm_decor); + iupMOT_SETARG(args, num_args, XmNmwmDecorations, mwm_decor); if (iupAttribGetBoolean(ih, "SAVEUNDER")) - iupmotSetArg(args, num_args, XmNsaveUnder, True); + iupMOT_SETARG(args, num_args, XmNsaveUnder, True); parent = iupDialogGetNativeParent(ih); if (parent) diff --git a/iup/src/mot/iupmot_draw.c b/iup/src/mot/iupmot_draw.c new file mode 100644 index 0000000..83a6d09 --- /dev/null +++ b/iup/src/mot/iupmot_draw.c @@ -0,0 +1,188 @@ +/** \file + * \brief Draw Functions + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> + +#include <Xm/Xm.h> +#include <X11/Xlib.h> + +#include "iup.h" + +#include "iup_attrib.h" +#include "iup_class.h" +#include "iup_str.h" +#include "iup_object.h" +#include "iup_image.h" +#include "iup_draw.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +struct _IdrawCanvas{ + Ihandle* ih; + int w, h; + + Window wnd; + Pixmap pixmap; + GC pixmap_gc, gc; +}; + +static void motDrawGetGeometry(Display *dpy, Drawable wnd, int *_w, int *_h, int *_d) +{ + Window root; + int x, y; + unsigned int w, h, b, d; + XGetGeometry(dpy, wnd, &root, &x, &y, &w, &h, &b, &d); + *_w = w; + *_h = h; + *_d = d; +} + +IdrawCanvas* iupDrawCreateCanvas(Ihandle* ih) +{ + IdrawCanvas* dc = calloc(1, sizeof(IdrawCanvas)); + int depth; + + dc->wnd = XtWindow(ih->handle); + dc->gc = XCreateGC(iupmot_display, dc->wnd, 0, NULL); + + motDrawGetGeometry(iupmot_display, dc->wnd, &dc->w, &dc->h, &depth); + + dc->pixmap = XCreatePixmap(iupmot_display, dc->wnd, dc->w, dc->h, depth); + dc->pixmap_gc = XCreateGC(iupmot_display, dc->pixmap, 0, NULL); + + return dc; +} + +void iupDrawKillCanvas(IdrawCanvas* dc) +{ + XFreeGC(iupmot_display, dc->pixmap_gc); + XFreePixmap(iupmot_display, dc->pixmap); + XFreeGC(iupmot_display, dc->gc); + + free(dc); +} + +void iupDrawUpdateSize(IdrawCanvas* dc) +{ + int w, h, depth; + motDrawGetGeometry(iupmot_display, dc->wnd, &w, &h, &depth); + + if (w != dc->w || h != dc->h) + { + XFreeGC(iupmot_display, dc->pixmap_gc); + XFreePixmap(iupmot_display, dc->pixmap); + + dc->pixmap = XCreatePixmap(iupmot_display, dc->wnd, dc->w, dc->h, depth); + dc->pixmap_gc = XCreateGC(iupmot_display, dc->pixmap, 0, NULL); + } +} + +void iupDrawFlush(IdrawCanvas* dc) +{ + XCopyArea(iupmot_display, dc->pixmap, dc->wnd, dc->gc, 0, 0, dc->w, dc->h, 0, 0); +} + +void iupDrawGetSize(IdrawCanvas* dc, int *w, int *h) +{ + if (w) *w = dc->w; + if (h) *h = dc->h; +} + +void iupDrawParentBackground(IdrawCanvas* dc) +{ + unsigned char r=0, g=0, b=0; + char* color = iupBaseNativeParentGetBgColorAttrib(dc->ih); + iupStrToRGB(color, &r, &g, &b); + iupDrawRectangle(dc, 0, 0, dc->w-1, dc->h-1, r, g, b, 1); +} + +void iupDrawRectangle(IdrawCanvas* dc, int x1, int y1, int x2, int y2, unsigned char r, unsigned char g, unsigned char b, int filled) +{ + XSetForeground(iupmot_display, dc->pixmap_gc, iupmotColorGetPixel(r, g, b)); + if (filled) + XFillRectangle(iupmot_display, dc->pixmap, dc->pixmap_gc, x1, y1, x2-x1+1, y2-y1+1); + else + XDrawRectangle(iupmot_display, dc->pixmap, dc->pixmap_gc, x1, y1, x2-x1+1, y2-y1+1); +} + +void iupDrawLine(IdrawCanvas* dc, int x1, int y1, int x2, int y2, unsigned char r, unsigned char g, unsigned char b) +{ + XSetForeground(iupmot_display, dc->pixmap_gc, iupmotColorGetPixel(r, g, b)); + XDrawLine(iupmot_display, dc->pixmap, dc->pixmap_gc, x1, y1, x2, y2); +} + +void iupDrawArc(IdrawCanvas* dc, int x1, int y1, int x2, int y2, double a1, double a2, unsigned char r, unsigned char g, unsigned char b, int filled) +{ + XSetForeground(iupmot_display, dc->pixmap_gc, iupmotColorGetPixel(r, g, b)); + if (filled) + { + XSetArcMode(iupmot_display, dc->pixmap_gc, ArcPieSlice); + XFillArc(iupmot_display, dc->pixmap, dc->pixmap_gc, x1, y1, x2-x1+1, y2-y1+1, iupROUND(a1*64), iupROUND((a2 - a1)*64)); + } + else + XDrawArc(iupmot_display, dc->pixmap, dc->pixmap_gc, x1, y1, x2-x1+1, y2-y1+1, iupROUND(a1*64), iupROUND((a2 - a1)*64)); +} + +void iupDrawPolygon(IdrawCanvas* dc, int* points, int count, unsigned char r, unsigned char g, unsigned char b, int filled) +{ + int i; + XPoint* pnt = (XPoint*)malloc(count*sizeof(XPoint)); /* XPoint uses short for coordinates */ + + for (i = 0; i < count; i++) + { + pnt[i].x = (short)points[2*i]; + pnt[i].y = (short)points[2*i+1]; + } + + XSetForeground(iupmot_display, dc->pixmap_gc, iupmotColorGetPixel(r, g, b)); + if (filled) + XFillPolygon(iupmot_display, dc->pixmap, dc->pixmap_gc, pnt, count, Complex, CoordModeOrigin); + else + XDrawLines(iupmot_display, dc->pixmap, dc->pixmap_gc, pnt, count, CoordModeOrigin); + + free(pnt); +} + +void iupDrawSetClipRect(IdrawCanvas* dc, int x1, int y1, int x2, int y2) +{ + XRectangle rect; + rect.x = (short)x1; + rect.y = (short)y1; + rect.width = (unsigned short)(x2-x1+1); + rect.height = (unsigned short)(y2-y1+1); + XSetClipRectangles(iupmot_display, dc->pixmap_gc, 0, 0, &rect, 1, Unsorted); +} + +void iupDrawResetClip(IdrawCanvas* dc) +{ + XSetClipMask(iupmot_display, dc->pixmap_gc, None); +} + +void iupDrawText(IdrawCanvas* dc, const char* text, int len, int x, int y, unsigned char r, unsigned char g, unsigned char b) +{ + XFontStruct* xfont = (XFontStruct*)IupGetAttribute(dc->ih, "XFONTSTRUCT"); + XSetForeground(iupmot_display, dc->pixmap_gc, iupmotColorGetPixel(r, g, b)); + XSetFont(iupmot_display, dc->pixmap_gc, xfont->fid); + XDrawString(iupmot_display, dc->pixmap, dc->pixmap_gc, x, y-xfont->ascent, text, len); +} + +void iupDrawImage(IdrawCanvas* dc, const char* name, int make_inactive, int x, int y) +{ + int img_w, img_h, bpp; + Pixmap pixmap = (Pixmap)iupImageGetImage(name, dc->ih, make_inactive); + if (!pixmap) + return; + + /* must use this info, since image can be a driver image loaded from resources */ + iupdrvImageGetInfo((void*)pixmap, &img_w, &img_h, &bpp); + + XCopyArea(iupmot_display, pixmap, dc->pixmap, dc->pixmap_gc, 0, 0, img_w, img_h, x, y); +} diff --git a/iup/src/mot/iupmot_drv.h b/iup/src/mot/iupmot_drv.h index 8a536ef..424ae9f 100755 --- a/iup/src/mot/iupmot_drv.h +++ b/iup/src/mot/iupmot_drv.h @@ -65,7 +65,7 @@ void iupmotGetWindowSize(Ihandle *ih, int *width, int *height); char* iupmotGetXWindowAttrib(Ihandle *ih); -#define iupmotSetArg(_a, _i, _n, _d) ((_a)[(_i)].name = (_n), (_a)[(_i)].value = (XtArgVal)(_d), (_i)++) +#define iupMOT_SETARG(_a, _i, _n, _d) ((_a)[(_i)].name = (_n), (_a)[(_i)].value = (XtArgVal)(_d), (_i)++) #ifdef __cplusplus diff --git a/iup/src/mot/iupmot_filedlg.c b/iup/src/mot/iupmot_filedlg.c index 768dd2b..0be6319 100755 --- a/iup/src/mot/iupmot_filedlg.c +++ b/iup/src/mot/iupmot_filedlg.c @@ -17,6 +17,7 @@ #include <Xm/DrawingA.h> #include <Xm/PushB.h> #include <Xm/Frame.h> +#include <Xm/List.h> #include "iup.h" #include "iupcbs.h" @@ -28,6 +29,7 @@ #include "iup_dialog.h" #include "iup_strmessage.h" #include "iup_drvinfo.h" +#include "iup_array.h" #include "iupmot_drv.h" @@ -87,14 +89,14 @@ static int motFileDlgCheckValue(Ihandle* ih, Widget w) return 0; } } - else + else if (!iupAttribGetBoolean(ih, "MULTIPLEFILES")) { if (iupdrvIsDirectory(value)) /* selected a directory */ { iupStrMessageShowError(ih, "IUP_INVALIDDIR"); return 0; } - else if (!iupdrvIsFile(value)) /* new file */ + else if (!iupdrvIsFile(value)) /* not a file == new file */ { value = iupAttribGet(ih, "ALLOWNEW"); if (!value) @@ -132,6 +134,51 @@ static void motFileDlgCBclose(Widget w, XtPointer client_data, XtPointer call_da iupAttribSetStr(ih, "_IUP_WM_DELETE", "1"); } +static int motFileDlgGetMultipleFiles(Ihandle* ih, const char* dir, Widget wList) +{ + int *pos, sel_count, dir_len; + int i, len, cur_len; + char *filename, *all_names; + Iarray* names_array; + XmString* items; + + if (!XmListGetSelectedPos(wList, &pos, &sel_count)) + return 0; + + names_array = iupArrayCreate(1024, 1); /* just set an initial size, but count is 0 */ + XtVaGetValues(wList, XmNitems, &items, NULL); + + cur_len = strlen(dir); + + all_names = iupArrayAdd(names_array, cur_len+1); + memcpy(all_names, dir, cur_len); + all_names[cur_len] = '|'; + dir_len = cur_len; + cur_len++; /* skip separator */ + + for (i = 0; i<sel_count; i++) + { + filename = iupmotConvertString(items[pos[i]-1]); /* XmListGetSelectedPos starts at 1 */ + len = strlen(filename)-dir_len; + + 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] = '|'; + } + + XtFree((char*)pos); + + cur_len = iupArrayCount(names_array); + all_names = iupArrayInc(names_array); + all_names[cur_len+1] = 0; + + iupAttribStoreStr(ih, "VALUE", all_names); + + iupArrayDestroy(names_array); + return 1; +} + static void motFileDlgCallback(Widget w, Ihandle* ih, XmFileSelectionBoxCallbackStruct* call_data) { (void)w; @@ -151,14 +198,38 @@ static void motFileDlgCallback(Widget w, Ihandle* ih, XmFileSelectionBoxCallback iupAttribSetStr(ih, "STATUS", "0"); iupAttribSetStr(ih, "FILEEXIST", NULL); } + else if (iupAttribGetBoolean(ih, "MULTIPLEFILES")) + { + Widget wList = XmFileSelectionBoxGetChild(w, XmDIALOG_LIST); + + /* VALUE obtained above contains exactly the DIRECTORY */ + char* dir = iupAttribGet(ih, "VALUE"); + int len = strlen(dir); + if (dir[len-1]=='/') dir[len-1] = 0; /* remove last '/' */ + iupAttribStoreStr(ih, "DIRECTORY", dir); + + if (!motFileDlgGetMultipleFiles(ih, iupAttribGet(ih, "DIRECTORY"), wList)) + { + iupStrMessageShowError(ih, "IUP_FILENOTEXIST"); + return; + } + + iupAttribSetStr(ih, "STATUS", "0"); + iupAttribSetStr(ih, "FILEEXIST", "YES"); + } else { IFnss file_cb = (IFnss)IupGetCallback(ih, "FILE_CB"); - if (file_cb && file_cb(ih, iupAttribGet(ih, "VALUE"), "OK") == IUP_IGNORE) + filename = iupAttribGet(ih, "VALUE"); + if (file_cb && file_cb(ih, filename, "OK") == IUP_IGNORE) return; - if (iupdrvIsFile(iupAttribGet(ih, "VALUE"))) /* check if file exists */ + if (iupdrvIsFile(filename)) /* check if file exists */ { + char* dir = iupStrFileGetPath(filename); + iupAttribStoreStr(ih, "DIRECTORY", dir); + free(dir); + iupAttribSetStr(ih, "FILEEXIST", "YES"); iupAttribSetStr(ih, "STATUS", "0"); } @@ -188,9 +259,8 @@ static void motFileDlgCallback(Widget w, Ihandle* ih, XmFileSelectionBoxCallback } } -static void motFileDlgHelpCallback(Widget w, XtPointer client_data, XtPointer call_data) +static void motFileDlgHelpCallback(Widget w, Ihandle *ih, XtPointer call_data) { - Ihandle *ih = (Ihandle*)client_data; Icallback cb = IupGetCallback(ih, "HELP_CB"); if (cb && cb(ih) == IUP_CLOSE) { @@ -340,14 +410,15 @@ static void motFileDlgPreviewCanvasExposeCallback(Widget w, Ihandle *ih, XtPoint static void motFileDlgBrowseSelectionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* list_data) { char* filename; + IFnss cb; XmStringGetLtoR(list_data->item, XmSTRING_DEFAULT_CHARSET, &filename); + cb = (IFnss)IupGetCallback(ih, "FILE_CB"); if (iupdrvIsFile(filename)) - { - IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); cb(ih, filename, "SELECT"); - } + else + cb(ih, filename, "OTHER"); XtFree(filename); (void)w; @@ -417,6 +488,13 @@ static int motFileDlgPopup(Ihandle* ih, int x, int y) if (dialogtype == IUP_DIALOGDIR) XtVaSetValues(filebox, XmNfileTypeMask, XmFILE_DIRECTORY, NULL); + if (iupAttribGetBoolean(ih, "MULTIPLEFILES")) + { + Widget wList = XmFileSelectionBoxGetChild(filebox, XmDIALOG_LIST); + XtVaSetValues(wList, XmNselectionPolicy, XmEXTENDED_SELECT, NULL); + XtAddCallback(wList, XmNextendedSelectionCallback, (XtCallbackProc)motFileDlgBrowseSelectionCallback, (XtPointer)ih); + } + /* just check for the path inside FILE */ value = iupAttribGet(ih, "FILE"); if (value && value[0] == '/') @@ -501,8 +579,10 @@ static int motFileDlgPopup(Ihandle* ih, int x, int y) file_cb = (IFnss)IupGetCallback(ih, "FILE_CB"); if (file_cb) { - Widget file_list = XmFileSelectionBoxGetChild(filebox, XmDIALOG_LIST); - XtAddCallback(file_list, XmNbrowseSelectionCallback, (XtCallbackProc)motFileDlgBrowseSelectionCallback, (XtPointer)ih); + Widget list = XmFileSelectionBoxGetChild(filebox, XmDIALOG_LIST); + XtAddCallback(list, XmNbrowseSelectionCallback, (XtCallbackProc)motFileDlgBrowseSelectionCallback, (XtPointer)ih); + list = XmFileSelectionBoxGetChild(filebox, XmDIALOG_DIR_LIST); + XtAddCallback(list, XmNbrowseSelectionCallback, (XtCallbackProc)motFileDlgBrowseSelectionCallback, (XtPointer)ih); if (iupAttribGetBoolean(ih, "SHOWPREVIEW")) { @@ -575,4 +655,6 @@ static int motFileDlgPopup(Ihandle* ih, int x, int y) void iupdrvFileDlgInitClass(Iclass* ic) { ic->DlgPopup = motFileDlgPopup; + + iupClassRegisterAttribute(ic, "MULTIPLEFILES", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); } diff --git a/iup/src/mot/iupmot_font.c b/iup/src/mot/iupmot_font.c index 8da06dd..42154b6 100755 --- a/iup/src/mot/iupmot_font.c +++ b/iup/src/mot/iupmot_font.c @@ -135,19 +135,19 @@ static XmFontList motFontCreateRenderTable(XFontStruct* fontstruct, int is_under Arg args[10]; int num_args = 0; - iupmotSetArg(args, num_args, XmNfontType, XmFONT_IS_FONT); - iupmotSetArg(args, num_args, XmNfont, (XtPointer)fontstruct); - iupmotSetArg(args, num_args, XmNloadModel, XmLOAD_IMMEDIATE); + iupMOT_SETARG(args, num_args, XmNfontType, XmFONT_IS_FONT); + iupMOT_SETARG(args, num_args, XmNfont, (XtPointer)fontstruct); + iupMOT_SETARG(args, num_args, XmNloadModel, XmLOAD_IMMEDIATE); if (is_underline) - iupmotSetArg(args, num_args, XmNunderlineType, XmSINGLE_LINE); + iupMOT_SETARG(args, num_args, XmNunderlineType, XmSINGLE_LINE); else - iupmotSetArg(args, num_args, XmNunderlineType, XmNO_LINE); + iupMOT_SETARG(args, num_args, XmNunderlineType, XmNO_LINE); if (is_strikeout) - iupmotSetArg(args, num_args, XmNstrikethruType, XmSINGLE_LINE); + iupMOT_SETARG(args, num_args, XmNstrikethruType, XmSINGLE_LINE); else - iupmotSetArg(args, num_args, XmNstrikethruType, XmNO_LINE); + iupMOT_SETARG(args, num_args, XmNstrikethruType, XmNO_LINE); rendition = XmRenditionCreate(NULL, "", args, num_args); diff --git a/iup/src/mot/iupmot_frame.c b/iup/src/mot/iupmot_frame.c index 39de5d8..cfda44f 100755 --- a/iup/src/mot/iupmot_frame.c +++ b/iup/src/mot/iupmot_frame.c @@ -42,22 +42,33 @@ static int motFrameSetBgColorAttrib(Ihandle* ih, const char* value) { Pixel color; - /* ignore given value, must use only from parent */ - value = iupBaseNativeParentGetBgColor(ih); + if (!iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) + { + /* ignore given value, must use only from parent */ + value = iupBaseNativeParentGetBgColor(ih); + } color = iupmotColorGetPixelStr(value); if (color != (Pixel)-1) { Widget title_label, child_manager; - iupmotSetBgColor(ih->handle, color); + if (!iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) + { + iupmotSetBgColor(ih->handle, color); - child_manager = XtNameToWidget(ih->handle, "*child_manager"); - iupmotSetBgColor(child_manager, color); + child_manager = XtNameToWidget(ih->handle, "*child_manager"); + iupmotSetBgColor(child_manager, color); - title_label = XtNameToWidget(ih->handle, "*title_label"); - if (!title_label) return 1; - iupmotSetBgColor(title_label, color); + title_label = XtNameToWidget(ih->handle, "*title_label"); + if (!title_label) return 1; + iupmotSetBgColor(title_label, color); + } + else + { + child_manager = XtNameToWidget(ih->handle, "*child_manager"); + iupmotSetBgColor(child_manager, color); + } return 1; } @@ -171,22 +182,25 @@ static int motFrameMapMethod(Ihandle* ih) { char* value = iupAttribGetStr(ih, "SUNKEN"); if (iupStrBoolean(value)) - iupmotSetArg(args, num_args, XmNshadowType, XmSHADOW_IN); + iupMOT_SETARG(args, num_args, XmNshadowType, XmSHADOW_IN); else - iupmotSetArg(args, num_args, XmNshadowType, XmSHADOW_ETCHED_IN); + iupMOT_SETARG(args, num_args, XmNshadowType, XmSHADOW_ETCHED_IN); + + if (iupAttribGet(ih, "BGCOLOR")) + iupAttribSetStr(ih, "_IUPFRAME_HAS_BGCOLOR", "1"); } /* Core */ - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ /* Manager */ - iupmotSetArg(args, num_args, XmNshadowThickness, 2); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); /* Frame */ - iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ - iupmotSetArg(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ + iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ ih->handle = XtCreateManagedWidget( iupDialogGetChildIdStr(ih), /* child identifier */ @@ -204,11 +218,11 @@ static int motFrameMapMethod(Ihandle* ih) Widget title_label; num_args = 0; /* Label */ - iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); - iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ - iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNlabelType, XmSTRING); + iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); /* Frame Constraint */ - iupmotSetArg(args, num_args, XmNchildType, XmFRAME_TITLE_CHILD); + iupMOT_SETARG(args, num_args, XmNchildType, XmFRAME_TITLE_CHILD); title_label = XtCreateManagedWidget("title_label", xmLabelWidgetClass, ih->handle, args, num_args); iupmotSetString(title_label, XmNlabelString, title); } diff --git a/iup/src/mot/iupmot_key.c b/iup/src/mot/iupmot_key.c index 835b5d7..9897741 100755 --- a/iup/src/mot/iupmot_key.c +++ b/iup/src/mot/iupmot_key.c @@ -393,33 +393,33 @@ void iupmotKeyPressEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) void iupmotButtonKeySetStatus(unsigned int state, unsigned int but, char* status, int doubleclick) { if (state & ShiftMask) - iupKEYSETSHIFT(status); + iupKEY_SETSHIFT(status); if (state & ControlMask) - iupKEYSETCONTROL(status); + iupKEY_SETCONTROL(status); if ((state & Button1Mask) || but==Button1) - iupKEYSETBUTTON1(status); + iupKEY_SETBUTTON1(status); if ((state & Button2Mask) || but==Button2) - iupKEYSETBUTTON2(status); + iupKEY_SETBUTTON2(status); if ((state & Button3Mask) || but==Button3) - iupKEYSETBUTTON3(status); + iupKEY_SETBUTTON3(status); if ((state & Button4Mask) || but==Button4) - iupKEYSETBUTTON4(status); + iupKEY_SETBUTTON4(status); if ((state & Button5Mask) || but==Button5) - iupKEYSETBUTTON5(status); + iupKEY_SETBUTTON5(status); if (state & Mod1Mask || state & Mod5Mask) /* Alt */ - iupKEYSETALT(status); + iupKEY_SETALT(status); if (state & Mod4Mask) /* Apple/Win */ - iupKEYSETSYS(status); + iupKEY_SETSYS(status); if (doubleclick) - iupKEYSETDOUBLE(status); + iupKEY_SETDOUBLE(status); } diff --git a/iup/src/mot/iupmot_label.c b/iup/src/mot/iupmot_label.c index 52dfc9a..afff3c3 100755 --- a/iup/src/mot/iupmot_label.c +++ b/iup/src/mot/iupmot_label.c @@ -147,8 +147,10 @@ static int motLabelSetPaddingAttrib(Ihandle* ih, const char* value) { XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, XmNmarginWidth, ih->data->horiz_padding, NULL); + return 0; } - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } static int motLabelMapMethod(Ihandle* ih) @@ -165,12 +167,12 @@ static int motLabelMapMethod(Ihandle* ih) if (iupStrEqualNoCase(value, "HORIZONTAL")) { ih->data->type = IUP_LABEL_SEP_HORIZ; - iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); + iupMOT_SETARG(args, num_args, XmNorientation, XmHORIZONTAL); } else /* "VERTICAL" */ { ih->data->type = IUP_LABEL_SEP_VERT; - iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); + iupMOT_SETARG(args, num_args, XmNorientation, XmVERTICAL); } } else @@ -180,32 +182,32 @@ static int motLabelMapMethod(Ihandle* ih) if (value) { ih->data->type = IUP_LABEL_IMAGE; - iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP); + iupMOT_SETARG(args, num_args, XmNlabelType, XmPIXMAP); } else { ih->data->type = IUP_LABEL_TEXT; - iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); + iupMOT_SETARG(args, num_args, XmNlabelType, XmSTRING); } } /* Core */ - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ /* Primitive */ - iupmotSetArg(args, num_args, XmNtraversalOn, False); - iupmotSetArg(args, num_args, XmNhighlightThickness, 0); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNhighlightThickness, 0); /* Label */ - iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ - iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ - iupmotSetArg(args, num_args, XmNmarginWidth, 0); - iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ - iupmotSetArg(args, num_args, XmNmarginLeft, 0); - iupmotSetArg(args, num_args, XmNmarginBottom, 0); - iupmotSetArg(args, num_args, XmNmarginRight, 0); + iupMOT_SETARG(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ + iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNmarginTop, 0); /* no extra margins */ + iupMOT_SETARG(args, num_args, XmNmarginLeft, 0); + iupMOT_SETARG(args, num_args, XmNmarginBottom, 0); + iupMOT_SETARG(args, num_args, XmNmarginRight, 0); ih->handle = XtCreateManagedWidget( iupDialogGetChildIdStr(ih), /* child identifier */ diff --git a/iup/src/mot/iupmot_list.c b/iup/src/mot/iupmot_list.c index f8e73ed..800e6e9 100755 --- a/iup/src/mot/iupmot_list.c +++ b/iup/src/mot/iupmot_list.c @@ -143,15 +143,36 @@ void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value) motListAddSortedItem(ih, value); else motListAddItem(ih, pos, value); + + iupListUpdateOldValue(ih, pos, 0); } void iupdrvListRemoveItem(Ihandle* ih, int pos) { /* The utility functions use 0=last 1=first */ if (ih->data->is_dropdown || ih->data->has_editbox) + { + if (ih->data->is_dropdown && !ih->data->has_editbox) + { + /* must check if removing the current item */ + int curpos; + XtVaGetValues(ih->handle, XmNselectedPosition, &curpos, NULL); + if (pos == curpos && iupdrvListGetCount(ih)>1) + { + if (curpos > 0) curpos--; + else curpos++; + + XtRemoveCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih); + XtVaSetValues(ih->handle, XmNselectedPosition, curpos, NULL); + XtAddCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih); + } + } XmComboBoxDeletePos(ih->handle, pos+1); + } else XmListDeletePos(ih->handle, pos+1); + + iupListUpdateOldValue(ih, pos, 1); } void iupdrvListRemoveAllItems(Ihandle* ih) @@ -174,7 +195,7 @@ void iupdrvListRemoveAllItems(Ihandle* ih) static char* motListGetIdValueAttrib(Ihandle* ih, const char* name_id) { int pos = iupListGetPos(ih, name_id); - if (pos != -1) + if (pos >= 0) { XmString* items; XtVaGetValues(ih->handle, XmNitems, &items, NULL); @@ -852,8 +873,10 @@ static int motListSetNCAttrib(Ihandle* ih, const char* value) Widget cbedit; XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); XtVaSetValues(cbedit, XmNmaxLength, ih->data->nc, NULL); + return 0; } - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } static int motListSetClipboardAttrib(Ihandle *ih, const char *value) @@ -1181,32 +1204,32 @@ static int motListMapMethod(Ihandle* ih) if (ih->data->is_dropdown || ih->data->has_editbox) { /* could not set XmNmappedWhenManaged to False because the list and the edit box where not displayed */ - /* iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); */ - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ - iupmotSetArg(args, num_args, XmNmarginHeight, 0); - iupmotSetArg(args, num_args, XmNmarginWidth, 0); + /* iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); if (iupAttribGetBoolean(ih, "CANFOCUS")) - iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); else - iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); - iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); - iupmotSetArg(args, num_args, XmNhighlightThickness, 2); - iupmotSetArg(args, num_args, XmNshadowThickness, 2); + iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); if (ih->data->has_editbox) { if (ih->data->is_dropdown) - iupmotSetArg(args, num_args, XmNcomboBoxType, XmDROP_DOWN_COMBO_BOX); /* hidden-list+edit */ + iupMOT_SETARG(args, num_args, XmNcomboBoxType, XmDROP_DOWN_COMBO_BOX); /* hidden-list+edit */ else - iupmotSetArg(args, num_args, XmNcomboBoxType, XmCOMBO_BOX); /* visible-list+edit */ + iupMOT_SETARG(args, num_args, XmNcomboBoxType, XmCOMBO_BOX); /* visible-list+edit */ } else - iupmotSetArg(args, num_args, XmNcomboBoxType, XmDROP_DOWN_LIST); /* hidden-list */ + iupMOT_SETARG(args, num_args, XmNcomboBoxType, XmDROP_DOWN_LIST); /* hidden-list */ ih->handle = XtCreateManagedWidget( child_id, /* child identifier */ @@ -1220,13 +1243,13 @@ static int motListMapMethod(Ihandle* ih) /* Create the scrolled window */ - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); - iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); - iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ - iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ - iupmotSetArg(args, num_args, XmNborderWidth, 0); - iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); + iupMOT_SETARG(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupMOT_SETARG(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ + iupMOT_SETARG(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ + iupMOT_SETARG(args, num_args, XmNborderWidth, 0); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); sb_win = XtCreateManagedWidget( child_id, /* child identifier */ @@ -1243,34 +1266,34 @@ static int motListMapMethod(Ihandle* ih) /* Create the list */ num_args = 0; - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ if (iupAttribGetBoolean(ih, "CANFOCUS")) - iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); else - iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); - iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); - iupmotSetArg(args, num_args, XmNhighlightThickness, 2); - iupmotSetArg(args, num_args, XmNshadowThickness, 2); + iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); - iupmotSetArg(args, num_args, XmNlistMarginHeight, 0); /* default padding */ - iupmotSetArg(args, num_args, XmNlistMarginWidth, 0); - iupmotSetArg(args, num_args, XmNlistSpacing, 0); - iupmotSetArg(args, num_args, XmNlistSizePolicy, XmCONSTANT); /* don't grow to fit, add scrollbar */ + iupMOT_SETARG(args, num_args, XmNlistMarginHeight, 0); /* default padding */ + iupMOT_SETARG(args, num_args, XmNlistMarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNlistSpacing, 0); + iupMOT_SETARG(args, num_args, XmNlistSizePolicy, XmCONSTANT); /* don't grow to fit, add scrollbar */ if (ih->data->is_multiple) - iupmotSetArg(args, num_args, XmNselectionPolicy, XmEXTENDED_SELECT); + iupMOT_SETARG(args, num_args, XmNselectionPolicy, XmEXTENDED_SELECT); else - iupmotSetArg(args, num_args, XmNselectionPolicy, XmBROWSE_SELECT); + iupMOT_SETARG(args, num_args, XmNselectionPolicy, XmBROWSE_SELECT); if (iupAttribGetBoolean(ih, "AUTOHIDE")) - iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); + iupMOT_SETARG(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); else - iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); + iupMOT_SETARG(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); ih->handle = XtCreateManagedWidget( child_id, /* child identifier */ diff --git a/iup/src/mot/iupmot_loop.c b/iup/src/mot/iupmot_loop.c index 828ddcd..c1f92ec 100755 --- a/iup/src/mot/iupmot_loop.c +++ b/iup/src/mot/iupmot_loop.c @@ -56,7 +56,7 @@ void iupdrvSetIdleFunction(Icallback f) mot_idle_id = XtAppAddWorkProc(iupmot_appcontext, motIdlecbWorkProc, NULL); } -static int motLoopStep(void) +static int motLoopProcessEvent(void) { XtAppProcessEvent(iupmot_appcontext, XtIMAll); return (mot_exitmainloop)? IUP_CLOSE : IUP_DEFAULT; @@ -79,7 +79,7 @@ int IupMainLoop(void) while (!mot_exitmainloop) { - if (motLoopStep() == IUP_CLOSE) + if (motLoopProcessEvent() == IUP_CLOSE) break; } @@ -88,19 +88,26 @@ int IupMainLoop(void) return IUP_NOERROR; } +int IupLoopStepWait(void) +{ + while(!XtAppPending(iupmot_appcontext)); + + return motLoopProcessEvent(); +} + int IupLoopStep(void) { if (!XtAppPending(iupmot_appcontext)) return IUP_DEFAULT; - return motLoopStep(); + return motLoopProcessEvent(); } void IupFlush(void) { while (XPending(iupmot_display) != 0) { - if (motLoopStep() == IUP_CLOSE) + if (motLoopProcessEvent() == IUP_CLOSE) break; } diff --git a/iup/src/mot/iupmot_menu.c b/iup/src/mot/iupmot_menu.c index be9b953..8f51334 100755 --- a/iup/src/mot/iupmot_menu.c +++ b/iup/src/mot/iupmot_menu.c @@ -125,7 +125,10 @@ static void motPopupMenuUnmapCallback(Widget w, Ihandle* ih, XtPointer call_data static void motMenuUnMapMethod(Ihandle* ih) { if (iupMenuIsMenuBar(ih)) + { XtDestroyWidget(ih->handle); + ih->parent = NULL; + } else XtDestroyWidget(XtParent(ih->handle)); /* in this case the RowColumn widget is a child of a MenuShell. */ } @@ -146,7 +149,6 @@ static int motMenuMapMethod(Ihandle* ih) XmNrowColumnType, XmMENU_BAR, XmNmarginHeight, 0, XmNmarginWidth, 0, - XmNresizeWidth, False, NULL); if (!ih->handle) return IUP_ERROR; @@ -161,8 +163,8 @@ static int motMenuMapMethod(Ihandle* ih) if (iupAttribGetBoolean(ih, "RADIO")) { - iupmotSetArg(args, num_args, XmNpacking, XmPACK_COLUMN); - iupmotSetArg(args, num_args, XmNradioBehavior, TRUE); + iupMOT_SETARG(args, num_args, XmNpacking, XmPACK_COLUMN); + iupMOT_SETARG(args, num_args, XmNradioBehavior, TRUE); } ih->handle = XmCreatePulldownMenu( @@ -183,7 +185,7 @@ static int motMenuMapMethod(Ihandle* ih) { /* top level menu used for IupPopup */ - iupmotSetArg(args, num_args, XmNpopupEnabled, XmPOPUP_AUTOMATIC); + iupMOT_SETARG(args, num_args, XmNpopupEnabled, XmPOPUP_AUTOMATIC); ih->handle = XmCreatePopupMenu( iupmot_appshell, @@ -307,19 +309,19 @@ static int motItemMapMethod(Ihandle* ih) if (iupAttribGetBoolean(ih->parent, "RADIO")) { - iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); - iupmotSetArg(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); - iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); - iupmotSetArg(args, num_args, XmNindicatorSize, 13); - iupmotSetArg(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); + iupMOT_SETARG(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); + iupMOT_SETARG(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); + iupMOT_SETARG(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); + iupMOT_SETARG(args, num_args, XmNindicatorSize, 13); + iupMOT_SETARG(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); } else { if (iupAttribGetBoolean(ih, "HIDEMARK")) - iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); + iupMOT_SETARG(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); else - iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK); - iupmotSetArg(args, num_args, XmNlabelType, iupAttribGet(ih, "TITLEIMAGE")? XmPIXMAP: XmSTRING); + iupMOT_SETARG(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK); + iupMOT_SETARG(args, num_args, XmNlabelType, iupAttribGet(ih, "TITLEIMAGE")? XmPIXMAP: XmSTRING); } ih->handle = XtCreateManagedWidget( diff --git a/iup/src/mot/iupmot_progressbar.c b/iup/src/mot/iupmot_progressbar.c index 7266d38..82fa178 100755 --- a/iup/src/mot/iupmot_progressbar.c +++ b/iup/src/mot/iupmot_progressbar.c @@ -98,25 +98,25 @@ static int motProgressBarMapMethod(Ihandle* ih) Arg args[30]; /* Core */ - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ /* Primitive */ - iupmotSetArg(args, num_args, XmNtraversalOn, False); - iupmotSetArg(args, num_args, XmNhighlightThickness, 0); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNhighlightThickness, 0); /* Scale */ - iupmotSetArg(args, num_args, XmNminimum, 0); - iupmotSetArg(args, num_args, XmNmaximum, SHRT_MAX); - iupmotSetArg(args, num_args, XmNslidingMode, XmTHERMOMETER); /* thermometer effect */ - iupmotSetArg(args, num_args, XmNsliderMark, XmNONE); - iupmotSetArg(args, num_args, XmNeditable, False); - iupmotSetArg(args, num_args, XmNshowValue, XmNONE); + iupMOT_SETARG(args, num_args, XmNminimum, 0); + iupMOT_SETARG(args, num_args, XmNmaximum, SHRT_MAX); + iupMOT_SETARG(args, num_args, XmNslidingMode, XmTHERMOMETER); /* thermometer effect */ + iupMOT_SETARG(args, num_args, XmNsliderMark, XmNONE); + iupMOT_SETARG(args, num_args, XmNeditable, False); + iupMOT_SETARG(args, num_args, XmNshowValue, XmNONE); if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL")) { - iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); + iupMOT_SETARG(args, num_args, XmNorientation, XmVERTICAL); if (ih->currentheight < ih->currentwidth) { @@ -126,7 +126,7 @@ static int motProgressBarMapMethod(Ihandle* ih) } } else - iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); + iupMOT_SETARG(args, num_args, XmNorientation, XmHORIZONTAL); ih->handle = XtCreateManagedWidget( iupDialogGetChildIdStr(ih), /* child identifier */ diff --git a/iup/src/mot/iupmot_tabs.c b/iup/src/mot/iupmot_tabs.c index 7c8a6b5..cafc41d 100755 --- a/iup/src/mot/iupmot_tabs.c +++ b/iup/src/mot/iupmot_tabs.c @@ -52,8 +52,10 @@ void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos) { Ihandle* child = IupGetChild(ih, pos); Ihandle* prev_child = IupGetChild(ih, iupdrvTabsGetCurrentTab(ih)); - IupSetAttribute(child, "VISIBLE", "YES"); - IupSetAttribute(prev_child, "VISIBLE", "NO"); + Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); + Widget prev_child_manager = (Widget)iupAttribGet(prev_child, "_IUPTAB_CONTAINER"); + XtMapWidget(child_manager); + if (prev_child_manager) XtUnmapWidget(prev_child_manager); XtVaSetValues(ih->handle, XmNcurrentPageNumber, pos, NULL); } @@ -200,7 +202,7 @@ static int motTabsSetTabTypeAttrib(Ihandle* ih, const char* value) ih->data->type = ITABS_TOP; if (ih->handle) - motTabsUpdateTabType(ih); + motTabsUpdateTabType(ih); /* for this to work must be updated in map */ return 0; } @@ -313,8 +315,10 @@ void motTabsPageChangedCallback(Widget w, Ihandle* ih, XmNotebookCallbackStruct IFnnn cb; Ihandle* child = IupGetChild(ih, nptr->page_number); Ihandle* prev_child = IupGetChild(ih, nptr->prev_page_number); - IupSetAttribute(child, "VISIBLE", "YES"); - IupSetAttribute(prev_child, "VISIBLE", "NO"); + Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); + Widget prev_child_manager = (Widget)iupAttribGet(prev_child, "_IUPTAB_CONTAINER"); + XtMapWidget(child_manager); + if (prev_child_manager) XtUnmapWidget(prev_child_manager); cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB"); if (cb) @@ -397,12 +401,12 @@ static void motTabsChildAddedMethod(Ihandle* ih, Ihandle* child) /* Create tabs */ /* Label */ - iupmotSetArg(args, num_args, XmNlabelType, tabtitle? XmSTRING: XmPIXMAP); - iupmotSetArg(args, num_args, XmNmarginHeight, 0); - iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNlabelType, tabtitle? XmSTRING: XmPIXMAP); + iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); /* Notebook Constraint */ - iupmotSetArg(args, num_args, XmNnotebookChildType, XmMAJOR_TAB); - iupmotSetArg(args, num_args, XmNpageNumber, pos); + iupMOT_SETARG(args, num_args, XmNnotebookChildType, XmMAJOR_TAB); + iupMOT_SETARG(args, num_args, XmNpageNumber, pos); tab_button = XtCreateManagedWidget("tab_button", xmPushButtonWidgetClass, ih->handle, args, num_args); /* Disable Drag Source */ @@ -450,10 +454,8 @@ static void motTabsChildAddedMethod(Ihandle* ih, Ihandle* child) iupAttribSetStr(child, "_IUPMOT_TABBUTTON", (char*)tab_button); iupAttribSetInt(child, "_IUPMOT_TABNUMBER", pos); - if (pos == iupdrvTabsGetCurrentTab(ih)) - IupSetAttribute(child, "VISIBLE", "YES"); - else - IupSetAttribute(child, "VISIBLE", "NO"); + if (pos != iupdrvTabsGetCurrentTab(ih)) + XtUnmapWidget(child_manager); } } @@ -464,20 +466,11 @@ static void motTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); if (child_manager) { - int cur_pos, pos; + int pos; Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); - cur_pos = iupdrvTabsGetCurrentTab(ih); pos = iupAttribGetInt(child, "_IUPMOT_TABNUMBER"); /* did not work when using XtVaGetValues(child_manager, XmNpageNumber) */ - if (cur_pos == pos) - { - if (cur_pos == 0) - cur_pos = 1; - else - cur_pos--; - - iupdrvTabsSetCurrentTab(ih, cur_pos); - } + iupTabsTestRemoveTab(ih, pos); XtDestroyWidget(tab_button); XtDestroyWidget(child_manager); @@ -501,22 +494,22 @@ static int motTabsMapMethod(Ihandle* ih) return IUP_ERROR; /* Core */ - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ /* Manager */ - iupmotSetArg(args, num_args, XmNshadowThickness, 0); - iupmotSetArg(args, num_args, XmNtraversalOn, True); - iupmotSetArg(args, num_args, XmNhighlightThickness, 0); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNhighlightThickness, 0); /* Notebook */ - iupmotSetArg(args, num_args, XmNbindingType, XmNONE); - iupmotSetArg(args, num_args, XmNbindingWidth, 0); - iupmotSetArg(args, num_args, XmNfirstPageNumber, 0); /* IupTabs index always starts with zero */ - iupmotSetArg(args, num_args, XmNbackPageSize, 0); - iupmotSetArg(args, num_args, XmNbackPageNumber, 1); - iupmotSetArg(args, num_args, XmNframeShadowThickness, 2); + iupMOT_SETARG(args, num_args, XmNbindingType, XmNONE); + iupMOT_SETARG(args, num_args, XmNbindingWidth, 0); + iupMOT_SETARG(args, num_args, XmNfirstPageNumber, 0); /* IupTabs index always starts with zero */ + iupMOT_SETARG(args, num_args, XmNbackPageSize, 0); + iupMOT_SETARG(args, num_args, XmNbackPageNumber, 1); + iupMOT_SETARG(args, num_args, XmNframeShadowThickness, 2); ih->handle = XtCreateManagedWidget( iupDialogGetChildIdStr(ih), /* child identifier */ @@ -589,5 +582,5 @@ void iupdrvTabsInitClass(Iclass* ic) iupClassRegisterAttribute(ic, "TABORIENTATION", iupTabsGetTabOrientationAttrib, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* can not be set, always HORIZONTAL in Motif */ iupClassRegisterAttributeId(ic, "TABTITLE", NULL, motTabsSetTabTitleAttrib, IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, motTabsSetTabImageAttrib, IUPAF_NO_INHERIT); - iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, motTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, motTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); } diff --git a/iup/src/mot/iupmot_text.c b/iup/src/mot/iupmot_text.c index 4a8f936..d9d2c74 100755 --- a/iup/src/mot/iupmot_text.c +++ b/iup/src/mot/iupmot_text.c @@ -142,8 +142,10 @@ static int motTextSetPaddingAttrib(Ihandle* ih, const char* value) { XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, XmNmarginWidth, ih->data->horiz_padding, NULL); + return 0; } - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } static int motTextSetReadOnlyAttrib(Ihandle* ih, const char* value) @@ -164,7 +166,7 @@ static char* motTextGetReadOnlyAttrib(Ihandle* ih) static int motTextSetInsertAttrib(Ihandle* ih, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; if (!value) return 0; @@ -207,12 +209,12 @@ static char* motTextGetSelectedTextAttrib(Ihandle* ih) static int motTextSetAppendAttrib(Ihandle* ih, const char* value) { XmTextPosition pos; - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; pos = XmTextGetLastPosition(ih->handle); /* disable callbacks */ iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); - if (ih->data->is_multiline && ih->data->append_newline) + if (ih->data->is_multiline && ih->data->append_newline && pos!=0) XmTextInsert(ih->handle, pos, "\n"); if (value) XmTextInsert(ih->handle, pos+1, (char*)value); @@ -482,8 +484,12 @@ static int motTextSetNCAttrib(Ihandle* ih, const char* value) if (!iupStrToInt(value, &ih->data->nc)) ih->data->nc = INT_MAX; if (ih->handle) + { XtVaSetValues(ih->handle, XmNmaxLength, ih->data->nc, NULL); - return 0; + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ } static int motTextSetClipboardAttrib(Ihandle *ih, const char *value) @@ -911,6 +917,10 @@ static void motTextLayoutUpdateMethod(Ihandle* ih) Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); if (spinbox && XmIsSpinBox(spinbox)) { + /* avoid abort in X */ + if (ih->currentwidth == 0) ih->currentwidth = 1; + if (ih->currentheight == 0) ih->currentheight = 1; + XtVaSetValues(ih->handle, XmNwidth, (XtArgVal)ih->currentwidth-ih->currentheight/2, XmNheight, (XtArgVal)ih->currentheight, @@ -952,13 +962,13 @@ static int motTextMapMethod(Ihandle* ih) /* Create the scrolled window */ /******************************/ - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); - iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); - iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ - iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ - iupmotSetArg(args, num_args, XmNborderWidth, 0); - iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); + iupMOT_SETARG(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupMOT_SETARG(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ + iupMOT_SETARG(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ + iupMOT_SETARG(args, num_args, XmNborderWidth, 0); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); sb_win = XtCreateManagedWidget( child_id, /* child identifier */ @@ -973,9 +983,9 @@ static int motTextMapMethod(Ihandle* ih) child_id = "text"; num_args = 0; - iupmotSetArg(args, num_args, XmNeditMode, XmMULTI_LINE_EDIT); + iupMOT_SETARG(args, num_args, XmNeditMode, XmMULTI_LINE_EDIT); if (wordwrap) - iupmotSetArg(args, num_args, XmNwordWrap, True); + iupMOT_SETARG(args, num_args, XmNwordWrap, True); } else { @@ -986,18 +996,18 @@ static int motTextMapMethod(Ihandle* ih) Widget spinbox; num_args = 0; - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between spin and text */ - iupmotSetArg(args, num_args, XmNborderWidth, 0); - iupmotSetArg(args, num_args, XmNshadowThickness, 0); - iupmotSetArg(args, num_args, XmNmarginHeight, 0); - iupmotSetArg(args, num_args, XmNmarginWidth, 0); - iupmotSetArg(args, num_args, XmNarrowSize, 8); + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNspacing, 0); /* no space between spin and text */ + iupMOT_SETARG(args, num_args, XmNborderWidth, 0); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); + iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNarrowSize, 8); if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT")) - iupmotSetArg(args, num_args, XmNarrowLayout, XmARROWS_BEGINNING); + iupMOT_SETARG(args, num_args, XmNarrowLayout, XmARROWS_BEGINNING); else - iupmotSetArg(args, num_args, XmNarrowLayout, XmARROWS_END); + iupMOT_SETARG(args, num_args, XmNarrowLayout, XmARROWS_END); spinbox = XtCreateManagedWidget( child_id, /* child identifier */ @@ -1019,61 +1029,61 @@ static int motTextMapMethod(Ihandle* ih) } num_args = 0; - iupmotSetArg(args, num_args, XmNeditMode, XmSINGLE_LINE_EDIT); + iupMOT_SETARG(args, num_args, XmNeditMode, XmSINGLE_LINE_EDIT); if (spin) { /* Spin Constraints */ - iupmotSetArg(args, num_args, XmNspinBoxChildType, XmNUMERIC); - iupmotSetArg(args, num_args, XmNminimumValue, 0); - iupmotSetArg(args, num_args, XmNmaximumValue, 100); - iupmotSetArg(args, num_args, XmNposition, 0); + iupMOT_SETARG(args, num_args, XmNspinBoxChildType, XmNUMERIC); + iupMOT_SETARG(args, num_args, XmNminimumValue, 0); + iupMOT_SETARG(args, num_args, XmNmaximumValue, 100); + iupMOT_SETARG(args, num_args, XmNposition, 0); if (iupAttribGetBoolean(ih, "SPINWRAP")) - iupmotSetArg(args, num_args, XmNwrap, TRUE); + iupMOT_SETARG(args, num_args, XmNwrap, TRUE); else - iupmotSetArg(args, num_args, XmNwrap, FALSE); + iupMOT_SETARG(args, num_args, XmNwrap, FALSE); } else { - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ } } - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ - iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ - iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); if (iupAttribGetBoolean(ih, "CANFOCUS")) - iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); else - iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); - iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); - iupmotSetArg(args, num_args, XmNhighlightThickness, 2); - iupmotSetArg(args, num_args, XmNverifyBell, False); - iupmotSetArg(args, num_args, XmNspacing, 0); + iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); + iupMOT_SETARG(args, num_args, XmNverifyBell, False); + iupMOT_SETARG(args, num_args, XmNspacing, 0); if (iupAttribGetBoolean(ih, "BORDER")) - iupmotSetArg(args, num_args, XmNshadowThickness, 2); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); else - iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); if (ih->data->is_multiline) { if (ih->data->sb & IUP_SB_HORIZ) - iupmotSetArg(args, num_args, XmNscrollHorizontal, True); + iupMOT_SETARG(args, num_args, XmNscrollHorizontal, True); else - iupmotSetArg(args, num_args, XmNscrollHorizontal, False); + iupMOT_SETARG(args, num_args, XmNscrollHorizontal, False); if (ih->data->sb & IUP_SB_VERT) - iupmotSetArg(args, num_args, XmNscrollVertical, True); + iupMOT_SETARG(args, num_args, XmNscrollVertical, True); else - iupmotSetArg(args, num_args, XmNscrollVertical, False); + iupMOT_SETARG(args, num_args, XmNscrollVertical, False); } ih->handle = XtCreateManagedWidget( diff --git a/iup/src/mot/iupmot_toggle.c b/iup/src/mot/iupmot_toggle.c index b18f24d..1fda258 100755 --- a/iup/src/mot/iupmot_toggle.c +++ b/iup/src/mot/iupmot_toggle.c @@ -236,8 +236,10 @@ static int motToggleSetPaddingAttrib(Ihandle* ih, const char* value) { XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, XmNmarginWidth, ih->data->horiz_padding, NULL); + return 0; } - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } static char* motToggleGetSelectColorAttrib(Ihandle* ih) @@ -336,40 +338,40 @@ static int motToggleMapMethod(Ihandle* ih) if (value) { ih->data->type = IUP_TOGGLE_IMAGE; - iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP); + iupMOT_SETARG(args, num_args, XmNlabelType, XmPIXMAP); } else { ih->data->type = IUP_TOGGLE_TEXT; - iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); + iupMOT_SETARG(args, num_args, XmNlabelType, XmSTRING); } /* Core */ - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ /* Primitive */ if (iupAttribGetBoolean(ih, "CANFOCUS")) - iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); else - iupmotSetArg(args, num_args, XmNtraversalOn, False); - iupmotSetArg(args, num_args, XmNhighlightThickness, 2); - iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); + iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); /* Label */ - iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ - iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ - iupmotSetArg(args, num_args, XmNmarginWidth, 0); - iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ - iupmotSetArg(args, num_args, XmNmarginLeft, 0); - iupmotSetArg(args, num_args, XmNmarginBottom, 0); - iupmotSetArg(args, num_args, XmNmarginRight, 0); + iupMOT_SETARG(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ + iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNmarginTop, 0); /* no extra margins */ + iupMOT_SETARG(args, num_args, XmNmarginLeft, 0); + iupMOT_SETARG(args, num_args, XmNmarginBottom, 0); + iupMOT_SETARG(args, num_args, XmNmarginRight, 0); if (radio) { - iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); - iupmotSetArg(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); + iupMOT_SETARG(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); + iupMOT_SETARG(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); if (!iupAttribGet(radio, "_IUPMOT_LASTTOGGLE")) { @@ -380,33 +382,33 @@ static int motToggleMapMethod(Ihandle* ih) else { if (ih->data->type == IUP_TOGGLE_TEXT && iupAttribGetBoolean(ih, "3STATE")) - iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_INDETERMINATE); + iupMOT_SETARG(args, num_args, XmNtoggleMode, XmTOGGLE_INDETERMINATE); else - iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); - iupmotSetArg(args, num_args, XmNindicatorType, XmN_OF_MANY); + iupMOT_SETARG(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); + iupMOT_SETARG(args, num_args, XmNindicatorType, XmN_OF_MANY); } if (ih->data->type == IUP_TOGGLE_IMAGE) { - iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); - iupmotSetArg(args, num_args, XmNalignment, XmALIGNMENT_CENTER); - iupmotSetArg(args, num_args, XmNshadowThickness, 2); + iupMOT_SETARG(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); + iupMOT_SETARG(args, num_args, XmNalignment, XmALIGNMENT_CENTER); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); } else { - iupmotSetArg(args, num_args, XmNspacing, 3); - iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); - iupmotSetArg(args, num_args, XmNalignment, XmALIGNMENT_BEGINNING); + iupMOT_SETARG(args, num_args, XmNspacing, 3); + iupMOT_SETARG(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); + iupMOT_SETARG(args, num_args, XmNalignment, XmALIGNMENT_BEGINNING); if (radio) { - iupmotSetArg(args, num_args, XmNindicatorSize, 13); - iupmotSetArg(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); + iupMOT_SETARG(args, num_args, XmNindicatorSize, 13); + iupMOT_SETARG(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); } else - iupmotSetArg(args, num_args, XmNindicatorSize, 15); + iupMOT_SETARG(args, num_args, XmNindicatorSize, 15); - iupmotSetArg(args, num_args, XmNshadowThickness, 0); - iupmotSetArg(args, num_args, XmNdetailShadowThickness, 2); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); + iupMOT_SETARG(args, num_args, XmNdetailShadowThickness, 2); } ih->handle = XtCreateManagedWidget( diff --git a/iup/src/mot/iupmot_tree.c b/iup/src/mot/iupmot_tree.c index eb230af..fa5ef09 100755 --- a/iup/src/mot/iupmot_tree.c +++ b/iup/src/mot/iupmot_tree.c @@ -46,48 +46,20 @@ typedef struct _motTreeItemData Pixmap image, image_mask; Pixmap image_expanded, image_expanded_mask; unsigned char kind; - void* userdata; } motTreeItemData; static void motTreeShowEditField(Ihandle* ih, Widget wItem); -static int motTreeGetNodeId(Ihandle* ih, Widget wItem); +static void motTreeRemoveNode(Ihandle* ih, Widget wItem, int del_data, int call_cb); -typedef int (*motTreeNodeFunc)(Ihandle* ih, Widget wItem, void* userdata); - -static int motTreeForEach(Ihandle* ih, Widget wItem, motTreeNodeFunc func, void* userdata) -{ - WidgetList wItemChildList = NULL; - int i, numChild; - - if (!wItem) - wItem = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); - - if (!func(ih, wItem, userdata)) - return 0; - - numChild = XmContainerGetItemChildren(ih->handle, wItem, &wItemChildList); - for (i=0; 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) +static Widget motTreeCopyItem(Ihandle* ih, Widget wItem, Widget wParent, int pos, int is_copy) { - Widget wNewItem; + Widget wItemNew; XmString title; motTreeItemData *itemData; Pixel fgcolor, bgcolor; @@ -96,13 +68,13 @@ static Widget motTreeCopyItem(Ihandle* ih, Widget wItem, Widget wParent, int pos 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); + iupMOT_SETARG(args, num_args, XmNentryParent, wParent); + iupMOT_SETARG(args, num_args, XmNmarginHeight, ih->data->spacing); + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNviewType, XmSMALL_ICON); + iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); /* Get values to copy */ XtVaGetValues(wItem, XmNlabelString, &title, @@ -113,49 +85,73 @@ static Widget motTreeCopyItem(Ihandle* ih, Widget wItem, Widget wParent, int pos XmNoutlineState, &state, NULL); - if (full_copy) /* during a full copy the userdata reference is not copied */ + if (is_copy) /* during a copy the itemdata reference is not reused */ { /* create a new one */ motTreeItemData* itemDataNew = malloc(sizeof(motTreeItemData)); memcpy(itemDataNew, itemData, sizeof(motTreeItemData)); - itemDataNew->userdata = NULL; itemData = itemDataNew; } - iupmotSetArg(args, num_args, XmNlabelString, title); - iupmotSetArg(args, num_args, XmNuserData, itemData); - iupmotSetArg(args, num_args, XmNforeground, fgcolor); - iupmotSetArg(args, num_args, XmNsmallIconPixmap, image); - iupmotSetArg(args, num_args, XmNsmallIconMask, mask); - iupmotSetArg(args, num_args, XmNoutlineState, state); + iupMOT_SETARG(args, num_args, XmNlabelString, title); + iupMOT_SETARG(args, num_args, XmNuserData, itemData); + iupMOT_SETARG(args, num_args, XmNforeground, fgcolor); + iupMOT_SETARG(args, num_args, XmNsmallIconPixmap, image); + iupMOT_SETARG(args, num_args, XmNsmallIconMask, mask); + iupMOT_SETARG(args, num_args, XmNoutlineState, state); - iupmotSetArg(args, num_args, XmNentryParent, wParent); - iupmotSetArg(args, num_args, XmNpositionIndex, pos); + iupMOT_SETARG(args, num_args, XmNentryParent, wParent); + iupMOT_SETARG(args, num_args, XmNpositionIndex, pos); XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); - iupmotSetArg(args, num_args, XmNbackground, bgcolor); + iupMOT_SETARG(args, num_args, XmNbackground, bgcolor); + + /* Add the new node */ + wItemNew = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); + ih->data->node_count++; + + XtRealizeWidget(wItemNew); + + return wItemNew; +} + +static void motTreeChildRebuildCacheRec(Ihandle* ih, Widget wItem, int *id) +{ + WidgetList itemChildList = NULL; + int i, numChild; - wNewItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); + /* Check whether we have child items */ + numChild = XmContainerGetItemChildren(ih->handle, wItem, &itemChildList); + + for (i = 0; i < numChild; i++) + { + (*id)++; + ih->data->node_cache[*id].node_handle = itemChildList[i]; - /* Root always expanded */ - XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); + /* go recursive to children */ + motTreeChildRebuildCacheRec(ih, itemChildList[i], id); + } - XtRealizeWidget(wNewItem); + if (itemChildList) XtFree((char*)itemChildList); +} - return wNewItem; +static void motTreeRebuildNodeCache(Ihandle* ih, int id, Widget wItem) +{ + ih->data->node_cache[id].node_handle = wItem; + motTreeChildRebuildCacheRec(ih, wItem, &id); } -static void motTreeCopyChildren(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int full_copy) +static void motTreeCopyChildren(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int is_copy) { WidgetList wItemChildList = NULL; int i = 0; int numChild = XmContainerGetItemChildren(ih->handle, wItemSrc, &wItemChildList); while(i != numChild) { - Widget wNewItem = motTreeCopyItem(ih, wItemChildList[i], wItemDst, i, full_copy); /* Use the same order they where enumerated */ + Widget wItemNew = motTreeCopyItem(ih, wItemChildList[i], wItemDst, i, is_copy); /* Use the same order they where enumerated */ /* Recursively transfer all the items */ - motTreeCopyChildren(ih, wItemChildList[i], wNewItem, full_copy); + motTreeCopyChildren(ih, wItemChildList[i], wItemNew, is_copy); /* Go to next sibling item */ i++; @@ -165,12 +161,18 @@ static void motTreeCopyChildren(Ihandle* ih, Widget wItemSrc, Widget wItemDst, i } /* Copies all items in a branch to a new location. Returns the new branch node. */ -static Widget motTreeCopyNode(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int full_copy) +static Widget motTreeCopyMoveNode(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int is_copy) { - Widget wNewItem, wParent; + Widget wItemNew, wParent; motTreeItemData *itemDataDst; unsigned char stateDst; - int pos; + int pos, id_new, count, id_src, id_dst; + + int old_count = ih->data->node_count; + + id_src = iupTreeFindNodeId(ih, wItemSrc); + id_dst = iupTreeFindNodeId(ih, wItemDst); + id_new = id_dst+1; /* contains the position for a copy operation */ XtVaGetValues(wItemDst, XmNoutlineState, &stateDst, XmNuserData, &itemDataDst, @@ -184,17 +186,46 @@ static Widget motTreeCopyNode(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int } else { + if (itemDataDst->kind == ITREE_BRANCH) + { + int child_count = iupdrvTreeTotalChildCount(ih, wItemDst); + id_new += child_count; + } + /* copy as next brother of item or collapsed branch */ XtVaGetValues(wItemDst, XmNentryParent, &wParent, NULL); XtVaGetValues(wItemDst, XmNpositionIndex, &pos, NULL); pos++; } - wNewItem = motTreeCopyItem(ih, wItemSrc, wParent, pos, full_copy); + /* move to the same place does nothing */ + if (!is_copy && id_new == id_src) + return NULL; + + wItemNew = motTreeCopyItem(ih, wItemSrc, wParent, pos, is_copy); + + motTreeCopyChildren(ih, wItemSrc, wItemNew, is_copy); + + count = ih->data->node_count - old_count; + iupTreeCopyMoveCache(ih, id_src, id_new, count, is_copy); - motTreeCopyChildren(ih, wItemSrc, wNewItem, full_copy); + if (!is_copy) + { + /* Deleting the node (and its children) from the old position */ + /* do not delete the itemdata, we reuse the references in CopyNode */ + motTreeRemoveNode(ih, wItemSrc, 0, 0); + + /* restore count, because we remove src */ + ih->data->node_count = old_count; + + /* compensate position for a move */ + if (id_new > id_src) + id_new -= count; + } - return wNewItem; + motTreeRebuildNodeCache(ih, id_new, wItemNew); + + return wItemNew; } static void motTreeContainerDeselectAll(Ihandle *ih) @@ -233,229 +264,181 @@ static void motTreeContainerSelectAll(Ihandle *ih) XtCallActionProc(ih->handle, "ContainerSelectAll", (XEvent*)&ev, 0, 0); } -static Widget motTreeGetLastVisibleNode(Ihandle* ih, Widget wItem) +static int motTreeIsNodeVisible(Widget wItem, Widget *wLastItemParent) { - unsigned char itemState; - - XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); - - if (itemState == XmEXPANDED) + unsigned char itemParentState; + Widget wItemParent = NULL; + XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL); + if (!wItemParent || wItemParent == *wLastItemParent) + return 1; + while(wItemParent) { - WidgetList wChildrenTree = NULL; - int numChildren = XmContainerGetItemChildren(ih->handle, wItem, &wChildrenTree); - if(numChildren) - wItem = motTreeGetLastVisibleNode(ih, wChildrenTree[numChildren - 1]); - if (wChildrenTree) XtFree((char*)wChildrenTree); + XtVaGetValues(wItemParent, XmNoutlineState, &itemParentState, NULL); + if (itemParentState != XmEXPANDED) + return 0; + + XtVaGetValues(wItemParent, XmNentryParent, &wItemParent, NULL); } - return wItem; + /* save last parent */ + XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL); + *wLastItemParent = wItemParent; + return 1; } -static Widget motTreeFindVisibleNodeId(Ihandle* ih, WidgetList itemList, int numItems, Widget itemNode) +static Widget motTreeGetLastVisibleNode(Ihandle* ih) { - Widget itemChild; - WidgetList itemChildList; - int i = 0; - int numChild; - unsigned char itemState; + int i; + Widget wLastItemParent = NULL; - while(i != numItems) + for (i = ih->data->node_count-1; i >= 0; i--) { - /* ID control to traverse items */ - ih->data->id_control++; /* not the real id since it counts only the visible ones */ - - /* StateID founded! */ - if(itemList[i] == itemNode) - return itemList[i]; - - /* Check whether we have child items */ - itemChildList = NULL; - numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); - XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); - - /* The itemWidget has child and it is expanded (visible) */ - if (numChild && itemState == XmEXPANDED) - { - /* pass the list of children of this item */ - itemChild = motTreeFindVisibleNodeId(ih, itemChildList, numChild, itemNode); - - /* StateID founded! */ - if(itemChild) - { - XtFree((char*)itemChildList); - return itemChild; - } - } - - if (itemChildList) XtFree((char*)itemChildList); - /* Go to next sibling item */ - i++; + if (motTreeIsNodeVisible(ih->data->node_cache[i].node_handle, &wLastItemParent)) + return ih->data->node_cache[i].node_handle; } - return NULL; + return ih->data->node_cache[0].node_handle; /* root is always visible */ } -static Widget motTreeFindVisibleNodeFromId(Ihandle* ih, WidgetList itemList, int numItems) +static Widget motTreeGetNextVisibleNode(Ihandle* ih, Widget wItem, int count) { - Widget itemChild; - WidgetList itemChildList; - int i = 0; - int numChild; - unsigned char itemState; + int i, id; + Widget wLastItemParent = NULL; - while(i != numItems) - { - /* ID control to traverse items */ - ih->data->id_control--; /* not the real id since it counts only the visible ones */ + id = iupTreeFindNodeId(ih, wItem); + id += count; - /* StateID founded! */ - if(ih->data->id_control < 0) - return itemList[i]; + for (i = id; i < ih->data->node_count; i++) + { + if (motTreeIsNodeVisible(ih->data->node_cache[i].node_handle, &wLastItemParent)) + return ih->data->node_cache[i].node_handle; + } - /* Check whether we have child items */ - itemChildList = NULL; - numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); - XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); + return ih->data->node_cache[0].node_handle; /* root is always visible */ +} - /* The itemWidget has child and it is expanded (visible) */ - if (numChild && itemState == XmEXPANDED) - { - /* pass the list of children of this item */ - itemChild = motTreeFindVisibleNodeFromId(ih, itemChildList, numChild); +static Widget motTreeGetPreviousVisibleNode(Ihandle* ih, Widget wItem, int count) +{ + int i, id; + Widget wLastItemParent = NULL; - /* StateID founded! */ - if(ih->data->id_control < 0) - { - if (itemChildList) XtFree((char*)itemChildList); - return itemChild; - } - } + id = iupTreeFindNodeId(ih, wItem); + id -= count; - if (itemChildList) XtFree((char*)itemChildList); - /* Go to next sibling item */ - i++; + for (i = id; i >= 0; i--) + { + if (motTreeIsNodeVisible(ih->data->node_cache[i].node_handle, &wLastItemParent)) + return ih->data->node_cache[i].node_handle; } - return NULL; + return motTreeGetLastVisibleNode(ih); } -static Widget motTreeGetNextVisibleNode(Ihandle* ih, Widget wRoot, Widget wItem) +static void motTreeChildCountRec(Ihandle* ih, Widget wItem, int *count) { - Widget wNext; + WidgetList itemChildList = NULL; + int i, numChild; - ih->data->id_control = -1; - motTreeFindVisibleNodeId(ih, &wRoot, 1, wItem); - ih->data->id_control++; /* more 1 visible node */ + /* Check whether we have child items */ + numChild = XmContainerGetItemChildren(ih->handle, wItem, &itemChildList); - wNext = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); + for (i = 0; i < numChild; i++) + { + (*count)++; - if (ih->data->id_control >= 0) - wNext = motTreeGetLastVisibleNode(ih, wRoot); + /* go recursive to children */ + motTreeChildCountRec(ih, itemChildList[i], count); + } - return wNext; + if (itemChildList) XtFree((char*)itemChildList); } -static Widget motTreeGetPreviousVisibleNode(Ihandle* ih, Widget wRoot, Widget wItem) +int iupdrvTreeTotalChildCount(Ihandle* ih, Widget wItem) { - ih->data->id_control = -1; - motTreeFindVisibleNodeId(ih, &wRoot, 1, wItem); - ih->data->id_control--; /* less 1 visible node */ - - if (ih->data->id_control < 0) - ih->data->id_control = 0; /* Begin of tree = Root id */ - - return motTreeFindVisibleNodeFromId(ih, &wRoot, 1); + int count = 0; + motTreeChildCountRec(ih, wItem, &count); + return count; } -static void motTreeUpdateBgColor(Ihandle* ih, WidgetList itemList, int numItems, Pixel bgcolor) +static void motTreeUpdateBgColor(Ihandle* ih, Pixel bgcolor) { - WidgetList itemChildList; - int i = 0; - int numChild; - - while(i != numItems) + int i; + for (i = 0; i < ih->data->node_count; i++) { - XtVaSetValues(itemList[i], XmNbackground, bgcolor, NULL); - - /* Check whether we have child items */ - itemChildList = NULL; - numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); - if(numChild) - motTreeUpdateBgColor(ih, itemChildList, numChild, bgcolor); - if (itemChildList) XtFree((char*)itemChildList); - - /* Go to next sibling item */ - i++; + XtVaSetValues(ih->data->node_cache[i].node_handle, XmNbackground, bgcolor, NULL); } } -static void motTreeUpdateImages(Ihandle* ih, WidgetList itemList, int numItems, int mode) +static void motTreeUpdateImages(Ihandle* ih, int mode) { - motTreeItemData *itemData; - int i = 0; - + int i; /* called when one of the default images is changed */ - - while(i != numItems) + for (i = 0; i < ih->data->node_count; i++) { - /* Get node attributes */ - XtVaGetValues(itemList[i], XmNuserData, &itemData, NULL); - + motTreeItemData *itemData; + Widget wItem = ih->data->node_cache[i].node_handle; + + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + if (itemData->kind == ITREE_BRANCH) { unsigned char itemState; - XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); + XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); if (itemState == XmEXPANDED) { if (mode == ITREE_UPDATEIMAGE_EXPANDED) { - XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image_expanded!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded: (Pixmap)ih->data->def_image_expanded, NULL); - XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_expanded_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded_mask: (Pixmap)ih->data->def_image_expanded_mask, NULL); + XtVaSetValues(wItem, XmNsmallIconPixmap, (itemData->image_expanded!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded: (Pixmap)ih->data->def_image_expanded, NULL); + XtVaSetValues(wItem, XmNsmallIconMask, (itemData->image_expanded_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded_mask: (Pixmap)ih->data->def_image_expanded_mask, NULL); } } else { if (mode == ITREE_UPDATEIMAGE_COLLAPSED) { - XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_collapsed, NULL); - XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_collapsed_mask, NULL); + XtVaSetValues(wItem, XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_collapsed, NULL); + XtVaSetValues(wItem, XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_collapsed_mask, NULL); } } - - /* Recursively traverse child items */ - { - WidgetList itemChildList; - int numChild; - itemChildList = NULL; - numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); - motTreeUpdateImages(ih, itemChildList, numChild, mode); - if (itemChildList) XtFree((char*)itemChildList); - } } else { if (mode == ITREE_UPDATEIMAGE_LEAF) { - XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_leaf, NULL); - XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_leaf_mask, NULL); + XtVaSetValues(wItem, XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_leaf, NULL); + XtVaSetValues(wItem, XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_leaf_mask, NULL); } } - - /* Go to next sibling node */ - i++; } } -static int motTreeSelectFunc(Ihandle* ih, Widget wItem, int *select) +static int motTreeIsNodeSelected(Widget wItem) +{ + unsigned char isSelected; + XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); + if(isSelected == XmSELECTED) + return 1; + else + return 0; +} + +static void motTreeSelectNode(Widget wItem, int select) +{ + if (select == -1) + select = !motTreeIsNodeSelected(wItem); /* toggle */ + + if (select) + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + else + XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); +} + +static int motTreeSelectFunc(Ihandle* ih, Widget wItem, int id, int *select) { int do_select = *select; if (do_select == -1) - { - unsigned char isSelected; - XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); - do_select = (isSelected == XmSELECTED)? 0: 1; /* toggle */ - } + do_select = !motTreeIsNodeSelected(wItem); /* toggle */ if (do_select) XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); @@ -463,272 +446,111 @@ static int motTreeSelectFunc(Ihandle* ih, Widget wItem, int *select) XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); (void)ih; + (void)id; return 1; } static void motTreeInvertAllNodeMarking(Ihandle* ih) { int select = -1; - motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSelectFunc, &select); + iupTreeForEach(ih, (iupTreeNodeFunc)motTreeSelectFunc, &select); } -typedef struct _motTreeRange{ - Widget wItem1, wItem2; - char inside, clear; -}motTreeRange; - -static int motTreeSelectRangeFunc(Ihandle* ih, Widget wItem, motTreeRange* range) +static void motTreeSelectRange(Ihandle* ih, Widget wItem1, Widget wItem2, int clear) { - int end_range = 0; - - if (range->inside == 0) /* detect the range start */ - { - if (range->wItem1 == wItem) range->inside=1; - else if (range->wItem2 == wItem) range->inside=1; - } - else if (range->inside == 1) /* detect the range end */ + int i; + int id1 = iupTreeFindNodeId(ih, wItem1); + int id2 = iupTreeFindNodeId(ih, wItem2); + if (id1 > id2) { - if (range->wItem1 == wItem) end_range=1; - else if (range->wItem2 == wItem) end_range=1; + int tmp = id1; + id1 = id2; + id2 = tmp; } - if (range->inside == 1) /* if inside, select */ - XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); - else if (range->clear) /* if outside and clear, unselect */ - XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); - - if (end_range || (range->inside && range->wItem1==range->wItem2)) - range->inside=-1; /* update after selecting the node */ - - (void)ih; - return 1; -} - -static void motTreeSelectRange(Ihandle* ih, Widget wItem1, Widget wItem2, int clear) -{ - motTreeRange range; - range.wItem1 = wItem1; - range.wItem2 = wItem2; - range.inside = 0; - range.clear = (char)clear; - motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSelectRangeFunc, &range); -} - -void motTreeExpandCollapseAllNodes(Ihandle* ih, WidgetList itemList, int numItems, unsigned char itemState) -{ - WidgetList itemChildList; - int numChild; - int i = 0; - - while(i != numItems) + for (i = 0; i < ih->data->node_count; i++) { - /* Check whether we have child items */ - itemChildList = NULL; - numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); - - if(numChild) + if (i < id1 || i > id2) { - XtVaSetValues(itemList[i], XmNoutlineState, itemState, NULL); - motTreeExpandCollapseAllNodes(ih, itemChildList, numChild, itemState); + if (clear) + XtVaSetValues(ih->data->node_cache[i].node_handle, XmNvisualEmphasis, XmNOT_SELECTED, NULL); } - - if (itemChildList) XtFree((char*)itemChildList); - /* Go to next sibling item */ - i++; + else + XtVaSetValues(ih->data->node_cache[i].node_handle, XmNvisualEmphasis, XmSELECTED, NULL); } } -static void motTreeDestroyItemData(Ihandle* ih, Widget wItem) +void motTreeExpandCollapseAllNodes(Ihandle* ih, unsigned char itemState) { - motTreeItemData *itemData = NULL; - XtVaGetValues(wItem, XmNuserData, &itemData, NULL); - if (itemData) + int i; + /* called when one of the default images is changed */ + for (i = 0; i < ih->data->node_count; i++) { - IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB"); - if (cb) cb(ih, motTreeGetNodeId(ih, wItem), (char*)itemData->userdata); - free(itemData); - XtVaSetValues(wItem, XmNuserData, NULL, NULL); - } -} - -static void motTreeRemoveChildren(Ihandle* ih, WidgetList itemList, int numItems, int del_userdata) -{ - WidgetList itemChildList; - int numChild; - int i = 0; + motTreeItemData *itemData; + Widget wItem = ih->data->node_cache[i].node_handle; - while(i != numItems) - { + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + /* Check whether we have child items */ - itemChildList = NULL; - numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); - if (numChild) - motTreeRemoveChildren(ih, itemChildList, numChild, del_userdata); - - if (del_userdata) - motTreeDestroyItemData(ih, itemList[i]); - - XtDestroyWidget(itemList[i]); - - if (itemChildList) XtFree((char*)itemChildList); - /* Go to next sibling item */ - i++; + if (itemData->kind == ITREE_BRANCH) + XtVaSetValues(wItem, XmNoutlineState, itemState, NULL); } } -static void motTreeRemoveNode(Ihandle* ih, Widget wItem, int del_userdata) +static void motTreeDestroyItemData(Ihandle* ih, Widget wItem, int del_data, IFns cb, int id) { - WidgetList wChildList = NULL; - int numChild = XmContainerGetItemChildren(ih->handle, wItem, &wChildList); - if (numChild) - motTreeRemoveChildren(ih, wChildList, numChild, del_userdata); - if (del_userdata) - motTreeDestroyItemData(ih, wItem); - XtDestroyWidget(wItem); - if (wChildList) XtFree((char*)wChildList); -} - -static Widget motTreeFindNodeID(Ihandle* ih, WidgetList itemList, int numItems, Widget itemNode) -{ - Widget itemChild; - WidgetList itemChildList; - int i = 0; - int numChild; - - while(i != numItems) + motTreeItemData *itemData = NULL; + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + if (itemData) { - /* ID control to traverse items */ - ih->data->id_control++; + if (cb) + cb(ih, (char*)ih->data->node_cache[id].userdata); - /* StateID founded! */ - if(itemList[i] == itemNode) - return itemList[i]; - - /* Check whether we have child items */ - itemChildList = NULL; - numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); - if(numChild) + if (del_data) { - /* pass the list of children of this item */ - itemChild = motTreeFindNodeID(ih, itemChildList, numChild, itemNode); - - /* StateID founded! */ - if(itemChild) - { - if (itemChildList) XtFree((char*)itemChildList); - return itemChild; - } + free(itemData); + XtVaSetValues(wItem, XmNuserData, NULL, NULL); } - - if (itemChildList) XtFree((char*)itemChildList); - /* Go to next sibling item */ - i++; } - - return NULL; } -static Widget motTreeFindNodeFromID(Ihandle* ih, WidgetList itemList, int numItems) +static void motTreeRemoveNodeRec(Ihandle* ih, Widget wItem, int del_data, IFns cb, int *id) { - Widget itemChild; - WidgetList itemChildList; - int i = 0; - int numChild; + WidgetList itemChildList = NULL; + int i, numChild; + int old_id = *id; - while(i != numItems) + /* Check whether we have child items */ + /* remove from children first */ + numChild = XmContainerGetItemChildren(ih->handle, wItem, &itemChildList); + for (i = 0; i < numChild; i++) { - /* ID control to traverse items */ - ih->data->id_control--; - - /* StateID founded! */ - if(ih->data->id_control < 0) - return itemList[i]; - - /* Check whether we have child items */ - itemChildList = NULL; - numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); - if(numChild) - { - /* pass the list of children of this item */ - itemChild = motTreeFindNodeFromID(ih, itemChildList, numChild); - - /* StateID founded! */ - if(ih->data->id_control < 0) - { - if (itemChildList) XtFree((char*)itemChildList); - return itemChild; - } - } - - if (itemChildList) XtFree((char*)itemChildList); - /* Go to next sibling item */ - i++; + /* go recursive to children */ + motTreeRemoveNodeRec(ih, itemChildList[i], del_data, cb, id); } + if (itemChildList) XtFree((char*)itemChildList); - return NULL; -} + /* actually do it for the node */ + ih->data->node_count--; + (*id)++; -static int motTreeGetNodeId(Ihandle* ih, Widget wItem) -{ - Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); - ih->data->id_control = -1; - if (motTreeFindNodeID(ih, &wRoot, 1, wItem)) - return ih->data->id_control; - else - return -1; + if (del_data || cb) + motTreeDestroyItemData(ih, wItem, del_data, cb, old_id); + + XtDestroyWidget(wItem); /* must manually destroy each node, this is NOT recursive */ } -static Widget motTreeFindUserDataID(Ihandle* ih, WidgetList itemList, int numItems, void* userdata) +static void motTreeRemoveNode(Ihandle* ih, Widget wItem, int del_data, int call_cb) { - Widget itemChild; - WidgetList itemChildList; - motTreeItemData *itemData; - int i = 0; - int numChild; - - while(i != numItems) - { - /* ID control to traverse items */ - ih->data->id_control++; - - XtVaGetValues(itemList[i], XmNuserData, &itemData, NULL); - - /* StateID founded! */ - if(itemData->userdata == userdata) - return itemList[i]; + IFns cb = call_cb? (IFns)IupGetCallback(ih, "NODEREMOVED_CB"): NULL; + int old_count = ih->data->node_count; + int id = iupTreeFindNodeId(ih, wItem); + int old_id = id; - /* Check whether we have child items */ - itemChildList = NULL; - numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); - if(numChild) - { - /* pass the list of children of this item */ - itemChild = motTreeFindUserDataID(ih, itemChildList, numChild, userdata); - - /* StateID founded! */ - if (itemChild) - { - if (itemChildList) XtFree((char*)itemChildList); - return itemChild; - } - } + motTreeRemoveNodeRec(ih, wItem, del_data, cb, &id); - if (itemChildList) XtFree((char*)itemChildList); - /* Go to next sibling item */ - i++; - } - - return NULL; -} - -static int motTreeGetUserDataId(Ihandle* ih, void* userdata) -{ - Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); - ih->data->id_control = -1; - if (motTreeFindUserDataID(ih, &wRoot, 1, userdata)) - return ih->data->id_control; - else - return -1; + if (call_cb) + iupTreeDelFromCache(ih, old_id, old_count-ih->data->node_count); } static void motTreeSetFocusNode(Ihandle* ih, Widget wItem) @@ -737,7 +559,7 @@ static void motTreeSetFocusNode(Ihandle* ih, Widget wItem) XmProcessTraversal(wItem, XmTRAVERSE_CURRENT); } -static Widget motTreeGetFocusNode(Ihandle* ih) +Widget iupdrvTreeGetFocusNode(Ihandle* ih) { Widget wItem = XmGetFocusWidget(ih->handle); /* returns the focus in the dialog */ if (wItem && XtParent(wItem) == ih->handle) /* is a node */ @@ -746,18 +568,6 @@ static Widget motTreeGetFocusNode(Ihandle* ih) return (Widget)iupAttribGet(ih, "_IUPTREE_LAST_FOCUS"); } -static Widget motTreeFindNodeFromString(Ihandle* ih, const char* name_id) -{ - if (name_id[0]) - { - Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); - iupStrToInt(name_id, &ih->data->id_control); - return motTreeFindNodeFromID(ih, &wRoot, 1); - } - else - return motTreeGetFocusNode(ih); -} - static void motTreeEnterLeaveWindowEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) { if (iupAttribGet(ih, "_IUPTREE_EDITFIELD")) @@ -812,16 +622,24 @@ static void motTreeFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add) { - Widget wItemPrev = motTreeFindNodeFromString(ih, name_id); - Widget wNewItem; + Widget wItemPrev = iupTreeGetNodeFromString(ih, name_id); + Widget wItemNew; XmString itemTitle; - motTreeItemData *itemData, *itemDataPrev; + motTreeItemData *itemData; Pixel bgcolor, fgcolor; - int kindPrev, num_args = 0; + int kindPrev = 0, num_args = 0; Arg args[30]; if (!wItemPrev) - return; + { + /* check if the root was really specified */ + int id = 0; + if (!iupStrToInt(name_id, &id) || id != -1) + return; + } + + if (!title) + title = ""; itemData = calloc(1, sizeof(motTreeItemData)); itemData->image = XmUNSPECIFIED_PIXMAP; @@ -836,138 +654,103 @@ void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* t XtVaGetValues(ih->handle, XmNforeground, &fgcolor, NULL); XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); - /* Get the kind of previous item */ - XtVaGetValues(wItemPrev, XmNuserData, &itemDataPrev, NULL); - kindPrev = itemDataPrev->kind; - - if (kindPrev == ITREE_BRANCH && add) + if (wItemPrev) { - /* wItemPrev is parent of the new item (firstchild of it) */ - iupmotSetArg(args, num_args, XmNentryParent, wItemPrev); - iupmotSetArg(args, num_args, XmNpositionIndex, 0); - } - else - { - /* wItemPrev is sibling of the new item (set its parent to the new item) */ - Widget wItemParent; - int pos; + motTreeItemData *itemDataPrev; - XtVaGetValues(wItemPrev, XmNentryParent, &wItemParent, NULL); - XtVaGetValues(wItemPrev, XmNpositionIndex, &pos, NULL); + /* Get the kind of previous item */ + XtVaGetValues(wItemPrev, XmNuserData, &itemDataPrev, NULL); + kindPrev = itemDataPrev->kind; + + if (kindPrev == ITREE_BRANCH && add) + { + /* wItemPrev is parent of the new item (firstchild of it) */ + iupMOT_SETARG(args, num_args, XmNentryParent, wItemPrev); + iupMOT_SETARG(args, num_args, XmNpositionIndex, 0); + } + else + { + /* wItemPrev is sibling of the new item (set its parent to the new item) */ + Widget wItemParent; + int pos; - iupmotSetArg(args, num_args, XmNentryParent, wItemParent); - iupmotSetArg(args, num_args, XmNpositionIndex, pos+1); + XtVaGetValues(wItemPrev, XmNentryParent, &wItemParent, NULL); + XtVaGetValues(wItemPrev, XmNpositionIndex, &pos, NULL); + + iupMOT_SETARG(args, num_args, XmNentryParent, wItemParent); + iupMOT_SETARG(args, num_args, XmNpositionIndex, pos+1); + } } - iupmotSetArg(args, num_args, XmNuserData, itemData); - iupmotSetArg(args, num_args, XmNforeground, fgcolor); - iupmotSetArg(args, num_args, XmNbackground, bgcolor); - iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); - iupmotSetArg(args, num_args, XmNmarginWidth, 0); - iupmotSetArg(args, num_args, XmNviewType, XmSMALL_ICON); - iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); - iupmotSetArg(args, num_args, XmNtraversalOn, True); - iupmotSetArg(args, num_args, XmNshadowThickness, 0); - iupmotSetArg(args, num_args, XmNlabelString, itemTitle); + iupMOT_SETARG(args, num_args, XmNuserData, itemData); + iupMOT_SETARG(args, num_args, XmNforeground, fgcolor); + iupMOT_SETARG(args, num_args, XmNbackground, bgcolor); + iupMOT_SETARG(args, num_args, XmNmarginHeight, ih->data->spacing); + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNviewType, XmSMALL_ICON); + iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); + iupMOT_SETARG(args, num_args, XmNlabelString, itemTitle); if (kind == ITREE_BRANCH) { if (ih->data->add_expanded) { - iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_expanded); - iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_expanded_mask); + iupMOT_SETARG(args, num_args, XmNsmallIconPixmap, ih->data->def_image_expanded); + iupMOT_SETARG(args, num_args, XmNsmallIconMask, ih->data->def_image_expanded_mask); } else { - iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_collapsed); - iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_collapsed_mask); + iupMOT_SETARG(args, num_args, XmNsmallIconPixmap, ih->data->def_image_collapsed); + iupMOT_SETARG(args, num_args, XmNsmallIconMask, ih->data->def_image_collapsed_mask); } } else { - iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_leaf); - iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_leaf_mask); + iupMOT_SETARG(args, num_args, XmNsmallIconPixmap, ih->data->def_image_leaf); + iupMOT_SETARG(args, num_args, XmNsmallIconMask, ih->data->def_image_leaf_mask); } + /* Add the new node */ + wItemNew = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); + if (wItemPrev) + iupTreeAddToCache(ih, add, kindPrev, wItemPrev, wItemNew); + else + { + iupTreeAddToCache(ih, 0, 0, NULL, wItemNew); + + if (ih->data->node_count == 1) + { + /* MarkStart node */ + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)wItemNew); - wNewItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); + /* Set the default VALUE */ + motTreeSetFocusNode(ih, wItemNew); + } + } if (kind == ITREE_BRANCH) { + iupAttribSetStr(ih, "_IUP_IGNORE_BRANCH_CB", "1"); if (ih->data->add_expanded) - { - iupAttribSetStr(ih, "_IUP_IGNORE_BRANCHOPEN", "1"); - XtVaSetValues(wNewItem, XmNoutlineState, XmEXPANDED, NULL); - } + XtVaSetValues(wItemNew, XmNoutlineState, XmEXPANDED, NULL); else - XtVaSetValues(wNewItem, XmNoutlineState, XmCOLLAPSED, NULL); + XtVaSetValues(wItemNew, XmNoutlineState, XmCOLLAPSED, NULL); + iupAttribSetStr(ih, "_IUP_IGNORE_BRANCH_CB", NULL); } - /* Root always expanded */ - XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); - - XtRealizeWidget(wNewItem); + XtRealizeWidget(wItemNew); XmStringFree(itemTitle); } -static void motTreeAddRootNode(Ihandle* ih) -{ - Widget wRootItem; - motTreeItemData *itemData; - Pixel bgcolor, fgcolor; - int num_args = 0; - Arg args[30]; - - itemData = calloc(1, sizeof(motTreeItemData)); - itemData->image = XmUNSPECIFIED_PIXMAP; - itemData->image_expanded = XmUNSPECIFIED_PIXMAP; - itemData->image_mask = XmUNSPECIFIED_PIXMAP; - itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP; - itemData->kind = ITREE_BRANCH; - - /* Get default foreground color */ - XtVaGetValues(ih->handle, XmNforeground, &fgcolor, NULL); - XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); - - iupmotSetArg(args, num_args, XmNentryParent, NULL); - iupmotSetArg(args, num_args, XmNuserData, itemData); - iupmotSetArg(args, num_args, XmNforeground, fgcolor); - iupmotSetArg(args, num_args, XmNbackground, bgcolor); - iupmotSetArg(args, num_args, XmNoutlineState, XmEXPANDED); - iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); - iupmotSetArg(args, num_args, XmNmarginWidth, 0); - iupmotSetArg(args, num_args, XmNviewType, XmSMALL_ICON); - iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); - iupmotSetArg(args, num_args, XmNtraversalOn, True); - iupmotSetArg(args, num_args, XmNshadowThickness, 0); - iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_expanded); - iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_expanded_mask); - - wRootItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); - - /* Select the new item */ - XtVaSetValues(wRootItem, XmNvisualEmphasis, XmSELECTED, NULL); - - XtRealizeWidget(wRootItem); - - /* Save the root node for later use */ - iupAttribSetStr(ih, "_IUPTREE_ROOTITEM", (char*)wRootItem); - - /* MarkStart node */ - iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)wRootItem); - - /* Set the default VALUE */ - /* In Motif this will set also the current focus */ - motTreeSetFocusNode(ih, wRootItem); -} - /*****************************************************************************/ static int motTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const char* value) { motTreeItemData *itemData; unsigned char itemState; - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return 0; @@ -1003,7 +786,7 @@ static int motTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const static int motTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* value) { motTreeItemData *itemData; - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return 0; @@ -1053,7 +836,6 @@ static int motTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* v static int motTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) { - Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); ih->data->def_image_expanded = iupImageGetImage(value, ih, 0); if (!ih->data->def_image_expanded) { @@ -1067,14 +849,13 @@ static int motTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) } /* Update all images, starting at root node */ - motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_EXPANDED); + motTreeUpdateImages(ih, ITREE_UPDATEIMAGE_EXPANDED); return 1; } static int motTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) { - Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); ih->data->def_image_collapsed = iupImageGetImage(value, ih, 0); if (!ih->data->def_image_collapsed) { @@ -1088,14 +869,13 @@ static int motTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) } /* Update all images, starting at root node */ - motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_COLLAPSED); + motTreeUpdateImages(ih, ITREE_UPDATEIMAGE_COLLAPSED); return 1; } static int motTreeSetImageLeafAttrib(Ihandle* ih, const char* value) { - Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); ih->data->def_image_leaf = iupImageGetImage(value, ih, 0); if (!ih->data->def_image_leaf) { @@ -1109,7 +889,7 @@ static int motTreeSetImageLeafAttrib(Ihandle* ih, const char* value) } /* Update all images, starting at root node */ - motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_LEAF); + motTreeUpdateImages(ih, ITREE_UPDATEIMAGE_LEAF); return 1; } @@ -1118,7 +898,7 @@ static char* motTreeGetStateAttrib(Ihandle* ih, const char* name_id) { int hasChildren; unsigned char itemState; - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return 0; @@ -1138,14 +918,21 @@ static char* motTreeGetStateAttrib(Ihandle* ih, const char* name_id) static int motTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value) { - Widget wItem = motTreeFindNodeFromString(ih, name_id); - if (!wItem) + motTreeItemData *itemData; + Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if (!wItem) return 0; - if (iupStrEqualNoCase(value, "EXPANDED")) - XtVaSetValues(wItem, XmNoutlineState, XmEXPANDED, NULL); - else - XtVaSetValues(wItem, XmNoutlineState, XmCOLLAPSED, NULL); + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + if (itemData->kind == ITREE_BRANCH) + { + iupAttribSetStr(ih, "_IUP_IGNORE_BRANCH_CB", "1"); + if (iupStrEqualNoCase(value, "EXPANDED")) + XtVaSetValues(wItem, XmNoutlineState, XmEXPANDED, NULL); + else + XtVaSetValues(wItem, XmNoutlineState, XmCOLLAPSED, NULL); + iupAttribSetStr(ih, "_IUP_IGNORE_BRANCH_CB", NULL); + } return 0; } @@ -1155,7 +942,7 @@ static char* motTreeGetColorAttrib(Ihandle* ih, const char* name_id) unsigned char r, g, b; Pixel color; char* str; - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return NULL; @@ -1170,7 +957,7 @@ static char* motTreeGetColorAttrib(Ihandle* ih, const char* name_id) static int motTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* value) { Pixel color; - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return 0; @@ -1182,36 +969,33 @@ static int motTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* v static char* motTreeGetDepthAttrib(Ihandle* ih, const char* name_id) { - Widget wRoot; - int dep = 0; - char* depth; - Widget wItem = motTreeFindNodeFromString(ih, name_id); + int depth = -1; + char* str; + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return NULL; - wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); - - while((wRoot != wItem) && (wItem != NULL)) + while(wItem != NULL) { XtVaGetValues(wItem, XmNentryParent, &wItem, NULL); - dep++; + depth++; } - depth = iupStrGetMemory(10); - sprintf(depth, "%d", dep); - return depth; + str = iupStrGetMemory(10); + sprintf(str, "%d", depth); + return str; } static int motTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value) { Widget wItemDst, wParent, wItemSrc; - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; - wItemSrc = motTreeFindNodeFromString(ih, name_id); + wItemSrc = iupTreeGetNodeFromString(ih, name_id); if (!wItemSrc) return 0; - wItemDst = motTreeFindNodeFromString(ih, value); + wItemDst = iupTreeGetNodeFromString(ih, value); if (!wItemDst) return 0; @@ -1224,11 +1008,8 @@ static int motTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char return 0; } - /* Copying the node and its children to the new position */ - motTreeCopyNode(ih, wItemSrc, wItemDst, 0); /* not a full copy, preserve user data */ - - /* Deleting the node (and its children) inserted into the old position */ - motTreeRemoveNode(ih, wItemSrc, 0); /* do not delete the user data, we copy the references in CopyNode */ + /* Move the node and its children to the new position */ + motTreeCopyMoveNode(ih, wItemSrc, wItemDst, 0); return 0; } @@ -1237,12 +1018,12 @@ static int motTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char { Widget wItemDst, wParent, wItemSrc; - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; - wItemSrc = motTreeFindNodeFromString(ih, name_id); + wItemSrc = iupTreeGetNodeFromString(ih, name_id); if (!wItemSrc) return 0; - wItemDst = motTreeFindNodeFromString(ih, value); + wItemDst = iupTreeGetNodeFromString(ih, value); if (!wItemDst) return 0; @@ -1255,8 +1036,8 @@ static int motTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char return 0; } - /* Copying the node and its children to the new position */ - motTreeCopyNode(ih, wItemSrc, wItemDst, 1); + /* Copy the node and its children to the new position */ + motTreeCopyMoveNode(ih, wItemSrc, wItemDst, 1); return 0; } @@ -1265,7 +1046,7 @@ static char* motTreeGetParentAttrib(Ihandle* ih, const char* name_id) { Widget wItemParent; char* str; - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return NULL; @@ -1275,7 +1056,7 @@ static char* motTreeGetParentAttrib(Ihandle* ih, const char* name_id) return NULL; str = iupStrGetMemory(10); - sprintf(str, "%d", motTreeGetNodeId(ih, wItemParent)); + sprintf(str, "%d", iupTreeFindNodeId(ih, wItemParent)); return str; } @@ -1283,7 +1064,7 @@ static char* motTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) { char* str; WidgetList wList = NULL; - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return NULL; @@ -1293,30 +1074,10 @@ static char* motTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) return str; } -static int motTreeCount(Ihandle* ih, Widget wItem) -{ - WidgetList wList = NULL; - int i, count = 0; - int childCount = XmContainerGetItemChildren(ih->handle, wItem, &wList); - count++; - for (i=0; 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); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return NULL; @@ -1331,15 +1092,64 @@ static char* motTreeGetKindAttrib(Ihandle* ih, const char* name_id) static char* motTreeGetValueAttrib(Ihandle* ih) { char* str; - Widget wItem = motTreeGetFocusNode(ih); + Widget wItem = iupdrvTreeGetFocusNode(ih); if (!wItem) - return "0"; /* default VALUE is root */ + { + if (ih->data->node_count) + return "0"; /* default VALUE is root */ + else + return "-1"; + } str = iupStrGetMemory(10); - sprintf(str, "%d", motTreeGetNodeId(ih, wItem)); + sprintf(str, "%d", iupTreeFindNodeId(ih, wItem)); + return str; +} + +static char* motTreeGetMarkedNodesAttrib(Ihandle* ih) +{ + char* str; + int i; + + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + return NULL; + + str = iupStrGetMemory(ih->data->node_count+1); + + for (i=0; i<ih->data->node_count; i++) + { + if (motTreeIsNodeSelected(ih->data->node_cache[i].node_handle)) + str[i] = '+'; + else + str[i] = '-'; + } + + str[ih->data->node_count] = 0; return str; } +static int motTreeSetMarkedNodesAttrib(Ihandle* ih, const char* value) +{ + int count, i; + + if (ih->data->mark_mode==ITREE_MARK_SINGLE || !value) + return 0; + + count = strlen(value); + if (count > ih->data->node_count) + count = ih->data->node_count; + + for (i=0; i<count; i++) + { + if (value[i] == '+') + XtVaSetValues(ih->data->node_cache[i].node_handle, XmNvisualEmphasis, XmSELECTED, NULL); + else + XtVaSetValues(ih->data->node_cache[i].node_handle, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + } + + return 0; +} + static int motTreeSetMarkAttrib(Ihandle* ih, const char* value) { if (ih->data->mark_mode==ITREE_MARK_SINGLE) @@ -1353,21 +1163,16 @@ static int motTreeSetMarkAttrib(Ihandle* ih, const char* value) motTreeInvertAllNodeMarking(ih); else if(iupStrEqualPartial(value, "INVERT")) { - unsigned char isSelected; - Widget wItem = motTreeFindNodeFromString(ih, &value[strlen("INVERT")]); + Widget wItem = iupTreeGetNodeFromString(ih, &value[strlen("INVERT")]); if (!wItem) return 0; - XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); - if (isSelected == XmSELECTED) - XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); - else - XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + motTreeSelectNode(wItem, -1); } else if(iupStrEqualNoCase(value, "BLOCK")) { Widget wItem = (Widget)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"); - Widget wFocusItem = motTreeGetFocusNode(ih); + Widget wFocusItem = iupdrvTreeGetFocusNode(ih); if(!wFocusItem || !wItem) return 0; motTreeSelectRange(ih, wFocusItem, wItem, 0); @@ -1379,10 +1184,10 @@ static int motTreeSetMarkAttrib(Ihandle* ih, const char* value) if (iupStrToStrStr(value, str1, str2, '-')!=2) return 0; - wItem1 = motTreeFindNodeFromString(ih, str1); + wItem1 = iupTreeGetNodeFromString(ih, str1); if (!wItem1) return 0; - wItem2 = motTreeFindNodeFromString(ih, str2); + wItem2 = iupTreeGetNodeFromString(ih, str2); if (!wItem2) return 0; @@ -1394,69 +1199,49 @@ static int motTreeSetMarkAttrib(Ihandle* ih, const char* value) static int motTreeSetValueAttrib(Ihandle* ih, const char* value) { - Widget wRoot, wItem; + Widget wItem, wItemParent; if (motTreeSetMarkAttrib(ih, value)) return 0; - wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); - - if (iupStrEqualNoCase(value, "ROOT")) - wItem = wRoot; + if (iupStrEqualNoCase(value, "ROOT") || iupStrEqualNoCase(value, "FIRST")) + wItem = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); else if(iupStrEqualNoCase(value, "LAST")) - wItem = motTreeGetLastVisibleNode(ih, wRoot); + wItem = motTreeGetLastVisibleNode(ih); else if(iupStrEqualNoCase(value, "PGUP")) { - Widget wItemFocus = motTreeGetFocusNode(ih); + Widget wItemFocus = iupdrvTreeGetFocusNode(ih); if(!wItemFocus) return 0; - ih->data->id_control = -1; - motTreeFindVisibleNodeId(ih, &wRoot, 1, wItemFocus); - ih->data->id_control -= 10; /* less 10 visible nodes */ - - if(ih->data->id_control < 0) - ih->data->id_control = 0; /* Begin of tree = Root id */ - - wItem = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); + wItem = motTreeGetPreviousVisibleNode(ih, wItemFocus, 10); } else if(iupStrEqualNoCase(value, "PGDN")) { - Widget wNext, wItemFocus; - - wItemFocus = motTreeGetFocusNode(ih); + Widget wItemFocus = iupdrvTreeGetFocusNode(ih); if(!wItemFocus) return 0; - ih->data->id_control = -1; - motTreeFindVisibleNodeId(ih, &wRoot, 1, wItemFocus); - ih->data->id_control += 10; /* more 10 visible nodes */ - - wNext = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); - - if (ih->data->id_control >= 0) - wNext = motTreeGetLastVisibleNode(ih, wRoot); - - wItem = wNext; + wItem = motTreeGetNextVisibleNode(ih, wItemFocus, 10); } else if(iupStrEqualNoCase(value, "NEXT")) { - Widget wItemFocus = motTreeGetFocusNode(ih); + Widget wItemFocus = iupdrvTreeGetFocusNode(ih); if (!wItemFocus) return 0; - wItem = motTreeGetNextVisibleNode(ih, wRoot, wItemFocus); + wItem = motTreeGetNextVisibleNode(ih, wItemFocus, 1); } else if(iupStrEqualNoCase(value, "PREVIOUS")) { - Widget wItemFocus = motTreeGetFocusNode(ih); + Widget wItemFocus = iupdrvTreeGetFocusNode(ih); if(!wItemFocus) return 0; - wItem = motTreeGetPreviousVisibleNode(ih, wRoot, wItemFocus); + wItem = motTreeGetPreviousVisibleNode(ih, wItemFocus, 1); } else - wItem = motTreeFindNodeFromString(ih, value); + wItem = iupTreeGetNodeFromString(ih, value); if (!wItem) return 0; @@ -1471,17 +1256,26 @@ static int motTreeSetValueAttrib(Ihandle* ih, const char* value) XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); } + + /* expand all parents */ + XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL); + while(wItemParent) + { + XtVaSetValues(wItemParent, XmNoutlineState, XmEXPANDED, NULL); + XtVaGetValues(wItemParent, XmNentryParent, &wItemParent, NULL); + } + /* set focus (will scroll to visible) */ motTreeSetFocusNode(ih, wItem); - iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", motTreeGetNodeId(ih, wItem)); + iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", iupTreeFindNodeId(ih, wItem)); return 0; } static int motTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) { - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return 0; @@ -1492,14 +1286,11 @@ static int motTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) static char* motTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) { - unsigned char isSelected; - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return NULL; - XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); - - if(isSelected == XmSELECTED) + if (motTreeIsNodeSelected(wItem)) return "YES"; else return "NO"; @@ -1507,7 +1298,7 @@ static char* motTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) static int motTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value) { - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return 0; @@ -1531,7 +1322,7 @@ static char* motTreeGetTitle(Widget wItem) static char* motTreeGetTitleAttrib(Ihandle* ih, const char* name_id) { - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return NULL; return motTreeGetTitle(wItem); @@ -1539,10 +1330,13 @@ static char* motTreeGetTitleAttrib(Ihandle* ih, const char* name_id) static int motTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value) { - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return 0; + if (!value) + value = ""; + iupmotSetString(wItem, XmNlabelString, value); return 0; @@ -1551,7 +1345,7 @@ static int motTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* v static int motTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const char* value) { XmFontList fontlist = NULL; - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return 0; @@ -1569,7 +1363,7 @@ static int motTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const cha static char* motTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) { XmFontList fontlist; - Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if (!wItem) return NULL; @@ -1577,118 +1371,81 @@ static char* motTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) return iupmotFindFontList(fontlist); } -static char* motTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id) -{ - int id; - char* str = (char*)(name_id+1); /* skip ':' */ - void* userdata = NULL; - if (sscanf(str, "%p", &userdata)!=1) - return NULL; - id = motTreeGetUserDataId(ih, userdata); - if (id == -1) - return NULL; - str = iupStrGetMemory(16); - sprintf(str, "%d", id); - return str; -} - -static char* motTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) -{ - motTreeItemData *itemData; - Widget wItem = motTreeFindNodeFromString(ih, name_id); - if (!wItem) - return NULL; - - XtVaGetValues(wItem, XmNuserData, &itemData, NULL); - - return itemData->userdata; -} - -static int motTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) -{ - motTreeItemData *itemData; - Widget wItem = motTreeFindNodeFromString(ih, name_id); - if (!wItem) - return 0; - - XtVaGetValues(wItem, XmNuserData, &itemData, NULL); - itemData->userdata = (void*)value; - - return 0; -} - static int motTreeSetRenameAttrib(Ihandle* ih, const char* value) { if (ih->data->show_rename) { - IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); - Widget wItemFocus = motTreeGetFocusNode(ih); - if (cbShowRename) - cbShowRename(ih, motTreeGetNodeId(ih, wItemFocus)); + Widget wItemFocus = iupdrvTreeGetFocusNode(ih); motTreeShowEditField(ih, wItemFocus); } - else - { - IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB"); - if (cbRenameNode) - { - Widget wItemFocus = motTreeGetFocusNode(ih); - cbRenameNode(ih, motTreeGetNodeId(ih, wItemFocus), motTreeGetTitle(wItemFocus)); - } - } (void)value; return 0; } +static void motTreeRemoveAllNodes(Ihandle* ih, int call_cb) +{ + IFns cb = call_cb? (IFns)IupGetCallback(ih, "NODEREMOVED_CB"): NULL; + int i, old_count = ih->data->node_count; + Widget wItem; + + for (i = 0; i < ih->data->node_count; i++) + { + wItem = ih->data->node_cache[i].node_handle; + + motTreeDestroyItemData(ih, wItem, 1, cb, i); + + XtDestroyWidget(wItem); /* must manually destroy each node, this is NOT recursive */ + } + + ih->data->node_count = 0; + + if (call_cb) + iupTreeDelFromCache(ih, 0, old_count); +} + static int motTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; - if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */ + if (iupStrEqualNoCase(value, "ALL")) { - Widget wItem = motTreeFindNodeFromString(ih, name_id); - Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); - - /* the root node can't be deleted */ - if(!wItem || wItem == wRoot) /* root is the unique child */ + motTreeRemoveAllNodes(ih, 1); + return 0; + } + if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the reference node */ + { + Widget wItem = iupTreeGetNodeFromString(ih, name_id); + if(!wItem) return 0; - /* deleting the specified node (and it's children) */ - motTreeRemoveNode(ih, wItem, 1); + /* deleting the reference node (and it's children) */ + motTreeRemoveNode(ih, wItem, 1, 1); } - else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */ + else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the reference node */ { - Widget wItem = motTreeFindNodeFromString(ih, name_id); + int numChild, i; + WidgetList wItemList = NULL; + Widget wItem = iupTreeGetNodeFromString(ih, name_id); if(!wItem) return 0; - { - /* deleting the selected node's children only */ - WidgetList wItemList = NULL; - int numChild = XmContainerGetItemChildren(ih->handle, wItem, &wItemList); - if(numChild) - motTreeRemoveChildren(ih, wItemList, numChild, 1); - if (wItemList) XtFree((char*)wItemList); - } + /* deleting the reference node children only */ + numChild = XmContainerGetItemChildren(ih->handle, wItem, &wItemList); + for(i = 0; i < numChild; i++) + motTreeRemoveNode(ih, wItemList[i], 1, 1); + if (wItemList) XtFree((char*)wItemList); } else if(iupStrEqualNoCase(value, "MARKED")) /* Delete the array of marked nodes */ { - WidgetList wSelectedItemList = NULL; - Widget wRoot; - int countItems, i; - - XtVaGetValues(ih->handle, XmNselectedObjects, &wSelectedItemList, - XmNselectedObjectCount, &countItems, NULL); - - wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); - - for(i = 0; i < countItems; i++) + int i; + for(i = 1; i < ih->data->node_count; /* increment only if not removed */) { - int ok = XmIsIconGadget(wSelectedItemList[i]); - if ((wSelectedItemList[i] != wRoot) && ok) /* the root node can't be deleted */ - motTreeRemoveNode(ih, wSelectedItemList[i], 1); + if (motTreeIsNodeSelected(ih->data->node_cache[i].node_handle)) + motTreeRemoveNode(ih, ih->data->node_cache[i].node_handle, 1, 1); + else + i++; } } @@ -1714,7 +1471,7 @@ static int motTreeSetIndentationAttrib(Ihandle* ih, const char* value) static int motTreeSetTopItemAttrib(Ihandle* ih, const char* value) { - Widget wItem = motTreeFindNodeFromString(ih, value); + Widget wItem = iupTreeGetNodeFromString(ih, value); Widget sb_win; Widget wItemParent; @@ -1735,10 +1492,11 @@ static int motTreeSetTopItemAttrib(Ihandle* ih, const char* value) return 0; } -static int motTreeSpacingFunc(Ihandle* ih, Widget wItem, void *data) +static int motTreeSpacingFunc(Ihandle* ih, Widget wItem, int id, void *data) { XtVaSetValues(wItem, XmNmarginHeight, ih->data->spacing, NULL); (void)data; + (void)id; return 1; } @@ -1752,7 +1510,7 @@ static int motTreeSetSpacingAttrib(Ihandle* ih, const char* value) if (ih->handle) { - motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSpacingFunc, 0); + iupTreeForEach(ih, (iupTreeNodeFunc)motTreeSpacingFunc, 0); return 0; } else @@ -1761,17 +1519,10 @@ static int motTreeSetSpacingAttrib(Ihandle* ih, const char* value) static int motTreeSetExpandAllAttrib(Ihandle* ih, const char* value) { - Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); - if (iupStrBoolean(value)) - motTreeExpandCollapseAllNodes(ih, &wRoot, 1, XmEXPANDED); + motTreeExpandCollapseAllNodes(ih, XmEXPANDED); else - { - motTreeExpandCollapseAllNodes(ih, &wRoot, 1, XmCOLLAPSED); - - /* The root node is always expanded */ - XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); - } + motTreeExpandCollapseAllNodes(ih, XmCOLLAPSED); return 0; } @@ -1801,16 +1552,13 @@ static int motTreeSetBgColorAttrib(Ihandle* ih, const char* value) color = iupmotColorGetPixelStr(value); if (color != (Pixel)-1) { - Widget wRoot; Widget clipwin = NULL; XtVaGetValues(sb_win, XmNclipWindow, &clipwin, NULL); if (clipwin) iupmotSetBgColor(clipwin, color); - wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); - /* Update all children, starting at root node */ - motTreeUpdateBgColor(ih, &wRoot, 1, color); + motTreeUpdateBgColor(ih, color); } iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */ @@ -1871,10 +1619,14 @@ static void motTreeSetRenameSelectionPos(Widget cbEdit, const char* value) static int motTreeCallBranchCloseCb(Ihandle* ih, Widget wItem) { - IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); + IFni cbBranchClose; + + if (iupAttribGet(ih, "_IUP_IGNORE_BRANCH_CB")) + return IUP_DEFAULT; - if(cbBranchClose) - return cbBranchClose(ih, motTreeGetNodeId(ih, wItem)); + cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); + if (cbBranchClose) + return cbBranchClose(ih, iupTreeFindNodeId(ih, wItem)); return IUP_DEFAULT; } @@ -1883,59 +1635,136 @@ static int motTreeCallBranchOpenCb(Ihandle* ih, Widget wItem) { IFni cbBranchOpen; - if (iupAttribGet(ih, "_IUP_IGNORE_BRANCHOPEN")) - { - iupAttribSetStr(ih, "_IUP_IGNORE_BRANCHOPEN", NULL); + if (iupAttribGet(ih, "_IUP_IGNORE_BRANCH_CB")) return IUP_DEFAULT; - } cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB"); if (cbBranchOpen) - return cbBranchOpen(ih, motTreeGetNodeId(ih, wItem)); + return cbBranchOpen(ih, iupTreeFindNodeId(ih, wItem)); return IUP_DEFAULT; } +static void motTreeFindRange(Ihandle* ih, WidgetList wSelectedItemList, int countItems, int *id1, int *id2) +{ + int i = 0, id; + + *id1 = ih->data->node_count; + *id2 = -1; + + for(i = 0; i < countItems; i++) + { + int is_icon = XmIsIconGadget(wSelectedItemList[i]); /* this line generates a warning in some compilers */ + if (is_icon) + { + id = iupTreeFindNodeId(ih, wSelectedItemList[i]); + if (id < *id1) + *id1 = id; + if (id > *id2) + *id2 = id; + } + } + + /* interactive selection of several nodes will NOT select hidden nodes, + so make sure that they are selected. */ + for(i = *id1; i <= *id2; i++) + { + if (!motTreeIsNodeSelected(ih->data->node_cache[i].node_handle)) + XtVaSetValues(ih->data->node_cache[i].node_handle, XmNvisualEmphasis, XmSELECTED, NULL); + } + + /* if last selected item is a branch, then select its children */ + iupTreeSelectLastCollapsedBranch(ih, id2); +} + +static Iarray* motTreeGetSelectedArrayId(Ihandle* ih, WidgetList wSelectedItemList, int countItems) +{ + Iarray* selarray = iupArrayCreate(1, sizeof(int)); + int i; + + for(i = 0; i < countItems; i++) + { + int is_icon = XmIsIconGadget(wSelectedItemList[i]); /* this line generates a warning in some compilers */ + if (is_icon) + { + int* id_hitem = (int*)iupArrayInc(selarray); + int j = iupArrayCount(selarray); + id_hitem[j-1] = iupTreeFindNodeId(ih, wSelectedItemList[i]); + } + } + + return selarray; +} + +static void motTreeCallMultiUnSelectionCb(Ihandle* ih) +{ + IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTIUNSELECTION_CB"); + IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbSelec || cbMulti) + { + WidgetList wSelectedItemList = NULL; + int countItems = 0; + + XtVaGetValues(ih->handle, XmNselectedObjects, &wSelectedItemList, + XmNselectedObjectCount, &countItems, NULL); + if (countItems > 1) + { + Iarray* markedArray = motTreeGetSelectedArrayId(ih, wSelectedItemList, countItems); + int* id_hitem = (int*)iupArrayGetData(markedArray); + int i, count = iupArrayCount(markedArray); + + if (cbMulti) + cbMulti(ih, id_hitem, iupArrayCount(markedArray)); + else + { + for (i=0; i<count; i++) + cbSelec(ih, id_hitem[i], 0); + } + + iupArrayDestroy(markedArray); + } + } +} + 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"); + int countItems, id1, id2, i; XtVaGetValues(ih->handle, XmNselectedObjects, &wSelectedItemList, XmNselectedObjectCount, &countItems, NULL); if (countItems == 0) return; - if (cbMulti || cbSelec) + /* Must be a continuous range of selection ids */ + motTreeFindRange(ih, wSelectedItemList, countItems, &id1, &id2); + countItems = id2-id1+1; + + if (cbMulti) { int* id_rowItem = malloc(sizeof(int) * countItems); - int i = 0; for(i = 0; i < countItems; i++) - id_rowItem[i] = motTreeGetNodeId(ih, wSelectedItemList[i]); + id_rowItem[i] = id1+i; - if (cbMulti) - cbMulti(ih, id_rowItem, countItems); - else - { - for (i=0; i<countItems; i++) - cbSelec(ih, id_rowItem[i], 1); - } + cbMulti(ih, id_rowItem, countItems); free(id_rowItem); } + else if (cbSelec) + { + for (i=0; i<countItems; i++) + cbSelec(ih, id1+i, 1); + } } 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 iupTreeFindNodeId(ih, wItem); return -1; } @@ -1965,7 +1794,7 @@ static void motTreeCallRenameCb(Ihandle* ih) cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); if (cbRename) { - if (cbRename(ih, motTreeGetNodeId(ih, wItem), title) == IUP_IGNORE) + if (cbRename(ih, iupTreeFindNodeId(ih, wItem), title) == IUP_IGNORE) ignore = 1; } @@ -1993,8 +1822,8 @@ static int motTreeCallDragDropCb(Ihandle* ih, Widget wItemDrag, Widget wItemDrop if (cbDragDrop) { - int drag_id = motTreeGetNodeId(ih, wItemDrag); - int drop_id = motTreeGetNodeId(ih, wItemDrop); + int drag_id = iupTreeFindNodeId(ih, wItemDrag); + int drop_id = iupTreeFindNodeId(ih, wItemDrop); return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl); } @@ -2069,6 +1898,10 @@ static void motTreeShowEditField(Ihandle* ih, Widget wItem) XmFontList fontlist; Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); + if (cbShowRename && cbShowRename(ih, iupTreeFindNodeId(ih, wItem))==IUP_IGNORE) + return; + XtVaGetValues(wItem, XmNx, &x, XmNy, &y, XmNwidth, &w, @@ -2083,16 +1916,16 @@ static void motTreeShowEditField(Ihandle* ih, Widget wItem) iupdrvImageGetInfo((void*)image, &w_img, NULL, NULL); w_img += 3; /* add some room for borders */ - iupmotSetArg(args, num_args, XmNx, x+w_img); /* x-position */ - iupmotSetArg(args, num_args, XmNy, y); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, w-w_img); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, h); /* default height to avoid 0 */ - iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); /* default padding */ - iupmotSetArg(args, num_args, XmNmarginWidth, 0); - iupmotSetArg(args, num_args, XmNforeground, color); - iupmotSetArg(args, num_args, XmNrenderTable, fontlist); - iupmotSetArg(args, num_args, XmNvalue, iupmotConvertString(title)); - iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNx, x+w_img); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, y); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, w-w_img); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, h); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNmarginHeight, ih->data->spacing); /* default padding */ + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNforeground, color); + iupMOT_SETARG(args, num_args, XmNrenderTable, fontlist); + iupMOT_SETARG(args, num_args, XmNvalue, iupmotConvertString(title)); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); cbEdit = XtCreateManagedWidget( child_id, /* child identifier */ @@ -2134,8 +1967,6 @@ static void motTreeSelectionCallback(Widget w, Ihandle* ih, XmContainerSelectCal (void)w; (void)nptr; -printf("SelectionCallback(%d)\n", nptr->selected_item_count); - if (ih->data->mark_mode == ITREE_MARK_MULTIPLE) { char key[5]; @@ -2149,11 +1980,13 @@ printf("SelectionCallback(%d)\n", nptr->selected_item_count); { if (IupGetCallback(ih, "MULTISELECTION_CB")) { + /* current selection same as the initial selection */ if (nptr->auto_selection_type==XmAUTO_NO_CHANGE) motTreeCallMultiSelectionCb(ih); } else { + /* current selection is caused by button drag */ if (nptr->auto_selection_type==XmAUTO_MOTION) motTreeCallMultiSelectionCb(ih); } @@ -2164,14 +1997,10 @@ printf("SelectionCallback(%d)\n", nptr->selected_item_count); cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); if (cbSelec) { - Widget wItemFocus = motTreeGetFocusNode(ih); - int curpos = motTreeGetNodeId(ih, wItemFocus); + Widget wItemFocus = iupdrvTreeGetFocusNode(ih); + int curpos = iupTreeFindNodeId(ih, wItemFocus); if (is_ctrl) - { - unsigned char isSelected; - XtVaGetValues(wItemFocus, XmNvisualEmphasis, &isSelected, NULL); - cbSelec(ih, curpos, isSelected == XmSELECTED? 1: 0); - } + cbSelec(ih, curpos, motTreeIsNodeSelected(wItemFocus)); else { int oldpos = iupAttribGetInt(ih, "_IUPTREE_OLDVALUE"); @@ -2218,7 +2047,7 @@ static void motTreeDefaultActionCallback(Widget w, Ihandle* ih, XmContainerSelec { IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); if (cbExecuteLeaf) - cbExecuteLeaf(ih, motTreeGetNodeId(ih, wItem)); + cbExecuteLeaf(ih, iupTreeFindNodeId(ih, wItem)); } } @@ -2295,15 +2124,14 @@ static void motTreeKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean iupmotHelpCallback(w, ih, NULL); else if ((motcode == XK_Down || motcode == XK_Up) && (evt->state & ControlMask)) { - Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); Widget wItem; - Widget wItemFocus = motTreeGetFocusNode(ih); + Widget wItemFocus = iupdrvTreeGetFocusNode(ih); /* Ctrl+Arrows move only focus */ if (motcode == XK_Down) - wItem = motTreeGetNextVisibleNode(ih, wRoot, wItemFocus); + wItem = motTreeGetNextVisibleNode(ih, wItemFocus, 1); else - wItem = motTreeGetPreviousVisibleNode(ih, wRoot, wItemFocus); + wItem = motTreeGetPreviousVisibleNode(ih, wItemFocus, 1); motTreeSetFocusNode(ih, wItem); *cont = False; @@ -2317,8 +2145,8 @@ static void motTreeKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean if (motcode == XK_Home) wItem = wRoot; - else - wItem = motTreeGetLastVisibleNode(ih, wRoot); + else /* motcode == XK_End */ + wItem = motTreeGetLastVisibleNode(ih); /* Ctrl+Arrows move only focus */ if (!(evt->state & ControlMask)) @@ -2326,7 +2154,7 @@ static void motTreeKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean /* Shift+Arrows select block */ if (evt->state & ShiftMask) { - Widget wItemFocus = motTreeGetFocusNode(ih); + Widget wItemFocus = iupdrvTreeGetFocusNode(ih); if (!wItemFocus) return; motTreeSelectRange(ih, wItemFocus, wItem, 1); @@ -2346,16 +2174,9 @@ static void motTreeKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean } else if(motcode == XK_space && (evt->state & ControlMask)) { - Widget wItemFocus = motTreeGetFocusNode(ih); + Widget wItemFocus = iupdrvTreeGetFocusNode(ih); if (wItemFocus) - { - unsigned char isSelected; - XtVaGetValues(wItemFocus, XmNvisualEmphasis, &isSelected, NULL); - if (isSelected == XmSELECTED) - XtVaSetValues(wItemFocus, XmNvisualEmphasis, XmNOT_SELECTED, NULL); - else - XtVaSetValues(wItemFocus, XmNvisualEmphasis, XmSELECTED, NULL); - } + motTreeSelectNode(wItemFocus, -1); } } @@ -2378,7 +2199,7 @@ static void motTreeButtonEvent(Widget w, Ihandle* ih, XButtonEvent* evt, Boolean if (evt->button==Button1) { - Widget wItemFocus = motTreeGetFocusNode(ih); + Widget wItemFocus = iupdrvTreeGetFocusNode(ih); static Widget wLastItem = NULL; static Time last = 0; int clicktwice = 0, doubleclicktime = XtGetMultiClickTime(iupmot_display); @@ -2395,6 +2216,11 @@ static void motTreeButtonEvent(Widget w, Ihandle* ih, XButtonEvent* evt, Boolean *cont = False; } wLastItem = wItemFocus; + + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && + !(evt->state & ShiftMask) && + !(evt->state & ControlMask)) + motTreeCallMultiUnSelectionCb(ih); } else if (evt->button==Button3) motTreeCallRightClickCb(ih, evt->x, evt->y); @@ -2436,21 +2262,18 @@ static void motTreeTransferProc(Widget drop_context, XtPointer client_data, Atom if (motTreeCallDragDropCb(ih, wItemDrag, wItemDrop, &is_ctrl) == IUP_CONTINUE) { - /* Copy the dragged item to the new position. */ - Widget wNewItem = motTreeCopyNode(ih, wItemDrag, wItemDrop, is_ctrl); + /* Copy or move the dragged item to the new position. */ + Widget wItemNew = motTreeCopyMoveNode(ih, wItemDrag, wItemDrop, is_ctrl); - if (!is_ctrl) + /* Set focus and selection */ + if (wItemNew) { - /* do not delete the user data, we copy the references in CopyNode */ - motTreeRemoveNode(ih, wItemDrag, 0); - } - - /* Select the dragged item */ - XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); - XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); - XtVaSetValues(wNewItem, XmNvisualEmphasis, XmSELECTED, NULL); + XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); + XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); + XtVaSetValues(wItemNew, XmNvisualEmphasis, XmSELECTED, NULL); - motTreeSetFocusNode(ih, wNewItem); + motTreeSetFocusNode(ih, wItemNew); + } } } @@ -2475,8 +2298,8 @@ static void motTreeDropProc(Widget w, XtPointer client_data, XmDropProcCallbackS drop_context = drop_data->dragContext; /* retrieve the data targets */ - iupmotSetArg(args, num_args, XmNexportTargets, &exportTargets); - iupmotSetArg(args, num_args, XmNnumExportTargets, &numExportTargets); + iupMOT_SETARG(args, num_args, XmNexportTargets, &exportTargets); + iupMOT_SETARG(args, num_args, XmNnumExportTargets, &numExportTargets); XtGetValues(drop_context, args, num_args); for (i = 0; i < (int)numExportTargets; i++) @@ -2495,17 +2318,17 @@ static void motTreeDropProc(Widget w, XtPointer client_data, XmDropProcCallbackS num_args = 0; if ((!found) || (drop_data->dropAction != XmDROP) || (drop_data->operation != XmDROP_COPY && drop_data->operation != XmDROP_MOVE)) { - iupmotSetArg(args, num_args, XmNtransferStatus, XmTRANSFER_FAILURE); - iupmotSetArg(args, num_args, XmNnumDropTransfers, 0); + iupMOT_SETARG(args, num_args, XmNtransferStatus, XmTRANSFER_FAILURE); + iupMOT_SETARG(args, num_args, XmNnumDropTransfers, 0); } else { /* set up transfer requests for drop site */ transferList[0].target = atomTreeItem; transferList[0].client_data = (XtPointer)wItemDrop; - iupmotSetArg(args, num_args, XmNdropTransfers, transferList); - iupmotSetArg(args, num_args, XmNnumDropTransfers, 1); - iupmotSetArg(args, num_args, XmNtransferProc, motTreeTransferProc); + iupMOT_SETARG(args, num_args, XmNdropTransfers, transferList); + iupMOT_SETARG(args, num_args, XmNnumDropTransfers, 1); + iupMOT_SETARG(args, num_args, XmNtransferProc, motTreeTransferProc); } XmDropTransferStart(drop_context, args, num_args); @@ -2584,23 +2407,23 @@ static void motTreeStartDrag(Widget w, XButtonEvent* evt, String* params, Cardin XmNforeground, &fg, NULL); - iupmotSetArg(args, num_args, XmNpixmap, pixmap); - iupmotSetArg(args, num_args, XmNmask, mask); + iupMOT_SETARG(args, num_args, XmNpixmap, pixmap); + iupMOT_SETARG(args, num_args, XmNmask, mask); drag_icon = XmCreateDragIcon(w, "drag_icon", args, num_args); exportList[0] = atomTreeItem; /* specify resources for DragContext for the transfer */ num_args = 0; - iupmotSetArg(args, num_args, XmNcursorBackground, bg); - iupmotSetArg(args, num_args, XmNcursorForeground, fg); - /* iupmotSetArg(args, num_args, XmNsourcePixmapIcon, drag_icon); works, but only outside the dialog, inside disapears */ - iupmotSetArg(args, num_args, XmNsourceCursorIcon, drag_icon); /* does not work, shows the default cursor */ - iupmotSetArg(args, num_args, XmNexportTargets, exportList); - iupmotSetArg(args, num_args, XmNnumExportTargets, 1); - iupmotSetArg(args, num_args, XmNdragOperations, XmDROP_MOVE|XmDROP_COPY); - iupmotSetArg(args, num_args, XmNconvertProc, motTreeConvertProc); - iupmotSetArg(args, num_args, XmNclientData, wItemDrag); + iupMOT_SETARG(args, num_args, XmNcursorBackground, bg); + iupMOT_SETARG(args, num_args, XmNcursorForeground, fg); + /* iupMOT_SETARG(args, num_args, XmNsourcePixmapIcon, drag_icon); works, but only outside the dialog, inside disapears */ + iupMOT_SETARG(args, num_args, XmNsourceCursorIcon, drag_icon); /* does not work, shows the default cursor */ + iupMOT_SETARG(args, num_args, XmNexportTargets, exportList); + iupMOT_SETARG(args, num_args, XmNnumExportTargets, 1); + iupMOT_SETARG(args, num_args, XmNdragOperations, XmDROP_MOVE|XmDROP_COPY); + iupMOT_SETARG(args, num_args, XmNconvertProc, motTreeConvertProc); + iupMOT_SETARG(args, num_args, XmNclientData, wItemDrag); /* start the drag and register a callback to clean up when done */ drop_context = XmDragStart(w, (XEvent*)evt, args, num_args); @@ -2628,10 +2451,10 @@ static void motTreeEnableDragDrop(Widget w) XtOverrideTranslations(w, XtParseTranslationTable(dragTranslations)); importList[0] = atomTreeItem; - iupmotSetArg(args, num_args, XmNimportTargets, importList); - iupmotSetArg(args, num_args, XmNnumImportTargets, 1); - iupmotSetArg(args, num_args, XmNdropSiteOperations, XmDROP_MOVE|XmDROP_COPY); - iupmotSetArg(args, num_args, XmNdropProc, motTreeDropProc); + iupMOT_SETARG(args, num_args, XmNimportTargets, importList); + iupMOT_SETARG(args, num_args, XmNnumImportTargets, 1); + iupMOT_SETARG(args, num_args, XmNdropSiteOperations, XmDROP_MOVE|XmDROP_COPY); + iupMOT_SETARG(args, num_args, XmNdropProc, motTreeDropProc); XmDropSiteUpdate(w, args, num_args); XtVaSetValues(XmGetXmDisplay(iupmot_display), XmNenableDragIcon, True, NULL); @@ -2648,13 +2471,13 @@ static int motTreeMapMethod(Ihandle* ih) /******************************/ /* Create the scrolled window */ /******************************/ - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAUTOMATIC); - iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); - iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); - iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ - iupmotSetArg(args, num_args, XmNborderWidth, 0); - iupmotSetArg(args, num_args, XmNshadowThickness, 2); + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNscrollingPolicy, XmAUTOMATIC); + iupMOT_SETARG(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupMOT_SETARG(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); + iupMOT_SETARG(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ + iupMOT_SETARG(args, num_args, XmNborderWidth, 0); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 2); sb_win = XtCreateManagedWidget( child_id, /* child identifier */ @@ -2672,37 +2495,37 @@ static int motTreeMapMethod(Ihandle* ih) num_args = 0; - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ - iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ - iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupMOT_SETARG(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupMOT_SETARG(args, num_args, XmNmarginWidth, 0); if (iupAttribGetBoolean(ih, "CANFOCUS")) - iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); else - iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); - iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); - iupmotSetArg(args, num_args, XmNhighlightThickness, 2); - iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); + iupMOT_SETARG(args, num_args, XmNshadowThickness, 0); - iupmotSetArg(args, num_args, XmNlayoutType, XmOUTLINE); - iupmotSetArg(args, num_args, XmNentryViewType, XmSMALL_ICON); - iupmotSetArg(args, num_args, XmNselectionPolicy, XmSINGLE_SELECT); - iupmotSetArg(args, num_args, XmNoutlineIndentation, 20); + iupMOT_SETARG(args, num_args, XmNlayoutType, XmOUTLINE); + iupMOT_SETARG(args, num_args, XmNentryViewType, XmSMALL_ICON); + iupMOT_SETARG(args, num_args, XmNselectionPolicy, XmSINGLE_SELECT); + iupMOT_SETARG(args, num_args, XmNoutlineIndentation, 20); if (iupAttribGetBoolean(ih, "HIDELINES")) - iupmotSetArg(args, num_args, XmNoutlineLineStyle, XmNO_LINE); + iupMOT_SETARG(args, num_args, XmNoutlineLineStyle, XmNO_LINE); else - iupmotSetArg(args, num_args, XmNoutlineLineStyle, XmSINGLE); + iupMOT_SETARG(args, num_args, XmNoutlineLineStyle, XmSINGLE); if (iupAttribGetBoolean(ih, "HIDEBUTTONS")) - iupmotSetArg(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_ABSENT); + iupMOT_SETARG(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_ABSENT); else - iupmotSetArg(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_PRESENT); + iupMOT_SETARG(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_PRESENT); ih->handle = XtCreateManagedWidget( child_id, /* child identifier */ @@ -2788,17 +2611,30 @@ static int motTreeMapMethod(Ihandle* ih) if (!ih->data->def_image_expanded_mask) ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP; } - motTreeAddRootNode(ih); + if (iupAttribGetInt(ih, "ADDROOT")) + iupdrvTreeAddNode(ih, "-1", ITREE_BRANCH, "", 0); IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)motTreeConvertXYToPos); + iupdrvTreeUpdateMarkMode(ih); + return IUP_NOERROR; } +static void motTreeUnMapMethod(Ihandle* ih) +{ + motTreeRemoveAllNodes(ih, 0); + + ih->data->node_count = 0; + + iupdrvBaseUnMapMethod(ih); +} + void iupdrvTreeInitClass(Iclass* ic) { /* Driver Dependent Class functions */ ic->Map = motTreeMapMethod; + ic->UnMap = motTreeUnMapMethod; /* Visual */ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motTreeSetBgColorAttrib, "TXTBGCOLOR", NULL, IUPAF_DEFAULT); @@ -2807,7 +2643,6 @@ void iupdrvTreeInitClass(Iclass* ic) /* IupTree Attributes - GENERAL */ iupClassRegisterAttribute(ic, "EXPANDALL", NULL, motTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY||IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "INDENTATION", motTreeGetIndentationAttrib, motTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT); - iupClassRegisterAttribute(ic, "COUNT", motTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, motTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); iupClassRegisterAttribute(ic, "TOPITEM", NULL, motTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); @@ -2827,7 +2662,6 @@ void iupdrvTreeInitClass(Iclass* ic) iupClassRegisterAttributeId(ic, "COLOR", motTreeGetColorAttrib, motTreeSetColorAttrib, IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "NAME", motTreeGetTitleAttrib, motTreeSetTitleAttrib, IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "TITLE", motTreeGetTitleAttrib, motTreeSetTitleAttrib, IUPAF_NO_INHERIT); - iupClassRegisterAttributeId(ic, "USERDATA", motTreeGetUserDataAttrib, motTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "CHILDCOUNT", motTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "TITLEFONT", motTreeGetTitleFontAttrib, motTreeSetTitleFontAttrib, IUPAF_NO_INHERIT); @@ -2836,6 +2670,7 @@ void iupdrvTreeInitClass(Iclass* ic) iupClassRegisterAttribute (ic, "MARK", NULL, motTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute (ic, "STARTING", NULL, motTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); iupClassRegisterAttribute (ic, "MARKSTART", NULL, motTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARKEDNODES", motTreeGetMarkedNodesAttrib, motTreeSetMarkedNodesAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); iupClassRegisterAttribute (ic, "VALUE", motTreeGetValueAttrib, motTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); @@ -2844,5 +2679,4 @@ void iupdrvTreeInitClass(Iclass* ic) iupClassRegisterAttribute(ic, "RENAME", NULL, motTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "MOVENODE", NULL, motTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "COPYNODE", NULL, motTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); - iupClassRegisterAttributeId(ic, "FINDUSERDATA", motTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); } diff --git a/iup/src/mot/iupmot_val.c b/iup/src/mot/iupmot_val.c index 200d2b4..ce9eba7 100755 --- a/iup/src/mot/iupmot_val.c +++ b/iup/src/mot/iupmot_val.c @@ -383,41 +383,41 @@ static int motValMapMethod(Ihandle* ih) int show_ticks; /* Core */ - iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ - iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ - iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ - iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ - iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupMOT_SETARG(args, num_args, XmNx, 0); /* x-position */ + iupMOT_SETARG(args, num_args, XmNy, 0); /* y-position */ + iupMOT_SETARG(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupMOT_SETARG(args, num_args, XmNheight, 10); /* default height to avoid 0 */ /* Primitive */ if (iupAttribGetBoolean(ih, "CANFOCUS")) - iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupMOT_SETARG(args, num_args, XmNtraversalOn, True); else - iupmotSetArg(args, num_args, XmNtraversalOn, False); - iupmotSetArg(args, num_args, XmNhighlightThickness, 2); - iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupMOT_SETARG(args, num_args, XmNtraversalOn, False); + iupMOT_SETARG(args, num_args, XmNhighlightThickness, 2); + iupMOT_SETARG(args, num_args, XmNnavigationType, XmTAB_GROUP); /* Scale */ - iupmotSetArg(args, num_args, XmNminimum, 0); - iupmotSetArg(args, num_args, XmNmaximum, SHRT_MAX); - iupmotSetArg(args, num_args, XmNslidingMode, XmSLIDER); - iupmotSetArg(args, num_args, XmNsliderMark, XmETCHED_LINE); - iupmotSetArg(args, num_args, XmNsliderSize, 16); - iupmotSetArg(args, num_args, XmNshowValue, XmNONE); + iupMOT_SETARG(args, num_args, XmNminimum, 0); + iupMOT_SETARG(args, num_args, XmNmaximum, SHRT_MAX); + iupMOT_SETARG(args, num_args, XmNslidingMode, XmSLIDER); + iupMOT_SETARG(args, num_args, XmNsliderMark, XmETCHED_LINE); + iupMOT_SETARG(args, num_args, XmNsliderSize, 16); + iupMOT_SETARG(args, num_args, XmNshowValue, XmNONE); if (ih->data->type == IVAL_HORIZONTAL) { - iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); + iupMOT_SETARG(args, num_args, XmNorientation, XmHORIZONTAL); if (ih->data->inverted) - iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_LEFT); + iupMOT_SETARG(args, num_args, XmNprocessingDirection, XmMAX_ON_LEFT); else - iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_RIGHT); + iupMOT_SETARG(args, num_args, XmNprocessingDirection, XmMAX_ON_RIGHT); } else { - iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); + iupMOT_SETARG(args, num_args, XmNorientation, XmVERTICAL); if (ih->data->inverted) - iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_TOP); + iupMOT_SETARG(args, num_args, XmNprocessingDirection, XmMAX_ON_TOP); else - iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_BOTTOM); + iupMOT_SETARG(args, num_args, XmNprocessingDirection, XmMAX_ON_BOTTOM); } ih->handle = XtCreateManagedWidget( diff --git a/iup/src/mot/iupunix_info.c b/iup/src/mot/iupunix_info.c index b522638..f09573c 100755 --- a/iup/src/mot/iupunix_info.c +++ b/iup/src/mot/iupunix_info.c @@ -282,7 +282,7 @@ char *iupdrvGetSystemName(void) char *iupdrvGetSystemVersion(void) { struct utsname un; - char *str = iupStrGetMemory(60); + char *str = iupStrGetMemory(100); uname(&un); strcpy(str, un.release); diff --git a/iup/src/win/iupwin_button.c b/iup/src/win/iupwin_button.c index 7f780e3..3b05ba7 100755 --- a/iup/src/win/iupwin_button.c +++ b/iup/src/win/iupwin_button.c @@ -27,6 +27,7 @@ #include "iupwin_drv.h" #include "iupwin_handle.h" #include "iupwin_draw.h" +#include "iupwin_info.h" #ifndef CDIS_SHOWKEYBOARDCUES @@ -308,18 +309,22 @@ static void winButtonDrawText(Ihandle* ih, HDC hDC, int rect_width, int rect_hei static void winButtonDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem) { + HDC hDC; iupwinBitmapDC bmpDC; int border, draw_border; int width = drawitem->rcItem.right - drawitem->rcItem.left; int height = drawitem->rcItem.bottom - drawitem->rcItem.top; - HDC hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height); + hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height); iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem); if ((drawitem->itemState & ODS_FOCUS) && !(drawitem->itemState & ODS_HOTLIGHT)) drawitem->itemState |= ODS_DEFAULT; + if (iupAttribGet(ih, "_IUPWINBUT_SELECTED")) + drawitem->itemState |= ODS_SELECTED; + border = winButtonGetBorder(); if (ih->data->type & IUP_BUTTON_IMAGE && iupAttribGet(ih, "IMPRESS") && !iupAttribGetStr(ih, "IMPRESSBORDER")) @@ -365,7 +370,7 @@ static int winButtonSetImageAttrib(Ihandle* ih, const char* value) (void)value; if (ih->data->type != IUP_BUTTON_TEXT) { - iupdrvDisplayUpdate(ih); + iupdrvPostRedraw(ih); return 1; } else @@ -377,7 +382,7 @@ static int winButtonSetImInactiveAttrib(Ihandle* ih, const char* value) (void)value; if (ih->data->type != IUP_BUTTON_TEXT) { - iupdrvDisplayUpdate(ih); + iupdrvPostRedraw(ih); return 1; } else @@ -389,7 +394,7 @@ static int winButtonSetImPressAttrib(Ihandle* ih, const char* value) (void)value; if (ih->data->type != IUP_BUTTON_TEXT) { - iupdrvDisplayUpdate(ih); + iupdrvPostRedraw(ih); return 1; } else @@ -400,7 +405,7 @@ static int winButtonSetActiveAttrib(Ihandle* ih, const char* value) { /* redraw IMINACTIVE image if any */ if (ih->data->type != IUP_BUTTON_TEXT) - iupdrvDisplayUpdate(ih); + iupdrvPostRedraw(ih); return iupBaseSetActiveAttrib(ih, value); } @@ -425,7 +430,7 @@ static int winButtonSetAlignmentAttrib(Ihandle* ih, const char* value) else /* "ACENTER" */ ih->data->vert_alignment = IUP_ALIGN_ACENTER; - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); return 1; } @@ -443,7 +448,7 @@ static int winButtonSetPaddingAttrib(Ihandle* ih, const char* value) { iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); if (ih->handle) - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); return 0; } @@ -454,7 +459,7 @@ static int winButtonSetBgColorAttrib(Ihandle* ih, const char* value) { iupAttribSetStr(ih, "BGCOLOR", value); iupImageUpdateParent(ih); - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); } return 1; } @@ -486,7 +491,9 @@ static int winButtonSetFgColorAttrib(Ihandle* ih, const char* value) if (iupStrToRGB(value, &r, &g, &b)) { ih->data->fgcolor = RGB(r,g,b); - iupdrvDisplayRedraw(ih); + + if (ih->handle) + iupdrvRedrawNow(ih); } return 1; } @@ -499,7 +506,7 @@ static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r { /* redraw IMPRESS image if any */ if ((msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) && iupAttribGet(ih, "IMPRESS")) - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); } switch (msg) @@ -514,6 +521,13 @@ static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r case WM_RBUTTONDOWN: { iupwinButtonDown(ih, msg, wp, lp); + + /* Feedback will NOT be done when not receiving the focus */ + if (msg==WM_LBUTTONDOWN && !iupAttribGetBoolean(ih, "FOCUSONCLICK")) + { + iupAttribSetStr(ih, "_IUPWINBUT_SELECTED", "1"); + iupdrvRedrawNow(ih); + } break; } case WM_XBUTTONUP: @@ -526,11 +540,24 @@ static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r /* BN_CLICKED will NOT be notified when not receiving the focus */ if (msg==WM_LBUTTONUP && !iupAttribGetBoolean(ih, "FOCUSONCLICK")) { - Icallback cb = IupGetCallback(ih, "ACTION"); + Icallback cb; + + iupAttribSetStr(ih, "_IUPWINBUT_SELECTED", NULL); + iupdrvRedrawNow(ih); + + cb = IupGetCallback(ih, "ACTION"); if (cb && cb(ih) == IUP_CLOSE) IupExitLoop(); } + if (!iupwinIsVistaOrNew()) + { + /* TIPs desapear forever after a button click in XP, + so we force an update. */ + char* tip = iupAttribGet(ih, "TIP"); + if (tip) + iupdrvBaseSetTipAttrib(ih, tip); + } break; } case WM_KEYDOWN: @@ -549,7 +576,12 @@ static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r if (!iupwin_comctl32ver6) { iupAttribSetStr(ih, "_IUPWINBUT_ENTERWIN", NULL); - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); + } + if (!iupAttribGetBoolean(ih, "FOCUSONCLICK")) + { + iupAttribSetStr(ih, "_IUPWINBUT_SELECTED", NULL); + iupdrvRedrawNow(ih); } break; case WM_MOUSEMOVE: @@ -558,7 +590,7 @@ static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r if (!iupAttribGet(ih, "_IUPWINBUT_ENTERWIN")) { iupAttribSetStr(ih, "_IUPWINBUT_ENTERWIN", "1"); - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); } } break; @@ -635,7 +667,7 @@ static int winButtonWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp) static int winButtonMapMethod(Ihandle* ih) { char* value; - DWORD dwStyle = WS_CHILD | + DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | BS_NOTIFY; /* necessary because of the base messages */ if (!ih->parent) @@ -661,7 +693,7 @@ static int winButtonMapMethod(Ihandle* ih) ih->data->type = IUP_BUTTON_IMAGE; value = iupAttribGet(ih, "TITLE"); - if (value) + if (value && *value!=0) ih->data->type |= IUP_BUTTON_TEXT; } else diff --git a/iup/src/win/iupwin_canvas.c b/iup/src/win/iupwin_canvas.c index bb88b8a..b865160 100755 --- a/iup/src/win/iupwin_canvas.c +++ b/iup/src/win/iupwin_canvas.c @@ -45,7 +45,7 @@ static void winCanvasSetScrollInfo(HWND hWnd, int imin, int imax, int ipos, int static int winCanvasSetBgColorAttrib(Ihandle *ih, const char *value) { (void)value; - iupdrvDisplayUpdate(ih); + iupdrvPostRedraw(ih); return 1; } @@ -220,7 +220,7 @@ static void winCanvasUpdateHorScroll(Ihandle* ih, WORD winop) xmax = iupAttribGetFloat(ih,"XMAX"); xmin = iupAttribGetFloat(ih,"XMIN"); - winCanvasGetScrollInfo(ih->handle, &iposx, &ipagex, SB_HORZ, winop==SB_THUMBTRACK? 1: 0); + winCanvasGetScrollInfo(ih->handle, &iposx, &ipagex, SB_HORZ, winop==SB_THUMBTRACK||winop==SB_THUMBPOSITION? 1: 0); if (!iupAttribGet(ih,"LINEX")) { @@ -296,7 +296,7 @@ static void winCanvasUpdateVerScroll(Ihandle* ih, WORD winop) ymax = iupAttribGetFloat(ih,"YMAX"); ymin = iupAttribGetFloat(ih,"YMIN"); - winCanvasGetScrollInfo(ih->handle, &iposy, &ipagey, SB_VERT, winop==SB_THUMBTRACK? 1: 0); + winCanvasGetScrollInfo(ih->handle, &iposy, &ipagey, SB_VERT, winop==SB_THUMBTRACK||winop==SB_THUMBPOSITION? 1: 0); if (!iupAttribGet(ih, "LINEY")) { @@ -372,6 +372,10 @@ static int winCanvasProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r GetClientRect(ih->handle, &rect); FillRect(hdc, &rect, iupwinBrushGet(color)); } + else + InvalidateRect(ih->handle,NULL,FALSE); /* This will invalidate all area. + Necessary in XP, or overlapping windows will have the effect of partial redrawing. */ + /* always return non zero value */ *result = 1; return 1; @@ -382,7 +386,7 @@ static int winCanvasProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r { PAINTSTRUCT ps; HDC hdc = BeginPaint(ih->handle, &ps); - iupAttribSetStr(ih, "HDC_WMPAINT", (char*)&hdc); + iupAttribSetStr(ih, "HDC_WMPAINT", (char*)hdc); iupAttribSetStrf(ih, "CLIPRECT", "%d %d %d %d", ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top); cb(ih, ih->data->posx, ih->data->posy); @@ -542,27 +546,13 @@ static int winCanvasProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *r return iupwinBaseProc(ih, msg, wp, lp, result); } -static void winCanvasRegisterClass(void) -{ - WNDCLASS wndclass; - ZeroMemory(&wndclass, sizeof(WNDCLASS)); - - wndclass.hInstance = iupwin_hinstance; - wndclass.lpszClassName = "IupCanvas"; - wndclass.lpfnWndProc = (WNDPROC)iupwinBaseWinProc; - wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); - wndclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; /* using CS_OWNDC will minimize the work of cdActivate in the CD library */ - wndclass.hbrBackground = NULL; /* remove the background to optimize redraw */ - - RegisterClass(&wndclass); -} - static int winCanvasMapMethod(Ihandle* ih) { CLIENTCREATESTRUCT clientstruct; void *clientdata = NULL; char *classname; - DWORD dwStyle = WS_CHILD, dwExStyle = 0; + DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS, + dwExStyle = 0; if (!ih->parent) return IUP_ERROR; @@ -574,14 +564,7 @@ static int winCanvasMapMethod(Ihandle* ih) } if (ih->firstchild) /* can be a container */ - { - dwStyle |= WS_CLIPSIBLINGS; - - if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) - dwExStyle |= WS_EX_COMPOSITED; - else - dwStyle |= WS_CLIPCHILDREN; - } + iupwinGetNativeParentStyle(ih, &dwExStyle, &dwStyle); if (iupAttribGetBoolean(ih, "MDICLIENT")) { @@ -693,6 +676,21 @@ static void winCanvasReleaseMethod(Iclass* ic) UnregisterClass("IupCanvas", iupwin_hinstance); } +static void winCanvasRegisterClass(void) +{ + WNDCLASS wndclass; + ZeroMemory(&wndclass, sizeof(WNDCLASS)); + + wndclass.hInstance = iupwin_hinstance; + wndclass.lpszClassName = "IupCanvas"; + wndclass.lpfnWndProc = (WNDPROC)iupwinBaseWinProc; + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; /* using CS_OWNDC will minimize the work of cdActivate in the CD library */ + wndclass.hbrBackground = NULL; /* remove the background to optimize redraw */ + + RegisterClass(&wndclass); +} + void iupdrvCanvasInitClass(Iclass* ic) { if (!iupwinClassExist("IupCanvas")) diff --git a/iup/src/win/iupwin_common.c b/iup/src/win/iupwin_common.c index a1a7c0f..ba68b78 100755 --- a/iup/src/win/iupwin_common.c +++ b/iup/src/win/iupwin_common.c @@ -94,16 +94,17 @@ void iupdrvBaseLayoutUpdateMethod(Ihandle *ih) SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER); } -void iupdrvDisplayRedraw(Ihandle *ih) +void iupdrvRedrawNow(Ihandle *ih) { /* REDRAW Now */ - RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_NOCHILDREN|RDW_UPDATENOW); + RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_UPDATENOW); } -void iupdrvDisplayUpdate(Ihandle *ih) +void iupdrvPostRedraw(Ihandle *ih) { /* Post a REDRAW */ - RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_NOCHILDREN); + /* can NOT use RDW_NOCHILDREN because IupList has internal children that needs to be redraw */ + RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT); } void iupdrvScreenToClient(Ihandle* ih, int *x, int *y) @@ -534,6 +535,8 @@ int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value) void iupdrvSetVisible(Ihandle* ih, int visible) { + if (iupStrEqual(ih->iclass->name, "colorbar")) + ih=ih; ShowWindow(ih->handle, visible? SW_SHOWNORMAL: SW_HIDE); } @@ -618,6 +621,18 @@ char* iupdrvBaseGetClientSizeAttrib(Ihandle* ih) #define IDC_HELP MAKEINTRESOURCE(32651) #endif +static HCURSOR winLoadComCtlCursor(LPCTSTR lpCursorName) +{ + HCURSOR cur = NULL; + HINSTANCE hinstDll = LoadLibrary("comctl32.dll"); + if (hinstDll) + { + cur = LoadCursor(hinstDll, lpCursorName); + FreeLibrary(hinstDll); + } + return cur; +} + static HCURSOR winGetCursor(Ihandle* ih, const char* name) { static struct { @@ -649,7 +664,7 @@ static HCURSOR winGetCursor(Ihandle* ih, const char* name) {"APPSTARTING", IDC_APPSTARTING} }; - HCURSOR cur; + HCURSOR cur = NULL; char str[50]; int i, count = sizeof(table)/sizeof(table[0]); @@ -676,14 +691,22 @@ static HCURSOR winGetCursor(Ihandle* ih, const char* name) if (i == count) { /* check other system cursors */ - /* cursor PEN is handled here */ + if (iupStrEqualNoCase(name, "PEN")) - name = "CURSOR_PEN"; + name = "CURSOR_PEN"; /* name in "iup.rc" */ /* check for an name defined cursor */ cur = iupImageGetCursor(name); } + if (!cur) + { + if (iupStrEqualNoCase(name, "SPLITTER_VERT")) + cur = winLoadComCtlCursor(MAKEINTRESOURCE(107)); + else if (iupStrEqualNoCase(name, "SPLITTER_HORIZ")) + cur = winLoadComCtlCursor(MAKEINTRESOURCE(135)); + } + iupAttribSetStr(ih, str, (char*)cur); return cur; } @@ -758,29 +781,29 @@ int iupwinButtonUp(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp) if (msg==WM_LBUTTONUP) { b = IUP_BUTTON1; - iupKEYSETBUTTON1(status); + iupKEY_SETBUTTON1(status); } else if (msg==WM_MBUTTONUP) { b = IUP_BUTTON2; - iupKEYSETBUTTON2(status); + iupKEY_SETBUTTON2(status); } else if (msg==WM_RBUTTONUP) { b = IUP_BUTTON3; - iupKEYSETBUTTON3(status); + iupKEY_SETBUTTON3(status); } else if (msg==WM_XBUTTONUP) { if (HIWORD(wp) == XBUTTON1) { b = IUP_BUTTON4; - iupKEYSETBUTTON4(status); + iupKEY_SETBUTTON4(status); } else { b = IUP_BUTTON5; - iupKEYSETBUTTON5(status); + iupKEY_SETBUTTON5(status); } } @@ -807,6 +830,14 @@ int iupwinMouseMove(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp) return 0; } +void iupwinGetNativeParentStyle(Ihandle* ih, DWORD *dwExStyle, DWORD *dwStyle) +{ + *dwStyle |= WS_CLIPCHILDREN; + + if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) + *dwExStyle |= WS_EX_COMPOSITED; +} + int iupwinCreateWindowEx(Ihandle* ih, LPCSTR lpClassName, DWORD dwExStyle, DWORD dwStyle) { ih->serial = iupDialogGetChildId(ih); diff --git a/iup/src/win/iupwin_dialog.c b/iup/src/win/iupwin_dialog.c index 39fdc0c..c13b88d 100755 --- a/iup/src/win/iupwin_dialog.c +++ b/iup/src/win/iupwin_dialog.c @@ -102,9 +102,9 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu else { int has_titlebar = iupAttribGetBoolean(ih, "MAXBOX") || - iupAttribGetBoolean(ih, "MINBOX") || - iupAttribGetBoolean(ih, "MENUBOX") || - IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ + iupAttribGetBoolean(ih, "MINBOX") || + iupAttribGetBoolean(ih, "MENUBOX") || + IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ *caption = 0; if (has_titlebar) @@ -118,14 +118,17 @@ void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu *border = 0; if (iupAttribGetBoolean(ih, "RESIZE")) { + /* has_border */ *border = GetSystemMetrics(SM_CXFRAME); /* Thickness of the sizing border around the perimeter of a window */ } /* that can be resized, in pixels. */ else if (has_titlebar) { + /* has_border */ *border = GetSystemMetrics(SM_CXFIXEDFRAME); /* Thickness of the frame around the perimeter of a window */ } /* that has a caption but is not sizable, in pixels. */ else if (iupAttribGetBoolean(ih, "BORDER")) { + /* has_border */ *border = GetSystemMetrics(SM_CXBORDER); } } @@ -712,28 +715,27 @@ static int winDialogMapMethod(Ihandle* ih) } if (iupAttribGetBoolean(ih, "RESIZE")) + { dwStyle |= WS_THICKFRAME; + has_border = 1; + } else iupAttribSetStr(ih, "MAXBOX", "NO"); /* Must also remove this to RESIZE=NO work */ - if (iupAttribGetBoolean(ih, "MAXBOX")) { dwStyle |= WS_MAXIMIZEBOX; has_titlebar = 1; } - if (iupAttribGetBoolean(ih, "MINBOX")) { dwStyle |= WS_MINIMIZEBOX; has_titlebar = 1; } - if (iupAttribGetBoolean(ih, "MENUBOX")) { dwStyle |= WS_SYSMENU; has_titlebar = 1; } - if (iupAttribGetBoolean(ih, "BORDER") || has_titlebar) has_border = 1; @@ -815,10 +817,7 @@ static int winDialogMapMethod(Ihandle* ih) if (iupAttribGetBoolean(ih, "DIALOGFRAME") && native_parent) dwExStyle |= WS_EX_DLGMODALFRAME; /* this will hide the MENUBOX but not the close button */ - if (iupAttribGetBoolean(ih, "COMPOSITED")) - dwExStyle |= WS_EX_COMPOSITED; - else - dwStyle |= WS_CLIPCHILDREN; + iupwinGetNativeParentStyle(ih, &dwExStyle, &dwStyle); if (iupAttribGetBoolean(ih, "HELPBUTTON")) dwExStyle |= WS_EX_CONTEXTHELP; @@ -878,7 +877,6 @@ static int winDialogMapMethod(Ihandle* ih) /* Reset attributes handled during creation that */ /* also can be changed later, and can be consulted from the native system. */ iupAttribSetStr(ih, "TITLE", NULL); - iupAttribSetStr(ih, "BORDER", NULL); /* Ignore VISIBLE before mapping */ iupAttribSetStr(ih, "VISIBLE", NULL); @@ -956,7 +954,7 @@ static int winDialogSetBgColorAttrib(Ihandle* ih, const char* value) { iupAttribStoreStr(ih, "_IUPWIN_BACKGROUND_COLOR", value); iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_BITMAP", NULL); - RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_ERASENOW); /* force a WM_ERASEBKGND now */ + RedrawWindow(ih->handle, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN); /* post WM_ERASEBKGND and WM_PAINT */ return 1; } return 0; @@ -973,7 +971,7 @@ static int winDialogSetBackgroundAttrib(Ihandle* ih, const char* value) { iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_COLOR", NULL); iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_BITMAP", (char*)hBitmap); - RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_ERASENOW); /* force a WM_ERASEBKGND now */ + RedrawWindow(ih->handle, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN); /* post WM_ERASEBKGND and WM_PAINT */ return 1; } } diff --git a/iup/src/win/iupwin_draw.c b/iup/src/win/iupwin_draw.c index 4a810e6..f663d20 100755 --- a/iup/src/win/iupwin_draw.c +++ b/iup/src/win/iupwin_draw.c @@ -14,12 +14,16 @@ #include <stdio.h> #include <string.h> #include <memory.h> +#include <math.h> #include "iup.h" #include "iup_attrib.h" #include "iup_class.h" #include "iup_str.h" +#include "iup_object.h" +#include "iup_image.h" +#include "iup_draw.h" #include "iupwin_drv.h" #include "iupwin_info.h" @@ -38,6 +42,11 @@ #endif +/****************************************************************************** + Themes +*******************************************************************************/ + + typedef HTHEME (STDAPICALLTYPE *_winThemeOpenData)(HWND hwnd, LPCWSTR pszClassList); typedef HRESULT (STDAPICALLTYPE *_winThemeCloseData)(HTHEME hTheme); typedef HRESULT (STDAPICALLTYPE *_winThemeDrawBackground)(HTHEME hTheme, HDC hDC, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect); @@ -61,58 +70,6 @@ static int winDrawThemeEnabled(void) return winThemeOpenData? 1: 0; } -void iupwinDrawText(HDC hDC, const char* text, int x, int y, int width, int height, HFONT hFont, COLORREF fgcolor, int style) -{ - COLORREF oldcolor; - RECT rect; - HFONT hOldFont = SelectObject(hDC, hFont); - - rect.left = x; - rect.top = y; - rect.right = x+width; - rect.bottom = y+height; - - SetTextAlign(hDC, TA_TOP|TA_LEFT); - SetBkMode(hDC, TRANSPARENT); - oldcolor = SetTextColor(hDC, fgcolor); - - DrawText(hDC, text, -1, &rect, style|DT_NOCLIP); - - SelectObject(hDC, hOldFont); - SetTextColor(hDC, oldcolor); - SetBkMode(hDC, OPAQUE); -} - -void iupwinDrawBitmap(HDC hDC, HBITMAP hBitmap, HBITMAP hMask, int x, int y, int width, int height, int bpp) -{ - HDC hMemDC = CreateCompatibleDC(hDC); - SelectObject(hMemDC, hBitmap); - - if (bpp == 32 && winAlphaBlend) - { - BLENDFUNCTION blendfunc; - blendfunc.BlendOp = AC_SRC_OVER; - blendfunc.BlendFlags = 0; - blendfunc.SourceConstantAlpha = 0xFF; - blendfunc.AlphaFormat = AC_SRC_ALPHA; - - winAlphaBlend(hDC, x, y, width, height, - hMemDC, 0, 0, width, height, - blendfunc); - } - else if (bpp == 8 && hMask) - MaskBlt(hDC, x, y, width, height, - hMemDC, 0, 0, - hMask, 0, 0, MAKEROP4(SRCCOPY, 0xAA0000)); - else - BitBlt(hDC, x, y, width, height, - hMemDC, 0, 0, - SRCCOPY); - - - DeleteDC(hMemDC); -} - void iupwinDrawInit(void) { if (!winAlphaBlend) @@ -201,7 +158,7 @@ int iupwinDrawGetThemeTabsBgColor(HWND hWnd, COLORREF *color) if (!hTheme) return 0; - if (iupwinIsVista()) + if (iupwinIsVistaOrNew()) ret = winThemeGetColor(hTheme, TABP_AEROWIZARDBODY, TIS_NORMAL, TMT_FILLCOLORHINT, color); else ret = winThemeGetColor(hTheme, TABP_BODY, TIS_NORMAL, TMT_FILLCOLORHINT, color); @@ -246,6 +203,79 @@ int iupwinDrawGetThemeFrameFgColor(HWND hWnd, COLORREF *color) return (ret == S_OK)? 1: 0; } +void iupwinDrawRemoveTheme(HWND hwnd) +{ + typedef HRESULT (STDAPICALLTYPE *winSetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList); + static winSetWindowTheme mySetWindowTheme = NULL; + if (!mySetWindowTheme) + { + HMODULE hinstDll = LoadLibrary("uxtheme.dll"); + if (hinstDll) + mySetWindowTheme = (winSetWindowTheme)GetProcAddress(hinstDll, "SetWindowTheme"); + } + + if (mySetWindowTheme) + mySetWindowTheme(hwnd, L"", L""); +} + + +/****************************************************************************** + Utilities +*******************************************************************************/ + + +void iupwinDrawText(HDC hDC, const char* text, int x, int y, int width, int height, HFONT hFont, COLORREF fgcolor, int style) +{ + COLORREF oldcolor; + RECT rect; + HFONT hOldFont = SelectObject(hDC, hFont); + + rect.left = x; + rect.top = y; + rect.right = x+width; + rect.bottom = y+height; + + SetTextAlign(hDC, TA_TOP|TA_LEFT); + SetBkMode(hDC, TRANSPARENT); + oldcolor = SetTextColor(hDC, fgcolor); + + DrawText(hDC, text, -1, &rect, style|DT_NOCLIP); + + SelectObject(hDC, hOldFont); + SetTextColor(hDC, oldcolor); + SetBkMode(hDC, OPAQUE); +} + +void iupwinDrawBitmap(HDC hDC, HBITMAP hBitmap, HBITMAP hMask, int x, int y, int width, int height, int bpp) +{ + HDC hMemDC = CreateCompatibleDC(hDC); + SelectObject(hMemDC, hBitmap); + + if (bpp == 32 && winAlphaBlend) + { + BLENDFUNCTION blendfunc; + blendfunc.BlendOp = AC_SRC_OVER; + blendfunc.BlendFlags = 0; + blendfunc.SourceConstantAlpha = 0xFF; + blendfunc.AlphaFormat = AC_SRC_ALPHA; + + winAlphaBlend(hDC, x, y, width, height, + hMemDC, 0, 0, width, height, + blendfunc); + } + else if (bpp == 8 && hMask) + MaskBlt(hDC, x, y, width, height, + hMemDC, 0, 0, + hMask, 0, 0, MAKEROP4(SRCCOPY, 0xAA0000)); + else + BitBlt(hDC, x, y, width, height, + hMemDC, 0, 0, + SRCCOPY); + + + DeleteDC(hMemDC); +} + static int winDrawGetStateId(int itemState) { if (itemState & ODS_DISABLED) @@ -282,21 +312,6 @@ void iupdrvDrawFocusRect(Ihandle* ih, void* gc, int x, int y, int w, int h) DrawFocusRect(hDC, &rect); } -void iupwinDrawRemoveTheme(HWND hwnd) -{ - typedef HRESULT (STDAPICALLTYPE *winSetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList); - static winSetWindowTheme mySetWindowTheme = NULL; - if (!mySetWindowTheme) - { - HMODULE hinstDll = LoadLibrary("uxtheme.dll"); - if (hinstDll) - mySetWindowTheme = (winSetWindowTheme)GetProcAddress(hinstDll, "SetWindowTheme"); - } - - if (mySetWindowTheme) - mySetWindowTheme(hwnd, L"", L""); -} - void iupwinDrawParentBackground(Ihandle* ih, HDC hDC, RECT* rect) { unsigned char r=0, g=0, b=0; @@ -326,3 +341,226 @@ void iupwinDrawDestroyBitmapDC(iupwinBitmapDC *bmpDC) DeleteDC(bmpDC->hBitmapDC); } + +/****************************************************************************** + Simple Draw +*******************************************************************************/ + +struct _IdrawCanvas{ + Ihandle* ih; + int w, h; + + int release_dc; + HBITMAP hBitmap, hOldBitmap; + HDC hBitmapDC, hDC; +}; + +IdrawCanvas* iupDrawCreateCanvas(Ihandle* ih) +{ + IdrawCanvas* dc = calloc(1, sizeof(IdrawCanvas)); + RECT rect; + + /* valid only inside the ACTION callback of an IupCanvas */ + dc->hDC = (HDC)IupGetAttribute(ih, "HDC_WMPAINT"); + if (!dc->hDC) + { + dc->hDC = GetDC(ih->handle); + dc->release_dc = 1; + } + + GetClientRect(ih->handle, &rect); + dc->w = rect.right - rect.left; + dc->h = rect.bottom - rect.top; + + dc->hBitmap = CreateCompatibleBitmap(dc->hDC, dc->w, dc->h); + dc->hBitmapDC = CreateCompatibleDC(dc->hDC); + dc->hOldBitmap = SelectObject(dc->hBitmapDC, dc->hBitmap); + + SetBkMode(dc->hBitmapDC, TRANSPARENT); + SetTextAlign(dc->hBitmapDC, TA_TOP|TA_LEFT); + + return dc; +} + +void iupDrawKillCanvas(IdrawCanvas* dc) +{ + SelectObject(dc->hBitmapDC, dc->hOldBitmap); + DeleteObject(dc->hBitmap); + DeleteDC(dc->hBitmapDC); + if (dc->release_dc) + DeleteDC(dc->hDC); + + free(dc); +} + +void iupDrawUpdateSize(IdrawCanvas* dc) +{ + int w, h; + RECT rect; + GetClientRect(dc->ih->handle, &rect); + w = rect.right - rect.left; + h = rect.bottom - rect.top; + + if (w != dc->w || h != dc->h) + { + SelectObject(dc->hBitmapDC, dc->hOldBitmap); + DeleteObject(dc->hBitmap); + DeleteDC(dc->hBitmapDC); + + dc->hBitmap = CreateCompatibleBitmap(dc->hDC, dc->w, dc->h); + dc->hBitmapDC = CreateCompatibleDC(dc->hDC); + dc->hOldBitmap = SelectObject(dc->hBitmapDC, dc->hBitmap); + + SetBkMode(dc->hBitmapDC, TRANSPARENT); + SetTextAlign(dc->hBitmapDC, TA_TOP|TA_LEFT); + } +} + +void iupDrawFlush(IdrawCanvas* dc) +{ + BitBlt(dc->hDC, 0, 0, dc->w, dc->h, dc->hBitmapDC, 0, 0, SRCCOPY); +} + +void iupDrawGetSize(IdrawCanvas* dc, int *w, int *h) +{ + if (w) *w = dc->w; + if (h) *h = dc->h; +} + +void iupDrawParentBackground(IdrawCanvas* dc) +{ + unsigned char r=0, g=0, b=0; + char* color = iupBaseNativeParentGetBgColorAttrib(dc->ih); + iupStrToRGB(color, &r, &g, &b); + iupDrawRectangle(dc, 0, 0, dc->w-1, dc->h-1, r, g, b, 1); +} + +void iupDrawRectangle(IdrawCanvas* dc, int x1, int y1, int x2, int y2, unsigned char r, unsigned char g, unsigned char b, int filled) +{ + RECT rect; + rect.left = x1; rect.top = y1; rect.right = x2+1; rect.bottom = y2+1; + SetDCBrushColor(dc->hBitmapDC, RGB(r,g,b)); + if (filled) + FillRect(dc->hBitmapDC, &rect, (HBRUSH)GetStockObject(DC_BRUSH)); + else + FrameRect(dc->hBitmapDC, &rect, (HBRUSH)GetStockObject(DC_BRUSH)); +} + +void iupDrawLine(IdrawCanvas* dc, int x1, int y1, int x2, int y2, unsigned char r, unsigned char g, unsigned char b) +{ + POINT line_poly[2]; + HPEN hPen = CreatePen(PS_SOLID, 1, RGB(r, g, b)); + HPEN hPenOld = SelectObject(dc->hBitmapDC, hPen); + line_poly[0].x = x1; + line_poly[0].y = y1; + line_poly[1].x = x2; + line_poly[1].y = y2; + Polyline(dc->hBitmapDC, line_poly, 2); + SelectObject(dc->hBitmapDC, hPenOld); + DeleteObject(hPen); +} + +#define IUP_DEG2RAD 0.01745329252 /* degrees to radians (rad = CD_DEG2RAD * deg) */ + +static int winDrawCalcArc(int c1, int c2, double a, int start) +{ + double proj, off; + if (start) + proj = cos(IUP_DEG2RAD * a); + else + proj = sin(IUP_DEG2RAD * a); + off = (c2+c1)/2.0 + (c2-c1+1)*proj/2.0; + return iupROUND(off); +} + +void iupDrawArc(IdrawCanvas* dc, int x1, int y1, int x2, int y2, double a1, double a2, unsigned char r, unsigned char g, unsigned char b, int filled) +{ + int XStartArc = winDrawCalcArc(x1, x2, a1, 1); + int XEndArc = winDrawCalcArc(x1, x2, a2, 0); + int YStartArc = winDrawCalcArc(y1, y2, a1, 1); + int YEndArc = winDrawCalcArc(y1, y2, a2, 0); + + if (filled) + { + HBRUSH hBrush = CreateSolidBrush(RGB(r,g,b)); + HPEN hBrushOld = SelectObject(dc->hBitmapDC, hBrush); + BeginPath(dc->hBitmapDC); + Pie(dc->hBitmapDC, x1, y1, x2+1, y2+1, XStartArc, YStartArc, XEndArc, YEndArc); + EndPath(dc->hBitmapDC); + FillPath(dc->hBitmapDC); + SelectObject(dc->hBitmapDC, hBrushOld); + DeleteObject(hBrush); + } + else + { + HPEN hPen = CreatePen(PS_SOLID, 1, RGB(r, g, b)); + HPEN hPenOld = SelectObject(dc->hBitmapDC, hPen); + Arc(dc->hBitmapDC, x1, y1, x2+1, y2+1, XStartArc, YStartArc, XEndArc, YEndArc); + SelectObject(dc->hBitmapDC, hPenOld); + DeleteObject(hPen); + } +} + +void iupDrawPolygon(IdrawCanvas* dc, int* points, int count, unsigned char r, unsigned char g, unsigned char b, int filled) +{ + if (filled) + { + HBRUSH hBrush = CreateSolidBrush(RGB(r,g,b)); + HPEN hBrushOld = SelectObject(dc->hBitmapDC, hBrush); + BeginPath(dc->hBitmapDC); + Polygon(dc->hBitmapDC, (POINT*)points, count); + EndPath(dc->hBitmapDC); + FillPath(dc->hBitmapDC); + SelectObject(dc->hBitmapDC, hBrushOld); + DeleteObject(hBrush); + } + else + { + HPEN hPen = CreatePen(PS_SOLID, 1, RGB(r, g, b)); + HPEN hPenOld = SelectObject(dc->hBitmapDC, hPen); + Polyline(dc->hBitmapDC, (POINT*)points, count); + SelectObject(dc->hBitmapDC, hPenOld); + DeleteObject(hPen); + } +} + +void iupDrawSetClipRect(IdrawCanvas* dc, int x1, int y1, int x2, int y2) +{ + HRGN clip_hrgn = CreateRectRgn(x1, y1, x2, y2); + SelectClipRgn(dc->hBitmapDC, clip_hrgn); + DeleteObject(clip_hrgn); +} + +void iupDrawResetClip(IdrawCanvas* dc) +{ + SelectClipRgn(dc->hBitmapDC, NULL); +} + +void iupDrawText(IdrawCanvas* dc, const char* text, int len, int x, int y, unsigned char r, unsigned char g, unsigned char b) +{ + HFONT hOldFont, hFont = (HFONT)IupGetAttribute(dc->ih, "HFONT"); + SetTextColor(dc->hBitmapDC, RGB(r, g, b)); + hOldFont = SelectObject(dc->hBitmapDC, hFont); + TextOut(dc->hBitmapDC, x, y, text, len); + SelectObject(dc->hBitmapDC, hOldFont); +} + +void iupDrawImage(IdrawCanvas* dc, const char* name, int make_inactive, int x, int y) +{ + int img_w, img_h, bpp; + HBITMAP hMask = NULL; + HBITMAP hBitmap = iupImageGetImage(name, dc->ih, make_inactive); + if (!hBitmap) + return; + + /* must use this info, since image can be a driver image loaded from resources */ + iupdrvImageGetInfo(hBitmap, &img_w, &img_h, &bpp); + + if (bpp == 8) + hMask = iupdrvImageCreateMask(IupGetHandle(name)); + + iupwinDrawBitmap(dc->hBitmapDC, hBitmap, hMask, x, y, img_w, img_h, bpp); + + if (hMask) + DeleteObject(hMask); +} diff --git a/iup/src/win/iupwin_drv.h b/iup/src/win/iupwin_drv.h index 3372c1a..7407a7a 100755 --- a/iup/src/win/iupwin_drv.h +++ b/iup/src/win/iupwin_drv.h @@ -77,6 +77,7 @@ int iupwinBaseContainerProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT /* Creates the Window with native parent and child ID, associate HWND with Ihandle*, and replace the WinProc by iupwinBaseWinProc */ int iupwinCreateWindowEx(Ihandle* ih, LPCSTR lpClassName, DWORD dwExStyle, DWORD dwStyle); +void iupwinGetNativeParentStyle(Ihandle* ih, DWORD *dwExStyle, DWORD *dwStyle); int iupwinClassExist(const char* name); int iupwinGetColorRef(Ihandle *ih, char *name, COLORREF *color); @@ -97,8 +98,8 @@ char* iupwinGetClipboardText(Ihandle* ih); int iupwinGetScreenRes(void); /* 1 point = 1/72 inch */ /* pixel = (point/72)*(pixel/inch) */ -#define IUPWIN_PT2PIXEL(_pt, _res) MulDiv(_pt, _res, 72) /* (((_pt)*(_res))/72) */ -#define IUPWIN_PIXEL2PT(_pixel, _res) MulDiv(_pixel, 72, _res) /* (((_pixel)*72)/(_res)) */ +#define iupWIN_PT2PIXEL(_pt, _res) MulDiv(_pt, _res, 72) /* (((_pt)*(_res))/72) */ +#define iupWIN_PIXEL2PT(_pixel, _res) MulDiv(_pixel, 72, _res) /* (((_pixel)*72)/(_res)) */ /* child window identifier of the first MDI child window created, diff --git a/iup/src/win/iupwin_filedlg.c b/iup/src/win/iupwin_filedlg.c index da66b4b..26994e5 100755 --- a/iup/src/win/iupwin_filedlg.c +++ b/iup/src/win/iupwin_filedlg.c @@ -63,7 +63,7 @@ static INT CALLBACK winFileDlgBrowseCallback(HWND hWnd, UINT uMsg, LPARAM lParam } else if (uMsg == BFFM_SELCHANGED) { - char* buffer = iupStrGetMemory(MAX_FILENAME_SIZE); + char buffer[MAX_FILENAME_SIZE]; ITEMIDLIST* selecteditem = (ITEMIDLIST*)lParam; buffer[0] = 0; SHGetPathFromIDList(selecteditem, buffer); @@ -90,7 +90,7 @@ static void winFileDlgGetFolder(Ihandle *ih) browseinfo.pszDisplayName = buffer; browseinfo.lpfn = winFileDlgBrowseCallback; browseinfo.lParam = (LPARAM)ih; - browseinfo.ulFlags = BIF_NEWDIALOGSTYLE; + browseinfo.ulFlags = IupGetGlobal("_IUPWIN_COINIT_MULTITHREADED")? 0: BIF_NEWDIALOGSTYLE; browseinfo.hwndOwner = parent; selecteditem = SHBrowseForFolder(&browseinfo); @@ -112,6 +112,37 @@ static void winFileDlgGetFolder(Ihandle *ih) /************************************************************************************************/ +static int winFileDlgGetSelectedFile(Ihandle* ih, HWND hWnd, char* filename) +{ + int ret = CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE); + if (ret < 0) + return 0; + + if (iupAttribGetBoolean(ih, "MULTIPLEFILES")) + { + /* check if there are more than 1 files and return only the first one */ + int found = 0; + while(*filename != 0) + { + if (*filename == '"') + { + if (!found) + found = 1; + else + { + *(filename-1) = 0; + return 1; + } + } + if (found) + *filename = *(filename+1); + filename++; + } + } + + return 1; +} + static UINT_PTR CALLBACK winFileDlgSimpleHook(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) { (void)wParam; @@ -152,16 +183,15 @@ static UINT_PTR CALLBACK winFileDlgSimpleHook(HWND hWnd, UINT uiMsg, WPARAM wPar IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); if (cb) { - char* filename = iupStrGetMemory(MAX_FILENAME_SIZE); - if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE) + char filename[MAX_FILENAME_SIZE]; + if (winFileDlgGetSelectedFile(ih, hWnd, filename)) { int ret; char* file_msg; if (!iupdrvIsFile(filename)) - break; - - if (pofn->hdr.code == CDN_FILEOK) + file_msg = "OTHER"; + else if (pofn->hdr.code == CDN_FILEOK) file_msg = "OK"; else file_msg = "SELECT"; @@ -267,9 +297,9 @@ static UINT_PTR CALLBACK winFileDlgPreviewHook(HWND hWnd, UINT uiMsg, WPARAM wPa LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam; Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER); IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); - char* filename = iupStrGetMemory(MAX_FILENAME_SIZE); + char filename[MAX_FILENAME_SIZE]; iupAttribSetStr(ih, "PREVIEWDC", (char*)lpDrawItem->hDC); - if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE) + if (winFileDlgGetSelectedFile(ih, hWnd, filename)) { if (iupdrvIsFile(filename)) cb(ih, filename, "PAINT"); @@ -324,16 +354,15 @@ static UINT_PTR CALLBACK winFileDlgPreviewHook(HWND hWnd, UINT uiMsg, WPARAM wPa case CDN_SELCHANGE: { HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS); - char* filename = iupStrGetMemory(MAX_FILENAME_SIZE); - if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE) + char filename[MAX_FILENAME_SIZE]; + if (winFileDlgGetSelectedFile(ih, hWnd, filename)) { int ret; char* file_msg; if (!iupdrvIsFile(filename)) - break; - - if (pofn->hdr.code == CDN_FILEOK) + file_msg = "OTHER"; + else if (pofn->hdr.code == CDN_FILEOK) file_msg = "OK"; else file_msg = "SELECT"; @@ -520,9 +549,14 @@ static int winFileDlgPopup(Ihandle *ih, int x, int y) if (iupAttribGetBoolean(ih, "MULTIPLEFILES")) { int i = 0; - + + char* dir = iupStrFileGetPath(openfilename.lpstrFile); /* the first part is the directory already */ + iupAttribStoreStr(ih, "DIRECTORY", dir); + free(dir); + /* If there is more than one file, replace terminator by the separator */ - if (openfilename.lpstrFile && openfilename.lpstrFile[openfilename.nFileOffset-1] == 0 && openfilename.nFileOffset>0) + if (openfilename.lpstrFile[openfilename.nFileOffset-1] == 0 && + openfilename.nFileOffset>0) { while (openfilename.lpstrFile[i] != 0 || openfilename.lpstrFile[i+1] != 0) { @@ -534,12 +568,16 @@ static int winFileDlgPopup(Ihandle *ih, int x, int y) } iupAttribSetStr(ih, "STATUS", "0"); - iupAttribSetStr(ih, "FILEEXIST", NULL); + iupAttribSetStr(ih, "FILEEXIST", "YES"); } else { if (iupdrvIsFile(openfilename.lpstrFile)) /* check if file exists */ { + char* dir = iupStrFileGetPath(openfilename.lpstrFile); + iupAttribStoreStr(ih, "DIRECTORY", dir); + free(dir); + iupAttribSetStr(ih, "FILEEXIST", "YES"); iupAttribSetStr(ih, "STATUS", "0"); } diff --git a/iup/src/win/iupwin_focus.c b/iup/src/win/iupwin_focus.c index 63da02d..2328dea 100755 --- a/iup/src/win/iupwin_focus.c +++ b/iup/src/win/iupwin_focus.c @@ -32,7 +32,7 @@ /* Since Windows XP, the focus feedback only appears after the user press a key. Except for the IupText where the feedback is the caret. - Before that if you click in a control the focus feedback will be hidden. + Before a key is pressed if you click in a control the focus feedback will be hidden. We manually send WM_CHANGEUISTATE because we do not use IsDialogMessage anymore, and the focus feedback was not shown even after the used press a key. @@ -43,19 +43,28 @@ void iupdrvSetFocus(Ihandle *ih) { SetFocus(ih->handle); - SendMessage(ih->handle, WM_CHANGEUISTATE, UIS_CLEAR|UISF_HIDEFOCUS, 0); + + /* See comments above */ + SendMessage(ih->handle, WM_CHANGEUISTATE, UIS_CLEAR|UISF_HIDEFOCUS, 0); /* clear+hidefocus=showfocus */ } void iupwinWmSetFocus(Ihandle *ih) { Ihandle* dialog = IupGetDialog(ih); if (ih != dialog) - iupAttribSetStr(dialog, "_IUPWIN_LASTFOCUS", (char*)ih); /* used by IupMenu */ + iupAttribSetStr(dialog, "_IUPWIN_LASTFOCUS", (char*)ih); /* used by IupMenu and here. */ else { /* if a control inside that dialog had the focus, then reset to it when the dialog gets the focus */ Ihandle* lastfocus = (Ihandle*)iupAttribGet(dialog, "_IUPWIN_LASTFOCUS"); - if (lastfocus) IupSetFocus(lastfocus); + if (lastfocus) + { + /* call the callback and update current focus before changing it again */ + iupCallGetFocusCb(ih); + + IupSetFocus(lastfocus); + return; + } } iupCallGetFocusCb(ih); diff --git a/iup/src/win/iupwin_font.c b/iup/src/win/iupwin_font.c index 659e2d9..c10befb 100755 --- a/iup/src/win/iupwin_font.c +++ b/iup/src/win/iupwin_font.c @@ -70,7 +70,7 @@ static IwinFont* winFindFont(const char *standardfont) if (height < 0) height_pixels = height; /* already in pixels */ else - height_pixels = -IUPWIN_PT2PIXEL(height, res); + height_pixels = -iupWIN_PT2PIXEL(height, res); if (height_pixels == 0) return NULL; @@ -119,7 +119,7 @@ static void winFontFromLogFont(LOGFONT* logfont, char * font) int is_strikeout = logfont->lfStrikeOut; int height_pixels = logfont->lfHeight; /* negative value */ int res = iupwinGetScreenRes(); - int height = IUPWIN_PIXEL2PT(-height_pixels, res); /* return in points */ + int height = iupWIN_PIXEL2PT(-height_pixels, res); /* return in points */ sprintf(font, "%s, %s%s%s%s %d", logfont->lfFaceName, is_bold?"Bold ":"", diff --git a/iup/src/win/iupwin_fontdlg.c b/iup/src/win/iupwin_fontdlg.c index 0602441..ce27cf2 100755 --- a/iup/src/win/iupwin_fontdlg.c +++ b/iup/src/win/iupwin_fontdlg.c @@ -68,7 +68,7 @@ static int winFontDlgPopup(Ihandle* ih, int x, int y) standardfont = iupAttribGet(ih, "VALUE"); if (!standardfont) - return IUP_ERROR; + standardfont = IupGetGlobal("DEFAULTFONT"); /* parse the old format first */ if (!iupFontParseWin(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout)) @@ -81,7 +81,7 @@ static int winFontDlgPopup(Ihandle* ih, int x, int y) if (height < 0) height_pixels = height; /* already in pixels */ else - height_pixels = -IUPWIN_PT2PIXEL(height, res); + height_pixels = -iupWIN_PT2PIXEL(height, res); if (height_pixels == 0) return IUP_ERROR; @@ -134,7 +134,7 @@ static int winFontDlgPopup(Ihandle* ih, int x, int y) if (height < 0) /* not an error, use old value as a reference for the units */ height = height_pixels; /* return in pixels */ else - height = IUPWIN_PIXEL2PT(-height_pixels, res); /* return in points */ + height = iupWIN_PIXEL2PT(-height_pixels, res); /* return in points */ iupAttribSetStrf(ih, "VALUE", "%s, %s%s%s%s %d", logfont.lfFaceName, is_bold?"Bold ":"", diff --git a/iup/src/win/iupwin_frame.c b/iup/src/win/iupwin_frame.c index 0949b5d..3f56aed 100755 --- a/iup/src/win/iupwin_frame.c +++ b/iup/src/win/iupwin_frame.c @@ -47,6 +47,27 @@ void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y) } } +static char* winFrameGetBgColorAttrib(Ihandle* ih) +{ + if (iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) + return NULL; + else + return iupBaseNativeParentGetBgColorAttrib(ih); +} + +static int winFrameSetBgColorAttrib(Ihandle* ih, const char* value) +{ + (void)value; + + if (iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) + { + IupUpdate(ih); /* post a redraw */ + return 1; + } + else + return 0; +} + static void winFrameDrawText(HDC hDC, const char* text, int x, int y, COLORREF fgcolor) { COLORREF oldcolor; @@ -126,6 +147,16 @@ static void winFrameDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem) DrawEdge(hDC, &drawitem->rcItem, EDGE_SUNKEN, BF_RECT); else DrawEdge(hDC, &drawitem->rcItem, EDGE_ETCHED, BF_RECT); + + if (iupAttribGet(ih, "_IUPFRAME_HAS_BGCOLOR")) + { + unsigned char r=0, g=0, b=0; + char* color = iupAttribGetStr(ih, "BGCOLOR"); + iupStrToRGB(color, &r, &g, &b); + SetDCBrushColor(hDC, RGB(r,g,b)); + InflateRect(&drawitem->rcItem, -2, -2); + FillRect(hDC, &drawitem->rcItem, (HBRUSH)GetStockObject(DC_BRUSH)); + } } iupwinDrawDestroyBitmapDC(&bmpDC); @@ -169,11 +200,13 @@ static int winFrameMapMethod(Ihandle* ih) title = iupAttribGet(ih, "TITLE"); if (title) iupAttribSetStr(ih, "_IUPFRAME_HAS_TITLE", "1"); - - if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) - dwExStyle |= WS_EX_COMPOSITED; else - dwStyle |= WS_CLIPCHILDREN; + { + if (iupAttribGet(ih, "BGCOLOR")) + iupAttribSetStr(ih, "_IUPFRAME_HAS_BGCOLOR", "1"); + } + + iupwinGetNativeParentStyle(ih, &dwExStyle, &dwStyle); if (!iupwinCreateWindowEx(ih, "BUTTON", dwExStyle, dwStyle)) return IUP_ERROR; @@ -195,7 +228,7 @@ void iupdrvFrameInitClass(Iclass* ic) /* Driver Dependent Attribute functions */ /* Visual */ - iupClassRegisterAttribute(ic, "BGCOLOR", iupBaseNativeParentGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", winFrameGetBgColorAttrib, winFrameSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); /* Special */ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_NOT_MAPPED); diff --git a/iup/src/win/iupwin_globalattrib.c b/iup/src/win/iupwin_globalattrib.c index a176925..bcd6355 100755 --- a/iup/src/win/iupwin_globalattrib.c +++ b/iup/src/win/iupwin_globalattrib.c @@ -148,6 +148,11 @@ int iupdrvSetGlobal(const char *name, const char *value) winGlobalSendKey(key, 0x03); return 0; } + if (iupStrEqual(name, "DLL_HINSTANCE")) + { + iupwin_dll_hinstance = (HINSTANCE)value; + return 0; + } return 1; } @@ -239,5 +244,7 @@ char *iupdrvGetGlobal(const char *name) return "YES"; return "NO"; } + if (iupStrEqual(name, "DLL_HINSTANCE")) + return (char*)iupwin_dll_hinstance; return NULL; } diff --git a/iup/src/win/iupwin_info.c b/iup/src/win/iupwin_info.c index 8ea7dd4..4d57289 100755 --- a/iup/src/win/iupwin_info.c +++ b/iup/src/win/iupwin_info.c @@ -18,7 +18,7 @@ #include "iupwin_info.h" -int iupwinIsVista(void) +int iupwinIsVistaOrNew(void) { OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); diff --git a/iup/src/win/iupwin_info.h b/iup/src/win/iupwin_info.h index d39bae0..8d461fb 100755 --- a/iup/src/win/iupwin_info.h +++ b/iup/src/win/iupwin_info.h @@ -16,7 +16,7 @@ int iupwinGetSystemMajorVersion(void); int iupwinGetComCtl32Version(void); char* iupwinGetSystemLanguage(void); int iupwinIsAppThemed(void); -int iupwinIsVista(void); +int iupwinIsVistaOrNew(void); /* color */ void iupwinGetSysColor(char* color, int wincolor); diff --git a/iup/src/win/iupwin_key.c b/iup/src/win/iupwin_key.c index 921ed94..899e837 100755 --- a/iup/src/win/iupwin_key.c +++ b/iup/src/win/iupwin_key.c @@ -317,32 +317,32 @@ int iupwinKeyEvent(Ihandle* ih, int wincode, int press) void iupwinButtonKeySetStatus(WORD keys, char* status, int doubleclick) { if (keys & MK_SHIFT) - iupKEYSETSHIFT(status); + iupKEY_SETSHIFT(status); if (keys & MK_CONTROL) - iupKEYSETCONTROL(status); + iupKEY_SETCONTROL(status); if (keys & MK_LBUTTON) - iupKEYSETBUTTON1(status); + iupKEY_SETBUTTON1(status); if (keys & MK_MBUTTON) - iupKEYSETBUTTON2(status); + iupKEY_SETBUTTON2(status); if (keys & MK_RBUTTON) - iupKEYSETBUTTON3(status); + iupKEY_SETBUTTON3(status); if (doubleclick) - iupKEYSETDOUBLE(status); + iupKEY_SETDOUBLE(status); if (GetKeyState(VK_MENU) & 0x8000) - iupKEYSETALT(status); + iupKEY_SETALT(status); if ((GetKeyState(VK_LWIN) & 0x8000) || (GetKeyState(VK_RWIN) & 0x8000)) - iupKEYSETSYS(status); + iupKEY_SETSYS(status); if (keys & MK_XBUTTON1) - iupKEYSETBUTTON4(status); + iupKEY_SETBUTTON4(status); if (keys & MK_XBUTTON2) - iupKEYSETBUTTON5(status); + iupKEY_SETBUTTON5(status); } diff --git a/iup/src/win/iupwin_label.c b/iup/src/win/iupwin_label.c index d5a1f53..95dd10c 100755 --- a/iup/src/win/iupwin_label.c +++ b/iup/src/win/iupwin_label.c @@ -173,7 +173,7 @@ static int winLabelSetAlignmentAttrib(Ihandle* ih, const char* value) else /* "ATOP" */ ih->data->vert_alignment = IUP_ALIGN_ATOP; - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); } return 0; } @@ -197,7 +197,7 @@ static int winLabelSetPaddingAttrib(Ihandle* ih, const char* value) iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); if (ih->handle && ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); return 0; } @@ -211,7 +211,7 @@ static int winLabelSetWordWrapAttrib(Ihandle* ih, const char* value) else ih->data->text_style &= ~DT_WORDBREAK; - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); } return 1; @@ -226,7 +226,7 @@ static int winLabelSetEllipsisAttrib(Ihandle* ih, const char* value) else ih->data->text_style &= ~DT_END_ELLIPSIS; - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); } return 1; @@ -240,12 +240,24 @@ static int winLabelSetFgColorAttrib(Ihandle* ih, const char* value) if (iupStrToRGB(value, &r, &g, &b)) { ih->data->fgcolor = RGB(r,g,b); - iupdrvDisplayRedraw(ih); + + if (ih->handle) + iupdrvRedrawNow(ih); } } return 1; } +static int winLabelSetUpdateAttrib(Ihandle* ih, const char* value) +{ + (void)value; + + if (ih->handle) + iupdrvPostRedraw(ih); /* Post a redraw */ + + return 1; +} + static int winLabelProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) { switch (msg) @@ -257,6 +269,7 @@ static int winLabelProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *re *result = WVR_HREDRAW|WVR_VREDRAW; return 1; } + break; } } @@ -266,7 +279,7 @@ static int winLabelProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *re static int winLabelMapMethod(Ihandle* ih) { char* value; - DWORD dwStyle = WS_CHILD | + DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | SS_NOTIFY; /* SS_NOTIFY is necessary because of the base messages */ if (!ih->parent) @@ -330,7 +343,7 @@ void iupdrvLabelInitClass(Iclass* ic) /* IupLabel only */ iupClassRegisterAttribute(ic, "ALIGNMENT", winLabelGetAlignmentAttrib, winLabelSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT:ACENTER", IUPAF_NO_INHERIT); - iupClassRegisterAttribute(ic, "IMAGE", NULL, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, winLabelSetUpdateAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "PADDING", iupLabelGetPaddingAttrib, winLabelSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); /* IupLabel Windows and GTK only */ diff --git a/iup/src/win/iupwin_list.c b/iup/src/win/iupwin_list.c index 8fdadb6..cb510b5 100755 --- a/iup/src/win/iupwin_list.c +++ b/iup/src/win/iupwin_list.c @@ -154,6 +154,8 @@ void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value) SendMessage(ih->handle, WIN_INSERTSTRING(ih), pos, (LPARAM)value); SendMessage(ih->handle, WIN_SETITEMDATA(ih), pos, (LPARAM)iupdrvFontGetStringWidth(ih, value)); winListUpdateScrollWidth(ih); + + iupListUpdateOldValue(ih, pos, 0); } void iupdrvListRemoveItem(Ihandle* ih, int pos) @@ -164,8 +166,14 @@ void iupdrvListRemoveItem(Ihandle* ih, int pos) int curpos = SendMessage(ih->handle, WIN_GETCURSEL(ih), 0, 0); if (pos == curpos) { - if (curpos > 0) curpos--; - else curpos++; + if (curpos > 0) + curpos--; + else + { + curpos=1; + if (iupdrvListGetCount(ih)==1) + curpos = -1; /* remove the selection */ + } SendMessage(ih->handle, WIN_SETCURSEL(ih), curpos, 0); } @@ -173,6 +181,8 @@ void iupdrvListRemoveItem(Ihandle* ih, int pos) SendMessage(ih->handle, WIN_DELETESTRING(ih), pos, 0L); winListUpdateScrollWidth(ih); + + iupListUpdateOldValue(ih, pos, 1); } void iupdrvListRemoveAllItems(Ihandle* ih) @@ -220,18 +230,29 @@ static void winListUpdateItemWidth(Ihandle* ih) } } +static int winListSetBgColorAttrib(Ihandle *ih, const char *value) +{ + (void)value; + if (ih->handle) + iupdrvPostRedraw(ih); + return 1; +} + static int winListSetStandardFontAttrib(Ihandle* ih, const char* value) { iupdrvSetStandardFontAttrib(ih, value); - winListUpdateItemWidth(ih); - winListUpdateScrollWidth(ih); + if (ih->handle) + { + winListUpdateItemWidth(ih); + winListUpdateScrollWidth(ih); + } return 1; } static char* winListGetIdValueAttrib(Ihandle* ih, const char* name_id) { int pos = iupListGetPos(ih, name_id); - if (pos != -1) + if (pos >= 0) { int len = SendMessage(ih->handle, WIN_GETTEXTLEN(ih), (WPARAM)pos, 0); char* str = iupStrGetMemory(len+1); @@ -514,8 +535,10 @@ static int winListSetNCAttrib(Ihandle* ih, const char* value) { HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_LIMITTEXT, ih->data->nc, 0L); + return 0; } - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } static int winListSetSelectionAttrib(Ihandle* ih, const char* value) @@ -995,13 +1018,27 @@ static int winListEditProc(Ihandle* ih, HWND cbedit, UINT msg, WPARAM wp, LPARAM if (msg==WM_KEYDOWN) /* process K_ANY before text callbacks */ { ret = iupwinBaseProc(ih, msg, wp, lp, result); - if (ret) return 1; + if (ret) + { + iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", "1"); + *result = 0; + return 1; + } + else + iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", NULL); } switch (msg) { case WM_CHAR: { + if (iupAttribGet(ih, "_IUPWIN_IGNORE_CHAR")) + { + iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", NULL); + *result = 0; + return 1; + } + if ((char)wp == '\b') { if (!winListCallEditCb(ih, cbedit, NULL, 0, -1)) @@ -1301,7 +1338,7 @@ static void winListLayoutUpdateMethod(Ihandle *ih) static int winListMapMethod(Ihandle* ih) { char* class_name; - DWORD dwStyle = WS_CHILD, + DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS, dwExStyle = WS_EX_CLIENTEDGE; if (!ih->parent) @@ -1426,7 +1463,7 @@ void iupdrvListInitClass(Iclass* ic) iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, winListSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* Visual */ - iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winListSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED); /* Special */ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED); diff --git a/iup/src/win/iupwin_loop.c b/iup/src/win/iupwin_loop.c index 7c5dbe7..fd25537 100755 --- a/iup/src/win/iupwin_loop.c +++ b/iup/src/win/iupwin_loop.c @@ -106,6 +106,18 @@ int IupMainLoop(void) return IUP_NOERROR; } +int IupLoopStepWait(void) +{ + MSG msg; + int ret = GetMessage(&msg, NULL, 0, 0); + if (ret == -1) /* error */ + return IUP_ERROR; + if (ret == 0 || /* WM_QUIT */ + winLoopProcessMessage(&msg) == IUP_CLOSE) /* ret != 0 */ + return IUP_CLOSE; + return IUP_DEFAULT; +} + int IupLoopStep(void) { MSG msg; diff --git a/iup/src/win/iupwin_menu.c b/iup/src/win/iupwin_menu.c index 74a8b52..06ad93e 100755 --- a/iup/src/win/iupwin_menu.c +++ b/iup/src/win/iupwin_menu.c @@ -385,7 +385,10 @@ static int winMenuMapMethod(Ihandle* ih) static void winMenuUnMapMethod(Ihandle* ih) { if (iupMenuIsMenuBar(ih)) + { SetMenu(ih->parent->handle, NULL); + ih->parent = NULL; + } DestroyMenu((HMENU)ih->handle); /* DestroyMenu is recursive */ } diff --git a/iup/src/win/iupwin_open.c b/iup/src/win/iupwin_open.c index 7357cde..3629ce4 100755 --- a/iup/src/win/iupwin_open.c +++ b/iup/src/win/iupwin_open.c @@ -76,8 +76,9 @@ int iupdrvOpen(int *argc, char ***argv) iupwin_hinstance = GetModuleHandle(NULL); IupSetGlobal("HINSTANCE", (char*)iupwin_hinstance); } - - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + if (CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)==RPC_E_CHANGED_MODE) + IupSetGlobal("_IUPWIN_COINIT_MULTITHREADED", "1"); { INITCOMMONCONTROLSEX InitCtrls; diff --git a/iup/src/win/iupwin_progressbar.c b/iup/src/win/iupwin_progressbar.c index 9038d79..4a52cc4 100755 --- a/iup/src/win/iupwin_progressbar.c +++ b/iup/src/win/iupwin_progressbar.c @@ -106,7 +106,7 @@ static int winProgressBarSetFgColorAttrib(Ihandle* ih, const char* value) static int winProgressBarMapMethod(Ihandle* ih) { - DWORD dwStyle = WS_CHILD; + DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS; if (!ih->parent) return IUP_ERROR; diff --git a/iup/src/win/iupwin_tabs.c b/iup/src/win/iupwin_tabs.c index 682f451..b39f7fe 100755 --- a/iup/src/win/iupwin_tabs.c +++ b/iup/src/win/iupwin_tabs.c @@ -232,10 +232,7 @@ static HWND winTabCreatePageWindow(Ihandle* ih) DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS, dwExStyle = 0; - if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) - dwExStyle |= WS_EX_COMPOSITED; - else - dwStyle |= WS_CLIPCHILDREN; + iupwinGetNativeParentStyle(ih, &dwExStyle, &dwStyle); hWnd = CreateWindowEx(dwExStyle, "IupTabsPage", NULL, dwStyle, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, @@ -255,9 +252,12 @@ static int winTabsSetPaddingAttrib(Ihandle* ih, const char* value) iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); if (ih->handle) + { SendMessage(ih->handle, TCM_SETPADDING, 0, MAKELPARAM(ih->data->horiz_padding, ih->data->vert_padding)); - - return 0; + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ } static int winTabsSetMultilineAttrib(Ihandle* ih, const char* value) @@ -368,6 +368,13 @@ static char* winTabsGetBgColorAttrib(Ihandle* ih) return IupGetGlobal("DLGBGCOLOR"); } +static int winTabsSetBgColorAttrib(Ihandle *ih, const char *value) +{ + (void)value; + iupdrvPostRedraw(ih); + return 1; +} + /* ------------------------------------------------------------------------- */ /* winTabs - Calls the user callback to change of tab */ @@ -397,6 +404,7 @@ static int winTabsWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) int prev_pos = SendMessage(ih->handle, TCM_GETCURSEL, 0, 0); iupAttribSetInt(ih, "_IUPTABS_PREV_CHILD_POS", prev_pos); + /* save the previous handle if callback exists */ if (cb) { Ihandle* prev_child = IupGetChild(ih, prev_pos); @@ -420,7 +428,9 @@ static int winTabsWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) Ihandle* prev_child = (Ihandle*)iupAttribGet(ih, "_IUPTABS_PREV_CHILD"); iupAttribSetStr(ih, "_IUPTABS_PREV_CHILD", NULL); - cb(ih, child, prev_child); + /* avoid duplicate calls when a Tab is inside another Tab. */ + if (prev_child) + cb(ih, child, prev_child); } } @@ -522,7 +532,7 @@ static void winTabsChildAddedMethod(Ihandle* ih, Ihandle* child) } } - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); } } } @@ -535,12 +545,11 @@ static void winTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) if (tab_page) { int pos = winTabsGetPageWindowPos(ih, tab_page); + iupTabsTestRemoveTab(ih, pos); + SendMessage(ih->handle, TCM_DELETEITEM, pos, 0); DestroyWindow(tab_page); - if (pos==0) pos++; - iupdrvTabsSetCurrentTab(ih, pos-1); - iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL); } } @@ -564,19 +573,14 @@ static int winTabsMapMethod(Ihandle* ih) if (ih->data->is_multiline) dwStyle |= TCS_MULTILINE; - if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) - { - dwExStyle |= WS_EX_COMPOSITED; + iupwinGetNativeParentStyle(ih, &dwExStyle, &dwStyle); - if (!ih->data->is_multiline && iupwinIsVista()) - { - /* workaround for composite bug in Vista */ - ih->data->is_multiline = 1; - dwStyle |= TCS_MULTILINE; - } + if (dwExStyle & WS_EX_COMPOSITED && !ih->data->is_multiline && iupwinIsVistaOrNew()) + { + /* workaround for composite bug in Vista */ + ih->data->is_multiline = 1; + dwStyle |= TCS_MULTILINE; } - else - dwStyle |= WS_CLIPCHILDREN; if (!iupwinCreateWindowEx(ih, WC_TABCONTROL, dwExStyle, dwStyle)) return IUP_ERROR; @@ -665,7 +669,7 @@ void iupdrvTabsInitClass(Iclass* ic) /* Driver Dependent Attribute functions */ /* Visual */ - iupClassRegisterAttribute(ic, "BGCOLOR", winTabsGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", winTabsGetBgColorAttrib, winTabsSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); /* Special */ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_NOT_MAPPED); @@ -676,5 +680,9 @@ void iupdrvTabsInitClass(Iclass* ic) iupClassRegisterAttribute(ic, "MULTILINE", winTabsGetMultilineAttrib, winTabsSetMultilineAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "TABTITLE", NULL, winTabsSetTabTitleAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, winTabsSetTabImageAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); - iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, winTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, winTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* necessary because transparent background does not work when not using visual styles */ + if (!iupwin_comctl32ver6) /* Used by iupdrvImageCreateImage */ + iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); } diff --git a/iup/src/win/iupwin_text.c b/iup/src/win/iupwin_text.c index dfe489a..2a61724 100755 --- a/iup/src/win/iupwin_text.c +++ b/iup/src/win/iupwin_text.c @@ -432,8 +432,8 @@ static int winTextSetLinColToPosition(Ihandle *ih, int lin, int col) col--; linmax = SendMessage(ih->handle, EM_GETLINECOUNT, 0, 0L); - if (lin > linmax) - lin = linmax; + if (lin > linmax-1) + lin = linmax-1; lineindex = SendMessage(ih->handle, EM_LINEINDEX, (WPARAM)lin, 0L); @@ -639,8 +639,12 @@ static int winTextSetPaddingAttrib(Ihandle* ih, const char* value) iupStrToIntInt(value, &(ih->data->horiz_padding), &(ih->data->vert_padding), 'x'); ih->data->vert_padding = 0; if (ih->handle) + { SendMessage(ih->handle, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELPARAM(ih->data->horiz_padding, ih->data->horiz_padding)); - return 0; + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ } static int winTextSetSelectedTextAttrib(Ihandle* ih, const char* value) @@ -713,8 +717,11 @@ static int winTextSetNCAttrib(Ihandle* ih, const char* value) SendMessage(ih->handle, EM_EXLIMITTEXT, 0, ih->data->nc); /* so it can be larger than 64k */ else SendMessage(ih->handle, EM_LIMITTEXT, ih->data->nc, 0L); + + return 0; } - return 0; + else + return 1; /* store until not mapped, when mapped will be set again */ } static int winTextSetSelectionAttrib(Ihandle* ih, const char* value) @@ -845,7 +852,7 @@ static char* winTextGetSelectionPosAttrib(Ihandle* ih) static int winTextSetInsertAttrib(Ihandle* ih, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; if (value) { @@ -867,9 +874,9 @@ static int winTextSetInsertAttrib(Ihandle* ih, const char* value) static int winTextSetAppendAttrib(Ihandle* ih, const char* value) { - int len; + int pos; char* str; - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; if (!value) value = ""; str = (char*)value; @@ -881,9 +888,9 @@ static int winTextSetAppendAttrib(Ihandle* ih, const char* value) str = iupStrToDos(str); } - len = GetWindowTextLength(ih->handle)+1; - SendMessage(ih->handle, EM_SETSEL, (WPARAM)len, (LPARAM)len); - if (ih->data->is_multiline && ih->data->append_newline) + pos = GetWindowTextLength(ih->handle)+1; + SendMessage(ih->handle, EM_SETSEL, (WPARAM)pos, (LPARAM)pos); + if (ih->data->is_multiline && ih->data->append_newline && pos!=1) { if (ih->data->has_formatting) SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\r"); @@ -920,7 +927,7 @@ static int winTextSetTabSizeAttrib(Ihandle* ih, const char* value) iupStrToInt(value, &tabsize); tabsize *= 4; SendMessage(ih->handle, EM_SETTABSTOPS, (WPARAM)1L, (LPARAM)&tabsize); - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); return 1; } @@ -1120,6 +1127,7 @@ static int winTextSetBgColorAttrib(Ihandle *ih, const char *value) SendMessage(ih->handle, EM_SETBKGNDCOLOR, 0, (LPARAM)color); } } + iupdrvPostRedraw(ih); return 1; } @@ -1529,15 +1537,27 @@ static int winTextProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res ret = iupwinBaseProc(ih, msg, wp, lp, result); if (ret) { + iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", "1"); *result = 0; return 1; } + else + iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", NULL); } switch (msg) { case WM_CHAR: { + /* even aborting WM_KEYDOWN, a WM_CHAR will be sent, so ignore it also */ + /* if a dialog was shown, the loop will be processed, so ignore out of focus WM_CHAR messages */ + if (GetFocus() != ih->handle || iupAttribGet(ih, "_IUPWIN_IGNORE_CHAR")) + { + iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", NULL); + *result = 0; + return 1; + } + if ((char)wp == '\b') { if (!winTextCallActionCb(ih, NULL, 0, -1)) @@ -1736,7 +1756,7 @@ static int winTextProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res static void winTextCreateSpin(Ihandle* ih) { HWND hSpin; - DWORD dwStyle = WS_CHILD|UDS_ARROWKEYS|UDS_HOTTRACK|UDS_NOTHOUSANDS; + DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS|UDS_ARROWKEYS|UDS_HOTTRACK|UDS_NOTHOUSANDS; int serial = iupDialogGetChildId(ih); if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT")) @@ -1826,7 +1846,7 @@ static void winTextLayoutUpdateMethod(Ihandle* ih) static int winTextMapMethod(Ihandle* ih) { - DWORD dwStyle = WS_CHILD, + DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS, dwExStyle = 0; char* winclass = "EDIT", *value; @@ -1873,7 +1893,7 @@ static int winTextMapMethod(Ihandle* ih) } else { - dwStyle |= ES_AUTOHSCROLL|ES_NOHIDESEL; + dwStyle |= ES_AUTOHSCROLL; if (iupAttribGetBoolean(ih, "PASSWORD")) dwStyle |= ES_PASSWORD; @@ -1950,8 +1970,8 @@ void iupdrvTextInitClass(Iclass* ic) iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, winTextSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* Overwrite Visual */ - iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED); - iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, winTextSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, winTextSetVisibleAttrib, "YES", "NO", IUPAF_DEFAULT); /* Special */ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED); /* usually black */ diff --git a/iup/src/win/iupwin_toggle.c b/iup/src/win/iupwin_toggle.c index fcaa438..c17f594 100755 --- a/iup/src/win/iupwin_toggle.c +++ b/iup/src/win/iupwin_toggle.c @@ -35,7 +35,9 @@ void iupdrvToggleAddCheckBox(int *x, int *y) { - (*x) += 16+6; + (*x) += 16+8; + if (!iupwin_comctl32ver6) + (*x) += 4; if ((*y) < 16) (*y) = 16; /* minimum height */ } @@ -229,7 +231,7 @@ static int winToggleSetImageAttrib(Ihandle* ih, const char* value) iupAttribSetStr(ih, "IMAGE", (char*)value); if (iupwin_comctl32ver6) - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); else { int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L); @@ -249,7 +251,7 @@ static int winToggleSetImInactiveAttrib(Ihandle* ih, const char* value) iupAttribSetStr(ih, "IMINACTIVE", (char*)value); if (iupwin_comctl32ver6) - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); else { int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L); @@ -269,7 +271,7 @@ static int winToggleSetImPressAttrib(Ihandle* ih, const char* value) iupAttribSetStr(ih, "IMPRESS", (char*)value); if (iupwin_comctl32ver6) - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); else { int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L); @@ -339,7 +341,7 @@ static int winToggleSetActiveAttrib(Ihandle* ih, const char* value) if (iupwin_comctl32ver6) { iupBaseSetActiveAttrib(ih, value); - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); return 0; } else @@ -382,11 +384,21 @@ static int winToggleSetPaddingAttrib(Ihandle* ih, const char* value) iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); if (ih->handle && iupwin_comctl32ver6 && ih->data->type == IUP_TOGGLE_IMAGE) - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); return 0; } +static int winToggleSetUpdateAttrib(Ihandle* ih, const char* value) +{ + (void)value; + + if (ih->handle) + iupdrvPostRedraw(ih); /* Post a redraw */ + + return 1; +} + static int winToggleSetBgColorAttrib(Ihandle* ih, const char* value) { (void)value; @@ -395,7 +407,7 @@ static int winToggleSetBgColorAttrib(Ihandle* ih, const char* value) /* update internal image cache for controls that have the IMAGE attribute */ iupAttribSetStr(ih, "BGCOLOR", value); iupImageUpdateParent(ih); - iupdrvDisplayRedraw(ih); + iupdrvRedrawNow(ih); } return 1; } @@ -591,7 +603,7 @@ static int winToggleMapMethod(Ihandle* ih) { Ihandle* radio = iupRadioFindToggleParent(ih); char* value; - DWORD dwStyle = WS_CHILD | + DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | BS_NOTIFY; /* necessary because of the base messages */ if (!ih->parent) @@ -673,11 +685,11 @@ void iupdrvToggleInitClass(Iclass* ic) iupClassRegisterAttribute(ic, "BGCOLOR", winToggleGetBgColorAttrib, winToggleSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); /* Special */ - iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force the new default value */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winToggleSetUpdateAttrib, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force the new default value */ iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, winToggleSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); /* IupToggle only */ - iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, NULL, IUPAF_SAMEASSYSTEM, "ACENTER:ACENTER", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, winToggleSetUpdateAttrib, IUPAF_SAMEASSYSTEM, "ACENTER:ACENTER", IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "IMAGE", NULL, winToggleSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, winToggleSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "IMPRESS", NULL, winToggleSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); diff --git a/iup/src/win/iupwin_tree.c b/iup/src/win/iupwin_tree.c index e6877dc..4a5f8be 100755 --- a/iup/src/win/iupwin_tree.c +++ b/iup/src/win/iupwin_tree.c @@ -31,17 +31,19 @@ #include "iupwin_draw.h" #include "iupwin_info.h" + typedef struct _winTreeItemData { COLORREF color; unsigned char kind; - void* userdata; HFONT hFont; short image; short image_expanded; } winTreeItemData; -#ifndef TVN_ITEMCHANGING /* Vista Only */ +/* Vista Only */ + +#ifndef TVN_ITEMCHANGING typedef struct tagNMTVITEMCHANGE { NMHDR hdr; UINT uChanged; @@ -54,257 +56,125 @@ typedef struct tagNMTVITEMCHANGE { #define TVN_ITEMCHANGINGW (TVN_FIRST-17) #endif -static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem); -typedef int (*winTreeNodeFunc)(Ihandle* ih, HTREEITEM hItem, void* userdata); - -static int winTreeForEach(Ihandle* ih, HTREEITEM hItem, winTreeNodeFunc func, void* userdata) -{ - HTREEITEM hItemChild; - - if (!hItem) - hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); +#ifndef TVS_EX_DOUBLEBUFFER +#define TVS_EX_DOUBLEBUFFER 0x0004 +#endif - while(hItem != NULL) - { - if (!func(ih, hItem, userdata)) - return 0; +#ifndef TVM_SETEXTENDEDSTYLE +#define TVM_SETEXTENDEDSTYLE (TV_FIRST + 44) +#endif - hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); - if (hItemChild) - { - /* Recursively traverse child items */ - if (!winTreeForEach(ih, hItemChild, func, userdata)) - return 0; - } - /* Go to next sibling item */ - hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); - } +static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem); - return 1; -} /*****************************************************************************/ /* FINDING ITEMS */ /*****************************************************************************/ -static HTREEITEM winTreeFindNodeID(Ihandle* ih, HTREEITEM hItem, HTREEITEM hNode) -{ - TVITEM item; - winTreeItemData* itemData; - - while(hItem != NULL) - { - /* ID control to traverse items */ - ih->data->id_control++; - - /* StateID founded! */ - if(hItem == hNode) - return hItem; - /* Get hItem attributes */ - item.hItem = hItem; - item.mask = TVIF_HANDLE|TVIF_PARAM; - SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); - itemData = (winTreeItemData*)item.lParam; - - /* Check whether we have child items */ - if (itemData->kind == ITREE_BRANCH) - { - /* Recursively traverse child items */ - HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); - hItemChild = winTreeFindNodeID(ih, hItemChild, hNode); - - /* StateID founded! */ - if(hItemChild) - return hItemChild; - } - /* Go to next sibling item */ - hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); - } - - return NULL; +InodeHandle* iupdrvTreeGetFocusNode(Ihandle* ih) +{ + return (InodeHandle*)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CARET, 0); } -static int winTreeGetNodeId(Ihandle* ih, HTREEITEM hItem) +static HTREEITEM winTreeFindNodeXY(Ihandle* ih, int x, int y) { - HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); - ih->data->id_control = -1; - if (winTreeFindNodeID(ih, hItemRoot, hItem)) - return ih->data->id_control; - else - return -1; + TVHITTESTINFO info; + info.pt.x = x; + info.pt.y = y; + return (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)(LPTVHITTESTINFO)&info); } -static HTREEITEM winTreeFindUserDataID(Ihandle* ih, HTREEITEM hItem, void* userdata) +static HTREEITEM winTreeFindNodePointed(Ihandle* ih) { - TVITEM item; - winTreeItemData* itemData; - - while(hItem != NULL) - { - /* ID control to traverse items */ - ih->data->id_control++; - - /* Get hItem attributes */ - item.hItem = hItem; - item.mask = TVIF_HANDLE|TVIF_PARAM; - SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); - itemData = (winTreeItemData*)item.lParam; - - /* userdata founded! */ - if(itemData->userdata == userdata) - return hItem; - - /* Check whether we have child items */ - if (itemData->kind == ITREE_BRANCH) - { - /* Recursively traverse child items */ - HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); - hItemChild = winTreeFindUserDataID(ih, hItemChild, userdata); - - /* userdata founded! */ - if (hItemChild) - return hItemChild; - } - - /* Go to next sibling item */ - hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); - } - - return NULL; + TVHITTESTINFO info; + DWORD pos = GetMessagePos(); + info.pt.x = LOWORD(pos); + info.pt.y = HIWORD(pos); + ScreenToClient(ih->handle, &info.pt); + return (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)(LPTVHITTESTINFO)&info); } -static int winTreeGetUserDataId(Ihandle* ih, void* userdata) +int iupwinGetColor(const char* value, COLORREF *color) { - HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); - ih->data->id_control = -1; - if (winTreeFindUserDataID(ih, hItemRoot, userdata)) - return ih->data->id_control; - else - return -1; + unsigned char r, g, b; + if (iupStrToRGB(value, &r, &g, &b)) + { + *color = RGB(r,g,b); + return 1; + } + return 0; } -static HTREEITEM winTreeFindNodeFromID(Ihandle* ih, HTREEITEM hItem) +static void winTreeChildCountRec(Ihandle* ih, HTREEITEM hItem, int *count) { - TVITEM item; - winTreeItemData* itemData; - + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); while(hItem != NULL) { - /* ID control to traverse items */ - ih->data->id_control--; - - /* StateID founded! */ - if(ih->data->id_control < 0) - return hItem; - - /* Get hItem attributes */ - item.hItem = hItem; - item.mask = TVIF_HANDLE|TVIF_PARAM; - SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); - itemData = (winTreeItemData*)item.lParam; - - /* Check whether we have child items */ - if (itemData->kind == ITREE_BRANCH) - { - /* Recursively traverse child items */ - HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); - hItemChild = winTreeFindNodeFromID(ih, hItemChild); + (*count)++; - /* StateID founded! */ - if(ih->data->id_control < 0) - return hItemChild; - } + /* go recursive to children */ + winTreeChildCountRec(ih, hItem, count); /* Go to next sibling item */ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); } - - return hItem; } -static HTREEITEM winTreeFindNodeFromString(Ihandle* ih, const char* name_id) +int iupdrvTreeTotalChildCount(Ihandle* ih, HTREEITEM hItem) { - if (name_id[0]) - { - HTREEITEM hRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); - iupStrToInt(name_id, &ih->data->id_control); - return winTreeFindNodeFromID(ih, hRoot); - } - else - return (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CARET, 0); + int count = 0; + winTreeChildCountRec(ih, hItem, &count); + return count; } -/* Recursively, find a new brother for the item - that will have its depth changed. Returns the new brother. */ -static HTREEITEM winTreeFindNewBrother(Ihandle* ih, HTREEITEM hBrotherItem) +static void winTreeChildRebuildCacheRec(Ihandle* ih, HTREEITEM hItem, int *id) { - TVITEM item; - winTreeItemData* itemData; - - while(hBrotherItem != NULL) + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + while(hItem != NULL) { - if(ih->data->id_control < 0) - return hBrotherItem; - - item.hItem = hBrotherItem; - item.mask = TVIF_HANDLE|TVIF_PARAM; - SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); - itemData = (winTreeItemData*)item.lParam; - - if (itemData->kind == ITREE_BRANCH) - { - HTREEITEM hItemChild; - - ih->data->id_control--; - hItemChild = winTreeFindNewBrother(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hBrotherItem)); + (*id)++; + ih->data->node_cache[*id].node_handle = hItem; - if(ih->data->id_control < 0) - return hItemChild; - } + /* go recursive to children */ + winTreeChildRebuildCacheRec(ih, hItem, id); - hBrotherItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hBrotherItem); + /* Go to next sibling item */ + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); } - - return hBrotherItem; } -static HTREEITEM winTreeFindNodePointed(Ihandle* ih) +static void winTreeRebuildNodeCache(Ihandle* ih, int id, HTREEITEM hItem) { - TVHITTESTINFO info; - DWORD pos = GetMessagePos(); - info.pt.x = LOWORD(pos); - info.pt.y = HIWORD(pos); - - ScreenToClient(ih->handle, &info.pt); - - return (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)(LPTVHITTESTINFO)&info); + ih->data->node_cache[id].node_handle = hItem; + winTreeChildRebuildCacheRec(ih, hItem, &id); } -int iupwinGetColor(const char* value, COLORREF *color) -{ - unsigned char r, g, b; - if (iupStrToRGB(value, &r, &g, &b)) - { - *color = RGB(r,g,b); - return 1; - } - return 0; -} /*****************************************************************************/ /* ADDING ITEMS */ /*****************************************************************************/ + +static void winTreeExpandItem(Ihandle* ih, HTREEITEM hItem, int expand); + void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add) { - TVITEM item, tviPrevItem; + TVITEM item; TVINSERTSTRUCT tvins; - HTREEITEM hPrevItem = winTreeFindNodeFromString(ih, name_id); - int kindPrev; + HTREEITEM hPrevItem = iupTreeGetNodeFromString(ih, name_id); + HTREEITEM hItemNew; winTreeItemData* itemData; if (!hPrevItem) - return; + { + /* check if the root was really specified */ + int id = 0; + if (!iupStrToInt(name_id, &id) || id != -1) + return; + } + + if (!title) + title = ""; itemData = calloc(1, sizeof(winTreeItemData)); itemData->image = -1; @@ -318,83 +188,71 @@ void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* t iupwinGetColor(iupAttribGetStr(ih, "FGCOLOR"), &itemData->color); if (kind == ITREE_BRANCH) - { item.iSelectedImage = item.iImage = (int)ih->data->def_image_collapsed; - - if (ih->data->add_expanded) - { - item.mask |= TVIF_STATE; - item.state = item.stateMask = TVIS_EXPANDED; - item.iSelectedImage = item.iImage = (int)ih->data->def_image_expanded; - } - } else item.iSelectedImage = item.iImage = (int)ih->data->def_image_leaf; /* Save the heading level in the node's application-defined data area */ tvins.item = item; - /* get the KIND attribute of node selected */ - tviPrevItem.hItem = hPrevItem; - tviPrevItem.mask = TVIF_PARAM|TVIF_CHILDREN; - SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&tviPrevItem); - kindPrev = ((winTreeItemData*)tviPrevItem.lParam)->kind; - - /* Define the parent and the position to the new node inside - the list, using the KIND attribute of node selected */ - if (kindPrev == ITREE_BRANCH && add) - { - tvins.hParent = hPrevItem; - tvins.hInsertAfter = TVI_FIRST; /* insert the new node after item selected, as first child */ - } - else - { - tvins.hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hPrevItem); - tvins.hInsertAfter = hPrevItem; /* insert the new node after item selected */ - } - - /* Add the node to the tree-view control */ - SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); - - if (kindPrev == ITREE_BRANCH && tviPrevItem.cChildren==0) + if (hPrevItem) { - /* this is the first child, redraw to update the '+'/'-' buttons */ - iupdrvDisplayRedraw(ih); - } -} + int kindPrev; + TVITEM tviPrevItem; -static void winTreeAddRootNode(Ihandle* ih) -{ - TVITEM item; - TVINSERTSTRUCT tvins; - HTREEITEM hNewItem; - winTreeItemData* itemData; + /* get the KIND attribute of reference node */ + tviPrevItem.hItem = hPrevItem; + tviPrevItem.mask = TVIF_PARAM|TVIF_CHILDREN; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&tviPrevItem); + kindPrev = ((winTreeItemData*)tviPrevItem.lParam)->kind; - itemData = calloc(1, sizeof(winTreeItemData)); - itemData->image = -1; - itemData->image_expanded = -1; - itemData->kind = ITREE_BRANCH; + /* Define the parent and the position to the new node inside + the list, using the KIND attribute of reference node */ + if (kindPrev == ITREE_BRANCH && add) + { + /* depth+1 */ + tvins.hParent = hPrevItem; + tvins.hInsertAfter = TVI_FIRST; /* insert the new node after the reference node, as first child */ + } + else + { + /* same depth */ + tvins.hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hPrevItem); + tvins.hInsertAfter = hPrevItem; /* insert the new node after reference node */ + } - item.mask = TVIF_PARAM | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; - item.state = item.stateMask = TVIS_EXPANDED; - item.iSelectedImage = item.iImage = (int)ih->data->def_image_expanded; - item.lParam = (LPARAM)itemData; + /* Add the new node */ + hItemNew = (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); + iupTreeAddToCache(ih, add, kindPrev, hPrevItem, hItemNew); - iupwinGetColor(iupAttribGetStr(ih, "FGCOLOR"), &itemData->color); + if (kindPrev == ITREE_BRANCH && tviPrevItem.cChildren==0) /* was 0, now is 1 */ + { + /* this is the first child, redraw to update the '+'/'-' buttons */ + if (ih->data->add_expanded) + winTreeExpandItem(ih, hPrevItem, 1); + else + winTreeExpandItem(ih, hPrevItem, 0); + } - /* Save the heading level in the node's application-defined data area */ - tvins.item = item; - tvins.hInsertAfter = TVI_FIRST; - tvins.hParent = TVI_ROOT; + } + else + { + tvins.hInsertAfter = TVI_FIRST; + tvins.hParent = TVI_ROOT; - /* Add the node to the tree-view control */ - hNewItem = (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); + /* Add the new node */ + hItemNew = (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); + iupTreeAddToCache(ih, 0, 0, NULL, hItemNew); - /* MarkStart node */ - iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)hNewItem); + if (ih->data->node_count == 1) + { + /* MarkStart node */ + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)hItemNew); - /* Set the default VALUE */ - winTreeSetFocusNode(ih, hNewItem); + /* Set the default VALUE */ + winTreeSetFocusNode(ih, hItemNew); + } + } } static int winTreeIsItemExpanded(Ihandle* ih, HTREEITEM hItem) @@ -408,13 +266,28 @@ static int winTreeIsItemExpanded(Ihandle* ih, HTREEITEM hItem) static void winTreeExpandItem(Ihandle* ih, HTREEITEM hItem, int expand) { - if (expand == -1) - expand = !winTreeIsItemExpanded(ih, hItem); /* toggle */ + TVITEM item; + winTreeItemData* itemData; + + iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", "1"); + /* it only works if the branch has children */ + SendMessage(ih->handle, TVM_EXPAND, expand? TVE_EXPAND: TVE_COLLAPSE, (LPARAM)hItem); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCH_CB", NULL); + + /* update image */ + item.hItem = hItem; + item.mask = TVIF_HANDLE|TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; if (expand) - SendMessage(ih->handle, TVM_EXPAND, TVE_EXPAND, (LPARAM)hItem); + item.iSelectedImage = item.iImage = (itemData->image_expanded!=-1)? itemData->image_expanded: (int)ih->data->def_image_expanded; else - SendMessage(ih->handle, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hItem); + item.iSelectedImage = item.iImage = (itemData->image!=-1)? itemData->image: (int)ih->data->def_image_collapsed; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); } /*****************************************************************************/ @@ -445,12 +318,12 @@ static void winTreeExpandTree(Ihandle* ih, HTREEITEM hItem, int expand) /* SELECTING ITEMS */ /*****************************************************************************/ -static int winTreeIsItemSelected(Ihandle* ih, HTREEITEM hItem) +static int winTreeIsNodeSelected(Ihandle* ih, HTREEITEM hItem) { return ((SendMessage(ih->handle, TVM_GETITEMSTATE, (WPARAM)hItem, TVIS_SELECTED)) & TVIS_SELECTED)!=0; } -static void winTreeSelectItem(Ihandle* ih, HTREEITEM hItem, int select) +static void winTreeSelectNode(Ihandle* ih, HTREEITEM hItem, int select) { TV_ITEM item; item.mask = TVIF_STATE | TVIF_HANDLE; @@ -458,16 +331,13 @@ static void winTreeSelectItem(Ihandle* ih, HTREEITEM hItem, int select) item.hItem = hItem; if (select == -1) - select = !winTreeIsItemSelected(ih, hItem); + select = !winTreeIsNodeSelected(ih, hItem); /* toggle */ item.state = select ? TVIS_SELECTED : 0; + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)&item); -} - -static HTREEITEM winTreeGetFocusNode(Ihandle* ih) -{ - return (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CARET, 0); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); } /* ------------Comment from wxWidgets-------------------- @@ -475,17 +345,17 @@ static HTREEITEM winTreeGetFocusNode(Ihandle* ih) item without changing anything else. */ static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem) { - HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); if (hItem != hItemFocus) { /* remember the selection state of the item */ - int wasSelected = winTreeIsItemSelected(ih, hItem); + int wasSelected = winTreeIsNodeSelected(ih, hItem); int wasFocusSelected = 0; - if (iupwinIsVista()) + if (iupwinIsVistaOrNew() && iupwin_comctl32ver6) iupAttribSetStr(ih, "_IUPTREE_ALLOW_CHANGE", (char*)hItem); /* Vista Only */ else - wasFocusSelected = hItemFocus && winTreeIsItemSelected(ih, hItemFocus); + wasFocusSelected = hItemFocus && winTreeIsNodeSelected(ih, hItemFocus); iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); @@ -493,58 +363,42 @@ static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem) { /* prevent the tree from unselecting the old focus which it would do by default */ SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)NULL); /* remove the focus */ - winTreeSelectItem(ih, hItemFocus, 1); /* select again */ + winTreeSelectNode(ih, hItemFocus, 1); /* select again */ } SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem); /* set focus, selection, and unselect the previous focus */ if (!wasSelected) - winTreeSelectItem(ih, hItem, 0); /* need to clear the selection if was not selected */ + winTreeSelectNode(ih, hItem, 0); /* need to clear the selection if was not selected */ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); iupAttribSetStr(ih, "_IUPTREE_ALLOW_CHANGE", NULL); } } -typedef struct _winTreeRange{ - HTREEITEM hItem1, hItem2; - char inside, clear; -}winTreeRange; - -static int winTreeSelectRangeFunc(Ihandle* ih, HTREEITEM hItem, winTreeRange* range) +static void winTreeSelectRange(Ihandle* ih, HTREEITEM hItem1, HTREEITEM hItem2, int clear) { - int end_range = 0; - - if (range->inside == 0) /* detect the range start */ + int i; + int id1 = iupTreeFindNodeId(ih, hItem1); + int id2 = iupTreeFindNodeId(ih, hItem2); + if (id2 == -1) id2 = ih->data->node_count-1; + if (id1 > id2) { - if (range->hItem1 == hItem) range->inside=1; - else if (range->hItem2 == hItem) range->inside=1; + int tmp = id1; + id1 = id2; + id2 = tmp; } - else if (range->inside == 1) /* detect the range end */ + + for (i = 0; i < ih->data->node_count; i++) { - if (range->hItem1 == hItem) end_range=1; - else if (range->hItem2 == hItem) end_range=1; + if (i < id1 || i > id2) + { + if (clear) + winTreeSelectNode(ih, ih->data->node_cache[i].node_handle, 0); + } + else + winTreeSelectNode(ih, ih->data->node_cache[i].node_handle, 1); } - - if (range->inside == 1) /* if inside, select */ - winTreeSelectItem(ih, hItem, 1); - else if (range->clear) /* if outside and clear, unselect */ - winTreeSelectItem(ih, hItem, 0); - - if (end_range || (range->inside && range->hItem1==range->hItem2)) - range->inside=-1; /* update after selecting the node */ - - return 1; -} - -static void winTreeSelectRange(Ihandle* ih, HTREEITEM hItemFrom, HTREEITEM hItemTo, int clear) -{ - winTreeRange range; - range.hItem1 = hItemFrom; - range.hItem2 = hItemTo; - range.inside = 0; - range.clear = (char)clear; - winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectRangeFunc, &range); } static void winTreeSelectAll(Ihandle* ih) @@ -558,9 +412,10 @@ static void winTreeClearSelection(Ihandle* ih, HTREEITEM hItemExcept) winTreeSelectRange(ih, hItemExcept, hItemExcept, 1); } -static int winTreeInvertSelectFunc(Ihandle* ih, HTREEITEM hItem, void* userdata) +static int winTreeInvertSelectFunc(Ihandle* ih, HTREEITEM hItem, int id, void* userdata) { - winTreeSelectItem(ih, hItem, -1); + (void)id; + winTreeSelectNode(ih, hItem, -1); (void)userdata; return 1; } @@ -568,14 +423,11 @@ static int winTreeInvertSelectFunc(Ihandle* ih, HTREEITEM hItem, void* userdata) typedef struct _winTreeSelArray{ Iarray* markedArray; char is_handle; - int id_control; }winTreeSelArray; -static int winTreeSelectedArrayFunc(Ihandle* ih, HTREEITEM hItem, winTreeSelArray* selarray) +static int winTreeSelectedArrayFunc(Ihandle* ih, HTREEITEM hItem, int id, winTreeSelArray* selarray) { - selarray->id_control++; - - if (winTreeIsItemSelected(ih, hItem)) + if (winTreeIsNodeSelected(ih, hItem)) { if (selarray->is_handle) { @@ -587,7 +439,7 @@ static int winTreeSelectedArrayFunc(Ihandle* ih, HTREEITEM hItem, winTreeSelArra { int* intArrayData = (int*)iupArrayInc(selarray->markedArray); int i = iupArrayCount(selarray->markedArray); - intArrayData[i-1] = selarray->id_control; + intArrayData[i-1] = id; } } @@ -599,10 +451,9 @@ static Iarray* winTreeGetSelectedArray(Ihandle* ih) Iarray* markedArray = iupArrayCreate(1, sizeof(HTREEITEM)); winTreeSelArray selarray; selarray.markedArray = markedArray; - selarray.id_control = -1; selarray.is_handle = 1; - winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectedArrayFunc, &selarray); + iupTreeForEach(ih, (iupTreeNodeFunc)winTreeSelectedArrayFunc, &selarray); return markedArray; } @@ -612,10 +463,9 @@ static Iarray* winTreeGetSelectedArrayId(Ihandle* ih) Iarray* markedArray = iupArrayCreate(1, sizeof(int)); winTreeSelArray selarray; selarray.markedArray = markedArray; - selarray.id_control = -1; selarray.is_handle = 0; - winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectedArrayFunc, &selarray); + iupTreeForEach(ih, (iupTreeNodeFunc)winTreeSelectedArrayFunc, &selarray); return markedArray; } @@ -625,7 +475,7 @@ static Iarray* winTreeGetSelectedArrayId(Ihandle* ih) /* COPYING ITEMS (Branches and its children) */ /*****************************************************************************/ /* Insert the copied item in a new location. Returns the new item. */ -static HTREEITEM winTreeCopyItem(Ihandle* ih, HTREEITEM hItem, HTREEITEM hParent, HTREEITEM hPosition, int full_copy) +static HTREEITEM winTreeCopyItem(Ihandle* ih, HTREEITEM hItem, HTREEITEM hParent, HTREEITEM hPosition, int is_copy) { TVITEM item; TVINSERTSTRUCT tvins; @@ -637,34 +487,34 @@ static HTREEITEM winTreeCopyItem(Ihandle* ih, HTREEITEM hItem, HTREEITEM hParent item.cchTextMax = 255; SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); - if (full_copy) /* during a full copy the userdata reference is not copied */ + if (is_copy) /* during a copy the itemdata reference is not reused */ { /* create a new one */ winTreeItemData* itemDataNew = malloc(sizeof(winTreeItemData)); memcpy(itemDataNew, (void*)item.lParam, sizeof(winTreeItemData)); - itemDataNew->userdata = NULL; item.lParam = (LPARAM)itemDataNew; } - /* Copy everything including user data reference */ + /* Copy everything including itemdata reference */ tvins.item = item; tvins.hInsertAfter = hPosition; tvins.hParent = hParent; - /* Add the node to the tree-view control */ + /* Add the new node */ + ih->data->node_count++; return (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); } -static void winTreeCopyChildren(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int full_copy) +static void winTreeCopyChildren(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int is_copy) { HTREEITEM hChildSrc = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItemSrc); - HTREEITEM hNewItem = TVI_FIRST; + HTREEITEM hItemNew = TVI_FIRST; while (hChildSrc != NULL) { - hNewItem = winTreeCopyItem(ih, hChildSrc, hItemDst, hNewItem, full_copy); /* Use the same order they where enumerated */ + hItemNew = winTreeCopyItem(ih, hChildSrc, hItemDst, hItemNew, is_copy); /* Use the same order they where enumerated */ /* Recursively transfer all the items */ - winTreeCopyChildren(ih, hChildSrc, hNewItem, full_copy); + winTreeCopyChildren(ih, hChildSrc, hItemNew, is_copy); /* Go to next sibling item */ hChildSrc = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hChildSrc); @@ -672,11 +522,18 @@ static void winTreeCopyChildren(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItem } /* Copies all items in a branch to a new location. Returns the new branch node. */ -static HTREEITEM winTreeCopyNode(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int full_copy) +static HTREEITEM winTreeCopyMoveNode(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int is_copy) { - HTREEITEM hNewItem, hParent; + HTREEITEM hItemNew, hParent; TVITEM item; winTreeItemData* itemDataDst; + int id_new, count, id_src, id_dst; + + int old_count = ih->data->node_count; + + id_src = iupTreeFindNodeId(ih, hItemSrc); + id_dst = iupTreeFindNodeId(ih, hItemDst); + id_new = id_dst+1; /* contains the position for a copy operation */ /* Get DST node attributes */ item.hItem = hItemDst; @@ -691,31 +548,64 @@ static HTREEITEM winTreeCopyNode(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hIte hItemDst = TVI_FIRST; } else - { + { + if (itemDataDst->kind == ITREE_BRANCH) + { + int child_count = iupdrvTreeTotalChildCount(ih, hItemDst); + id_new += child_count; + } + /* copy as next brother of item or collapsed branch */ hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItemDst); } - hNewItem = winTreeCopyItem(ih, hItemSrc, hParent, hItemDst, full_copy); + /* move to the same place does nothing */ + if (!is_copy && id_new == id_src) + return NULL; + + hItemNew = winTreeCopyItem(ih, hItemSrc, hParent, hItemDst, is_copy); + + winTreeCopyChildren(ih, hItemSrc, hItemNew, is_copy); + + count = ih->data->node_count - old_count; + iupTreeCopyMoveCache(ih, id_src, id_new, count, is_copy); + + if (!is_copy) + { + /* Deleting the node (and its children) from the old position */ + /* do not delete the itemdata, we reuse the references in CopyNode */ + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemSrc); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); - winTreeCopyChildren(ih, hItemSrc, hNewItem, full_copy); + /* restore count, because we remove src */ + ih->data->node_count = old_count; - return hNewItem; + /* compensate position for a move */ + if (id_new > id_src) + id_new -= count; + } + + winTreeRebuildNodeCache(ih, id_new, hItemNew); + + return hItemNew; } /*****************************************************************************/ /* MANIPULATING IMAGES */ /*****************************************************************************/ -static void winTreeUpdateImages(Ihandle* ih, HTREEITEM hItem, int mode) +static void winTreeUpdateImages(Ihandle* ih, int mode) { - HTREEITEM hItemChild; + HTREEITEM hItem; TVITEM item; winTreeItemData* itemData; + int i; /* called when one of the default images is changed */ - - while(hItem != NULL) + for (i = 0; i < ih->data->node_count; i++) { + hItem = ih->data->node_cache[i].node_handle; + /* Get node attributes */ item.hItem = hItem; item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE; @@ -742,10 +632,6 @@ static void winTreeUpdateImages(Ihandle* ih, HTREEITEM hItem, int mode) SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); } } - - /* Recursively traverse child items */ - hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); - winTreeUpdateImages(ih, hItemChild, mode); } else { @@ -756,9 +642,6 @@ static void winTreeUpdateImages(Ihandle* ih, HTREEITEM hItem, int mode) SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); } } - - /* Go to next sibling node */ - hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); } } @@ -828,29 +711,57 @@ static int winTreeCallBranchLeafCb(Ihandle* ih, HTREEITEM hItem) if (itemData->kind == ITREE_BRANCH) { + if (iupAttribGet(ih, "_IUPTREE_IGNORE_BRANCH_CB")) + return IUP_DEFAULT; + if (item.state & TVIS_EXPANDED) { IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); if (cbBranchClose) - return cbBranchClose(ih, winTreeGetNodeId(ih, hItem)); + return cbBranchClose(ih, iupTreeFindNodeId(ih, hItem)); } else { IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB"); if (cbBranchOpen) - return cbBranchOpen(ih, winTreeGetNodeId(ih, hItem)); + return cbBranchOpen(ih, iupTreeFindNodeId(ih, hItem)); } } else { IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); if (cbExecuteLeaf) - return cbExecuteLeaf(ih, winTreeGetNodeId(ih, hItem)); + return cbExecuteLeaf(ih, iupTreeFindNodeId(ih, hItem)); } return IUP_DEFAULT; } +static void winTreeCallMultiUnSelectionCb(Ihandle* ih) +{ + IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTIUNSELECTION_CB"); + IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbSelec || cbMulti) + { + Iarray* markedArray = winTreeGetSelectedArrayId(ih); + int* id_hitem = (int*)iupArrayGetData(markedArray); + int i, count = iupArrayCount(markedArray); + + if (count > 1) + { + if (cbMulti) + cbMulti(ih, id_hitem, iupArrayCount(markedArray)); + else + { + for (i=0; i<count; i++) + cbSelec(ih, id_hitem[i], 0); + } + } + + iupArrayDestroy(markedArray); + } +} + static void winTreeCallMultiSelectionCb(Ihandle* ih) { IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB"); @@ -885,6 +796,8 @@ static void winTreeCallSelectionCb(Ihandle* ih, int status, HTREEITEM hItem) IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); if (cbSelec) { + int id; + if (ih->data->mark_mode == ITREE_MARK_MULTIPLE && IupGetCallback(ih,"MULTISELECTION_CB")) { if ((GetKeyState(VK_SHIFT) & 0x8000)) @@ -894,7 +807,9 @@ static void winTreeCallSelectionCb(Ihandle* ih, int status, HTREEITEM hItem) if (iupAttribGet(ih, "_IUPTREE_IGNORE_SELECTION_CB")) return; - cbSelec(ih, winTreeGetNodeId(ih, hItem), status); + id = iupTreeFindNodeId(ih, hItem); + if (id != -1) + cbSelec(ih, id, status); } } @@ -911,8 +826,8 @@ static int winTreeCallDragDropCb(Ihandle* ih, HTREEITEM hItemDrag, HTREEITEM hIt if (cbDragDrop) { - int drag_id = winTreeGetNodeId(ih, hItemDrag); - int drop_id = winTreeGetNodeId(ih, hItemDrop); + int drag_id = iupTreeFindNodeId(ih, hItemDrag); + int drop_id = iupTreeFindNodeId(ih, hItemDrop); return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl); } @@ -929,8 +844,8 @@ static int winTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) { ih->data->def_image_expanded = (void*)winTreeGetImageIndex(ih, value); - /* Update all images, starting at root node */ - winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_EXPANDED); + /* Update all images */ + winTreeUpdateImages(ih, ITREE_UPDATEIMAGE_EXPANDED); return 1; } @@ -939,8 +854,8 @@ static int winTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) { ih->data->def_image_collapsed = (void*)winTreeGetImageIndex(ih, value); - /* Update all images, starting at root node */ - winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_COLLAPSED); + /* Update all images */ + winTreeUpdateImages(ih, ITREE_UPDATEIMAGE_COLLAPSED); return 1; } @@ -949,8 +864,8 @@ static int winTreeSetImageLeafAttrib(Ihandle* ih, const char* value) { ih->data->def_image_leaf = (void*)winTreeGetImageIndex(ih, value); - /* Update all images, starting at root node */ - winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_LEAF); + /* Update all images */ + winTreeUpdateImages(ih, ITREE_UPDATEIMAGE_LEAF); return 1; } @@ -959,7 +874,7 @@ static int winTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const { TVITEM item; winTreeItemData* itemData; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return 0; @@ -986,7 +901,7 @@ static int winTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* v { TVITEM item; winTreeItemData* itemData; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return 0; @@ -1025,7 +940,7 @@ static int winTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* v static int winTreeSetTopItemAttrib(Ihandle* ih, const char* value) { - HTREEITEM hItem = winTreeFindNodeFromString(ih, value); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, value); if (hItem) SendMessage(ih->handle, TVM_ENSUREVISIBLE, 0, (LPARAM)hItem); return 0; @@ -1056,9 +971,8 @@ static int winTreeSetSpacingAttrib(Ihandle* ih, const char* value) static int winTreeSetExpandAllAttrib(Ihandle* ih, const char* value) { HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); - HTREEITEM hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItemRoot); /* skip the root node that is always expanded */ int expand = iupStrBoolean(value); - winTreeExpandTree(ih, hItem, expand); + winTreeExpandTree(ih, hItemRoot, expand); return 0; } @@ -1131,7 +1045,7 @@ static char* winTreeGetTitle(Ihandle* ih, HTREEITEM hItem) static char* winTreeGetTitleAttrib(Ihandle* ih, const char* name_id) { - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return NULL; return winTreeGetTitle(ih, hItem); @@ -1140,10 +1054,13 @@ static char* winTreeGetTitleAttrib(Ihandle* ih, const char* name_id) static int winTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value) { TVITEM item; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return 0; + if (!value) + value = ""; + item.hItem = hItem; item.mask = TVIF_HANDLE | TVIF_TEXT; item.pszText = (char*)value; @@ -1151,60 +1068,11 @@ static int winTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* v return 0; } -static char* winTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id) -{ - int id; - char* str = (char*)(name_id+1); /* skip ':' */ - void* userdata = NULL; - if (sscanf(str, "%p", &userdata)!=1) - return NULL; - id = winTreeGetUserDataId(ih, userdata); - if (id == -1) - return NULL; - str = iupStrGetMemory(16); - sprintf(str, "%d", id); - return str; -} - -static char* winTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) -{ - TVITEM item; - winTreeItemData* itemData; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); - if (!hItem) - return NULL; - - item.hItem = hItem; - item.mask = TVIF_HANDLE | TVIF_PARAM; - SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); - itemData = (winTreeItemData*)item.lParam; - - return itemData->userdata; -} - -static int winTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) -{ - TVITEM item; - winTreeItemData* itemData; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); - if (!hItem) - return 0; - - item.hItem = hItem; - item.mask = TVIF_HANDLE | TVIF_PARAM; - SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); - itemData = (winTreeItemData*)item.lParam; - - itemData->userdata = (void*)value; - - return 0; -} - static char* winTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) { TVITEM item; winTreeItemData* itemData; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return NULL; @@ -1220,7 +1088,7 @@ static int winTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const cha { TVITEM item; winTreeItemData* itemData; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return 0; @@ -1230,11 +1098,23 @@ static int winTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const cha itemData = (winTreeItemData*)item.lParam; if (value) + { itemData->hFont = iupwinGetHFont(value); + if (itemData->hFont) + { + TV_ITEM item; + item.mask = TVIF_STATE | TVIF_HANDLE | TVIF_TEXT; + item.stateMask = TVIS_BOLD; + item.hItem = hItem; + item.pszText = winTreeGetTitle(ih, hItem); /* reset text to resize item */ + item.state = (strstr(value, "Bold")||strstr(value, "BOLD"))? TVIS_BOLD: 0; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)&item); + } + } else itemData->hFont = NULL; - iupdrvDisplayUpdate(ih); + iupdrvPostRedraw(ih); return 0; } @@ -1259,7 +1139,7 @@ static char* winTreeGetStateAttrib(Ihandle* ih, const char* name_id) { TVITEM item; winTreeItemData* itemData; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return NULL; @@ -1281,25 +1161,34 @@ static char* winTreeGetStateAttrib(Ihandle* ih, const char* name_id) static int winTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value) { - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return 0; - winTreeExpandItem(ih, hItem, iupStrEqualNoCase(value, "EXPANDED")); + /* Get Children: branch or leaf */ + item.mask = TVIF_HANDLE|TVIF_PARAM; + item.hItem = hItem; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + if (itemData->kind == ITREE_BRANCH) + winTreeExpandItem(ih, hItem, iupStrEqualNoCase(value, "EXPANDED")); + return 0; } static char* winTreeGetDepthAttrib(Ihandle* ih, const char* name_id) { - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); - HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); - int depth = 0; + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + int depth = -1; char* str; - if (!hItem) + if (!hItem) return NULL; - while((hItemRoot != hItem) && (hItem != NULL)) + while(hItem != NULL) { hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); depth++; @@ -1314,12 +1203,13 @@ static int winTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char { HTREEITEM hItemDst, hParent, hItemSrc; - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; - hItemSrc = winTreeFindNodeFromString(ih, name_id); + + hItemSrc = iupTreeGetNodeFromString(ih, name_id); if (!hItemSrc) return 0; - hItemDst = winTreeFindNodeFromString(ih, value); + hItemDst = iupTreeGetNodeFromString(ih, value); if (!hItemDst) return 0; @@ -1332,11 +1222,8 @@ static int winTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char return 0; } - /* Copying the node and its children to the new position */ - winTreeCopyNode(ih, hItemSrc, hItemDst, 0); /* not a full copy, preserve user data */ - - /* do not delete the user data, we copy the references in CopyNode */ - SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemSrc); + /* Move the node and its children to the new position */ + winTreeCopyMoveNode(ih, hItemSrc, hItemDst, 0); return 0; } @@ -1345,12 +1232,13 @@ static int winTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char { HTREEITEM hItemDst, hParent, hItemSrc; - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; - hItemSrc = winTreeFindNodeFromString(ih, name_id); + + hItemSrc = iupTreeGetNodeFromString(ih, name_id); if (!hItemSrc) return 0; - hItemDst = winTreeFindNodeFromString(ih, value); + hItemDst = iupTreeGetNodeFromString(ih, value); if (!hItemDst) return 0; @@ -1363,8 +1251,8 @@ static int winTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char return 0; } - /* Copying the node and its children to the new position */ - winTreeCopyNode(ih, hItemSrc, hItemDst, 1); + /* Copy the node and its children to the new position */ + winTreeCopyMoveNode(ih, hItemSrc, hItemDst, 1); return 0; } @@ -1375,7 +1263,7 @@ static char* winTreeGetColorAttrib(Ihandle* ih, const char* name_id) char* str; TVITEM item; winTreeItemData* itemData; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return NULL; @@ -1398,7 +1286,7 @@ static int winTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* v unsigned char r, g, b; TVITEM item; winTreeItemData* itemData; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return 0; @@ -1410,7 +1298,7 @@ static int winTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* v if (iupStrToRGB(value, &r, &g, &b)) { itemData->color = RGB(r,g,b); - iupdrvDisplayUpdate(ih); + iupdrvPostRedraw(ih); } return 0; @@ -1435,7 +1323,7 @@ static char* winTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) { int count; char* str; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return NULL; @@ -1454,18 +1342,11 @@ static char* winTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) return str; } -static char* winTreeGetCountAttrib(Ihandle* ih) -{ - char* str = iupStrGetMemory(10); - sprintf(str, "%d", (int)SendMessage(ih->handle, TVM_GETCOUNT, 0, 0)); - return str; -} - static char* winTreeGetKindAttrib(Ihandle* ih, const char* name_id) { TVITEM item; winTreeItemData* itemData; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return NULL; @@ -1483,7 +1364,7 @@ static char* winTreeGetKindAttrib(Ihandle* ih, const char* name_id) static char* winTreeGetParentAttrib(Ihandle* ih, const char* name_id) { char* str; - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return NULL; @@ -1492,15 +1373,13 @@ static char* winTreeGetParentAttrib(Ihandle* ih, const char* name_id) return NULL; str = iupStrGetMemory(10); - sprintf(str, "%d", winTreeGetNodeId(ih, hItem)); + sprintf(str, "%d", iupTreeFindNodeId(ih, hItem)); return str; } -static void winTreeDelNodeData(Ihandle* ih, HTREEITEM hItem) +static void winTreeRemoveItemData(Ihandle* ih, HTREEITEM hItem, IFns cb, int id) { TVITEM item; - HTREEITEM hChildItem; - item.hItem = hItem; item.mask = TVIF_HANDLE|TVIF_PARAM; if (SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item)) @@ -1508,81 +1387,153 @@ static void winTreeDelNodeData(Ihandle* ih, HTREEITEM hItem) winTreeItemData* itemData = (winTreeItemData*)item.lParam; if (itemData) { - IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB"); - if (cb) cb(ih, winTreeGetNodeId(ih, hItem), (char*)itemData->userdata); + if (cb) + cb(ih, (char*)ih->data->node_cache[id].userdata); + free(itemData); item.lParam = (LPARAM)NULL; SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); } } +} + +static void winTreeRemoveNodeDataRec(Ihandle* ih, HTREEITEM hItem, IFns cb, int *id) +{ + int old_id = *id; - hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + /* Check whether we have child items */ + /* remove from children first */ + HTREEITEM hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); while (hChildItem) { - winTreeDelNodeData(ih, hChildItem); + /* go recursive to children */ + winTreeRemoveNodeDataRec(ih, hChildItem, cb, id); + + /* Go to next sibling item */ hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hChildItem); } + + /* actually do it for the node */ + ih->data->node_count--; + (*id)++; + + winTreeRemoveItemData(ih, hItem, cb, old_id); +} + +static void winTreeRemoveNodeData(Ihandle* ih, HTREEITEM hItem, int call_cb) +{ + IFns cb = call_cb? (IFns)IupGetCallback(ih, "NODEREMOVED_CB"): NULL; + int old_count = ih->data->node_count; + int id = iupTreeFindNodeId(ih, hItem); + int old_id = id; + + winTreeRemoveNodeDataRec(ih, hItem, cb, &id); + + if (call_cb) + iupTreeDelFromCache(ih, old_id, old_count-ih->data->node_count); +} + +static void winTreeRemoveAllNodeData(Ihandle* ih, int call_cb) +{ + IFns cb = call_cb? (IFns)IupGetCallback(ih, "NODEREMOVED_CB"): NULL; + int i, old_count = ih->data->node_count; + HTREEITEM hItem; + + for (i = 0; i < ih->data->node_count; i++) + { + hItem = ih->data->node_cache[i].node_handle; + winTreeRemoveItemData(ih, hItem, cb, i); + } + + ih->data->node_count = 0; + + if (call_cb) + iupTreeDelFromCache(ih, 0, old_count); } static int winTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value) { - if (!ih->handle) /* do not store the action before map */ + if (!ih->handle) /* do not do the action before map */ return 0; - if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */ + if (iupStrEqualNoCase(value, "ALL")) { - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); - HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + winTreeRemoveAllNodeData(ih, 1); - /* the root node can't be deleted */ - if(!hItem || hItem == hItemRoot) + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + return 0; + } + if (iupStrEqualNoCase(value, "SELECTED")) /* selected here means the reference one */ + { + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); + if(!hItem) return 0; - /* deleting the specified node (and it's children) */ - winTreeDelNodeData(ih, hItem); + /* deleting the reference node (and it's children) */ + winTreeRemoveNodeData(ih, hItem, 1); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItem); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); return 0; } - else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */ + else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the reference node */ { - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); HTREEITEM hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); if(!hItem) return 0; - /* deleting the selected node's children */ + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + + /* deleting the reference node children */ while (hChildItem) { - winTreeDelNodeData(ih, hChildItem); + winTreeRemoveNodeData(ih, hChildItem, 1); SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hChildItem); hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); } + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); return 0; } else if(iupStrEqualNoCase(value, "MARKED")) { - int i, count; - Iarray* markedArray; - HTREEITEM* hItemArrayData; - HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + int i, del_focus = 0; + HTREEITEM hItemFocus; - /* Delete the array of marked nodes */ - markedArray = winTreeGetSelectedArray(ih); - hItemArrayData = (HTREEITEM*)iupArrayGetData(markedArray); - count = iupArrayCount(markedArray); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + hItemFocus = iupdrvTreeGetFocusNode(ih); - for(i = 0; i < count; i++) + for(i = 1; i < ih->data->node_count; /* increment only if not removed */) { - if (hItemArrayData[i] != hItemRoot) /* the root node can't be deleted */ + if (winTreeIsNodeSelected(ih, ih->data->node_cache[i].node_handle)) { - winTreeDelNodeData(ih, hItemArrayData[i]); - SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemArrayData[i]); + HTREEITEM hItem = ih->data->node_cache[i].node_handle; + if (hItemFocus == hItem) + { + del_focus = 1; + i++; + } + else + { + winTreeRemoveNodeData(ih, hItem, 1); + SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItem); + } } + else + i++; } - iupArrayDestroy(markedArray); + if (del_focus) + { + winTreeRemoveNodeData(ih, hItemFocus, 1); + SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemFocus); + } + + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); return 0; } @@ -1592,22 +1543,13 @@ static int winTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* static int winTreeSetRenameAttrib(Ihandle* ih, const char* value) { - HTREEITEM hItemFocus = winTreeGetFocusNode(ih); if (ih->data->show_rename) { - IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); - if (cbShowRename) - cbShowRename(ih, winTreeGetNodeId(ih, hItemFocus)); - + HTREEITEM hItemFocus; SetFocus(ih->handle); /* the tree must have focus to activate the edit */ + hItemFocus = iupdrvTreeGetFocusNode(ih); SendMessage(ih->handle, TVM_EDITLABEL, 0, (LPARAM)hItemFocus); } - else - { - IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB"); - if (cbRenameNode) - cbRenameNode(ih, winTreeGetNodeId(ih, hItemFocus), winTreeGetTitle(ih, hItemFocus)); - } (void)value; return 0; @@ -1615,11 +1557,11 @@ static int winTreeSetRenameAttrib(Ihandle* ih, const char* value) static char* winTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) { - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return NULL; - if (winTreeIsItemSelected(ih, hItem)) + if (winTreeIsNodeSelected(ih, hItem)) return "YES"; else return "NO"; @@ -1627,17 +1569,23 @@ static char* winTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) static int winTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value) { - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return 0; - winTreeSelectItem(ih, hItem, iupStrBoolean(value)); + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + { + HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); + winTreeSelectNode(ih, hItemFocus, 0); + } + + winTreeSelectNode(ih, hItem, iupStrBoolean(value)); return 0; } static int winTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) { - HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, name_id); if (!hItem) return 0; @@ -1649,15 +1597,59 @@ static int winTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) static char* winTreeGetValueAttrib(Ihandle* ih) { char* str; - HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); if (!hItemFocus) - return "0"; /* default VALUE is root */ + { + if (ih->data->node_count) + return "0"; /* default VALUE is root */ + else + return "-1"; + } str = iupStrGetMemory(16); - sprintf(str, "%d", winTreeGetNodeId(ih, hItemFocus)); + sprintf(str, "%d", iupTreeFindNodeId(ih, hItemFocus)); + return str; +} + +static char* winTreeGetMarkedNodesAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(ih->data->node_count+1); + int i; + + for (i=0; i<ih->data->node_count; i++) + { + if (winTreeIsNodeSelected(ih, ih->data->node_cache[i].node_handle)) + str[i] = '+'; + else + str[i] = '-'; + } + + str[ih->data->node_count] = 0; return str; } +static int winTreeSetMarkedNodesAttrib(Ihandle* ih, const char* value) +{ + int count, i; + + if (ih->data->mark_mode==ITREE_MARK_SINGLE || !value) + return 0; + + count = strlen(value); + if (count > ih->data->node_count) + count = ih->data->node_count; + + for (i=0; i<count; i++) + { + if (value[i] == '+') + winTreeSelectNode(ih, ih->data->node_cache[i].node_handle, 1); + else + winTreeSelectNode(ih, ih->data->node_cache[i].node_handle, 0); + } + + return 0; +} + static int winTreeSetMarkAttrib(Ihandle* ih, const char* value) { if (ih->data->mark_mode==ITREE_MARK_SINGLE) @@ -1665,7 +1657,7 @@ static int winTreeSetMarkAttrib(Ihandle* ih, const char* value) if(iupStrEqualNoCase(value, "BLOCK")) { - HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); winTreeSelectRange(ih, (HTREEITEM)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"), hItemFocus, 0); } else if(iupStrEqualNoCase(value, "CLEARALL")) @@ -1673,14 +1665,14 @@ static int winTreeSetMarkAttrib(Ihandle* ih, const char* value) else if(iupStrEqualNoCase(value, "MARKALL")) winTreeSelectAll(ih); else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */ - winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeInvertSelectFunc, NULL); + iupTreeForEach(ih, (iupTreeNodeFunc)winTreeInvertSelectFunc, NULL); else if(iupStrEqualPartial(value, "INVERT")) /* iupStrEqualPartial allows the use of "INVERTid" form */ { - HTREEITEM hItem = winTreeFindNodeFromString(ih, &value[strlen("INVERT")]); + HTREEITEM hItem = iupTreeGetNodeFromString(ih, &value[strlen("INVERT")]); if (!hItem) return 0; - winTreeSelectItem(ih, hItem, -1); /* toggle */ + winTreeSelectNode(ih, hItem, -1); /* toggle */ } else { @@ -1690,10 +1682,10 @@ static int winTreeSetMarkAttrib(Ihandle* ih, const char* value) if (iupStrToStrStr(value, str1, str2, '-')!=2) return 0; - hItem1 = winTreeFindNodeFromString(ih, str1); + hItem1 = iupTreeGetNodeFromString(ih, str1); if (!hItem1) return 0; - hItem2 = winTreeFindNodeFromString(ih, str2); + hItem2 = iupTreeGetNodeFromString(ih, str2); if (!hItem2) return 0; @@ -1711,9 +1703,9 @@ static int winTreeSetValueAttrib(Ihandle* ih, const char* value) if (winTreeSetMarkAttrib(ih, value)) return 0; - hItemFocus = winTreeGetFocusNode(ih); + hItemFocus = iupdrvTreeGetFocusNode(ih); - if(iupStrEqualNoCase(value, "ROOT")) + if(iupStrEqualNoCase(value, "ROOT") || iupStrEqualNoCase(value, "FIRST")) hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); else if(iupStrEqualNoCase(value, "LAST")) hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0); @@ -1759,15 +1751,14 @@ static int winTreeSetValueAttrib(Ihandle* ih, const char* value) else if(iupStrEqualNoCase(value, "PREVIOUS")) hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemFocus); else - hItem = winTreeFindNodeFromString(ih, value); + hItem = iupTreeGetNodeFromString(ih, value); if (hItem) { if (ih->data->mark_mode==ITREE_MARK_SINGLE) { - iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); - winTreeSelectItem(ih, hItem, 1); - iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + winTreeSelectNode(ih, hItemFocus, 0); + winTreeSelectNode(ih, hItem, 1); } winTreeSetFocusNode(ih, hItem); } @@ -1832,27 +1823,60 @@ static LRESULT CALLBACK winTreeEditWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARA return CallWindowProc(oldProc, hwnd, msg, wp, lp); } -static void winTreeDrag(Ihandle* ih, int x, int y) +static void winTreeBeginDrag(Ihandle* ih, int x, int y) { - HTREEITEM hItemDrop; + HIMAGELIST dragImageList; + + HTREEITEM hItemDrag = winTreeFindNodeXY(ih, x, y); + if (!hItemDrag) + return; + + SendMessage(ih->handle, TVM_ENDEDITLABELNOW, TRUE, 0); + + /* store the drag-and-drop item */ + iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", (char*)hItemDrag); + /* get the image list for dragging */ + dragImageList = (HIMAGELIST)SendMessage(ih->handle, TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItemDrag); + if (dragImageList) + { + POINT pt; + ImageList_BeginDrag(dragImageList, 0, 0, 0); + + pt.x = x; + pt.y = y; + + ClientToScreen(ih->handle, &pt); + ImageList_DragEnter(NULL, pt.x, pt.y); + + iupAttribSetStr(ih, "_IUPTREE_DRAGIMAGELIST", (char*)dragImageList); + } + + ShowCursor(FALSE); + SetCapture(ih->handle); /* drag only inside the tree */ +} + +static void winTreeDrag(Ihandle* ih, int x, int y) +{ + HTREEITEM hItemDrop = winTreeFindNodeXY(ih, x, y); + HTREEITEM hItemDrag = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM"); HIMAGELIST dragImageList = (HIMAGELIST)iupAttribGet(ih, "_IUPTREE_DRAGIMAGELIST"); + if (dragImageList) { - POINT pnt; - pnt.x = x; - pnt.y = y; - GetCursorPos(&pnt); - ClientToScreen(GetDesktopWindow(), &pnt) ; - ImageList_DragMove(pnt.x, pnt.y); + POINT pt; + pt.x = x; + pt.y = y; + ClientToScreen(ih->handle, &pt); + ImageList_DragMove(pt.x, pt.y); } - if ((hItemDrop = winTreeFindNodePointed(ih)) != NULL) + if (hItemDrop && hItemDrop!=hItemDrag) { if(dragImageList) ImageList_DragShowNolock(FALSE); - SendMessage(ih->handle, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)hItemDrop); + SendMessage(ih->handle, TVM_SETINSERTMARK, TRUE, (LPARAM)hItemDrop); /* store the drop item to be executed */ iupAttribSetStr(ih, "_IUPTREE_DROPITEM", (char*)hItemDrop); @@ -1860,6 +1884,8 @@ static void winTreeDrag(Ihandle* ih, int x, int y) if(dragImageList) ImageList_DragShowNolock(TRUE); } + else + iupAttribSetStr(ih, "_IUPTREE_DROPITEM", NULL); } static void winTreeDrop(Ihandle* ih) @@ -1882,7 +1908,7 @@ static void winTreeDrop(Ihandle* ih) ShowCursor(TRUE); /* Remove drop target highlighting */ - SendMessage(ih->handle, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)NULL); + SendMessage(ih->handle, TVM_SETINSERTMARK, 0, (LPARAM)NULL); iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", NULL); iupAttribSetStr(ih, "_IUPTREE_DROPITEM", NULL); @@ -1901,16 +1927,12 @@ static void winTreeDrop(Ihandle* ih) if (winTreeCallDragDropCb(ih, hItemDrag, hItemDrop, &is_ctrl) == IUP_CONTINUE) { - /* Copy the dragged item to the new position. */ - HTREEITEM hItemNew = winTreeCopyNode(ih, hItemDrag, hItemDrop, is_ctrl); - - if (!is_ctrl) - { - /* do not delete the user data, we copy the references in CopyNode */ - SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemDrag); - } + /* Copy or move the dragged item to the new position. */ + HTREEITEM hItemNew = winTreeCopyMoveNode(ih, hItemDrag, hItemDrop, is_ctrl); - SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItemNew); /* set focus and selection */ + /* Set focus and selection */ + if (hItemNew) + SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItemNew); } } @@ -1929,9 +1951,7 @@ static void winTreeExtendSelect(Ihandle* ih, int x, int y) hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM"); if (hItemFirstSel) { - iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); winTreeSelectRange(ih, hItemFirstSel, hItem, 1); - iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); iupAttribSetStr(ih, "_IUPTREE_LASTSELITEM", (char*)hItem); winTreeSetFocusNode(ih, hItem); @@ -1952,10 +1972,10 @@ static int winTreeMouseMultiSelect(Ihandle* ih, int x, int y) if (GetKeyState(VK_CONTROL) & 0x8000) /* Control key is down */ { /* Toggle selection state */ - winTreeSelectItem(ih, hItem, -1); + winTreeSelectNode(ih, hItem, -1); iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItem); - winTreeCallSelectionCb(ih, winTreeIsItemSelected(ih, hItem), hItem); + winTreeCallSelectionCb(ih, winTreeIsNodeSelected(ih, hItem), hItem); winTreeSetFocusNode(ih, hItem); return 1; @@ -1965,9 +1985,11 @@ static int winTreeMouseMultiSelect(Ihandle* ih, int x, int y) HTREEITEM hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM"); if (hItemFirstSel) { - iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + int last_id = iupTreeFindNodeId(ih, hItem); winTreeSelectRange(ih, hItemFirstSel, hItem, 1); - iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + + /* if last selected item is a branch, then select its children */ + iupTreeSelectLastCollapsedBranch(ih, &last_id); winTreeCallMultiSelectionCb(ih); winTreeSetFocusNode(ih, hItem); @@ -1975,11 +1997,15 @@ static int winTreeMouseMultiSelect(Ihandle* ih, int x, int y) } } + winTreeCallMultiUnSelectionCb(ih); + /* simple click */ winTreeClearSelection(ih, hItem); iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItem); iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1"); + /* Call SELECT_CB for all unselected nodes */ + return 0; } @@ -2039,7 +2065,7 @@ static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res if (wp == VK_RETURN) { - HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); if (winTreeCallBranchLeafCb(ih, hItemFocus) != IUP_IGNORE) winTreeExpandItem(ih, hItemFocus, -1); @@ -2056,14 +2082,14 @@ static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res { if (GetKeyState(VK_CONTROL) & 0x8000) { - HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); /* Toggle selection state */ - winTreeSelectItem(ih, hItemFocus, -1); + winTreeSelectNode(ih, hItemFocus, -1); } } else if (wp == VK_UP || wp == VK_DOWN) { - HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); if (wp == VK_UP) hItemFocus = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemFocus); else @@ -2084,9 +2110,7 @@ static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res HTREEITEM hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM"); if (hItemFirstSel) { - iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); winTreeSelectRange(ih, hItemFirstSel, hItemFocus, 1); - iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); winTreeCallMultiSelectionCb(ih); winTreeSetFocusNode(ih, hItemFocus); @@ -2138,10 +2162,20 @@ static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res } break; case WM_MOUSEMOVE: - if (ih->data->show_dragdrop && (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM") != NULL) - winTreeDrag(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); + if (ih->data->show_dragdrop && (wp & MK_LBUTTON)) + { + if (!iupAttribGet(ih, "_IUPTREE_DRAGITEM")) + winTreeBeginDrag(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); + else + winTreeDrag(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); + } else if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT")) - winTreeExtendSelect(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); + { + if (wp & MK_LBUTTON) + winTreeExtendSelect(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); + else + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", NULL); + } iupwinMouseMove(ih, msg, wp, lp); break; @@ -2157,6 +2191,7 @@ static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT")) { iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", NULL); + if (iupAttribGet(ih, "_IUPTREE_LASTSELITEM")) { winTreeCallMultiSelectionCb(ih); @@ -2205,14 +2240,19 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) else if (msg_info->code == TVN_SELCHANGED) { NMTREEVIEW* info = (NMTREEVIEW*)msg_info; - winTreeCallSelectionCb(ih, 0, info->itemOld.hItem); /* node unselected */ - winTreeCallSelectionCb(ih, 1, info->itemNew.hItem); /* node selected */ + if (ih->data->mark_mode!=ITREE_MARK_MULTIPLE || /* (NOT) Multiple selection with Control or Shift key is down */ + !(GetKeyState(VK_CONTROL) & 0x8000 || GetKeyState(VK_SHIFT) & 0x8000)) + { + winTreeCallSelectionCb(ih, 0, info->itemOld.hItem); /* node unselected */ + winTreeCallSelectionCb(ih, 1, info->itemNew.hItem); /* node selected */ + } } else if(msg_info->code == TVN_BEGINLABELEDIT) { char* value; HWND hEdit; NMTVDISPINFO* info = (NMTVDISPINFO*)msg_info; + IFni cbShowRename; if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT")) { @@ -2220,6 +2260,13 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) return 1; } + cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); + if (cbShowRename && cbShowRename(ih, iupTreeFindNodeId(ih, info->item.hItem))==IUP_IGNORE) + { + *result = TRUE; /* prevent the change */ + return 1; + } + hEdit = (HWND)SendMessage(ih->handle, TVM_GETEDITCONTROL, 0, 0); /* save the edit box. */ @@ -2253,57 +2300,30 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) } else if(msg_info->code == TVN_ENDLABELEDIT) { + IFnis cbRename; NMTVDISPINFO* info = (NMTVDISPINFO*)msg_info; iupAttribSetStr(ih, "_IUPWIN_EDITBOX", NULL); - if (info->item.pszText) - { - IFnis cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); - if (cbRename) - { - if (cbRename(ih, winTreeGetNodeId(ih, info->item.hItem), info->item.pszText) == IUP_IGNORE) - { - *result = FALSE; - return 1; - } - } + if (!info->item.pszText) /* cancel, so abort */ + return 0; - *result = TRUE; - return 1; - } - } - else if(msg_info->code == TVN_BEGINDRAG) - { - if (ih->data->show_dragdrop) + cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); + if (cbRename) { - NMTREEVIEW* pNMTreeView = (NMTREEVIEW*)msg_info; - HTREEITEM hItemDrag = pNMTreeView->itemNew.hItem; - HIMAGELIST dragImageList; - - /* store the drag-and-drop item */ - iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", (char*)hItemDrag); - - /* get the image list for dragging */ - dragImageList = (HIMAGELIST)SendMessage(ih->handle, TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItemDrag); - if (dragImageList) + if (cbRename(ih, iupTreeFindNodeId(ih, info->item.hItem), info->item.pszText) == IUP_IGNORE) { - POINT pt = pNMTreeView->ptDrag; - ImageList_BeginDrag(dragImageList, 0, 0, 0); - - ClientToScreen(ih->handle, &pt); - ImageList_DragEnter(NULL, pt.x, pt.y); - - iupAttribSetStr(ih, "_IUPTREE_DRAGIMAGELIST", (char*)dragImageList); + *result = FALSE; + return 1; } - - ShowCursor(FALSE); - SetCapture(ih->handle); /* drag only inside the tree */ } + + *result = TRUE; + return 1; } else if(msg_info->code == NM_DBLCLK) { - HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + HTREEITEM hItemFocus = iupdrvTreeGetFocusNode(ih); TVITEM item; winTreeItemData* itemData; @@ -2317,7 +2337,7 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) { IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); if(cbExecuteLeaf) - cbExecuteLeaf(ih, winTreeGetNodeId(ih, hItemFocus)); + cbExecuteLeaf(ih, iupTreeFindNodeId(ih, hItemFocus)); } } else if(msg_info->code == TVN_ITEMEXPANDING) @@ -2351,7 +2371,7 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) HTREEITEM hItem = winTreeFindNodePointed(ih); IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB"); if (cbRightClick) - cbRightClick(ih, winTreeGetNodeId(ih, hItem)); + cbRightClick(ih, iupTreeFindNodeId(ih, hItem)); } else if (msg_info->code == NM_CUSTOMDRAW) { @@ -2374,7 +2394,7 @@ static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); itemData = (winTreeItemData*)item.lParam; - if (winTreeIsItemSelected(ih, hItem)) + if (GetFocus()==ih->handle && (customdraw->nmcd.uItemState & CDIS_SELECTED)) customdraw->clrText = winTreeInvertColor(itemData->color); else customdraw->clrText = itemData->color; @@ -2402,47 +2422,34 @@ static int winTreeConvertXYToPos(Ihandle* ih, int x, int y) info.pt.y = y; hItem = (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)&info); if (hItem) - return winTreeGetNodeId(ih, hItem); + return iupTreeFindNodeId(ih, hItem); return -1; } /*******************************************************************************************/ -static void winTreeUnMapMethod(Ihandle* ih) -{ - Iarray* bmp_array; - HIMAGELIST image_list; - - HTREEITEM itemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); - winTreeDelNodeData(ih, itemRoot); - - image_list = (HIMAGELIST)SendMessage(ih->handle, TVM_GETIMAGELIST, TVSIL_NORMAL, 0); - if (image_list) - ImageList_Destroy(image_list); - - bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY"); - if (bmp_array) - iupArrayDestroy(bmp_array); - - iupdrvBaseUnMapMethod(ih); -} static int winTreeMapMethod(Ihandle* ih) { - DWORD dwStyle = WS_CHILD | WS_BORDER | TVS_SHOWSELALWAYS; + DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_BORDER | TVS_SHOWSELALWAYS; - /* can be set only on the Tree View creation */ + /* styles can be set only on the Tree View creation */ - if (!ih->data->show_dragdrop) - dwStyle |= TVS_DISABLEDRAGDROP; + /* always disable the internal drag&drop, because it affects our selection and drawing */ + dwStyle |= TVS_DISABLEDRAGDROP; if (ih->data->show_rename) dwStyle |= TVS_EDITLABELS; if (!iupAttribGetBoolean(ih, "HIDELINES")) + { dwStyle |= TVS_HASLINES; + if (!iupAttribGetInt(ih, "ADDROOT")) + dwStyle |= TVS_LINESATROOT; + } + if (!iupAttribGetBoolean(ih, "HIDEBUTTONS")) dwStyle |= TVS_HASBUTTONS; @@ -2455,6 +2462,11 @@ static int winTreeMapMethod(Ihandle* ih) if (!iupwinCreateWindowEx(ih, WC_TREEVIEW, 0, dwStyle)) return IUP_ERROR; + if (!iupwin_comctl32ver6) /* To improve drawing of items when TITLEFONT is set */ + SendMessage(ih->handle, CCM_SETVERSION, 5, 0); + else + SendMessage(ih->handle, TVM_SETEXTENDEDSTYLE, TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTreeProc); IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTreeWmNotify); @@ -2466,7 +2478,7 @@ static int winTreeMapMethod(Ihandle* ih) winTreeSetBgColorAttrib(ih, value); iupAttribSetStr(ih, "BGCOLOR", NULL); } - else if (iupwinGetSystemMajorVersion()<6) /* force background in XP because of the editbox background */ + else if (!iupwin_comctl32ver6 || iupwinGetSystemMajorVersion()<6) /* force background in XP because of the editbox background */ winTreeSetBgColorAttrib(ih, IupGetGlobal("TXTBGCOLOR")); } @@ -2475,8 +2487,8 @@ static int winTreeMapMethod(Ihandle* ih) ih->data->def_image_collapsed = (void*)winTreeGetImageIndex(ih, "IMGCOLLAPSED"); ih->data->def_image_expanded = (void*)winTreeGetImageIndex(ih, "IMGEXPANDED"); - /* Add the Root Node */ - winTreeAddRootNode(ih); + if (iupAttribGetInt(ih, "ADDROOT")) + iupdrvTreeAddNode(ih, "-1", ITREE_BRANCH, "", 0); /* configure for DRAG&DROP of files */ if (IupGetCallback(ih, "DROPFILES_CB")) @@ -2484,9 +2496,31 @@ static int winTreeMapMethod(Ihandle* ih) IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winTreeConvertXYToPos); + iupdrvTreeUpdateMarkMode(ih); + return IUP_NOERROR; } +static void winTreeUnMapMethod(Ihandle* ih) +{ + Iarray* bmp_array; + HIMAGELIST image_list; + + winTreeRemoveAllNodeData(ih, 0); + + ih->data->node_count = 0; + + image_list = (HIMAGELIST)SendMessage(ih->handle, TVM_GETIMAGELIST, TVSIL_NORMAL, 0); + if (image_list) + ImageList_Destroy(image_list); + + bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY"); + if (bmp_array) + iupArrayDestroy(bmp_array); + + iupdrvBaseUnMapMethod(ih); +} + void iupdrvTreeInitClass(Iclass* ic) { /* Driver Dependent Class functions */ @@ -2500,7 +2534,6 @@ void iupdrvTreeInitClass(Iclass* ic) /* IupTree Attributes - GENERAL */ iupClassRegisterAttribute(ic, "EXPANDALL", NULL, winTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "INDENTATION", winTreeGetIndentationAttrib, winTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT); - iupClassRegisterAttribute(ic, "COUNT", winTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, winTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); iupClassRegisterAttribute(ic, "TOPITEM", NULL, winTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); @@ -2521,7 +2554,6 @@ void iupdrvTreeInitClass(Iclass* ic) iupClassRegisterAttributeId(ic, "NAME", winTreeGetTitleAttrib, winTreeSetTitleAttrib, IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "TITLE", winTreeGetTitleAttrib, winTreeSetTitleAttrib, IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "CHILDCOUNT", winTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); - iupClassRegisterAttributeId(ic, "USERDATA", winTreeGetUserDataAttrib, winTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "COLOR", winTreeGetColorAttrib, winTreeSetColorAttrib, IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "TITLEFONT", winTreeGetTitleFontAttrib, winTreeSetTitleFontAttrib, IUPAF_NO_INHERIT); @@ -2530,6 +2562,7 @@ void iupdrvTreeInitClass(Iclass* ic) iupClassRegisterAttribute (ic, "MARK", NULL, winTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute (ic, "STARTING", NULL, winTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); iupClassRegisterAttribute (ic, "MARKSTART", NULL, winTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARKEDNODES", winTreeGetMarkedNodesAttrib, winTreeSetMarkedNodesAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); iupClassRegisterAttribute (ic, "VALUE", winTreeGetValueAttrib, winTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); @@ -2538,5 +2571,8 @@ void iupdrvTreeInitClass(Iclass* ic) iupClassRegisterAttribute(ic, "RENAME", NULL, winTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "MOVENODE", NULL, winTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttributeId(ic, "COPYNODE", NULL, winTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); - iupClassRegisterAttributeId(ic, "FINDUSERDATA", winTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + + /* necessary because transparent background does not work when not using visual styles */ + if (!iupwin_comctl32ver6) /* Used by iupdrvImageCreateImage */ + iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); } diff --git a/iup/src/win/iupwin_val.c b/iup/src/win/iupwin_val.c index 706c612..5c956d9 100755 --- a/iup/src/win/iupwin_val.c +++ b/iup/src/win/iupwin_val.c @@ -56,6 +56,13 @@ void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h) } } +static int winValSetBgColorAttrib(Ihandle *ih, const char *value) +{ + (void)value; + iupdrvPostRedraw(ih); + return 1; +} + static int winValSetStepAttrib(Ihandle* ih, const char* value) { int linesize; @@ -110,18 +117,6 @@ static int winValSetValueAttrib(Ihandle* ih, const char* value) /*********************************************************************************************/ -static int winValCtlColor(Ihandle* ih, HDC hdc, LRESULT *result) -{ - COLORREF cr; - if (iupwinGetParentBgColor(ih, &cr)) - { - SetDCBrushColor(hdc, cr); - *result = (LRESULT)GetStockObject(DC_BRUSH); - return 1; - } - return 0; -} - static int winValCustomScroll(Ihandle* ih, int msg) { double old_val = ih->data->val; @@ -190,6 +185,19 @@ static void winValIncPageValue(Ihandle *ih, int dir) winValCustomScroll(ih, 0); } +static int winValCtlColor(Ihandle* ih, HDC hdc, LRESULT *result) +{ + COLORREF cr; + if (iupwinGetParentBgColor(ih, &cr)) + { + SetBkColor(hdc, cr); + SetDCBrushColor(hdc, cr); + *result = (LRESULT)GetStockObject(DC_BRUSH); + return 1; + } + return 0; +} + static int winValProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) { (void)lp; @@ -240,7 +248,7 @@ static int winValProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *resu static int winValMapMethod(Ihandle* ih) { - DWORD dwStyle = WS_CHILD | TBS_AUTOTICKS; + DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | TBS_AUTOTICKS; int show_ticks; if (!ih->parent) @@ -312,4 +320,7 @@ void iupdrvValInitClass(Iclass* ic) iupClassRegisterAttribute(ic, "STEP", iupValGetStepAttrib, winValSetStepAttrib, "0.01", NULL, IUPAF_NO_INHERIT); /* force new default value */ iupClassRegisterAttribute(ic, "TICKSPOS", NULL, NULL, "NORMAL", NULL, IUPAF_NOT_MAPPED); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winValSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); } |